在web前端开发,特别是富ajax应用,经常会出现前端大段大段拼接html的片段,这使得本事很简单的渲染逻辑变得很难维护也很难阅读。为了解决这一问题,借鉴目前比较流行的模版语言的思想,jstemplate作为这方面比较流行的解决方案值得学习。自己在学习的过程中,将官方的文档做一简单整理,翻译给大家。

 

一.helloworld(完整例子)

     1)模版文件

 

<div id="t1">
    <h1 jscontent="title"></h1>
    <ul>
      <li jscontent="$this" jsselect="favs"></li>
    </ul>
  </div>

 

    2)填充数据

 


var favdata = { title: 'Favorite Things', favs: ['raindrops', 'whiskers', 'mittens'] };


 

    3)添加js库

 


<script src="util.js" type="text/javascript"></script> <script src="jsevalcontext.js" type="text/javascript"></script> <script src="jstemplate.js" type="text/javascript"></script>

 

    4)调用

 

function showData(data) {
      // This is the javascript code that processes the template:
      var input = new JsEvalContext(data);  //初始化数据
      var output = document.getElementById('t1'); //输出模版
      jstProcess(input, output);
    }

 

    当showdata调用后,模版渲染完毕产生的html即:

 

 


<div jstcache="0" id="t1"> <h1 jstcache="1" jscontent="title">Favorite Things</h1> <ul jstcache="0"> <li jsinstance="0" jstcache="2" jsselect="favs" jscontent="$this">raindrops</li> <li jsinstance="1" jstcache="3" jsselect="favs" jscontent="$this">whiskers</li> <li jsinstance="2" jstcache="4" jsselect="favs" jscontent="$this">mittens</li> </ul> </div>


 

二.有用属性标签和概念解释

 

     上面已经对jstemplate做了一个简单的应用,然而要真的理解它,并使用其高级点应用,需要了解一下一些概念。

 

environment)[ 03-environ.html ]

 

        有几个变量需要注意:

 

  • JsEvalContext 像其他context一样,它在整个代码执行过程中存在,存放所有的上下文数据,可以是字符串也可以json数据,一切你感兴趣的和有用的数据。

var mydata = {dataProperty: 'Nonny'}; var context = new JsEvalContext(mydata); context.setVariable('declaredVar', 'Ho');



  • this 和 $this

    this即为模版定义的html的某个节点,而$this是该节点绑定的context的数据。如



     


 

<div id="witha">
  <div id="Hey" jscontent="this.parentNode.id + this.id + 
      dataProperty + $this.dataProperty + declaredVar"></div>
  </div>

 

     这里this即为Hey div。而$this为context。

 

  2.jscontent

 

<div id="tpl">
    <span jsselect="username" jscontent="$this"></span>'s Address Book
  </div>

 

    即将该属性所在的节点值替换成jscontent的属性值。

 

  3.jsselect

 

    jsselect可以生成一个基于原context的新context。对于数组的数据,它能够自动遍历所有的元素并执行处理。

 

   语言有点抽象,举个例子:

 

  假如context值为:

 

var tplData = {
    username:"Jane User",
    addresses:[
      {location:"111 8th Av.", label:"NYC front door"},
      {location:"76 9th Av.", label:"NYC back door"},
      {location:"Mountain View", label:"Mothership"}
    ]};

   模版为:

 

<div id="tpl">
    <span jsselect="username" jscontent="$this"></span>'s Address Book
  </div>

transclude),所以新的该节点绑定的contex为字符串:Jane User,故渲染完成后为:

 

 

<span jscontent="username" jstcache="1">Jane Userff</span>

   这里可以看出,实际上和模版为:

 

<span jscontent="username"></span>'s Address Book

   的一样。

 

  因此,此标签更多用在数组上。

 

<table cellpadding="5">
  <tr><td><h2>Location:</h2></td><td><h2>Label:</h2></td></tr>
  <tr jsselect="addresses"><td jscontent="location"></td><td jscontent="label"></td></tr>
  </table>

  当处理器执行jsselect时,由于addresses是个数组,所以会遍历产生3个context,渲染的结果即:

 

<tr jsselect="addresses" jstcache="2" jsinstance="0">
<td jscontent="location" jstcache="3">111 8th Av.</td>
<td jscontent="label" jstcache="4">NYC front door</td>
</tr>
<tr jsselect="addresses" jstcache="2" jsinstance="1">
<td jscontent="location" jstcache="3">76 9th Av.</td>
<td jscontent="label" jstcache="4">NYC back door</td>
</tr>
<tr jsselect="addresses" jstcache="2" jsinstance="*2">
<td jscontent="location" jstcache="3">Mountain View</td>
<td jscontent="label" jstcache="4">Mothership</td>
</tr>

06-jsdisplay.html07-jsdisplay-empty.html ]

 

none。对于设置块的动态隐藏有奇效。

 

transclude [ 08-transclude.html ]

 

     对于嵌套的数据结构,对于模版来讲,嵌套深度并不能知晓,深度是由数据控制的,为了能够方便写出此类场景的模版,引入了该属性。例:

<html>
<head><title>Outline Tree Using Jstemplates</title>
  <script src="../util.js" type="text/javascript"></script>
  <script src="../jsevalcontext.js" type="text/javascript"></script>
  <script src="../jstemplate.js" type="text/javascript"></script>
  <script type="text/javascript">
    // Hierarchical data:
    var tplData = 
      { title: "Jstemplates", items: [
        { title: "Using Jstemplates", items: [
          { title: "The Jstemplates Module"},
          { title: "Javascript Data"},
          { title: "Template HTML"},
          { title: "Processing Templates with Javascript Statements"}
          ]
        },
        { title: "Template Processing Instructions", items: [
          { title: "Processing Environment" },
          { title: "Instruction Attributes", items: [
            {title: "jscontent"}, {title: "jsselect"}, {title: "jsdisplay"}, 
            {title: "transclude"},{title: "jsvalues"}, {title: "jsskip"}, {title: "jseval"}
          ]}
        ]}
      ]};
      
    var PEG_NAME = 'peg';
    var TEMPLATE_NAME = 'tpl';
    
    // Called by the body onload handler:
    function jsinit() {
      pegElement = domGetElementById(document, PEG_NAME);
      loadData(pegElement, TEMPLATE_NAME, tplData);
    }
  
    function loadData(peg, templateId, data) {
      // Get a copy of the template:
      var templateToProcess = jstGetTemplate(templateId);  //clone出一个,而非直接替换使用
      
      // Wrap our data in a context object:
      var processingContext = new JsEvalContext(data);
  
      // Process the template
      jstProcess(processingContext, templateToProcess);
      
      // Clear the element to which we'll attach the processed template:
      peg.innerHTML = '';
      
      // Attach the template:
            domAppendChild(peg, templateToProcess);
    }
    </script>
    <link rel="stylesheet" type="text/css" href="css/maps2.deb.css"/>
</head>
<body οnlοad="jsinit()">

<!-- 
This is the div to which the instantiated template will be attached.
-->
<div id="peg"></div>

<!--
A container to hide our template:
-->
<div style="display:none">
<!-- 
This is the template div. It will be copied and attached to the div above with:
 var apt = jstGetTemplate('apt');
 appendChild(panel, apt)
-->
  <div id="tpl">
    <span jscontent="title">Outline heading</span>
    <ul jsdisplay="items.length">
      <li jsselect="items">
        <!--Recursive tranclusion: -->
        <div transclude="tpl"></div>
      </li>
    </ul>
  </div>

</div>
</body>
</html>

 

 

  6.jsvalues(jsvars同)

 

  • $ 可以通过$引用  

JsEvalContext,如果

  •  

jsvalues="$varname:varvalue",则可以通过

  • $varname来引用。
  • . 可以修改该节点的属性。如 jsvalues=".id:'Joe';.style.fontSize:'30pt'",这该节点的id,style就会被赋值为该值
  • 表达式   

jsvalues="sum:1+2"

  •  =  

this.setAttribute('sum', '3')

  • .

 


 

       该属性顾名思义,其值是一段js,在渲染所在节点时可以获得执行。例如:

利用$,创建一个counter变量

 


processingContext.setVariable('$counter', counter);


 

<span jscontent="title" 
          jseval="title? $counter.full++: $counter.empty++">
      Outline heading
    </span>

   在其他片段可以引用。

<div id="titleCountTpl">
  <p>
      This outline has <span jscontent="$counter.empty"></span> empty titles 
      and <span jscontent="$counter.full"></span> titles with content.
  </p>
  </div>

 

     8.jsskip

 

 处理器将不在处理当前节点和子节点。 它在增加处理性能方面有一定作用,比如避免不必要的深层树遍历。

 

 

<div id="tpl2">
<h1 jsselect="username" jscontent="$this + '\'s Previous Searches'"></h1>
<ul jsskip="true">
<li jsselect="addresses" jscontent="location"></li>
</ul>
</div>

上面的属性的执行顺序为:

 

transclude. If a transclude attribute is present no further Jst attributes are processed.

jsselect. If 

jsselect is array-valued, remaining attributes will be copied to each new duplicate element created by the 

jsselect and processed when the new elements are processed.

jsdisplayjsvarsjsvaluesjsevaljsskipjscontent