Ahonn's BlogAhonn's Blog

Jade 模板引擎

#Jade#前端

最近在改一个 Hexo 的主题 apollo。然后看到这个主题用的是叫做 Jade 的模版引擎写的。之前了解过几个模版引擎 ejs,swig 什么的,但是这些都是在原有的 HTML 中插标签,看起来有点乱。看到 Jade 后就深深的被它那如同 Python 的缩进语法深深吸引了,遂上网学习一发。

Jade 是 JavaScript 实现的,供 Node 使用,原生支持 Express。但也有 PHP,Python 等其他语言的实现。(要是 HTML 模版用 Jade,CSS 用 Styl,后端用 Python,那岂不是很好玩~全是缩进缩进缩进=。=)

DOCTYPE

添加文档类型可以通过 !!! 或者 doctype 来添加。

标签、属性

Jade 写起来就跟在 Sublime Text 中用 Emmet 写 HTML 一样。标签直接写,Class 用 .,ID 用 #。不同的是,层级关系 Jade 使用缩进表示,类似于 Python,而 Emmet 插件的写法是只有一行的。结果写出来就是这个样子滴:

doctype html
html
	head.class
    	title
    body#id
jade

渲染出来的结果:

<!DOCTYPE html>
<html>
  <head class="class">
    <title></title>
  </head>
  <body id="id">
  </body>
</html>
html

看起来超级简洁,而且都不需要去写闭合标签。不过比较需要注意缩进,坏处就是如果复制代码过来的话可能需要重新人脑格式化一下。

那么问题来了,其他属性怎么办?不是 Class 和 id 的话,就可以在 标签后面加个括号,写在括号里面。当属性值 undefined 或者 null 时,该属性将不会编译。

a(href="http://www.ahonn.me", class=null)
jade

渲染为:

<a href="http://www.ahonn.me></a>
html

这样就解决了其他属性的问题了~

文本

那么标签里的文本怎么写呢,so easy~ 只要跟在标签的后面就行了。Like this:

a(href="http://www.ahonn.me") Ahonn
jade

渲染为:

<a href="http://www.ahonn.me>Ahonn</a>
html

大段文本的话可以使用| 或者.

使用 |

p
  | one
  | two
  | there
jade

使用.:

p.
  one
  two
  there
jade

上面两种写法渲染后是不一样的,使用 | 的写法渲染后不会换行,而使用 . 会根据格式原样输出。

<!-- 使用 | -->
<p>one two there</p>
<!-- 使用 . -->
<p>one
two
there
</p>
html

在使用 scriptstyletextarea 等只包含文本标签时,可以不加前缀 |

当需要在模版中写 JavaScript 时,推荐使用 .

既然是 HTML 模版,那么一定是可以结合数据的。这时候,我们可以用 #{} 将变量包起来。这样的话 #{} 中的值将会被转义成对应的数据。

例如:

- var name = "ahonn"
p.
 My name is #{name}
jade

渲染为:

<p>My name is ahonn</p>
html

注释

jade 支持 HTML 的注释,即在 html 代码中能看到的注释,还有一种是 Jade 的注释,不会被渲染。

// HTML 注释
p foo
//- Jade 注释,这个注释只有在 .jade 文件中显示
p bar
jade

渲染为:

<!-- HTML 注释 -->
<p>foo</p>
<p>bar</p>
html

代码

在 Jade 中可以定义变量,写条件语句或者循环什么的,这时候就需要使用到 - 前缀,这不会被输出。 - 支持 JavaScript 的语法。

- var foo = 'bar';
- if (foo === 'bar')
- for (var key in obj)
  p= obj[key]
jade

上面写的条件和循环语句是 JavaScript 中的写法,同时 Jade 也有自己的条件和循环语句。

循环

- var items = ["one", "two", "there"]
each item, i in items
  li #{item}: #{i}
jade

渲染为:

<li>one: 0</li>
<li>two: 1</li>
<li>three: 2</li>
html

条件

条件语句类似 Python,不需要加 ()

for user in users
  if user.role == 'admin'
    p #{user.name} is an admin
  else
    p= user.name
jade

Jade 支持转义和非转义输出,使用 = 时将会转义,而 != 将会原样输出。

例如:

- var  ahonn = 'nnoha'
p= ahonn
p!= ahonn
jade

渲染为:

<p>nnoha</p>
<p>ahonn</p>
html

继承、包含

继承

Jade 支持通过 blockextends 关键字老实现模版继承,block 部分将在子模块实现。

举个栗子🌰:

layout.jade

!!!
html
  head
  	block title
  body
  	block content
jade

index.jade

extends layout

block title
  title= ahonn

block content
  p.
    My name is ahonn.
    This is index.jade
jade

index.jade 继承 layout.jade,layout 中的 block 部分将在子模版 index 中实现。

index.jade 渲染为:

<DOCTYPE html>
<html>
  <head>
    <title>ahonn</title>
  </head>
  <body>
  	<p>My name is ahonn.
    This is index.jade
    </p>
  </body>
</html>
html

包含

Jade 可以使用 include 静态包含其他文件

head.jade

head
  title!= ahonn
jade

body.jade

body
  p.
    My name is ahonn.
    This is index.jade
jade

index.jade

html
  include head
  include body
jade

渲染结果将于上面继承的相同。

Mixins

Mixins 相当于 JavaScript 中的函数,实际上 Mixins 在编译过程中就是被转换为 JavaScript 函数的。

不带参数的 🌰:

mixin list
  ul
	li foo
    li bar

h2!= Ahonn
+list()
jade

渲染为:

<h2>Ahonn</h2>
<ul>
  <li>foo</li>
  <li>bar</li>
</ul>
html

带参数的 🌰:

mixin list(items)
  ul
    - each item in items
      li= item

- var items = ["foo", "bar"]
h2!= Ahonn
+list(items)
jade

渲染结果与上面无参数的 Mixins 相同。

总结

使用 Jade 写模版非常的简洁,各种 includeextends 使用起来也非常方便,可以模块化的去写各个组件。优点显而易见,对于我这种写 Python 的来说简直是大爱。不过可能这种写法相对于其他模版引擎来说差别较大,跟 HTML 代码的差别也挺大,所以相对来说也是比较少人去用了。而且用这个写的话,写的人来维护的倒是挺方便简洁,但是如果是其他人来维护的话还是比较难上手的,有点增加维护成本的感觉。不过我个人倒是挺喜欢的。