Template7
Template7 是一个移动设备优先的 JavaScript 模板引擎,其语法类似于Handlebars。在Framework7中被用作默认的模板引擎。
极轻(压缩后大约 1KB) ,速度极快(在Safari手机浏览器中比 Handlebars 快2-3倍)。
下载和安装 Template7
首先我们需要下载 Template7 必须的文件:
- 我们能从 Template7 的 GitHub 仓库下载
-
或者通过 Bower 安装, 在终端中输入:
$ bower install template7
在下载安装包的disk文件夹中,有我们需要 JavaScript 文件 (.js)。
然后在 HTML 页面加入如下代码:
<html>
<head>
...
<script src="path/to/template7.min.js"></script>
</head>
<body>
...
</body>
</html>
模板
Template7 模板类似于 Handlebars 模板, 看起来像嵌入表达式整齐的 HTML:
<div class="list-block">
<ul>
{{#each items}}
<li class="item-content">
<div class="item-inner">
<div class="item-title">{{title}}</div>
</div>
</li>
{{/each}}
</ul>
</div>
表达式语法
Template7 支持下列表达式:
变量:
-
{{title}}- 普通变量。 从当前上下文中输出 "title" 变量 -
{{../title}}- 普通变量。 从父级上下文中输出 "title" 变量 -
{{../../title}}- 普通变量。从父级的父级上下文中输出 "title" 变量 -
{{this}}- 普通变量。输出当前上下文 -
{{person.name}}- 普通变量。在当前上下文中输出 "name" 的属性 "person" 变量 -
{{../person.name}}- 普通变量。和上一个相通,只是在父级上下文中 -
{{@index}}- 使用额外的数据变量。在“Helpers”中这样的数据变量很有帮助
区块表达式
-
{{#each}}- 区块表达式开始 -
{{else}}- 开始区块相反的表达式 (where supported) -
{{/each}}- 区块表达式结束 -
{{#each reverse="true"}}- 区块开始,带有属性reverse:true
Helpers
Helpers 可以是普通表达式或区块表达式:
-
{{join myArray delimiter=", "}}- 执行 "join" helper,传递"myArray"变量到当前上下文,带有属性delimiter:', '
编译和渲染
Template7 是 Window function 的一个全局变量。
首先我们需要做出字符串模板。比如,我们可以把模板存储在 script 标签中:
<script id="template" type="text/template7">
<p>Hello, my name is {{firstName}} {{lastName}}</p>
</script>
然后我嘛需要用 JavaScript 编译它。Template7 会将我们的模板字符串转换为普通的 JavaScript 方法:
var template = $$('#template').html();
// 用 Template7 编译
var compiledTemplate = Template7.compile(template);
// 然后我们可以通过传递所需的上下文数据来渲染编译后的模板
var context = {
firstName: 'John',
lastName: 'Doe'
};
var html = compiledTemplate(context);
现在,
html
变量包含:
<p>Hello, my name is John Doe</p>
内置的 Helpers
Template7 内置的 Helpers 就像预定义好的方法一样来处理带有上下文的一些事情。
{{#each}}...{{else}}...{{/each}}
{{#each}}
是一个块表达式,遍历数组项或对象的属性。
以下是在 helper 中可用的其它变量:
-
@index- 项的数字索引。只有数组具有 -
@first- 等同于数组的第一项。只有数组具有 -
@last- 等同于数组的最后一项。只有数组具有 -
@key- 当前对象属性的名称。只有对象具有
| 模板 -> | 上下文 -> | 输出 | 遍历数组项 |
|---|---|---|
|
|
|
|
|
|
遍历对象属性 |
|
|
|
{{else}} 表达式 |
|
|
|
|
|
|
{{#if}}...{{else}}...{{/if}}
{{#if}} helper 渲染内容,当传递的上下文不是 "false" (或 "undefined" 或 "null" 或 "" 或 "0") 的时候,相反它会渲染通过内置的 helper 表达式传递到 {{else}} 的内容:
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{else}} 表达式 |
|
|
|
{{#unless}}...{{else}}...{{/unless}}
{{#unless}} helper 渲染数据,如果传递的上下文是 "false" (或 "undefined" 或 "null" 或 "" 或 "0") ,相反它会渲染通过内置的 helper 表达式传递到 {{else}} 的内容:
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{else}} 表达式 |
|
|
|
{{#with}}...{{/with}}
{{#with}} helper 将传递的上下文替换为渲染的上下文:
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{#变量名}}...{{/变量名}}
如果你用 helper 名称传递一个区块表达式,它会像{{#each}} helper 一样处理一个数组上下文,如果是一个对象会像 {{#with}} 一样处理:
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
|
|
|
{{join delimiter=""}}
这个 helper 会用传递的定界符将数组项连接为一个单独的字符串
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{escape}}
这个 helper 返回转义的 HTML 字符串。它仅转义以下字符:
< > " &
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{js "表达式"}}
这个 helper 允许直接在模板中执行一些简单的 JavaScript,动态的修改或判断上下文或一些 JS 计算
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
{{#js_compare "表达式"}}...{{/js_compare}}
这个区块 helper 可用轻松的比较上下文变量。如果 JavaScript 表达式不是 "false" (或 "undefined" 或 "null" 或 "" 或 "0")时,它会渲染上下文,相反它会渲染通过内置的 helper 表达式传递到 {{else}} 的内容:
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
|
|
|
注意在 js 和 js_compare helper 中,你需要用 this.variableName
来代替
variableName
自定义 Helpers
Template7 允许用以下方法注册自定义 helpers:
Template7.registerHelper(name, helper)
- name - string - helper 名称
- helper - function - helper方法,处理传递的上下文
Helper 函数可以接收很多需要的参数,这些参数可以是上下文,字符串或 hash 数据。
下面让我们看一下如何用简单的 {{#if}} 注册一个helper:
Template7.registerHelper('if', function (condition, options) {
// "this" 在函数上下文中等同于表达式执行的上下文
// "condition" 参数包含传递的上下文或条件
/*
@options 对象包含如下属性和方法:
"hash" - 包含传递带有参数的hash对象
"fn" - 方法传递 helper 块内容到编译器
"inverse" - 方法传递相反的 helper ({{else}}) 内容到编译器
"data" - 包含额外的表达式数据,比如数组的 @index 或对象的 @key
*/
// 首先我们需要先判断传递的上下文是一个函数
if (typeof condition === 'function') condition = condition.call(this);
// 判断上下文的条件
if (condition) {
// 我们需要传递带有相同数据的区块内容到编译器:
options.fn(this, options.data);
}
else {
// 传递相反的 helper ({{else}}) 内容到编译器:
options.inverse(this, options.data);
}
});
在 {{join}} helper 的例子中:
Template7.registerHelper('join', function (arr, options) {
// 首先我们需要攀登传递的 arr 参数是一个函数
if (typeof arr === 'function') arr = arr.call(this);
/*
传递的分界符是 options.hash 的对象:
console.log(options.hash) -> {delimiter: ', '}
*/
// 返回被串联的数组
return arr.join(options.hash.delimiter);
});
我们可以用以下语法创建一个 Framework7 的 list-block 链接:
{{link url title target="_blank"}}
Template7.registerHelper('link', function (url, title, options){
var ret = '<li>' +
'<a href="' + url + '" class="item-content item-link" target="' + options.hash.target + '">' +
'<div class="item-inner">' +
'<div class="item-title">' + title + '</div>' +
'</div>' +
'</a>' +
'</li>';
return ret;
});
| 模板 -> | 上下文 -> | 输出 |
|---|---|---|
|
|
|
注意,所有的自定义 helper 应该在你编译模板前定义好!
移除自定义 Helpers
Template7 允许使用以下方法移除自定义 helpers :
Template7.unregisterHelper(name)
- name - string - helper 名称
全局上下文
Template7 也支持全局上下文,可以很容易访问任何上下文内容。
我们可以在
Template7.global
属性中定义:
Template7.global = {
os: 'iOS',
browser: 'Chrome',
username: 'johndoe',
email: [email protected]'
};
我们可以用{{@global}}变量在模板中访问它:
<p>Hello, [email protected]}}. Your email is [email protected]}}</p>
访问根上下文
有时我们可能需要访问最初传入到模板中的根上下文。对于这种情况我们需要用 {{@root}}
变量。当我们的上下文内容较深时,这种方式尤为重要:
{
persons: [
{
name: 'John',
hobby: ['Cars', 'Food']
},
{
name: 'Kyle',
hobby: ['Travel', 'Puzzles']
},
],
showHobby: true
}
{{#each persons}}
<h2>{{name}}</h2>
<h3>Hobby:</h3>
{{#if @root.showHobby}}
<ul>
{{#each hobby}}
<li>{{this}}</li>
{{/each}}
</ul>
{{/if}}
{{/each}}
Partials
Template7 允许使用 partials 复用模板。正常情况下在 Template7 模板中 复用模板 Partials时通用的。可以被其它模板调用。
我们可以使用以下方法注册和注销 partials :
Template7.registerPartial(name, template) - 注册 partial
- name - string - partial 名称
- helper - string - partial 模板
Template7.unregisterPartial(name) - 注销 partial
- name - string - partial 名称
然后我们可以使用特殊的
{{> "partialName"}} helper 来利用我们的 partials
模板:
<ul class="users">
{{#each users}}
{{> "user"}}
{{/each}}
</ul>
<ul class="admins">
{{#each admins}}
{{> "user"}}
{{/each}}
</ul>
注册 partial:
Template7.registerPartial('user', '<li><h2>{{firstName}} {{lastName}}</h2><p>{{bio}}</p></li>')
将上下文应用到模板:
{
users: [
{
firstName: 'John',
lastName: 'Doe',
bio: 'Lorem ipsum dolor'
},
{
firstName: 'Jane',
lastName: 'Doe',
bio: 'Donec sodales euismod augue'
}
],
admins: [
{
firstName: 'Mike',
lastName: 'Doe',
bio: 'Lorem ipsum dolor'
},
{
firstName: 'Kate',
lastName: 'Doe',
bio: 'Donec sodales euismod augue'
}
]
}
我们会得到以下输出:
<ul class="users">
<li>
<h2>John Doe</h2>
<p>Lorem ipsum dolor</p>
</li>
<li>
<h2>Jane Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
<ul class="admins">
<li>
<h2>Mike Doe</h2>
<p>Lorem ipsum dolor</p>
</li>
<li>
<h2>Kate Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
递归 Partials
我们甚至可以 partials 来递归模板,像嵌入的注释:
// 带有一个 partial 的简单模板
var template = '{{> "comments"}}'
// 注册 partial
Template7.registerPartial(
'comments',
'<ul>' +
'{{#each comments}}' +
'<li>' +
'<h2>{{author}}</h2>' +
'<p>{{text}}</p>' +
'{{#if comments}}{{> "comments"}}{{/if}}' +
'</li>' +
'{{/each}}' +
'</ul>'
);
// 编译模板
var compiledTemplate = Template7.compile(template);
// 渲染模板
var output = compiledTemplate({
comments: [
{
author: 'John Doe',
text: 'Lorem ipsum dolor',
comments: [
{
author: 'Mike Doe',
text: 'Aliquam erat volutpat'
},
{
author: 'Kate Doe',
text: 'Donec eget fringilla turpis'
}
]
},
{
author: 'Jane Doe',
text: 'Donec sodales euismod augue'
}
]
})
输出如下:
<ul class="comments">
<li>
<h2>John Doe</h2>
<p>Lorem ipsum dolor</p>
<ul class="comments">
<li>
<h2>Mike Doe</h2>
<p>Aliquam erat volutpat</p>
</li>
<li>
<h2>Kate Doe</h2>
<p>Donec eget fringilla turpis</p>
</li>
</ul>
</li>
<li>
<h2>Jane Doe</h2>
<p>Donec sodales euismod augue</p>
</li>
</ul>
性能提醒
Template7 速度很快,你可以让它在你的app中运行更快。最慢的部分是在编译/渲染过程,当你执行
Template7.compile()。因此不要多次编译相同的模板,一次就足够了:
// app 开始
// 在app加载或初始化时编译模板
var searchTemplate = $('script#search-template').html();
var compiledSearchTemplate = Template7.compile(searchTemplate);
var listTemplate = $('script#list-template').html();
var compiledListTemplate = Template7.compile(listTemplate);
// 现在只需要用所需的上下文执行编译模板
var html = compiledSearchTemplate({/*...some data...*/});
// Do something with html...
