在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.html, 07-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.
jsdisplay
jsvars
jsvalues
jseval
jsskip
jscontent