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

ASP.NET MVC 中的 jQuery 模板/视图引擎

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (59投票s)

2011年4月28日

CPOL

22分钟阅读

viewsIcon

231338

downloadIcon

4102

本文解释了如何在 ASP.NET MVC 中使用客户端视图引擎。

目录

  1. 引言
  2. 背景
  3. Using the Code
    1. 模型
    2. 控制器 (Controller)
    3. 视图
  4. 实现
    1. 列表页
    2. 详情页
    3. 编辑页
    4. 分层视图
  5. 结论
  6. 历史

引言

Microsoft ASP.NET MVC 框架遵循标准的 MVC 模式——模型包含要显示的数据,控制器在某些事件发生时执行操作,初始化模型并将其传递给视图,视图接收模型并呈现将发送到客户端浏览器的 HTML 输出。此架构如下图所示

JavaScript-View-Engine/template-mvc.png

客户端(浏览器)向服务器端发送 HTTP Web 请求。在服务器上,我们有处理请求的控制器,使用模型获取数据,并将其传递给视图。视图生成应发送回客户端的 HTML。在 MVC 3 中,可以使用多种视图引擎——标准 ASP.NET 视图引擎、Razor、Spark、NHaml 等。所有这些视图引擎都使用不同的语法来生成视图;但是,它们的工作方式都相同——在服务器端获取模型,使用模板进行格式化,然后将 HTML 发送到客户端浏览器。

本文介绍了一种不同的视图引擎概念——在客户端浏览器中呈现视图的客户端视图引擎。在这个概念中,模型和控制器仍然在服务器端。但是,服务器端生成的输出不是 HTML,而是 JSON,它在客户端被接收,并使用 JavaScript 模板引擎生成 HTML。此架构如下图所示

JavaScript-View-Engine/template-json.png

向控制器发送 HTTP 请求和处理模型与标准方法相同。但是,在这种情况下,模型不是直接传递给服务器端视图,而是以 JSON 对象的形式发送到客户端,由客户端视图引擎处理。

背景

此示例展示了如何在 ASP.NET MVC 项目中使用客户端 JavaScript 模板引擎来代替标准的服务器端模板引擎。JavaScript 模板引擎使用 JSON 对象作为模型并在客户端生成 HTML。JavaScript 模板引擎的原理如下图所示

JavaScript-View-Engine/templating-engine.png

使用 JavaScript 模板引擎,您需要将模型对象(通常是某个 JavaScript 对象)传递给视图。视图将有一个定义如何呈现此模型对象的模板。一旦它将 JavaScript 模型与模板绑定,它将生成 HTML,就像标准的服务器端视图引擎一样。如您所见,客户端模板引擎的工作方式与标准服务器端 MVC 渲染引擎相同。唯一的区别是视图在浏览器中处理。

目前,有几种模板引擎,如 jsRender(已弃用的 jQuery 模板 的继任者)、KnockoutPurenoTemplatejsTemplatePopulatejTemplates,但此示例使用 jQuery loadJSON 模板引擎。jQuery loadJSON 插件是一个模板引擎,它将 JSON 对象绑定到干净的 HTML 模板并在客户端生成视图。要将 JavaScript 模型与模板绑定,您需要调用类似以下代码行

$("#template").loadJSON(model); //If you use loadJSON plugin
$("#template").render(model);   //if you use jsRender plugin

此调用将从当前浏览器的 HTML 中获取 HTML 片段,并将其用作与 JavaScript 对象(模型)绑定的模板。例如,假设您有以下 JSON 对象应放置在模板中

model = {
        "Name":"Emkay Entertainments",
        "Address":["Nobel House","London","UK"],
        "Contact":"Phone"
}
<div id="template">
     <textarea id="Name" />
     <span class="Address"></span>
     <input name="Contact" />
</div>

如果您将此模型应用于模板并调用 loadJSON,您将获得以下输出

<div id="template">
     <textarea id="Name">Emkay Entertainments</textarea>
     <span class="Address">Nobel House</span>
     <span class="Address">London</span>
     <span class="Address">UK</span>
     <input name="Contact" value="Phone"/>
</div>

这是一个简单的 JavaScript 模板引擎,它具有实现有效客户端模板引擎所需的所有功能,但您还有其他选择。例如,使用 jsrender 模板生成的相同代码将是

var model = {
    "Name":"Emkay Entertainments",
    "Address":[{"Item":"Nobel House"},
               {"Item":"London"},
	       {"Item":"UK"}	       ],
    "Contact":"Phone"
}
<script id="template" type="text/x-jsrender">
 <textarea id="Name">{{:Name}}</textarea>
 {{for Address}}
	<span>{{:Item}}</span>
 {{/for}}
 <input name="Contact" value="{{:Contact}}"/>
</script>

在 JavaScript 中,您可以看到非常相似的数据结构。在模板中添加了与属性名称匹配的占位符,它们被 {{:}} 包裹。此外,您还可以使用 for 循环。为了将模型加载到模板中,您需要使用以下代码

$( "#view" ).html(
  $( "#template" ).render( model )
);

结果,ID 为“view”的元素将填充 HTML,这是合并模型和模板的结果。结果将如下图所示

<div id="view">
     <textarea id="Name">Emkay Entertainments</textarea>
     <span>Nobel House</span>
     <span>London</span>
     <span>UK</span>
     <input name="Contact" value="Phone"/>
</div>

尽管示例中将使用 loadJSON 插件,但某些部分简要介绍了使用 PurejQuery 模板 的替代实现示例。

我们为什么要使用这种架构?这种架构有以下几个优点

  1. 性能 - 在这种架构中,视图处理被转移到浏览器,利用了浏览器的资源。服务器应该更快地返回响应,因为服务器端没有视图处理。
  2. 吞吐量 - 在这种架构中,返回的是 JSON 对象而不是 HTML,JSON 对象比 HTML 小,因为它不包含包装纯信息的冗余标签。JSON 对象只包含应显示的数据,加载速度更快。
  3. 缓存 - 客户端使用的 HTML 模板不包含任何数据。因此,它们可以被缓存并重复用于不同的视图页面。唯一改变的是加载到模板中的 JSON 数据。
  4. 跨平台支持 - 在这种架构中,同一个 Web 服务器可以支持不同的平台,从移动设备到标准浏览器,而无需知道客户端是谁。服务器将相同的 JSON 数据返回给所有客户端,您可以在客户端放置不同的模板,这些模板将最适合设备的屏幕分辨率和支持的功能。例如,在移动设备上,您可以定义一个不显示富 UI 元素的较小模板,而在标准浏览器中,您将使用完整的富客户端 UI。

在以下部分中,我将向您展示如何使用客户端模板引擎创建基于 JSON 的 ASP.NET MVC 应用程序。

使用代码

本文提供了一个代码示例,演示了如何在 ASP.NET MVC 中使用客户端视图引擎。以下部分展示了如何将 jQuery loadJSON 插件集成到 ASP.NET MVC 应用程序中,以取代标准的服务器端视图引擎。

模型

在此示例中,两个包含公司及其员工信息的类用作模型。Company/Employee 模型类的源代码如下所示

public class Company
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Town { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }
    public string Contact { get; set; }
    public bool IsFeatured { get; set; }
    public string[] Country { get; set; }
    public string Logo { get; set; }
    public Employee Manager { get; set; }
    public Employee[] Employees { get; set; }
}
public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Company 类有两个对 Employee 类的引用,一个指向代表经理的单个员工,另一个指向该公司员工的数组。

这些模型类将在控制器中序列化,Company/Employee 类实例的 JSON 表示将提供给放置在客户端的视图。

控制器

控制器不是一个标准的控制器,它响应用户操作并返回视图,就像在标准服务器端视图引擎中工作一样。在 JavaScript 模板引擎中,控制器应该只返回一个将用作客户端模型的 JSON 对象。这个 JSON 对象将在 JavaScript 模板函数中被接受,并且 HTML 输出将直接在浏览器页面中生成。这个示例包含三个页面:公司列表、公司详细信息以及可以编辑公司详细信息的表单。因此,控制器中应该实现两个动作方法。第一个动作返回公司列表,第二个动作根据 ID 返回单个公司(当显示详细信息和填充公司数据表单时将调用此动作)。控制器的源代码如下所示

public class CompanyController : Controller
{
    public ActionResult List()
    {
       return Json(DataRepository.GetCompanies(), 
                   JsonRequestBehavior.AllowGet);
    }

    public ActionResult Data(int? ID)
    {
       return Json(DataRepository.GetCompanies().First(
          c => c.ID == ID), JsonRequestBehavior.AllowGet);
    }
}

Action 方法获取模型类,将其格式化为 JSON 结果,并将 JSON 返回给视图引擎。客户端的视图引擎将在视图需要模型时调用这些操作。

视图

使用 JavaScript 模板引擎时,视图可以是静态页面。您可以将标准 .aspx 页面用作视图,但也可以使用纯 HTML 页面。给定示例有四个视图页面

  1. 显示公司列表的列表页
  2. 显示单个公司详细信息的详细信息页
  3. 一个编辑页面,其中有关单个公司的信息加载到表单中,可以在其中更改详细信息并将其发布到服务器端(尽管发布结果超出了本文的范围)。
  4. 一个层次结构页面,显示了如何使用客户端模板来呈现复杂的嵌套结构——这是唯一使用 Employee 类的示例。

这些是客户端页面的典型使用案例。在以下部分中,将详细描述这些视图页面,并解释如何使用客户端引擎来呈现它们。

实施

在本节中,我将展示如何使用 jQuery 模板实现标准列表、详细信息和编辑页面。

列表页

列表页用于定义将用于在浏览器中列出公司的模板。此示例中使用了一个静态视图页面,如下所示

<html>
<head>
    <title>Listing JSON aray using the HTML template</title>
    <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            $('li').loadJSON('/Company/List');
        });
    </script>
</head>
<body>
    <div id="page-wrap">
        <div id="contact-area">
            <ul>
                <li><a href="details.html" class="ID">
                <span class="Name"></span>
            </a><span class="Address"></span>
          </li>
            </ul>
        </div>
    </div>
</body>
</html>

无序列表中放置了纯 HTML 代码,定义了将用于生成输出的项目模板。此部分代码如下所示

<li>    
    <a href="details.html" class="ID">
    <span class="Name"></span>
    </a>
    <span class="Address"></span>
</li> 

li 标签包含其 class 属性与模型类中的属性匹配的 HTML 元素。视图使用标题中的此 JavaScript 行进行初始化

$('li').loadJSON('/Company/List');   

此行从 /Company/List URL 加载 JSON 数组并将其加载到 lI 元素中。Company/List URL 激活 Company 控制器中的 List 方法,该方法返回格式化为 JSON 数组的公司列表。当 loadJSON 插件应用于此元素时,对象的属性将放置在模板中。此外,此模板项会为绑定到模板的数组中模型的每个实例复制。结果,将创建一组 li 元素,表示从 /Company/List URL 加载的公司列表。下面显示了在浏览器中生成的视图

JavaScript-View-Engine/loadJSON-list.png

jQuery loadJSON 插件在加载值之前会检查 HTML 元素的类型。在大多数元素中,值将作为元素的内部文本放置(例如,SPANPDIV 标签)。但是,如果它找到一个链接元素,插件会将其属性作为附加参数添加到 href 属性中包含的 URL 中,而不是作为内部文本。在上面的示例中,参数 ID=17、ID=18、ID=19 等被附加到链接的 href 属性。因此,要添加链接的文本,您需要将一个额外的 SPAN 标签放在链接内部,该标签将从不同的属性加载。您可以在此处找到列表功能的实时示例。

使用 jQuery 模板/jsRender 模板的替代实现

请注意,如果您愿意,可以使用任何其他模板引擎。例如,如果使用 jQuery 模板,模板将类似于以下代码所示

<ul id="template">
    <li> 
        <a href="/Home/PopulateEdit/${ID}">${Name}</a>
        ${Address}
    </li>
</ul> 

jQuery 模板 中,占位符是括在 ${} 中的属性名称——在上面的示例中,JSON 对象的 IDNameAddress 属性将分别放置在 ${ID}${Name}${Address} 占位符中。下面显示了用于将 JSON 数据加载到模板中的 JavaScript 代码

//Prepare template based on the inner HTML in the UL tag with id "template"
$.template("my_template", $("#template").html());
//Perform AJAX call and pass returned JSON array to template
$.getJSON('/Home/Populate', function (data) {
    $("#template").html($.tmpl("my_template", data));
}); 

jQuery 模板 中,您需要获取放置在带有 id 为“template”的无序列表中的模板代码,并使用 $.template() 方法对其进行编译。在生成视图时,已编译的模板可以通过名称 my_template 进行引用。然后,执行 AJAX 调用从 /Populate/List URL 加载 JSON,并将此控制器返回的数据绑定到模板,并将其设置为 id 为“template”的无序列表的 HTML 代码。模板的结果与 loadJSON 插件返回的结果相同——只有视图和初始化代码的语法不同。

jQuery 模板 插件现在已弃用,不再进行积极开发或维护。我建议改用 jsRender。它具有非常相似的语法,只有微小的变化。例如,在 jsRender 中,您可以使用

  • {{:ID}} 如果您想放置数据的原始值,或者
  • {{>ID}} 如果您想使用 HTML 编码

以下示例显示了使用通过 AJAX 返回的数据从模板加载 HTML 的等效代码

//Perform AJAX call and pass returned JSON array to template
$.getJSON('/Home/Populate', function (data) {
    $("#view").html($("template").render(data));
});

如您所见,它非常相似,因此如果您已经在使用 jQuery 模板 插件并希望将代码转换为其他模板,我建议使用 jsRender

详情页

“详情”页面用于显示单个公司的详细信息。它从 /Company/Details 页面获取 JSON 对象,并将 JSON 对象加载到 HTML 模板中。此示例中使用的“详情”页面如下所示

<html>
<head>
    <title>Displaying details of the single JSON object</title>
    <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
        var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
            $('div#data').loadJSON('/Company/Data/'+id);
        });
    </script>
</head>
<body>
<div id="page-wrap">
    <div id="contact-area">
    <div id="data">
          <h1 id="Name"></h1>
              <img id="Logo" alt="" src=""/>
          <label for="Address">Address:</label>
              <span id="Address"></span>
          <label for="Contact">Contact by:</label>
              <span id="Contact"></span>
          <label for="Town">Town:</label>
              <span id="Town"></span>
           <form action="edit.html" method="get">
              <input type="hidden" id="ID" name="ID"/>
              <input type="submit" value="Edit" class="submit-button"/>
           </form>
        </div>
    </div>
</div>
</body>
</html>

页面包含空白 HTML 模板的定义,其中元素的 id 属性与模型中的属性匹配。标题中的 JavaScript 调用从页面 URL 获取 ID 参数,并使用该参数调用 /Company/Details 服务器端页面,如以下代码示例所示

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$('div#data').loadJSON('/Company/Data/'+id);

当此 URL 发送到服务器时,CompanyController 中的控制器动作 Details(int? ID) 将被调用,并返回一个公司作为 JSON 结果。此 JSON 对象将加载到 ID 为“data”的 DIV 中,并且该 DIV 中的元素将被填充。您可以在此处查看详细信息页面的实时示例。下面显示了示例项目中一个公司生成的视图示例

使用 Pure 模板引擎的替代实现

与前面的例子类似,除了 loadJSON,可以使用任何其他模板引擎。例如,如果使用 Pure 模板引擎,模板可以与代码示例中所示的相同(Pure 使用与 loadJSON 相同的干净 HTML 代码)。JavaScript 初始化调用如下所示

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$.getJSON('/Home/Populate/'+id, function (company) {
    $("'div#data'").render(company, {  '#Name': 'Name', '#Address': 'Address',
                                       '#Logo@alt': 'Name', '#Logo@src':'Logo' });
});

在上面的示例中,执行了一个 AJAX 调用,从 /Home/Populate/<<id>> URL 加载 JSON 对象,并在回调函数中,JSON 对象加载到 ID 为“data”的 div 中,如前一个示例所示。Render 函数的第二个参数是一个指令,它将 HTML 元素映射到 JSON 属性。在上面示例中显示的指令中,JSON 对象的 NameAddress 属性加载到 idNameAddress 的元素中。在 ID 为“Logo”的元素的 alt 属性中加载了 Name,在 ID 为“Logo”的元素的 src 属性中放置了 JSON 对象的 Logo 属性。Pure 的优点是您可以定义元素、它们的属性和 JSON 对象的属性之间的自定义映射规则。如果您不想使用指令,可以使用 .autoRender() 函数而不是 .render().autoRender() 函数类似于上面示例中所示的 .loadJSON() 函数;但是,.autoRender() 函数仅通过类名将元素与属性匹配(这是 Pure 模板引擎中的“默认指令”)。

编辑详情

编辑页与详情页类似。但是,这里将单个公司记录加载到 HTML 表单中。编辑页的示例在以下列表中显示

<html>
<head>
    <title>Load Form with JSON data</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link rel="stylesheet" type="text/css" href="/Content/style.css" />
    <script src="/scripts/jQuery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="/scripts/jQuery.loadJSON.js")" type="text/javascript"></script>
        <script language="javascript" type="text/javascript">
            $(document).ready(function () {
             var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
             $('form').loadJSON('/Company/Data/' + id);
            });
        </script>
</head>
<body>
<div id="page-wrap">
    <div id="contact-area">    
        <form name="form_simple" id="form-simple" action="details.html" method="get">
            <input type="hidden" id="ID" name="ID" />
        <label for="Name">Name</label>
        <input name="Name" id="Name" type="text" />
        <label for="Address">Address</label>
        <textarea name="Address" id="Address" rows="5" cols="20"></textarea>
        <label for="Country">Country</label>
        <select name="Country" multiple="multiple">
                    <option value="">-</option>
            <option value="UK">United Kingdom</option>
                    <option value="SRB">Serbia</option>
            <option value="USA">United States of America</option>
            <option value="FRA">France</option>  
        </select>
        <label for="IsFeatured">Is Featured</label>
        <input name="IsFeatured" id="IsFeatured" type="checkbox" value="true"/>
        <label for="Town">Town</label>
        <select name="Town" id="Town">
                    <option value="" selected="selected">-</option>
            <option value="London">London City</option>
            <option value="Liverpool">Liverpool City</option>
            <option value="Lothian">Lothian City</option>
            <option value="Newcastle">Newcastle City</option>
                    <option value="Buckinghamshire">Buckinghamshire City</option>
                    <option value="Essex">Essex City</option>  
        </select>
        <label for="Contact">Contact</label>
            <input name="Contact" type="radio" value="Email"/> Email
            <input name="Contact" type="radio" value="Phone" /> Phone
            <input name="Contact" type="radio" value="Post" /> Post
                <input type="submit" value="Details" class="submit-button" />
    </form>
    </div>
</div>
</body>
</html>

标题应包含一个 JavaScript 调用,该调用将 URL 中的 JSON 对象加载到表单中。此 JavaScript 调用如下所示

var id = window.location.href.match("(ID=|id=|/)[0-9]+")[0].match("[0-9]+");
$('form').loadJSON('/Company/Data/' + id); 

此调用的结果是一个表单,其中填充了从 /Company/Data/<ID> URL 加载的 JSON 对象的属性。可以在此处找到使用 loadJSON 插件填充表单的实时示例,并且此处描述了填充表单时使用的详细规则。下面显示了填充有 JSON 数据的表单示例

JavaScript-View-Engine/loadJSON-edit.png

jQuery loadJSON 插件将检查应加载 JSON 属性的每个表单元素的类型,并根据类型,它将属性作为文本放入文本框和文本区域,作为选定项目放入单选按钮组、单选和多选列表,以及作为选中/未选中状态放入复选框。在其他插件中,您需要手动设置加载表单元素的映射规则。

在其他插件中,我没有找到填充表单的等效简单实现,因此本示例不会在任何替代实现中显示。

分层视图

最后一个视图展示了如何使用客户端引擎渲染复杂/分层结构。前面的例子使用了简单的结构(公司数组,单个公司),但正如您在模型中可能看到的,公司和员工之间存在关系。当 Company/List 操作返回公司列表时,返回的结构如下所示(JSON 结果)

[
    {   "ID": 17, "Name": "Emkay Entertainments", 
        "Address": "Nobel House, Regent Centre",
        "Town": "Lothian", "Contact": "Phone", "IsFeatured": true,
        "Manager": { "FirstName": "Nick", "LastName": "Donovan" },
        "Employees": [  { "FirstName": "John", "LastName": "Doe" },
                        { "FirstName": "Alex", "LastName": "Watkins" },
                        { "FirstName": "Mick", "LastName": "Henning"}]
    },
    {   "ID": 18, "Name": "The Empire", "Address": "Milton Keynes Leisure Plaza",
        "Town": "Buckinghamshire", "Contact": "Post", "IsFeatured": false,
        "Manager": { "FirstName": "Ana", "LastName": "Frank" },
        "Employees": [  { "FirstName": "Mark", "LastName": "Anderson" },
                        { "FirstName": "John", "LastName": "Haus" },
                        { "FirstName": "Sinthia", "LastName": "Clouny"}]
    } 
]

如您所见,在返回的公司数组中,每个公司对象都返回了简单的属性(NameAddress 等)以及嵌套对象 Manager 和嵌套数组 Employees。嵌套结构也可以使用客户端引擎显示。

如果使用 loadJSON,HTML 模板应该具有与返回的 JSON 响应结构匹配的嵌套元素。下面列出了可以与 loadJSON 插件一起使用的 HTML 模板示例

<ol>
    <li>
        <div class="divEmployees">
        <h3>Employees <img class="closed" 
            src="/Content/images/details_open.png" alt="open/close"/></h3>
        <dl class="Employees"> 
            <dt class="FirstName"></dt><dd class="LastName"></dd>
        </dl>
        </div>
        <a href="details.html" class="ID">
            <span class="Name"></span></a>
        <span class="Address"></span>
        <h3>Manager:</h3>
            <span class="Manager">
                <span class="FirstName"></span> <span class="LastName"></span>     
            </span>
    </li>
</ol>

在模板中放置了公司字段(IDNameAddress)的占位符,与列表示例相同。有一个 Manager 占位符(在 SPAN 标签中)用于引用经理对象,该对象有两个占位符用于经理的名字和姓氏。此外,在 DL 标签中有一个 Employees 数组的占位符,其中将加载通过“Employee”数组与公司关联的 Employee 对象数组。在该占位符中,放置了嵌套数组中返回的每个员工的名字和姓氏的嵌套占位符。当使用 loadJSON 函数将 JSON 对象加载到此模板中时,会生成元素的嵌套结构(向右移动),如下图所示

JavaScript-View-Engine/loadJSON-hierarchy-view.png

在第一层中,列出了有序列表中的公司,其中显示了基本的公司详细信息和嵌套的经理对象。对于每个公司,都会生成一个嵌套的员工列表,这些员工为公司工作。在上面的截图中,第一家和第四家公司的员工已展开,而其他公司则已折叠。您可以在此处查看实时示例,但没有显示/隐藏员工的按钮。显示/隐藏嵌套员工列表的功能是使用不属于模板引擎的自定义 JavaScript 实现的——您可以在下面找到有关此脚本的更多详细信息。

使用 Pure 模板引擎的替代实现

除了 loadJSON,您可以使用任何其他模板引擎。如果使用 Pure,可以使用相同的 HTML 模板,但您需要定义分层模板与服务器端返回的 JSON 对象之间的映射规则。如果使用 Pure 引擎,以下脚本会生成视图

 $.getJSON('/Company/List', function (data) {
    $("ol").render(data, {
        li: {
            'company<-': {
                '.ID': 'company.Name',
                '.ID@href': 'company.ID',
                '.Address': 'company.Address',
                '.Manager .FirstName': 'company.Manager.FirstName',
                '.Manager .LastName': 'company.Manager.LastName',
                'dl.Employees': {
                    'employee<-company.Employees': {
                        '.FirstName': 'employee.FirstName',
                        '.LastName': 'employee.LastName'
                        }
                    }
                }
            }
    });
});

在这个例子中,JSON 对象从 '/Company/List' URL 获取,返回的 JSON 对象被渲染到包含模板的 OL 元素中。唯一的区别是显式定义映射规则的指令——我将尝试解释本例中使用的指令。Render 函数找到一个 li 元素并遍历 'company<-' 指令返回的数组。循环中的每个对象都将被标识为 'company'。在类名为 IDAddress 的元素中,放置了数组中的 company.Namecompany.Address 字段,在类名为 "ID" 的链接的 href 属性中放置了公司的 ID。在类名为 "FirstName" 和 "LastName" 的元素中,这些元素位于类名为 "Manager" 的元素内部,放置了 company.Manager.FirstNamecompany.Manager.LastName(嵌套对象 manager 的属性)。

内部列表是使用指令中的最后一个语句生成的。在类名为 "Employees" 的 DL 元素中,对数组 company.Employees 应用了一个循环——循环中的每个元素都使用 'employee' 标识符进行标识。在类名为 "FirstName" 和 "LastName" 的 DTDD 元素中,这些元素位于 DL 元素内部,放置了 JSON 对象的 employee.FirstNameemployee.LastName 属性。

Pure 引擎是比 loadJSON 插件更强大的模板引擎,因为它具有复杂的指令,使您能够根据需要精确地自定义映射规则。但是,正如您所见,您需要学习用于指令的语法才能自定义渲染规则。语法的解释不属于本文(这只是一个具体的示例),因此如果您对此感兴趣,请在 Pure 网站上查找更多详细信息。

应用自定义 JavaScript 代码

请注意,视图引擎只为您提供静态 HTML 结构——如果您需要一些交互,可以向此结构添加自定义函数。例如,在此视图中,添加了每次用户单击图像时打开和关闭嵌套员工列表的功能。以下列表显示了显示/隐藏嵌套列表的代码示例

$("dl.Employees").hide();
$(".closed").click(function (item) {
    if ($(this).hasClass("closed")) {
        this.src = "/Content/images/details_close.png";
        $(this).removeClass("closed");
        $("dl", $(this).parents("li")).fadeIn("slow");
    } else {
        this.src = "/Content/images/details_open.png";
        $(this).addClass("closed");
        $("dl", $(this).parents("li")).fadeOut("slow");
    }
});

此代码最初隐藏所有嵌套员工,并为图像附加单击处理程序,根据状态显示/隐藏所选公司的员工。这完全独立于模板引擎代码,因此只要它们生成相同的输出,相同的函数就可以与不同的视图引擎一起使用。这种方法没有限制;只要您知道所需的结构,就可以将任何 JavaScript 代码应用于模板引擎生成的结构。除了自定义代码,您还可以应用一些现有插件,这些插件将继续处理与客户端的交互。

例如,如果您需要一个可扩展的表格,您可以使用 DataTables 插件,它已经处理了您所需的大部分常见功能。在这种情况下,模板引擎可以用于生成 DataTables 插件所需的初始 HTML 结构,然后您可以将此插件应用于生成的结构,并让插件处理所有后续的自定义交互。

结论

本文解释了如何将 loadJSON 插件用作客户端模板引擎,并展示了如何将 JSON 对象直接加载到客户端的 HTML 元素中。使用客户端模板引擎有几个优点

  1. 性能 - 从服务器端加载 JSON 对象,只有最少的数据从服务器传输到客户端。这样,不需要从服务器加载不必要的 HTML 标签,并且加载数据所需的时间更短。
  2. 缓存 - 示例使用静态 HTML 页面作为视图。因此,如果使用活动视图(例如 .aspx 页面),它们可以在服务器端缓存。这使得服务器端响应时间更短。
  3. 真正的设计与代码分离 - 使用服务器端模板引擎时,视图中的代码并不完全干净。HTML 代码包含一些绑定服务器端数据到视图元素所需的元素。本文中的示例表明视图是完全干净的——视图页面中除了 HTML 代码之外没有任何其他内容(甚至没有自定义属性)。

然而,这并非 Web 开发的“圣杯”,因为它不能解决所有问题,也不是完美的解决方案。如果您需要在视图中放置一些复杂的逻辑,例如,确定某个元素是否应该禁用或隐藏,或者如果您需要动态显示/隐藏某些元素,您无法使用简单的客户端视图引擎来实现这一点。在这种情况下,最好保留服务器端代码数据,因为它更容易通过代码、局部视图和服务器端控件进行控制。但是,应用客户端视图引擎(在适当的情况下)会带来上述几个好处。

在本示例中,使用 loadJSON 插件是因为它是最简单的可用插件,并且最适合展示客户端视图引擎概念。但是,您可以使用任何其他模板引擎,方法将类似。我推荐的其他模板引擎有:

  1. jsRender - 这是已弃用的 jQuery 模板的继任者,jQuery 模板曾是标准 jQuery API 的一部分。
  2. Pure - 一款优秀的模板引擎,提供了复杂的语言来定义模板中元素与 JSON 数据源匹配的规则。该引擎的缺点是您需要学习指令中用于定义数据如何绑定到模板的模板语言。
  3. Knockout - 我发现的最先进的模板,支持绑定、JSON 模型的变更跟踪/更新等。如果您想完全控制您的模板引擎,我推荐这款。

没有最好的模板引擎,本文中提到的每个引擎都有其优点和缺点。loadJSON 插件的主要优点是它的简单性和无需指定任何映射规则即可正确填充表单元素的能力。然而,在其他模板引擎中,通过或多或少的努力也可以实现同样的效果。

历史

  • 2011年4月28日:初始版本
ASP.NET MVC 中的 jQuery 模板/视图引擎 - CodeProject - 代码之家
© . All rights reserved.