JavaScript 模板


Demo


https://blueimp.github.io/JavaScript-Templates/

概述


1KB 轻量级、快速且强大的 JavaScript 模板引擎,零依赖。

强大的兼容性,与包括Node.js 等服务器端环境,RequireJSwebpack 等模块加载器,以及所有的 web 浏览器所兼容。

使用介绍


客户端

通过 NPM 安装 blueimp-tmpl 插件包:

$ npm install blueimp-tmpl

在你的 html 页面中引入压缩包的 JavaScript 模板脚本:

<script src="js/tmpl.min.js"></script>

然后新加一个 script 标签,其 type 属性要设为“text/x-tmpl”,同时赋一个独立 id,标签的内容则是你需定义的模板:

<script type="text/x-tmpl" id="tmpl-demo">
  <h3>{%=o.title%}</h3>
  <p>Released under the
  <a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p>
  <h4>Features</h4>
  <ul>
  {% for (var i=0; i<o.features.length; i++) { %}
      <li>{%=o.features[i]%}</li>
  {% } %}
  </ul>
</script>

小写“o”,模板函数 data 参数的引用(请参阅后面 API 部分了解如何修改此标识符)。

在你的 js 代码中,要创建一个对象类型的 data 变量以用作模板的数据:

var data = {
  title: 'JavaScript Templates',
  license: {
    name: 'MIT license',
    url: 'https://opensource.org/licenses/MIT'
  },
  features: ['lightweight & fast', 'powerful', 'zero dependencies']
}

在实际应用中,该 data 可能是请求某个 JSON 资源时的返回值。

通过调用 tmpl() 函数进行页面渲染,传递的第一个参数为上面模板定义时的那个独立 id,第二个参数则是 data 对象:

document.getElementById('result').innerHTML = tmpl('tmpl-demo', data)
服务端

接下来会举个例子,演示如何将 JavaScript 模板引擎结合到 Node.js 服务端中进行应用。

通过 NPM 安装 blueimp-tmpl 插件包:

$ npm install blueimp-tmpl

按照以下内容新建一个 template.html 文件:

<!DOCTYPE HTML>
<title>{%=o.title%}</title>
<h3><a href="{%=o.url%}">{%=o.title%}</a></h3>
<h4>Features</h4>
<ul>
{% for (var i=0; i<o.features.length; i++) { %}
    <li>{%=o.features[i]%}</li>
{% } %}
</ul>

然后按照以下内容再新建一个 server.js 文件:

require('http')
  .createServer(function (req, res) {
    var fs = require('fs'),
      // The tmpl module exports the tmpl() function:
      tmpl = require('./tmpl'),
      // Use the following version if you installed the package with npm:
      // tmpl = require("blueimp-tmpl"),
      // Sample data:
      data = {
        title: 'JavaScript Templates',
        url: 'https://github.com/blueimp/JavaScript-Templates',
        features: ['lightweight & fast', 'powerful', 'zero dependencies']
      }
    // Override the template loading method:
    tmpl.load = function (id) {
      var filename = id + '.html'
      console.log('Loading ' + filename)
      return fs.readFileSync(filename, 'utf8')
    }
    res.writeHead(200, { 'Content-Type': 'text/x-tmpl' })
    // Render the content:
    res.end(tmpl('template', data))
  })
  .listen(8080, 'localhost')
console.log('Server running at http://localhost:8080/')

最后便能通过下面命令运行程序:

$ node server.js

依赖项


本 JavaScript 模板脚本具有零依赖性。

API


tmpl() 函数

tmpl() 函数是在全局 window 对象下定义的,所以可以作为全局函数进行调用:

var result = tmpl('tmpl-demo', data)

tmpl() 函数在调用时,首参数既可以传模板 id,也可以传一串定义了模板内容的字符串:

var result = tmpl('<h3>{%=o.title%}</h3>', data)

如果不传递第二个参数,那么 tmpl() 会返回一个可复用的模板函数:

var func = tmpl('<h3>{%=o.title%}</h3>')
document.getElementById('result').innerHTML = func(data)
模板缓存

通过 id 加载的模板会缓存到 tmpl.cache 的映射表中:

var func = tmpl('tmpl-demo'), // Loads and parses the template
  cached = typeof tmpl.cache['tmpl-demo'] === 'function', // true
  result = tmpl('tmpl-demo', data) // Uses cached template function

tmpl.cache['tmpl-demo'] = null
result = tmpl('tmpl-demo', data) // Loads and parses the template again
编码输出

tmpl.encode 方法用于转义模板输出中的 HTML 特殊字符:

var output = tmpl.encode('<>&"\'\x00') // 渲染为"&lt;&gt;&amp;&quot;&#39;"

tmpl.encode 利用正则表达式 tmpl.encReg 和编码映射 tmpl.encMap 来匹配及替换特殊字符,通过上述方式实现输出内容的修改。

对于匹配正则表达式,但未能找到编码映射的字符串,在输出中会被移除。下面依此举一个自动 trim 输入值的例子(trim 指删除一个字符串头尾的空白符):

tmpl.encReg = /(^\s+)|(\s+$)|[<>&"'\x00]/g
var output = tmpl.encode('    Banana!    ') // 渲染为 "Banana" (清除空白符)
局部辅助变量

模板中可用的局部变量如下:

  • o:调用 tmpl() 函数时传递的 data 对象参数(请参阅下一节内容以了解如何修改参数变量名)。
  • tmpl:对 tmpl 函数对象的引用。
  • _s:渲染结果内容的字符串。
  • _etmpl.encode 方法的引用。
  • print:向渲染结果添加字符串的辅助函数。
  • include:在渲染结果中包含其他模板内容的辅助函数。

要引入额外的局部辅助变量,可以扩展字符串 tmpl.helper。下面示例新增了一个快捷函数来执行 console.log,以及新增了一个字符流处理函数,该函数将模板渲染结果按流式传给回调参数(注意每组变量声明都是用逗号分隔):

tmpl.helper +=
  ',log=function(){console.log.apply(console, arguments)}' +
  ",st='',stream=function(cb){var l=st.length;st=_s;cb( _s.slice(l));}"

这些新的辅助函数可用于将模板内容流式传输到控制台输出:

<script type="text/x-tmpl" id="tmpl-demo">
  <h3>{%=o.title%}</h3>
  {% stream(log); %}
  <p>Released under the
  <a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p>
  {% stream(log); %}
  <h4>Features</h4>
  <ul>
  {% stream(log); %}
  {% for (var i=0; i<o.features.length; i++) { %}
      <li>{%=o.features[i]%}</li>
      {% stream(log); %}
  {% } %}
  </ul>
  {% stream(log); %}
</script>
模板函数相关参数

生成的模板函数只接受一个参数,即提供给 tmpl(id, data) 函数的 data 对象。该参数在模板定义中会作为变量 o 使用。

可以通过覆盖 tmpl.arg 来修改参数名:

tmpl.arg = 'p'

// Renders "<h3>JavaScript Templates</h3>":
var result = tmpl('<h3>{%=p.title%}</h3>', { title: 'JavaScript Templates' })
模板解析

模板内容使用正则表达式 tmpl.regexp 和替换函数 tmpl.func 进行匹配和替换。替换函数基于 String replace() 进行操作。

要为模板语法使用不同的标签,请将 tmpl.regexp 设为修改后的正则表达式,具体就是换掉所有的“{%”和“%}”符号,例如改成“[%”和“%]”:

tmpl.regexp = /([\s'\\])(?!(?:[^[]|\[(?!%))*%\])|(?:\[%(=|#)([\s\S]+?)%\])|(\[%)|(%\])/g

默认情况下,插件保留空白符(换行符、回车符、制表符和空格)。若你想要清除这些不必要的空白符,你可以覆盖 tmpl.func 函数为下面示例的代码:

var originalFunc = tmpl.func
tmpl.func = function (s, p1, p2, p3, p4, p5, offset, str) {
  if (p1 && /\s/.test(p1)) {
    if (
      !offset ||
      /\s/.test(str.charAt(offset - 1)) ||
      /^\s+$/g.test(str.slice(offset))
    ) {
      return ''
    }
    return ' '
  }
  return originalFunc.apply(tmpl, arguments)
}

模板语法


数据呈现

呈现带有 HTML 特殊字符转义的变量:

<h3>{%=o.title%}</h3>

呈现变量时不进行转义:

<h3>{%#o.user_id%}</h3>

呈现执行函数调用的输出:

<a href="{%=encodeURI(o.url)%}">Website</a>

使用点号输出变量的嵌套属性:

<strong>{%=o.author.name%}</strong>
指令

使用 print(str) 将转义内容添加到输出中:

<span>Year: {% var d=new Date(); print(d.getFullYear()); %}</span>

使用 print(str, true) 将未转义的内容添加到输出:

<span>{% print("Fast &amp; powerful", true); %}</span>

使用 include(str, obj) 包含来自不同模板的内容:

<div>
  {% include('tmpl-link', {name: "Website", url: "https://example.org"}); %}
</div>

If else 条件

{% if (o.author.url) { %}
<a href="{%=encodeURI(o.author.url)%}">{%=o.author.name%}</a>
{% } else { %}
<em>No author url.</em>
{% } %}

For 循环

<ul>
{% for (var i=0; i<o.features.length; i++) { %}
    <li>{%=o.features[i]%}</li>
{% } %}
</ul>

模板编译


JavaScript 模板项目附带一个编译脚本,它允许你将模板编译为 JavaScript 代码,并将它们全部组合成一个压缩版的 js 文件(.min.js)用于运行。

编译脚本是为 Node.js 构建的。

使用步骤如下,首先,通过 NPM 安装 JavaScript 模板项目:

$ npm install blueimp-tmpl

这一步这会将可执行文件 tmpl.js 放入文件夹 node_modules/.bin。另外,如果你进行的是全局安装(在安装命令加上 -g 选项,即 npm install blueimp-tmpl -g),那便能够在系统 PATH 环境变量中进行调用。

tmpl.js 可执行文件接受一个或多个模板文件的路径作为命令行参数,并将生成的 JavaScript 代码打印到控制台输出。可以通过以下命令行将生成的代码存储在一个新 js 文件中,这样你的项目便可以轻松引用该脚本:

$ tmpl.js index.html > tmpl.js

tmpl.js 命令行参数中的文件,可以是纯模板文件,也可以是内嵌了模板代码块的 HTML 文档。对纯模板文件而言,其文件名(不包括扩展名)会用作模板 id。

生成的文件可以引用到你的项目中,换言之就是替代了原始的 tmpl.js 成为运行脚本。它为你提供的是相同的 API,以及一个 tmpl(id, data) 函数,该函数第一个参数是模板 id,第二参数是 data 对象,第二参数是可选参数。

测试


JavaScript 模板项目带有单元测试

有以下两种不同的方式可以运行测试:

  • 在浏览器中打开 test/index.html
  • 或者,终端进入到代码包的根目录,然后执行命令 npm test

第一个用例测试浏览器集成,第二个测试 Node.js 集成。