_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
};
var template = _.template("Hello {{ name }}!");
var ans = template({name: "Mustache"});
console.log(ans); // Hello Mustache!
比较好的方法是作为 _.template 的第二个参数 settings 传入:
var settings = {
interpolate: /\{\{(.+?)\}\}/g // 覆盖 _.templateSettings.interpolate
};
var template = _.template("Hello {{ name }}!", settings);
var ans = template({name: "Mustache"});
console.log(ans); // Hello Mustache!
我们还能设定 settings.variable 指定 scope:
var template = _.template("Using 'with': <%= data.answer %>", {variable: 'data'})
var ans = template({answer: 'no'});
console.log(ans) // Using 'with': no
预编译
模板引擎一般都带有预编译功能,_.template 也不例外。
什么是预编译?有什么用?
上面的代码有两个痛点:
性能:模板引擎渲染的时候依赖 Function 构造器实现,Function 与 eval、setTimeout、setInterval 一样,提供了使用文本访问 javascript 解析引擎的方法,但这样执行 javascript 的性能非常低下。
JST is a server-side thing, not client-side. This mean that you compile Unserscore template on server side by some server-side script and save the result in a file. Then use this file as compiled Unserscore template.
前文 浅谈 Web 中前后端模板引擎的使用 我们简单了解了模板引擎在前后端的应用场景,本文重点深入 Underscore 的模板函数 _.template,来看看它的用法以及实现原理。
from simplest
我们从 官方文档 中最简单的例子说起。
{name: 'moe'} 模拟后台请求到的接口数据,而变量 html 则为拼接成的字符串,之后便可以用 innerHTML 方法加入到页面生成 DOM。
这一切是如何做到的?我们可以打印看下 compliled 方法是个什么样子(需要去 Underscore 源码中打印)。
大概是这个样子(其实不完全准确,真实的应该还会有个 _ 参数传入,使得函数能用 Underscore 内部方法):
仔细想想,其实就是对模板字符串进行了正则解析,将需要填入数据的位置预留出来,拼接成一个字符串,用 new Function 构造一个方法(动态执行 JavaScript 字符串),方法中有大量的字符串拼接过程,然后将数据代入这个方法,返回我们需要的 HTML 字符串。
盗用 木神 两张图,过程非常清晰。
三种模板
_.template 支持以下三种模板。
<% %>
里包裹的是一些可执行的 JavaScript 语句,比如 if-else 语句,for 循环语句,等等。<%= %>
正是我们前面使用的,会打印传入数据相应的 key 的值,<%- %>
和前者相比,多了步 HTML 实体编码的过程,可以有效防止 XSS 攻击。举个栗子:
将数据用
li
标签循环展示,并且将第一个值实体编码了。其他功能
_.template 最基础的应用就是这样。
如果你不喜欢它默认的模板风格,也可以自己定义,注意 key 必须和源码中的 key 保持一致,才能覆盖。
有两种方式,一种是直接修改 _.templateSettings 变量(不推荐,修改了源码中的变量)
比较好的方法是作为 _.template 的第二个参数 settings 传入:
我们还能设定 settings.variable 指定 scope:
预编译
模板引擎一般都带有预编译功能,_.template 也不例外。
什么是预编译?有什么用?
上面的代码有两个痛点:
性能:模板引擎渲染的时候依赖 Function 构造器实现,Function 与 eval、setTimeout、setInterval 一样,提供了使用文本访问 javascript 解析引擎的方法,但这样执行 javascript 的性能非常低下。
调试:由于是动态执行字符串,若遇到错误调试器无法捕获错误源,导致模板 BUG 调试变得异常痛苦。在没有进行容错的引擎中,局部模板若因为数据异常甚至可以导致整个应用崩溃,随着模板的数目增加,维护成本将剧增。
如果我们 JavaScript 代码中直接保存 _.template 的结果,那么以上两个问题就不复存在。而
_.template(jstText).source
则保存了_.template(jstText)
返回的方法字符串。小结
关于 _.template 方法的具体实现,可以参考楼主的 underscore-1.8.3.js 源码解读全文注释版 ,全局搜索即可。
关于前端模板引擎,其实楼主也是个初学者,学习过程中搜到的资料与大家分享下,有机会一定要用下各种模板引擎然后分析下。