Bootstrap

Hogan.js模板引擎

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.jsMustache 模板引擎的另一套实现,增加了预编译机制,这意味着你得到的变量,块,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>
    

    img

空列表

// 数据
{
    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
;