juqery模板 Templates

现在已经有了许多JavaScript的解决方案模板,从这方面说,标准化的模板解决方案必然是大势所趋。在本节中,我们向你简要描述四个最流行最有趣的模板。现有的模板解决方案能解决什么?那些特色在jQuery核心中有意义。

微模板

John Resig的微型模板引擎非常小(未压缩仅2KB)。然而,这点小小的代码已经抓到了渲染一个模板的核心功能。

下面是一个用微模板引擎显示单个JavaScript产品对象的例子。

<script src="../jquery-1.4.1.js" type="text/javascript">>;/script>;
<script src="MicroTemplating.js" type="text/javascript">;</script>;
<script type="text/javascript">;
    var product = { name: "Laptop", price: 788.67 };
    $(showProduct);
    function showProduct() {
        $("#results").html( tmpl("productTemplate", product) );
    }
    function formatPrice(price) {
        return "$" + price;
    }
</script>;

tmpl()方法用来从一个product模板和product对象生成一个字符串。其结果分配给一个名叫results的div元素的innerHTML。

product模板在页面body的SCRIPT中定义。

<script type="text/html" id="productTemplate">
    Product Name: <%= name %>
    <br />
    Product Price: <%= formatPrice(price) %> 
</script>
<div id="results"></div>

注意,SCRIPT的type属性为“text/ html”。用这种方式来声明web浏览器会忽略SCRIPT里的内容,将其内容当作字符串来对待。

注意,模板包含代表产品名称和价格属性的表达式。调用JavaScript的formatPrice()方法来格式化产品的价格。在模板里你可以调用任何JavaScript函数。

这里是如何渲染一个product对象数组的示例:

function showProducts() { 
    // parse the template 
    var template = tmpl("productTemplate"); 
    // loop through the products 
    var results = ''; 
    for (var i = 0; i < products.length; i++) { 
        results += template(products[i]); 
    } 
    // show the results 
    $("#results").html(results); 
}

tmpl()函数支持currying(关于什么currying,可以在网上查阅资料)。如果没有提供数据给tmpl()函数,他将返回一个javascript函数,代表解析的模板。

在上面的代码中,模板被解析,然后为每一个product调用模板方法生成一个字符串。最后,字符串分配给名叫results的div元素的innerHTML。
jTemplates

jTemplates是一个功能丰富的模板引擎,它作为一个jQuery插件来执行。jTemplates支持很多先进的功能,包括:

外部模板--您可以通过提供的URL从外部文件加载模板,外部文件可以包含多个模板; 
外部数据--您可以从外部URL加载数据; 
实时刷新--你可以自动定期的更新模板内容; 
HTML编码--你可以阻止诸如<和>的编码字符对JavaScript插入的攻击; 
Includes--您可以在一个模板中包含另一个模板; 
调试模式--您可以在出错的地方终止模板引擎,并显示错误信息。 
下面示例中的代码演示了如何使用jTemplates显示产品清单。

<script src="../jquery-1.4.1.js" type="text/javascript"></script>
<script src="jquery-jtemplates_uncompressed.js" type="text/javascript"></script>
<script type="text/javascript">
    var data = { 
        products: [
            { name: "Laptop", price: 788.67 },
            { name: "Comb", price: 2.50 },
            { name: "Pencil", price: 1.99 }
        ]};
    $(showProducts);
    function showProducts() {
        // attach the template
        $("#results").setTemplateElement("template");
        // process the template
        $("#results").processTemplate(data);
    }
    function formatPrice(price) {
        return "$" + price;
    }
</script>

setTemplateElement()方法给HTML元素指定一个模板,processTemplate()方法使用所提供的数据处理模板。

上面的代码中,加载的模板为名为textarea的元素,下面就是模板在页面主体中呈现的外观。

<textarea id="template" style="display:none">
    {#foreach $T.products as product}
    <div>
        Product Name: {$T.product.name}
        <br />
        Product Price: {formatPrice($T.product.price)} 
    </div>
    {#/for}
</textarea>

注意,一个jTemplate模板可以包含诸如#foreach、#for、and #if的特殊命令。至于调用formatPrice()函数,它表明模板也可以包含任意JavaScript函数的调用。

默认情况下,为了防止JavaScript的插入攻击,在传递给模板的数据中,jTemplate 的HTML编码了包含的特殊字符。例如,如果一个产品的名称为<b>Laptop<b>,那么,名称将被转换成&lt;b&gt;Laptop&lt;/b&gt; 。

jTemplates使您可以同时从外部URL加载模板和数据。例如,下面的代码将从一个名为MyTemplates.htm的文件中加在模板,从一个名为MyData.htm文件中加在一系列数据。

function showProducts() { 
    $.jTemplatesDebugMode(true); 
    // attach the template 
    $("#results").setTemplateURL("MyTemplate.htm"); 
    // process the template 
    $("#results").processTemplateURL("MyData.htm"); 
}

MyTemplate.htm文件如下所示:

{#foreach $T.products as product} 
    Product Name: {$T.product.name} 
    Product Price: {formatPrice($T.product.price)}  
{#/for}

jTemplates允许您可以在一个单一文件定义多个模板,虽然在MyTemplate.htm文件没有演示此功能。

最后,MyData.htm文件如下所示:

{"products": [ 
  { "name": "Laptop", "price": "788.67" }, 
  { "name": "Comb", "price": 2.50 }, 
  { "name": "Pencil", "price": 1.99 } 
] }

当然,包含在MyData.htm的内容有数据库动态生成。

PURE(纯粹分离式渲染引擎)

PURE 模板引擎的目的在于使开发人员不使用任何特殊标记来声明模板。使用PURE有两种方法:autoRender()方法或render()方法。

使用autoRender()方法时,PURE自动将JSON的属性名称映射到css的class上。例如,你可以编写下面的代码来显示单个产品。

$(showProduct); 
function showProduct() { 
    var product = { name: "Laptop", price: 788.67 }; 
    $('div.product').autoRender(product); 
}

autoRender()通过将product的name和price 属性分别映射到class为name和price 的元素上来显示产品。

<div class="product"> 
    Product Name: <span class="name"></span> 
    <br /> 
    Product Price: <span class="price"></span>         
</div>

请注意,模板中没有特殊字符,PURE用纯粹的HTML完成一切。

autoRender()方法依赖于JSON的属性名映射到class名的协议,如果你不想依赖于该协议,你可以用render()方法来代替。

function showProduct() { 
    var product = { name: "Laptop", price: 788.67 }; 
    var directives = { 'span#name' : 'name', 'span#price': 'price'}; 
    $('div.product').render(product, directives); 
}

请注意,一系列指令和要显示的项目传递给render()。这些选择器将选择器映射到JSON属性名,第一个指令将Id为name的span元素映射到name属性,第二个指令将Id为price的span元素映射到price属性。下面是HTML:

<div class="product"> 
    Product Name: <span id="name"></span> 
    <br /> 
    Product Price: <span id="price"></span>         
</div>

PURE也可以用来渲染一个JavaScript对象数组。例如,下面的代码渲染一个product数组。

function showProducts() { 
    var data = { "products": [ 
            { name: "Laptop", price: 788.67 }, 
            { name: "Comb", price: 2.50 }, 
            { name: "Pencil", price: 1.99 } 
        ]}; 
    $('#productTemplate').autoRender(data); 
}

由于数组名为product,PURE将每一个product映射到class为product的元素上,以下模板显示所有的三个product。

<div id="productTemplate"> 
<div class="products"> 
    Product Name: <span class="name"></span> 
    <br /> 
    Product Price: <span class="price"></span>         
</div> 
</div> 
ASP.NET Ajax 模板

在 ASP.NET的Ajax库支持客户端模板。这个库支持很多先进的功能:

伪变量--你可以在模板中用一组诸如代表模板实例当前索引的$index特别变量; 
动态模板-- 在渲染JavaScript对象数组时,你可以动态的改变模板; 
动态占位--在渲染JavaScript对象数组时,你可以动态的更改模板的占位符。 
例如,您可以使用下面的代码在模板中渲染产品列表:

var products = [
    { name: "Laptop", price: 788.67 },
    { name: "Comb", price: 2.50 },
    { name: "Pencil", price: 1.99 }            
];
Sys.require([Sys.components.dataView], function () {
    $("#products").dataView(
    {
        data: products
    });
});

DataView()方法用来在一个模板中显示系列产品。模板包含在名为product的div元素中。

<div id="products" class="sys-template"> <div id="{{ $id('product') }}"> Product Name: {{ name }} <br /> Product Price: {{ formatPrice(price) }} </div> </div>

请注意,ASP.NET Ajax模板只是一个dom元素。因为模板仅仅是一个DOM元素,模板就不需要包裹在SCRIPT或TEXTARE或HTML注释中。在这种情况下,一个DIV元素为每一个产品创建一个新实例。

此外,请注意$id()伪变量。$id()解决模板和元素id的有关问题。如果你为一个模板添加一个带有id的元素,模板用来收集选项,结果是将出现重复id。$id()伪变量为每一个模板实例生成唯一的ids,使你避免了这个问题。

ASP.NET Ajax还支持一种所谓的动态模板。想想以下,你已经为每一个新产品创建了一个模板,通常的产品模板看起来是这样的:

<!-- New template --> 
<div id="newTemplate" class="sys-template"> 
    <div> 
        <img src="new.gif" /> 
        Product Name: {{ name }} 
        <br /> 
        Product Price: {{ formatPrice(price) }}  
    </div> 
</div> 
<!-- Normal template --> 
<div id="normalTemplate" class="sys-template"> 
    <div> 
        Product Name: {{ name }} 
        <br /> 
        Product Price: {{ formatPrice(price) }}  
    </div> 
</div>
 

这两个模板其实是一样的,除非新的模板显示一个新的图像。

你可以在每一个模板显示之前创建一个itemRendering事件处理程序。在该程序中,你可以指定用来显示数据项的模板。

function itemRendering(dataView, args) { 
    // Get the current data item 
    var product = args.get_dataItem(); 
    // Set the template dynamically 
    if (product.dateCreated.getFullYear() == 2010) { 
        args.set_itemTemplate("#newTemplate"); 
    } else { 
        args.set_itemTemplate("#normalTemplate"); 
    } 
}
 

上面的代码使用两个模板中的一个来显示产品。如果产品是新的(创建于2010年)用newTemplate来显示,否则用normalTemplate模板。

ASP.NET Ajax还支持一种所谓的动态占位。动态占位使你可以在文档的不用位置显示不同项。例如,你可能希望你所有的新产品在你文档中的“新产品”区域显示:

<h1>New Products</h1> 
<div id="newPlaceholder"></div> 
 
<h1>All Products</h1> 
<div id="normalTemplate" class="sys-template"> 
    <div> 
        Product Name: {{ name }} 
        <br /> 
        Product Price: {{ formatPrice(price) }}  
    </div> 
</div>

请注意名为newPlaceholder的div元素。你希望所有新产品都出现在这里。

这里是你如何编写itemRendering处理程序在新的占位符中放置新产品--创建于2010的产品。

function itemRendering(dataView, args) { 
    // Get the current data item 
    var product = args.get_dataItem(); 
    // Set the template dynamically 
    if (product.dateCreated.getFullYear() == 2010) { 
        args.set_itemPlaceholder("#newPlaceholder"); 
    }  
}
 

在jQuery core中增加模板支持
这部分包含一个提案--给jQuery核心中添加一个声明和渲染模板的标准方法。这节包括模板API、示例代码和讨论要点。

API
jQuery.fn.render
通过给单个的数据项或一组数据项应用一个模板来生成DOM元素。

jQuery("#template") 
   .render(arrayOrObject, options) 
   .appendTo("selector");

参数

 

参数 类型 描述 
data 任何数据对象 任何数据对象 如果是数组,为每一项实例化化一次。否则,该模板仅实例化一次 
options 对象 对象的字面意义代表可选设置。你可以设置一个渲染和渲染的事件处理程序。你可以传递任何值,这些值将被传入到模板中


示例

下面是一个使用render()方法的简单例子。render()方法用来以列表的方式显示系列产品的name和price。

<script type="text/javascript"> 
jQuery(function(){ 
  var products = [ 
        { name: "Product 1", price: 12.99}, 
        { name: "Product 2", price: 9.99}, 
        { name: "Product 3", price: 35.59} 
  ]; 
 
  $("#template") 
     .render(products)  
     .appendTo("ul"); 
}); 
</script> 
<script id="template" type="text/html"> 
 <li>{%= name %} - {%= price %}</li> 
</script>
<ul></ul>
 

执行上面的代码得到的是下面的无需列表。

产品1 - 12.99 
Product 2 – 9.99产品2 - 9.99 
Product 3 – 35.59产品3 - 35.59 
jQuery DOM操作
jQuery DOM操作方法支持声明一个模板。例如,你可以使用jQuery.fn.append方法:

jQuery("selector") 
   .append("#template", arrayOrObject, options);
 

参数

 

参数 类型 描述 
selector 字符串 代表模板选择符的一个字符串 
data 任何数据对象 任何数据对象 如果是数组,为每一项实例化化一次。否则,该模板仅实例化一次 
options 对象 对象的字面意义代表可选设置。你可以设置一个渲染和渲染的事件处理程序。你可以传递任何值,这些值将被传入到模板中


示例

下面的代码使用append()方法而不是render()方法在一个无需列表中显示系列产品的name和price。

<script type="text/javascript"> 
jQuery(function(){ 
  var products = [ 
        { name: "Product 1", price: 12.99}, 
        { name: "Product 2", price: 9.99}, 
        { name: "Product 3", price: 35.59} 
  ]; 
  $("ul").append("#template", products); 
}); 
</script> 
<script id="template" type="text/html"> 
 <li>{%= name %} - {%= price %}</li> 
</script> 
<ul></ul>
 

jQuery.templates
你可以指定一个或多个编译的模板给Query.templates对象设置。当你想给模板一个语义化的名字以便在一个文档中很方便的多次使用同一模板时,这很有用。

用jQuery.tmpl()函数编译一个模板

示例

<script type="text/javascript"> 
    // Assign compiled template 
    jQuery.templates.foo = jQuery.tmpl("<li>{%=name%}</li>"); 
    // use name foo as template in append() method: 
    jQuery("#container").append("foo", products); 
</script>
 

jQuery.tmplFn
在一个模板实例中,你可以使用两个内置的函数text()和html()渲染一个数据项。你可以通过给jQuery.tmpFn对象指定一个新的函数在模板实例中扩展一组可用的函数。

下面的代码向你演示了如何创建even()函数,该函数在轮替模板时返回true。在下面的示例中,even()函数用来在模板中交替呈现粗体行。

<script type="text/javascript"> 
    $(function() { 
        var products = [ 
            { name: "Product 1", price: 12.99 }, 
            { name: "Product 2", price: 9.99 }, 
            { name: "Product 3", price: 35.59 } 
        ];
        $.tmplFn.even = function() { 
            var context = jQuery._.context; 
            return (context.index % 2 === 0); 
        }; 
        $("div").append("#template", products); 
    }); 
</script> 
<script id="template" type="text/html"> 
  <div> 
  {% if (even()) { %} 
     <b> {%= name %} </b> 
  {% } else { %} 
     {%= name %}  
  {% }; %}  
  </div> 
</script> 
<div> 
</div>
模板语法
内嵌表达式
表达式可以用{%= ... %} 的语法形式插入,这个分隔符最大限度的减少了编码标记的机会,同时避免与现有的服务器端和客户端的扩展标记相冲突(例如:{%=...%}可能与ASP和 ASP.NET相冲突)。

示例

简单的数据插入:

<script type="text/html" id="tmp1"> 
    <li>{%= last %}, {%= first %}</li> 
</script>
 

表达式为javascript,你可以调用任何JavaScript函数用或使用更复杂的表达式。但是,注意,保持模板尽可能的简单是首选,后面要描述的两个回调有助于理解这些。

<script type="text/html" id="tmp1"> 
    <li>{%= last + " " + first %}</li> 
</script>

HTML插入
默认情况下,数据项在模板中被渲染时不会被HTML编码。如果你在一个模板中显示用户提交的数据,那么恶意用户就能够执行跨站点脚本攻击(XSS)。

注意下面代码中第一个产品的名字,第一个产品包含一个没有任何恶意的onClick事件处理程序,当数据项显示,有人点击了产品名字,JavaScript得到执行。

<script type="text/javascript"> 
jQuery(function(){ 
  var products = [ 
        { name: "<a onclick='alert(\"do evil\")'>click here</a>", price: 12.99}, 
        { name: "Product 2", price: 9.99}, 
        { name: "Product 3", price: 35.59} 
  ]; 
  $("ul").append("#template", products); 
}); 
</script> 
<script id="template" type="text/html"> 
 <li>{%= name %} - {%= price %}</li> 
</script> 
<ul></ul>
 

为了很容易的在一个模板中给要显示的数据进行HTML编码,使你免遭这种XSS的进攻,可以使用一个名为text()的内置函数。text()函数将一个数据项转换成文本节点。这里告诉你如何使用text()函数。

<script type="text/javascript"> 
jQuery(function(){ 
  var products = [ 
        { name: "<a onclick='alert(\"do evil\")'>click here</a>", price: 12.99}, 
        { name: "Product 2", price: 9.99}, 
        { name: "Product 3", price: 35.59} 
  ]; 
  $("ul").append("#template", products); 
}); 
</script> 
<script id="template" type="text/html"> 
 <li>{% text(name) %} - {%= price %}</li> 
</script> 
<ul></ul>
 

代码块
除了表达式,你可以在模板中插入代码执行自定义逻辑、条件或循环。代码块用{%....%}语法来分隔(没有=)。

示例

这个例子显示系列产品的name,如果有可用的“specials”则显示。

<script type="text/html" id="tmp1"> 
<li> 
    {%= name %} 
    {% if (specials.length) { %} 
    <ul> 
    {% for (var i = 0, l = specials.length; i < l; i++) { %} 
        <li>{%= specials[i].details %}</li> 
    {% } %} 
    </ul> 
    {% } %} 
</li> 
</script>

上下文
在模板中,你可以使用一个名叫$context 的特殊变量,这与提案后面要描述的rendering和rendered回调是同一个对象。$context具有以下属性:

 

参数 描述  
data 传递给render()和append()函数的数组或对象 
dataItem 但是,这个放到with() 块中,使得数据的每一个字段可以直接使用。例如,如果数据为[{name:"dave"},{name:"bob"}] ,那么{%= name } 就可以使用。但是要注意,指向一个不存在的字段将是无效的。数据为[{name:"dave"},{firstname:"bob"}] ,那么第二个表达式“name”将无效。 
index 传递给模板的当前数据项在数组中的索引。如果是一个对象,索引为0 
options 传递给模板的选项参数。这个提供了给模板传递额外参数的方法。


你对$context 变量的修改在模板中将保持一致。例如,你可以在render()函数中给$context 变量添加计算字段。

function rendering(context) { 
  context.tax = context.dataItem.price * 0.23; 
}
 

你可以在模板中使用tax计算字段,保持模板简单,避免需要调试的内嵌表达式。

<script type="text/html" id="tmp1"> 
  The product with tax costs {%= $context.tax %} 
</script>
 

你可以使用$context.options变量指向任何需要传递给render()和append()函数的选项。下面的示例演示了如何根据传递给append()函数的showSalePrice 参数值来显示正常价格或零售价格。

<script type="text/javascript"> 
    jQuery(function() { 
        var products = [ 
            { name: "Product 1", price: 12.99, salePrice: 10.99 }, 
            { name: "Product 2", price: 9.99, salePrice: 7.99 }, 
            { name: "Product 3", price: 35.59, salePrice: 33.59 } 
        ]; 
        $("ul").append("#template", products, { showSalePrice: true });     
    }); 
</script> 
<script id="template" type="text/html"> 
 <li> 
     {%= name %} -  
     {%= $context.options.showSalePrice ? salePrice : price %} 
 </li> 
</script> 
<ul></ul>
 

注意如何在模板中根据$ context.options.showSalePrice属性来显示正常价格或零售价格。

模板渲染和呈现回调
你可以利用传递给render()函数或append()的options参数来指定模板回调函数。有两个回调函数:

rendering:该函数在模板渲染时立即调用。它作为模板自身内同一$context对象的参数。回调返回flase以防渲染数据项。 
rendered:该函数在模板渲染时立即调用,但是在DOM元素已添加到文档之前。 它同样作为模板自身内同一$context对象的参数。 
以下几节讨论使用rendering和rendered函数的几种情况:

执行复杂的计算
想象以下你要计算在模板中显示的每个product的税率,但你又不想计算税率的逻辑出现在模板自身中。此时,你可以像这样在rendering函数中执行税率计算:

<script type="text/javascript"> 
    jQuery(function() { 
        var products = [ 
          { name: "Product 1", price: 12.99 }, 
          { name: "Product 2", price: 9.99 }, 
          { name: "Product 3", price: 35.59 } 
        ]; 
        $("ul").append("#template", products, { rendering: rendering }); 
       function rendering(context) { 
            var item = context.dataItem; 
            // setup additional information to be used more clearly within the template 
            // (avoids complex expressions) 
            item.tax = Math.floor(item.price * 8.75) / 100; 
        } 
    }); 
</script> 
<script id="template" type="text/html"> 
 <li>{%= name %} - price with tax {%= price + tax %} </li> 
</script> 
<ul></ul>
 

取消模板渲染
你可以利用rendering()回调取消特定模板实例的渲染。下面的代码演示了如何仅渲染标了删除标记的产品。

<script type="text/javascript"> 
   jQuery(function() { 
        var products = [ 
            { name: "Product 1", price: 12.99 }, 
            { name: "Product 2", price: 9.99, deleted: true }, 
            { name: "Product 3", price: 35.59 } 
        ]; 
        $("ul").append("#template", products, { rendering: rendering }); 
        function rendering(context) { 
            if (context.dataItem.deleted) { 
                return false; 
            } 
        } 
    });
</script> 
<script id="template" type="text/html"> 
 <li>{%= name %} - {%= price %}</li> 
</script> 
<ul></ul>

当rendering()返回false时,模板不会显示。在上面的示例代码中,当产品标上删除标记时,模板不会渲染。

嵌套模板
利用回调函数,你可以创建其嵌套模板。例如,下面代码显示了如何显示联系人名单,每个联系人有一个或多个电话号码。contactTemplate 用来显示联系人名单,phoneTemplate 用来显示每个电话号码。

<script type="text/javascript"> 
    $(function() {    
        var contacts = [ 
            { name: "Dave Reed", phones: ["209-989-8888", "209-800-9090"] }, 
            { name: "Stephen Walther", phones: ["206-999-8888"] }, 
            { name: "Boris Moore", phones: ["415-999-2545"] } 
        ]; 
        $("div").append("#contactTemplate", contacts, {rendered:rendered}); 
    }); 
    function rendered(context, dom) { 
        $("div.phones", dom) 
            .append("#phoneTemplate", context.dataItem.phones); 
    }  
</script> 
<script id="contactTemplate" type="text/html"> 
 <div> 
     {%= name %} 
     <div class="phones"></div> 
 </div> 
</script> 
<script id="phoneTemplate" type="text/html"> 
 <div> 
     Phone: {%= $context.dataItem %} 
 </div> 
</script> 
<div></div>
 

创建插件
假设你想在模板中使用插件--如jQuery UI Datepicker。此外,想象以下,你希望插件显示数据项的值。例如,你希望DatePicker 默认显示数据项的一个date属性。在这种情况下,你需要利用rendered()回调创建插件并用数据项的值初始化插件。

例如,下面的代码显示联系人的名单,rendered() 用来创建一个jQuery UI Datepicker插件,并在模板中的一个input元素中附加插件。DataPicker 的默认值为联系人的生日。

<script type="text/javascript"> 
    $(function() { 
        var contacts = [ 
            { name: "Dave Reed", birthdate: new Date("12/25/1980") }, 
            { name: "Stephen Walther", birthdate: new Date("12/25/1977") }, 
            { name: "Boris Moore", birthdate: new Date("12/25/1934") }, 
            { name: "Eilon Lipton", birthdate: new Date("12/25/2004") }, 
            { name: "Assad Safiullah", birthdate: new Date("12/25/1954") } 
        ]; 
        $("div").append("#template", contacts, { rendered: rendered }); 
    }); 
    function rendered(context, dom) { 
        $("input", dom) 
            .datepicker({ defaultDate: context.dataItem.birthdate }) 
    }     
</script> 
<script id="template" type="text/html"> 
 <div> 
     {%= name %} 
     <br /> 
     birthdate: <input /> 
 </div> 
</script> 
 
<div></div>
 

无表达式模板
如果你不想任何诸如{%=....%}的表达式出现在模板中,你可以在模板实例中使用rendered函数动态的为一个元素赋值。例如,下面模板显示产品清单。注意,模板只包含HTML标记,没有表达式。


讨论(Discussion)
这些都是在论坛讨论中提出的问题。

HTML编码
在目前的提案中,数据项默认是不被编码的。这意味着,除非你采取额外的行为,用模板显示用户提交的数据的文档将为跨站点脚本(XSS)攻击大开门户。在早期的提案中,我们讨论为HTML编码内容创建一个诸如{!productName }特别分隔符。在目前的提案中,我们建议使用text()模板函数,而不是用{%= text(productName) %} 。

脚本与样式模板容器
在目前的提案中,我们建议在<script id="template" type="text/html"></script>元素中包裹模板。有人提议,较好的选择是用<style id="template" type="text/html"></style>元素,因为样式更好的体现了模板表象的性质。

样式元素的缺点在于不允许出现在文档的body中,如果你不能修改head元素的内容--例如,你正在使用内容管理系统(CMS)工作,你就无法创建模板。

从技术上讲,当前的提案与用SCRIPT或STYLE包裹模板是兼容的。如果你愿意,你可以使用Style元素并替换type属性。

模板应是真正的DOM元素
只有几个人建议模板应代表真正的DOM元素,这也与ASP . NET Ajax 库创建模板的方法相似。换句话说,给模板使用标准的DOM元素,用display:none隐藏模板。

使用真正的DOM元素模板的主要缺点在于使用真正的DOM元素会导致不良副作用。例如,考虑下面的代码:

<div id="template" style="display:none"> 
  <img src="{%= imageUrl %}" /> 
  <br /> {% imageTitle %} 
</div>

在这种情况下,浏览器会尝试加载位于{%= imageUrl } 地址的图片,这并不是你向发生的。像这样的例子有很多,一个表达式会导致意想不到的副作用或无效的 HTML。例如,如果是在form中,模板中的input可能post一个实际的值。另一个很好的例子是在<div id="{ = foo %}"/>其中的id属性包含无效的值。

修订历史
2010年2月27日--公布初步的提案; 
2010年3月2日--针对社区反馈更新提案; 
将renderTemplate() 重命名为 template() ; 
将分隔符{{ ... }} 改为[[ ... ]] ; 
增加[[! ... ]] 用来显示无编码的HTML; 
移除上下文变量和诸如$id()、$index、writeHtml()和write() 的方法; 
增加rendering()函数; 
增加templateSetup()函数; 
2010年3月9日--针对John Resig 的原型和社区的反馈更新提案; 
将template() 重命名为render() ; 
新增DOM操作(如append()); 
将表达式中的分隔符改为{%= ... %} ,代码中的分隔符改为{% ... %} ; 
删除templateSetup()方法。 

posted @ 2016-04-06 13:01  默默盟主  阅读(415)  评论(0编辑  收藏  举报