65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET (Web Form / MVC) 中使用 Mustache.js 的客户端模板

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2014 年 5 月 21 日

CPOL

7分钟阅读

viewsIcon

38224

downloadIcon

728

本文将介绍如何在 ASP.NET (Web Form / MVC) 中使用 Mustache.js 进行客户端模板开发。

引言

对于小段标记的生成,string 连接方法是一种有效的方式。随着标记量的增长,它会增加连接代码的复杂性,导致难以维护。

客户端模板是简单的 string 连接的强大替代方案,它允许您以一种非常易于维护的方式快速有效地将 JSON 数据转换为 HTML。客户端模板通过将简单的 HTML 与数据表达式相结合来定义可重用的标记部分,这些表达式的范围可以是从简单的占位符(用数据值替换)到能够直接在模板中执行更强大的数据处理的完整 JavaScript 逻辑。

Mustache (模板系统)

Mustache 是一个开源的 Web 模板系统,为 ActionScript、C++、Clojure、CoffeeScript、ColdFusion、D、Erlang、Fantom、Go、Java、JavaScript、Lua、.NET、Objective-C、Perl、PHP、Python、Ruby、Scala 和 XQuery 等语言开发。

您可以通过访问 http://mustache.github.io/. 来获取该库。Mustache 是“无逻辑”的模板语法。“无逻辑”意味着它不依赖于过程式语句(ifelsefor 等):Mustache 模板完全由标签定义。它之所以命名为“Mustache”,是因为大量使用了类似于胡子的花括号。Mustache 主要用于移动和 Web 应用程序。

Mustache.js 与 ASP.NET Web Form

本文的这一部分将介绍如何在 Web Form 中使用客户端模板,而不是 string 连接。那么,让我们开始吧。首先,创建一个将使用 string 连接来显示 person 详细信息的 Web Form。创建一个 Person 类,用于在 Web 上显示人员列表。

namespace MustacheTemplate
{
    public class Person
    {
        public int PersonID { get; set; }
        public string Name { get; set; }
        public bool Registered { get; set; }
    }
}

定义一个 Web 方法,该方法将从 Web Form 的后台页面返回人员列表。

using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Web.Services;
 
namespace MustacheTemplate
{
    public partial class ShowTemplate : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
 
        }
        [WebMethod]
        public static string GetAllPerson()
        {
            var RegisteredUsers = new List<Person>();
            RegisteredUsers.Add(new Person() { PersonID = 1, Name = "Sandeep Singh", 
            Registered = true });
            RegisteredUsers.Add(new Person() { PersonID = 2, Name = "Raviender Singh", 
            Registered = false });
            RegisteredUsers.Add(new Person() { PersonID = 3, Name = "Hameer Singh", 
            Registered = true });
            RegisteredUsers.Add(new Person() { PersonID = 4, Name = "Kuldepp Singh", 
            Registered = false });
            JavaScriptSerializer js = new JavaScriptSerializer();
            return js.Serialize(RegisteredUsers);            
        }
    }
}

现在定义渲染 Web 上 person 列表的 Web Form。以下代码段是一个 Web Form。

<%@ Page Language="C#" AutoEventWireup="true" 
CodeBehind="ShowTemplate.aspx.cs" Inherits="MustacheTemplate.ShowTemplate" %>
<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-2.1.0.min.js"></script>    
    <script type="text/javascript">
        $(document).ready(function ()
        {
            var tablePerson = $("#tblPerson");
            var divPerson = $("#divPerson");
            $.ajax({
                cache: false,
                type: "POST",
                url: "ShowTemplate.aspx/GetAllPerson",
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data)
                {
                    var personList = JSON.parse(data.d);
                    $.each(personList, function (id, person)
                    {
                        var personRow = "<tr><td>" + person.PersonID + "</td>" +
                            "<td>" + person.Name + "</td>" +
                            "<td>" + person.Registered + "</td></tr>";
                        tablePerson.append(personRow);
                    });
                },
                error: function (xhr, ajaxOptions, thrownError)
                {
                    alert('Failed to retrieve person list.');
                }
            });
        });
    </script>    
</head>
<body>
    <form id="form1" runat="server">
    <table id="tblPerson" border="1" style="border-collapse:collapse">
        <tr>            
            <th>Id</th>
            <th>Name</th>
            <th>Registered</th>
        </tr>
    </table>
    </form>
</body>
</html>

现在,运行应用程序,您将得到如图 1.1 所示的结果。

Person list

图 1.1 人员列表

请注意,在 Web Form 代码中,您正在连接一个 string 来显示人员详细信息。这是一小段标记,所以看起来并不复杂,但当您开发复杂的标记时,它将不易于维护和阅读,因此您需要为其定义一个单独的模板,并在 Web Form 中需要它的地方调用它。那么,让我们看一下模板的代码。

以下代码段是一个 Mustache 模板,它将显示 person 的详细信息。

<script type="text/template" id="tempPerson">        
    <tr>
       <td>{{PersonID}}</td>
       <td> {{Name}}</td>
       <td>{{Registered}}</td>
    </tr>        
</script>

以下代码段在 JavaScript 中渲染上述 Mustache 模板。

function (id, person) 
{
  var template = $('#tempPerson').html();
  var html = Mustache.render(template, person);
}

以下代码段是使用 Mustache 模板并在 Web 上渲染它的 Web Form。您的 Person 类和 get Person list 方法将与之前的相同。

<%@ Page Language="C#" AutoEventWireup="true" 
CodeBehind="MustacheExample.aspx.cs" 
Inherits="MustacheTemplate.MustacheExample" %>
 
<!DOCTYPE html>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <script src="Scripts/jquery-2.1.0.min.js"></script>
    <script src="Scripts/mustache.js"></script>    
    <script type="text/javascript">
        $(document).ready(function ()
        {
            var tablePerson = $("#tblPerson");
            var divPerson = $("#divPerson");
            $.ajax({
                cache: false,
                type: "POST",
                url: "ShowTemplate.aspx/GetAllPerson",
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data)
                {
                    var personList = JSON.parse(data.d);
                    $.each(personList, function (id, person)
                    {
                        var template = $('#tempPerson').html();
                        var html = Mustache.render(template, person);
                        tablePerson.append(html);
                    });
                },
                error: function (xhr, ajaxOptions, thrownError)
                {
                    alert('Failed to retrieve person list.');
                }
            });
        });
    </script>    
    <script type="text/template" id="Script1">        
        <tr>
            <td>{{PersonID}}</td>
            <td> {{Name}}</td>
            <td>{{Registered}}</td>
        </tr>        
    </script>
 
</head>
<body>
    <form id="form2" runat="server">
    <table id="Table1" border="1" style="border-collapse:collapse">
        <tr>            
            <th>Id</th>
            <th>Name</th>
            <th>Registered</th>
        </tr>
    </table>
    </form>
</body>
</html>

让我们运行应用程序,您将得到与图 1.1 相同的结果。

现在您只想显示注册用户;即 Registered 属性为 true 的注册用户。然后,您需要按以下方式修改您的模板。

 <script type="text/template" id=" tempPerson">
    {{#Registered}}
     <tr>
        <td>{{PersonID}}</td>
        <td> {{Name}}</td>
        <td>{{Registered}}</td>
     </tr>
    {{/Registered}}
</script>

上面的代码仅返回 Registered 属性为 true 的两个 person 的详细信息。您将条件添加到模板中,而无需 ifelse;这就是为什么它被称为“无逻辑”。

Mustache.js 与 ASP.NET MVC

在前一篇文章 “在 ASP.Net MVC 中使用 AJAX 渲染部分视图和 JSON 数据” 中,我向您介绍了在 ASP.NET MVC 中渲染 JSON 数据的概念,当时我使用了 string 连接方法,但本文的这一部分将介绍如何在 ASP.NET MVC 应用程序中使用 Mustache 客户端模板,而不是 string 连接。我将通过一个简单的例子来解释这个概念。这个例子是根据发布者在 Web 上显示书籍。我从下拉列表中选择一个发布者,然后在 Web 页面上根据发布者显示书籍信息。那么,让我们详细看看这个例子。

入门

我向应用程序添加了 ADO.NET Entity Model,以执行从“Development”数据库映射的数据库操作。ADO.NET Entity Model 是一个对象关系映射 (ORM),它在 ADO.NET 组件之上创建了一个更高的 abstract 对象模型。这个 ADO.NET Entity Model 被映射到“Development”数据库,因此上下文类是“DevelopmentEntities”,它继承自 DbContext 类。

这个“Development”数据库有两个表,一个是 Publisher 表,另一个是 BOOK 表。表之间是 1 对多关系,换句话说,一个发布者可以出版多本书,但每本书都与一个发布者相关联。如果您想了解更多关于此应用程序数据库设计的信息,请查看我之前的文章 “使用 LINQ to SQL 的简单 MVC 应用程序”。

ADO.NET Entity Model 已映射到这两个表。这的连接字符串的名称与上下文类名称相同,并且此连接字符串在 web.config 文件中创建。您可以更改连接字符串的名称。上下文类名称和连接字符串名称只是一种约定,而不是配置,因此您可以将其更改为一个有意义的名称。下图 1.2 显示了 ADO.NET Entity Model 与两个表的映射。

 The ADO.NET Entity Model mapping with Publisher and Book tables

图 1.2 ADO.NET Entity Model 与 Publisher 和 Book 表的映射

现在 ADO.NET Entity Model 已为应用程序准备就绪,是时候进行应用程序的下一步,即模型设计了,所以让我们看看应用程序的模型。

模型设计

正如您已经知道的,应用程序的目的是创建两个实体(PublisherBOOK),我已经创建了相同的实体,因此我需要创建两个模型,一个用于发布者,另一个用于书籍。我在 Model 文件夹下创建一个发布者模型 (Publisher.cs),该模型具有发布者 ID 和发布者列表,如下面的代码片段所示。

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace MustacheMVCApplication.Models
{
    public class PublisherModel
    {
        public PublisherModel()
        {
            PublisherList = new List<SelectListItem>();
        }
 
        [Display(Name = "Publisher")]
        public int Id { get; set; }
        public IEnumerable<SelectListItem> PublisherList { get; set; }
    }
}

发布者模型之后,我在同一文件夹下创建一个图书模型 (Book.cs),该模型具有与图书相关的基本属性。以下是图书模型的代码片段。

namespace MustacheMVCApplication.Models
{
    public class BookModel
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string Year { get; set; }
        public decimal Price { get; set; }
    }
}

现在模型已准备就绪,可以继续进行控制器设计了。

控制器设计

我创建了两个控制器,一个用于发布者,它在下拉列表中显示发布者列表;另一个是图书控制器,它根据发布者显示图书详细信息。发布者控制器定义了一个操作方法,该方法在两个概念中都是相同的;渲染部分视图和 JSON 数据,图书控制器也定义了一个操作方法,该方法渲染 JSON 数据。

现在,按照 MVC 的约定,在 Controllers 文件夹下创建一个发布者控制器 (PublisherController.cs)。此控制器有一个操作方法,用于在视图中显示发布者列表。以下是发布者控制器的代码片段。

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MustacheMVCApplication.Models;
 
namespace MustacheMVCApplication.Controllers
{
    public class PublisherController : Controller
    {
        public ActionResult Index()
        {
            PublisherModel model = new PublisherModel();
            using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
            {
                List<DAL.Publisher> PublisherList = context.Publishers.ToList();
                model.PublisherList = PublisherList.Select(x =>
                                        new SelectListItem()
                                        {
                                            Text = x.Name,
                                            Value = x.Id.ToString()
                                        });
                                 }
            return View(model);
        }
    }
}

现在,在应用程序的 Controllers 文件夹下创建一个图书控制器 (BookController.cs)。ASP.NET MVC 以 JsonResult 操作结果的形式提供了原生的 JSON 支持,它接受一个模型对象,并将其序列化为 JSON 格式。为了通过 JSON 为您的控制器操作添加 AJAX 支持,只需使用 Controller.Json() 方法创建一个包含要序列化的对象的 new JsonResult

现在,在图书控制器中创建一个名为 BooksByPublisherId() 的操作方法,该方法返回 JsonResult。此操作方法根据作为参数传递到此操作方法中的发布者 ID 检索书籍列表。以下是此图书控制器的代码片段。

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MustacheMVCApplication.Models;
 
namespace MustacheMVCApplication.Controllers
{
    public class BookController : Controller
    {
        public JsonResult BooksByPublisherId(int id)
        {
            IEnumerable<BookModel> modelList = new List<BookModel>();
            using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
            {
                var books = context.BOOKs.Where(x => x.PublisherId == id).ToList();
                modelList = books.Select(x =>
                                            new BookModel()
                                            {
                                                Title = x.Title,
                                                Author = x.Auther,
                                                Year = x.Year,
                                                Price = x.Price
                                            });
            }
            return Json(modelList,JsonRequestBehavior.AllowGet); 
        } 
    }
}

我在 RouteConfig 类 (App_Start/RouteConfig.cs) 的 RegisterRoute() 方法中为此操作定义了一个路由。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Publisher", action = "Index", id = UrlParameter.Optional }
    );
    routes.MapRoute("BooksByPublisherId",
    "book/booksbypublisherid/",
    new { controller = "Book", action = "BooksByPublisherId" },
    new[] { "MustacheMVCApplication.Controllers" });
}

现在,为发布者创建一个 Index 视图,其中包含用于发布者的下拉列表,该列表使用 AJAX 根据发布者下拉列表中选定的值显示图书详细信息。此视图使用 Mustache 客户端模板来显示图书详细信息。以下是图书详细信息的代码片段。

<script type="text/template" id="tempBook">
   <b>Title :</b> {{Title}} <br/>
   <b> Author :</b> {{Author}}<br/>
   <b> Year :</b> {{Year }} <br/>
   <b> Price :</b> {{Price }}<hr/>
</script>

以下代码段用于在 JavaScript 中渲染此模板。

function (id, book)
{
    var template = $('#tempBook').html();
    var bookData = Mustache.render(template, book);
} 

以下代码段是整个 Index 视图。

@model MustacheMVCApplication.Models.PublisherModel
 
<script src="~/Scripts/jquery-2.1.0.min.js"></script>
<script src="~/Scripts/mustache.js"></script>    
<script type="text/javascript">
    $(document).ready(function () {
        $("#Id").change(function () {
            var id = $("#Id").val();
            var booksDiv = $("#booksDiv");
            $.ajax({
                cache: false,
                type: "GET",
                url: "@(Url.RouteUrl("BooksByPublisherId"))",
                data: { "id": id },
                success: function (data) {
                    var result = "";
                    booksDiv.html('');
                    $.each(data, function (id, book) {
                        var template = $('#tempBook').html();
                        var bookData = Mustache.render(template, book);
                        booksDiv.append(bookData);
                    });
                    
                },
                error: function (xhr, AJAXOptions, thrownError) {
                    alert('Failed to retrieve books.');
                }
            });
        });
    });
</script>
<script type="text/template" id="Script2">        
        <b>Title :</b> {{Title}} <br/>   
        <b> Author :</b> {{Author}}<br/> 
        <b> Year :</b>  {{Year }} <br/> 
        <b> Price :</b> {{Price }}<hr/>  
    </script>
<div>
    @Html.LabelFor(model=>model.Id)
    @Html.DropDownListFor(model => model.Id, Model.PublisherList)
</div>
<div id="booksDiv"> 
</div>

让我们运行应用程序。您将得到如图 1.3 所示的结果。

 Books detail of a publisher

图 1.3 发布者的书籍详细信息

结论

虽然客户端模板方法可能看起来工作量很大,但在大多数情况下,它易于维护和降低带宽成本的优点使其非常值得付出前期成本。当您的应用程序依赖于许多导致复杂客户端标记的 AJAX 交互时,客户端模板通常是一个不错的选择。如果您有任何疑问,请在此处评论或直接通过 https://twitter.com/ss_shekhawat 与我联系。

© . All rights reserved.