Hogan.js模板引擎
Hogan.js是Twitter开源的一款轻量级、高效的JavaScript模板引擎,它使得在客户端或者服务器端生成HTML变得简单而直观,在github上拥有者5.1K的star
https://github.com/twitter/hogan.js
https://twitter.github.io/hogan.js/
简介
- Hogan.js的设计目标是提供一个高效、灵活且易于理解的模板语法,用于动态生成HTML代码。它的灵感来源于 Mustache 模板语言,但提供了更丰富的内建功能和更好的性能。Hogan.js的主要优势在于其紧凑的语法,对大型应用的高性能支持,以及与Twitter的其他前端框架(如 Flight)的良好集成。
- Hogan.js 是 Mustache 模板引擎的另一套实现,增加了预编译机制,这意味着你得到的变量,块,lambda表达式,部分模板,过滤器,和其他一切你期望从mustache模板快得多
特性
- 快
- Hogan有单独的扫描,语法分析和代码生成阶段。这样就可以添加新的功能不需触摸扫描仪,和许多不同的代码生成技术,可以尝试不改变解析器。
- Hogan扫描和解析方法出现。这可能是有用的,在服务器上的预处理模板。
- Hogan还支持模板继承,并保持与其他实现像mustache.java ,mustache.php,和GRMustache。
- 高性能:通过预编译优化,提供高效的渲染体验。
- 小巧无依赖:易于集成到现有项目,减少加载时间。
端编译
Hogan.js浏览器端编译
Hogan.js 是 Mustache 模板引擎的另一套实现,增加了预编译机制,使得模板字符串可以在打包阶段被预先处理成模板函数,这样浏览器就不必再重复去编译模板。
Hogan.js 同时提供了可以运行与_浏览器端,浏览器端负责用预编译后的代码渲染页面。
var Template = {
_cache: {},
// 所有的模板放在这个对象下
_template: {
hello: /*TMPL*/"hello {{name}}!"/*TMPL*/
},
// 这个适配函数会同时处理字符串模板和模板函数的情况
render: function (name, data) {
if (!this._cache[name]) {
// 如果代码被预编译过,则不需要 compile
if (typeof this._template[name] === 'function') {
this._cache[name] = new Hogan.Template(this._template[name]);
} else if (typeof this._template[name] === 'string') {
this._cache[name] = Hogan.compile(this._template[name]);
}
}
return this._cache[name].render(data);
}
};
console.log(Template.render('hello', {name: "a"})); // hello a!
console.log(Template.render('hello', {name: "hs"})); // hello hs!
nodejs 环境中的预编译
Hogan.js 同时提供了可以运行 node.js 环境下的代码,node.js 负责打包时预编译,浏览器端负责用预编译后的代码渲染页面。
var hogan = require("hogan.js");
var fs = require("fs");
var fileContent = fs.readFileSync("demo.js", "utf-8");
fileContent.replace(/\/\*TMPL\*\/"(.*?)"\/\*TMPL\*\//g, function ($0, $1) {
return hogan.compile($1, {
asString: true
});
});
fs.writeFileSync("demo.js", fileContent, "utf-8");
源代码编译完之后,模板字符串就变成了模板函数
/* ... */
hello: function(c,p,i){var _=this;_.b(i=i||"");_.b("hello ");_.b(_.v(_.f("name",c,p,0)));_.b("!");return _.fl();;}
/* ... */
console.log(Template.render('hello', {name: "foo"})); // hello foo!
console.log(Template.render('hello', {name: "bar"})); // hello bar!
安装使用
// 安装
npm install hogan.js
// 引入hogan
var hogan = require('hogan.js');
// 渲染所需模板
var template = '<div>Hey! I am {{name}}!</div>';
// 渲染所需数据
var data = {
name : 'Rosen'
};
// 模板的编译
var compiledTemplate = hogan.compile(template);
// 模板的渲染
var result = compiledTemplate.render(data);
// 输出结果
console.log(result);
// output: <div>Hey! I am Rosen!</div>
npm里还有一个叫hogan的组件,是对hogan.js做的一个套壳的包装,同学们如果使用hogan出错的话,可以换成这里的hogan.js,还是原厂的好!除了引用名称,其他用法都是完全一样的。
语法
变量读取
{{变量}}语法
-
如果读取变量是一个字符串(非html结构片段),会直接替换变量
// 变量 { name : 'Rosen' }; // 模板: <div>Hey! I am {{name}}!</div> // 结果: <div>Hey! I am Rosen!</div>
-
如果读取变量是一个字符串(html结构片段),直接替换变量是不对html编码,放在dom里就是一段dom
// 数据: { name : '<span color="red">Rosen</span>' }; // 模板 <div>Hey! I am {{{name}}}!</div> // 结果 <div>Hey! I am <span color="red">Rosen</span>!</div>
IF 语句
{{#if condition}}
// 条件成立时执行的代码
{{else}}
// 条件不成立时执行的代码
{{/if}}
示例:
{{#if condition1}}
// 条件1成立时执行的代码
{{else if condition2}}
// 条件2成立时执行的代码
{{else if condition3}}
// 条件3成立时执行的代码
{{else}}
// 所有条件均不成立时执行的代码
{{/if}}
列表循环
{{#list}} {{/list}} 列表循环
// 数据
{
list: [
{name: 'Jack'},
{name: 'Tom'},
{name: 'Marry'}
],
isJack: true
}
// 列表循环
{{#list}}
<div>my name is {{name}}</div>
{{/list}}
// 结果
<div>my name is Jack</div>
<div>my name is Tom</div>
<div>my name is Marry</div>
-
两层循环标准的写法如下,项目中使用这种写法
两层循环 <script> var tab = { data: { "aa": [ { "name": "lily", "age": 18, "food": "苹果", "videoList": [ { "fileName": "aa", } ] }, { "name": "lucy", "age": 20, "food": "香蕉", "videoList": [ { "fileName": "cc", }, { "fileName": "dd", } ] } ] }, onload: function () { var tpl = `{{#listaa}} <ul> <div>我叫{{name}},我今年{{age}}岁,我喜欢吃{{food}}</div> {{#videoList}} {{!注释: 指定渲染的数据对象后,下面的数据都可以直接用 标签名=数据名}} <li>{{fileName}}</li> {{/videoList}} </ul> {{/listaa}}`; var template = Hogan.compile(tpl); var result = template.render({ listaa: this.data.aa //指定渲染的数据对象 }); // 最后添加到指定标签 $('.box').append(result); } } // 调用 tab.onload(); </script>
空列表
// 数据
{
list: [],
isJack: false
}
// 空列表
{{^list}}
这是一个空列表!
{{/list}}
// 结果
这是一个空列表!
真值判断
{{#布尔值类型变量名}} 我是Jack {{/布尔值类型变量名}}
// 数据
{
isJack: true
}
//真值判断
{{#isJack}}
我是Jack
{{/isJack}}
// 结果
我是Jack
非真值判断
判断当值是 (false null undefined 0 ‘’ NaN) 时,才渲染输出该区块内容
{{^布尔值类型变量名}} 我是Jack {{/布尔值类型变量名}}
// 数据
{
isJack: false
}
//非真值判断
{{^isJack}}
不认识Jack
{{/isJack}}
// 结果
不认识Jack
枚举元素
{{.}} 枚举类型没有索引名时,只能用{{.}},表示枚举类型的当前元素,一般都是枚举数组,不能枚举字符串
//数据
{
list: ['Jack', 'Tom', 'Marry']
}
// 用法
{{#list}}
<div>{{.}}</div>
{{/list}}
// 结果
<div>Jack</div>
<div>Tom</div>
<div>Marry</div>
注释
// 用法
{{!这是一个注释}}
<span>Hello Jack</span>
区块表示
以
#
开始、以/
结束表示区块,它会根据当前上下文中的键值来对区块进行一次或多次渲染
var data = {
people: [{
name: "Jack",
age: 18
}, {
name: "Davide",
age: 19
}]
};
var template = "{{#people}}名字:{{name}},年龄:{{age}};{{/people}}";
var hogan = Hogan.compile(template); //Hogan模版对象
var html = hogan.render(data); //结果:名字:Jack,年龄:18;名字:Davide,年龄:19;
子模块表示
以">"开始表示子模块,如{{>modular}};当结构比较复杂时,我们可以使用该语法将复杂的结构拆分成几个小的子模块,
var data = {
name: "执念",
age: 18,
sex: "男"
};
var template1 = "我的名字:{{name}};{{>age}};{{>sex}};";
var template2 = {
age: "年龄:{{age}}",
sex: "性别:{{sex}}"
};
var hogan = Hogan.compile(template1); //Hogan模版对象
var html = hogan.render(data, template2); //结果:我的名字:执念;年龄:18;性别:男;
预编译模板
asString选项用于控制编译后的模板是否作为字符串返回,而不是作为模板对象返回。当设置 asString: true 时,Hogan.compile() 方法会将编译后的模板转换为字符串,并返回字符串表示的模板,而不是模板对象。
//使用 asString 选项将编译后的模板输出为字符串,以便预编译模板并在运行时使用
var compiledTemplateString = Hogan.compile(templateText, { asString: true });
转义
{{keyName}}输出会将等特殊字符转译,如果想保持内容原样输出可以使用{{{}}}或者{{&}}
var data = {
specialChar: "<span>转义</span>"
};
var template = "{{specialChar}}<br />{{{specialChar}}}<br />{{&specialChar}}";
var hogan = Hogan.compile(template); //Hogan模版对象
var html = hogan.render(data); //结果:<span>转义</span><br /><span>转义</span><br /><span>转义</span>
-
正常的{{specialChar}}被Hogan转义,最终会以纯文本方式显示
-
而{{{specialChar}}}和{{&specialChar}}中包含的标签依旧正常输出,未转义。
自定义分割符
分隔符在模板引擎中起到标识模板变量的开始和结束的作用。在 Hogan.js 中,默认的分隔符是 {{ 和 }},用于标识模板变量的起始和结束位置。
//使用 delimiters 选项来指定模板中的自定义分隔符
var templateText = "Hello, <%name%>!";
var template = Hogan.compile(templateText, { delimiters: '<% %>' });
Lambdas表达式
当值是可调用的对象,例如function或者lambda,那么对象会被调用并且跳过文本。
被跳过的文字不进行渲染。{{tags}}将不会被展开——由lambda自身来决定。通过这种方式,可以实现过滤器以及缓存。
模板 :
{{#wrapped}}
{{name}} is awesome.
{{/wrapped}}
Hash - data绑定数据:
{
"name": "Willy",
"wrapped": function() {
return function(text) {
return "<b>" + text + "</b>"
}
}
}
输出 - render()渲染输出结果:
var output = template.render(data);
console.log(output);
<b>Willy is awesome.</b>
在这里wrapped值为function,对象被调用。
禁用Lambda特性
//使用 disableLambda 选项来禁用 Mustache 的高阶部分/lambda-replace 特性
var templateText = "{{#func}}{{/func}}";
var template = Hogan.compile(templateText, { disableLambda: true });
参考资料
- https://www.cnblogs.com/heater-5/articles/9343042.html
- http://cw.hubwiz.com/card/c