模板引擎

模板引擎是一种复用思想,通过定义模板,用的时候和数据一起编译,生成html,以便浏览器渲染。从这个定义里我们可以找出几个关键点

  1. 编译(模板 + 数据) => html

模板引擎有好多种,下面介绍2种典型的模板引擎

  • ejs:嵌入js语法的模板引擎(e = embed),类似于jsp,asp,erb的,在html里嵌入模板特性,如果熟悉html写起来就非常简单,只要区分哪些地方是可变,哪些地方是不变即可
  • jade:缩进式极简写法的模板引擎,发展历史 HAML -> Jade -> Slim -> Slm,最早是ruby里有的,目前以jade用的最多,这种写法虽好,,但需要大脑去转换,这其实是比较麻烦的,如果对html不是特别熟悉,这种思维转换是非常难受的。

更多见 https://github.com/tj/consolidate.js#supported-template-engines

ejs

准备工作

  1. cd web/tpl/ejs
  2. npm init(注意名字不要用ejs,不然无法安装ejs模块的)
  3. touch index.js
  4. npm install --save ejs

定义模板

首先我们定义user.ejs

  1. <% if (user) { %>
  2. <h2><%= user.name %></h2>
  3. <% } %>

这段模板里,首先我们看到的if语句,判断user对象是否存在,如果存在就显示<h2>标签,并把user.name作为变量,嵌入到<h2>标签的显示内容里,一会编译的时候我们讲讲这种嵌入的好处。

我们知道模板原理

  1. 编译(模板 + 数据) => html

编译

下面我们看一下具体如何实现编译

  1. var fs = require('fs')
  2. var ejs = require('ejs')
  3. // 读取模板文件,放到user_tpl_str变量中
  4. var user_tpl_str = fs.readFileSync('./user.ejs').toString();
  5. console.log(user_tpl_str)
  6. // 通过ejs的render方法,对user_tpl_str和数据进行编译
  7. var html = ejs.render(user_tpl_str, {
  8. user:{
  9. name: 'i5ting'
  10. }
  11. });
  12. console.log(html)

下面执行,看一下编译后的结果

  1. $ node index.js
  2. <% if (user) { %>
  3. <h2><%= user.name %></h2>
  4. <% } %>
  5. <h2>i5ting</h2>

核心要点

  1. 通过fs.readFileSync读取模板文件
  2. 通过ejs.render方法进行编译
  3. 模板是固定的,不可变,而数据可以在编译时填入的,是可变的
  4. 编译后的结果是浏览器能够渲染的html代码

上面的数据是一个plain old object

  1. {
  2. user:{
  3. name: 'i5ting'
  4. }
  5. }

它是编译时传进去,也就是说我们可以按照自己的需要改变,并多次复用模板。

再想想user.ejs里的这句

  1. <h2><%= user.name %></h2>

它会编译成

  1. <h2>i5ting</h2>

如果我想让它输出其他名字呢?其实只要改变以user.name的数据即可

模板是可以嵌入逻辑的,上面的user.ejs里使用if指令,也就是只有满足条件的情况下才会输入对应的html,这在我们的页面里是经常使用的技巧。

  1. // 如果user为空,测试编译结果
  2. var empty_html = ejs.render(user_tpl_str, {
  3. user:undefined
  4. });
  5. console.log(empty_html)

这种情况下,执行是不会打出任何内容的,因为user不存在。

模板里支持for循环的,我们看一下list.ejs,列出所有用户列表

  1. <ul>
  2. <% users.forEach(function(user){ %>
  3. <li><%= user.name %></li>
  4. <% }) %>
  5. </ul>

核心代码

  1. // 通过ejs的render方法,对user_tpl_str和数据进行编译
  2. var html = ejs.render(user_tpl_str, {
  3. users:[
  4. {
  5. name: '朴灵'
  6. }, {
  7. name: 'alsotang'
  8. },{
  9. name: 'i5ting'
  10. }
  11. ]
  12. });

这里主要是传入的数据是对象数组而已,然后模板里通过forEach遍历,然后再生产html,下面看一下执行结果

  1. $ node list.js
  2. <ul>
  3. <% users.forEach(function(user){ %>
  4. <li><%= user.name %></li>
  5. <% }) %>
  6. </ul>
  7. <ul>
  8. <li>朴灵</li>
  9. <li>alsotang</li>
  10. <li>i5ting</li>
  11. </ul>

其实还有很多特性,限于篇幅,这里就不详细讲了,自己查看官方文档

jade

准备工作

  1. cd web/tpl/jade
  2. npm init(注意名字不要用jade,不然无法安装jade模块的)
  3. touch index.js
  4. npm install --save pug

这里安装的pug模块,原因是jade因为版权问题,已更名为pug,但我们更喜欢称她为jade,所以本书都会这样约定,大家要注意区别

定义模板

user.jade

  1. if user
  2. h2= user.name

这段模板里,首先我们看到的if语句,判断user对象是否存在,如果存在就显示<h2>标签,并把user.name作为变量,嵌入到<h2>标签的显示内容里,和上面的ejs版本是一样的。

编译

下面我们看一下具体如何实现编译index.js

  1. var fs = require('fs')
  2. var pug = require('pug');
  3. // 读取模板文件,放到user_tpl_str变量中
  4. var user_tpl_str = fs.readFileSync('./user.jade').toString();
  5. console.log(user_tpl_str)
  6. // 通过ejs的render方法,对user_tpl_str和数据进行编译
  7. var html = pug.render(user_tpl_str, {
  8. user:{
  9. name: 'i5ting'
  10. }
  11. });
  12. console.log(html)

对比一下上面ejs编译实现,其实就是把ejs模块替换成pug而已,其他都是一模一样的。

下面执行,看一下编译后的结果

  1. $ node index.js
  2. if user
  3. h2= user.name
  4. <h2>i5ting</h2>

重复一下核心要点

  1. 通过fs.readFileSync读取模板文件
  2. 通过pug.render方法进行编译
  3. 模板是固定的,不可变,而数据可以在编译时填入的,是可变的
  4. 编译后的结果是浏览器能够渲染的html代码

下面我们看一下在jade里如何使用for循环,显示用户列表,看list.jade

  1. ul
  2. each user in users
  3. li= user.name

index.js编译核心代码

  1. // 通过jade的render方法,对user_tpl_str和数据进行编译
  2. var html = pug.render(user_tpl_str, {
  3. users:[
  4. {
  5. name: '朴灵'
  6. }, {
  7. name: 'alsotang'
  8. },{
  9. name: 'i5ting'
  10. }
  11. ]
  12. });

是不是和ejs的一模一样?

执行效果是一模一样的,如下

  1. $ node list.js
  2. ul
  3. each user in users
  4. li= user.name
  5. <ul><li>朴灵</li><li>alsotang</li><li>i5ting</li></ul>

更多用法见官网

比较一下ejs和jade

user.ejs

  1. <% if (user) { %>
  2. <h2><%= user.name %></h2>
  3. <% } %>

特点

  • 内嵌js语句<% js语句 %>
  • html标签:<h2>

user.jade

  1. if user
  2. h2= user.name

特点

  • 内嵌js语句if user,和ejs里的不太一样,极简,没有括号和结尾大括号
  • 极简html标签:h2

总结一下,如果大家对html/css/js不是特别熟悉,使用ejs是比较好的选择,学习成本较低。如果你是一个极客,并且对html/css/js有比较好的掌握,那么用jade更好一些,代码更少。其实技术选型更多的还是要看团队综合情况的,不是一个人的喜好选择。

设置

  1. // view engine setup
  2. app.set('views', path.join(__dirname, 'views'));
  3. app.set('view engine', 'jade');

jade

jade学习

html转jade是比较省力的一种方法

使用场景:尤其是写bootstrap的时候,当然静态页面转jade也一样

hade是一个html2jade.org的copy,平常打开这个网站比较慢,索性还是在本地弄一个,用的时候一条命令打开

  1. [sudo] npm install -g hade
  2. hade

视图与模板引擎 - 图1

好处

  • html和jade互转
  • 对于学习jade是比较好的练习

详见https://github.com/i5ting/hade

more

Template engine consolidation library for node.js

https://github.com/tj/consolidate.js

Supported template engines