第五章:视图和模板《Developing JavaScript Web Applications》学习笔记

模板

jQuery.tmpl是jQuery官方指定的jQuery模板库,这个库有一个主要的函数jQuery.tmpl(),可以给它传入一个模板和一些数据,函数会返回渲染好的元素节点,可以将渲染的结果追加至页面里。如果数据是数组的话,对于数组中的每个数据项都会生成渲染好的模板,否则,将只会渲染一个模板:

var object = {
url: "http://example.com",
getName: function(){ return "Trevor"; }
};
var template = '<li><a href="${url}">${getName()}</a></li>';
var element = jQuery.tmpl(template, object);
// 得到的结果: <li><a href="http://example.com">Trevor</a></li>
$("body").append(element);

这里你可以看到我们使用${} 语法来书写插见的变量。不管括号中的变量名是什么,都会根据传入jQuery.tmpl() 的对象来计算得出要填充的文本,不考虑它是一种属性还是一个函数。
然而模板的功能要比这种纯粹的插值替换强大很多。很多模板库都具有一些高级功能,诸如条件流(conditional flow)和迭代。你可以通过使用if 和else 语句来实现条件流,就像用纯粹的JavaScript 写出的代码一样。惟一和JavaScript 语法不同的地方是,这里需将关键字用双括号括起来,以便模板引擎能正确识别它们:

{{if url}}
${url}
{{/if}}

遍历是所有模板类库都提供的基础功能。使用模板类库的{{each}} 关键字可以遍历任何JavaScript 类型,包括Object 和Array。你可以使用$value 变量来访问当前正被遍历的值

var object = {
foo: "bar",
messages: ["Hi there", "Foo bar"]
};

然后使用接下来的模板来遍历这个message 数组,显示每条消息。此外,数组元素的索引也可以使用$index 变量来输出:

<ul>
{{each messages}}
<li>${$index + 1}: <em>${$value}</em></li>
{{/each}}
</ul>

模板Helpers

有时在视图内部使用“通用helper 函数”(generic helper function)是非常好用的,比如格式化一个日期或数字。将它抽象出来,并用命名空间进行管理,而不是直接将函数掺杂进视图中,这样才能保持逻辑和视图之间的解耦。例如:

// helper.js
var helper = {};
helper.autoLink = function(data){
var re = /((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g;
return(data.replace(re, '<a target="_blank" href="$1">$1</a> ') );
};
// template.html
<div>
${ helper.autoLink(this.data) }
</div>

这里还有一个额外的好处,autoLink() 函数是通用的,在应用的任何地方都可以重用它。

模板存储

说到模板存储,有这样一些内容需要考虑:

  1. 在JavaScript 中以行内形式存储。---违背了MVC 架构的原则
  2. 在自定义 script 标签里以行内形式存储。--推荐这种方式,浏览器不必对它们进行渲染,而仅将它们解析为内容文本
  3. 远程加载。--影像UI 的渲染
  4. 在 HTML 中以行内形式存储。--增加了初始页面的体积

其中一些非常适合在MVC 架构中使用。作者推荐使用第2种方式,即在自定义script标签里以行内形式存储模板。例如:

<script type="text/x-jquery-tmpl" id="someTemplate">
<span>${getName()}</span>
</script>
<script>
var data = {
getName: function(){ return "Bob" }
};
var element = $("#someTemplate").tmpl(data);
element.appendTo($("body"));
</script>

绑定

我们希望,当模型记录创建、更新或销毁时,都会触发change 事件,并重新渲染视图。在下面的例子中,我们创建了一个基础的
User 类,新建了事件绑定和触发,最后监听了change 事件,当触发change 事件时重新渲染视图:

<script>
var User = function(name){
this.name = name;
};
User.records = []
User.bind = function(ev, callback) {
var calls = this._callbacks || (this._callbacks = {});
(this._callbacks[ev] || (this._callbacks[ev] = [])).push(callback);
};
User.trigger = function(ev) {
var list, calls, i, l;
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
jQuery.each(list, function(){ this() })
};
User.create = function(name){
this.records.push(new this(name));
this.trigger("change")
};
jQuery(function($){
User.bind("change", function(){
var template = $("#userTmpl").tmpl(User.records);
$("#users").empty();
$("#users").append(template);
});
}):
</script>
<script id="userTmpl" type="text/x-jquery-tmpl">
<li>${name}</li>
</script>
<ul id="users">
</ul>

现在无论何时修改User 的记录,User 的模型的change 事件都会被触发,调用我们模板的回调函数并重绘用户列表。这很有帮助,因为我们只需关注创建和更新用户的记录,而不必担心视图的更新,视图的更新是自动的。比如,我们创建一个新的User :

User.create("Sam Seaborn");

标签: none

添加新评论