2013-12-11 发布

Jade —— 源于 Node.js 的 HTML 模板引擎

207.8k 次阅读  ·  读完需要 69 分钟

54

Jade 是一个高性能的模板引擎,它深受 Haml 影响,它是用 JavaScript 实现的,并且可以供 Node 使用。

试玩

你可以在网上试玩 Jade

特性

  • 客户端支持
  • 代码高可读
  • 灵活的缩进
  • 块展开
  • Mixins
  • 静态包含
  • 属性改写
  • 安全,默认代码是转义的
  • 运行时和编译时上下文错误报告
  • 命令行下编译jade模板
  • HTML5 模式 (使用 !!! 5 文档类型)
  • 在内存中缓存(可选)
  • 合并动态和静态标签类
  • 可以通过 filters 修改树
  • 模板继承
  • 原生支持 Express JS
  • 通过 each 枚举对象、数组甚至是不能枚举的对象
  • 块注释
  • 没有前缀的标签
  • AST Filters
  • 过滤器
  • Emacs Mode
  • Vim Syntax
  • TextMate Bundle
  • Coda/SubEtha syntax Mode
  • Screencasts
  • html2jade 转换器

其它实现

jade有其他语言的实现,可以实现前后端渲染的统一:

安装

  1. npm install jade

浏览器支持

把 Jade 编译为一个可供浏览器使用的单文件,只需要简单的执行:

  1. make jade.js

如果你已经安装了 uglifyjs (npm install uglify-js),你可以执行下面的命令它会生成所有的文件。其实每一个正式版本里都帮你做了这事。

  1. make jade.min.js

默认情况下,为了方便调试Jade会把模板组织成带有形如 __.lineno = 3 的行号的形式。 在浏览器里使用的时候,你可以通过传递一个选项 { compileDebug: false } 来去掉这个。
下面的模板

  1. p Hello #{name}

会被翻译成下面的函数:

  1. function anonymous(locals, attrs, escape, rethrow) {
  2. var buf = [];
  3. with (locals || {}) {
  4. var interp;
  5. buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
  6. }
  7. return buf.join("");
  8. }

通过使用 Jade 的 ./runtime.js你可以在浏览器使用这些预编译的模板而不需要使用 Jade, 你只需要使用 runtime.js 里的工具函数, 它们会放在 jade.attrsjade.escape 这些里。 把选项 { client: true } 传递给 jade.compile(), Jade 会把这些帮助函数的引用放在jade.attrsjade.escape.

  1. function anonymous(locals, attrs, escape, rethrow) {
  2. var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;
  3. var buf = [];
  4. with (locals || {}) {
  5. var interp;
  6. buf.push('\n<p>Hello ' + escape((interp = name) == null ? '' : interp) + '\n</p>');
  7. }
  8. return buf.join("");
  9. }

API

  1. var jade = require('jade');
  2. // Compile a function
  3. var fn = jade.compile('string of jade', options);
  4. fn(locals);

选项

  • self 使用 self 命名空间来持有本地变量. (默认为 false)
  • locals 本地变量对象
  • filename 异常发生时使用,includes 时必需
  • debug 输出 token 和翻译后的函数体
  • compiler 替换掉 jade 默认的编译器
  • compileDebug false的时候调试的结构不会被输出
  • pretty 为输出加上了漂亮的空格缩进 (默认为 false)

标签

标签就是一个简单的单词:

  1. html

它会被转换为 <html></html>

标签也是可以有 id 的:

  1. div#container

它会被转换为 <div id="container"></div>

怎么加 class 呢?

  1. div.user-details

转换为 <div class="user-details"></div>

多个 class 和 id? 也是可以搞定的:

  1. div#foo.bar.baz

转换为 <div id="foo" class="bar baz"></div>

不停的 div div div 很讨厌啊 , 可以这样:

  1. #foo
  2. .bar

这个算是我们的语法糖,它已经被很好的支持了,上面的会输出:

  1. <div id="foo"></div><div class="bar"></div>

标签文本

只需要简单的把内容放在标签之后:

  1. p wahoo!

它会被渲染为 <p>wahoo!</p>.

很帅吧,但是大段的文本怎么办呢:

  1. p
  2. | foo bar baz
  3. | rawr rawr
  4. | super cool
  5. | go jade go

渲染为 <p>foo bar baz rawr.....</p>

怎么和数据结合起来? 所有类型的文本展示都可以和数据结合起来,如果我们把 { name: 'tj', email: 'tj@vision-media.ca' } 传给编译函数,下面是模板上的写法:

  1. #user #{name} &lt;#{email}&gt;

它会被渲染为 <div id="user">tj &lt;tj@vision-media.ca&gt;</div>

当就是要输出 #{} 的时候怎么办? 转义一下!

  1. p \#{something}

它会输出 <p>#{something}</p>

同样可以使用非转义的变量 !{html}, 下面的模板将直接输出一个 <script> 标签:

  1. - var html = "<script></script>"
  2. | !{html}

内联标签同样可以使用文本块来包含文本:

  1. label
  2. | Username:
  3. input(name='user[name]')

或者直接使用标签文本:

  1. label Username:
  2. input(name='user[name]')

 包含文本的标签,比如 <script><style>, 和 <textarea> 不需要前缀 | 字符, 比如:

  1. html
  2. head
  3. title Example
  4. script
  5. if (foo) {
  6. bar();
  7. } else {
  8. baz();
  9. }

这里还有一种选择,可以使用 . 来开始一段文本块,比如:

  1. p.
  2. foo asdf
  3. asdf
  4. asdfasdfaf
  5. asdf
  6. asd.

会被渲染为:

  1. <p>foo asdf
  2. asdf
  3. asdfasdfaf
  4. asdf
  5. asd
  6. .
  7. </p>

这和带一个空格的 . 是不一样的, 带空格的会被 Jade 的解析器忽略,当作一个普通的文字:

  1. p .

渲染为:

  1. <p>.</p>

需要注意的是文本块需要两次转义。比如想要输出下面的文本:

  1. </p>foo\bar</p>

使用:

  1. p.
  2. foo\\bar

注释

单行注释和 JavaScript 里是一样的,通过 // 来开始,并且必须单独一行:

  1. // just some paragraphs
  2. p foo
  3. p bar

渲染为:

  1. <!-- just some paragraphs -->
  2. <p>foo</p>
  3. <p>bar</p>

Jade 同样支持不输出的注释,加一个短横线就行了:

  1. //- will not output within markup
  2. p foo
  3. p bar

渲染为:

  1. <p>foo</p>
  2. <p>bar</p>

块注释

块注释也是支持的:

  1. body
  2. //
  3. #content
  4. h1 Example

渲染为:

  1. <body>
  2. <!--
  3. <div id="content">
  4. <h1>Example</h1>
  5. </div>
  6. -->
  7. </body>

Jade 同样很好的支持了条件注释:

  1. body
  2. //if IE
  3. a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox

渲染为:

  1. <body>
  2. <!--[if IE]>
  3. <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
  4. <![endif]-->
  5. </body>

内联

Jade 支持以自然的方式定义标签嵌套:

  1. ul
  2. li.first
  3. a(href='#') foo
  4. li
  5. a(href='#') bar
  6. li.last
  7. a(href='#') baz

块展开

块展开可以帮助你在一行内创建嵌套的标签,下面的例子和上面的是一样的:

  1. ul
  2. li.first: a(href='#') foo
  3. li: a(href='#') bar
  4. li.last: a(href='#') baz

Case

case 表达式按下面这样的形式写:

  1. html
  2. body
  3. friends = 10
  4. case friends
  5. when 0
  6. p you have no friends
  7. when 1
  8. p you have a friend
  9. default
  10. p you have #{friends} friends

块展开在这里也可以使用:

  1. friends = 5
  2. html
  3. body
  4. case friends
  5. when 0: p you have no friends
  6. when 1: p you have a friend
  7. default: p you have #{friends} friends

属性

Jade 现在支持使用 ( 和 ) 作为属性分隔符

  1. a(href='/login', title='View login page') Login

当一个值是 undefined 或者 null 属性  会被加上,
所以呢,它不会编译出 'something="null"'.

  1. div(something=null)

Boolean 属性也是支持的:

  1. input(type="checkbox", checked)

使用代码的 Boolean 属性只有当属性为 true 时才会输出:

  1. input(type="checkbox", checked=someValue)

多行同样也是可用的:

  1. input(type='checkbox',
  2. name='agreement',
  3. checked)

多行的时候可以不加逗号:

  1. input(type='checkbox'
  2. name='agreement'
  3. checked)

加点空格,格式好看一点?同样支持

  1. input(
  2. type='checkbox'
  3. name='agreement'
  4. checked)

冒号也是支持的:

  1. rss(xmlns:atom="atom")

假如我有一个 user 对象 { id: 12, name: 'tobi' }
我们希望创建一个指向 /user/12 的链接 href, 我们可以使用普通的 JavaScript 字符串连接,如下:

  1. a(href='/user/' + user.id)= user.name

或者我们使用 Jade 的修改方式, 这个我想很多使用 Ruby 或者 CoffeeScript 的人会看起来像普通的 JS..:

  1. a(href='/user/#{user.id}')= user.name

class 属性是一个特殊的属性,你可以直接传递一个数组,比如 bodyClasses = ['user', 'authenticated'] :

  1. body(class=bodyClasses)

HTML

内联的 HTML 是可以的,我们可以使用管道定义一段文本 :

  1. html
  2. body
  3. | <h1>Title</h1>
  4. | <p>foo bar baz</p>

或者我们可以使用 . 来告诉 Jade 我们需要一段文本:

  1. html
  2. body.
  3. <h1>Title</h1>
  4. <p>foo bar baz</p>

上面的两个例子都会渲染成相同的结果:

  1. <html><body><h1>Title</h1>
  2. <p>foo bar baz</p>
  3. </body></html>

这条规则适应于在 Jade 里的任何文本:

  1. html
  2. body
  3. h1 User <em>#{name}</em>

Doctypes

添加文档类型只需要简单的使用 !!!, 或者 doctype 跟上下面的可选项:

  1. !!!

会渲染出 transitional 文档类型, 或者:

  1. !!! 5

  1. !!! html

  1. doctype html

Doctype 是大小写不敏感的, 所以下面两个是一样的:

  1. doctype Basic
  2. doctype basic

当然也是可以直接传递一段文档类型的文本:

  1. doctype html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"

渲染后:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN">

会输出 HTML5 文档类型. 下面的默认的文档类型,可以很简单的扩展:

  1. var doctypes = exports.doctypes = {
  2. '5': '<!DOCTYPE html>',
  3. 'xml': '<?xml version="1.0" encoding="utf-8" ?>',
  4. 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
  5. 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
  6. 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
  7. 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
  8. '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
  9. 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
  10. 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
  11. };

通过下面的代码可以很简单的改变默认的文档类型:

  1. jade.doctypes.default = 'whatever you want';

过滤器

过滤器前缀 :, 比如 :markdown 会把下面块里的文本交给专门的函数进行处理。查看顶部 特性 里有哪些可用的过滤器。

  1. body
  2. :markdown
  3. Woah! jade _and_ markdown, very **cool**
  4. we can even link to [stuff](http://google.com)

渲染为:

  1. <body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://google.com">stuff</a></p></body>

代码

Jade 目前支持三种类型的可执行代码。第一种是前缀 -, 这是不会被输出的:

  1. - var foo = 'bar';

这可以用在条件语句或者循环中:

  1. - for (var key in obj)
  2. p= obj[key]

由于 Jade 的缓存技术,下面的代码也是可以的:

  1. - if (foo)
  2. ul
  3. li yay
  4. li foo
  5. li worked
  6. - else
  7. p oh no! didnt work

哈哈,甚至是很长的循环也是可以的:

  1. - if (items.length)
  2. ul
  3. - items.forEach(function(item){
  4. li= item
  5. - })

所以你想要的!

下一步我们要 转义 输出的代码,比如我们返回一个值,只要前缀一个 =

  1. - var foo = 'bar'
  2. = foo
  3. h1= foo

它会渲染为 bar<h1>bar</h1>. 为了安全起见,使用 = 输出的代码默认是转义的,如果想直接输出不转义的值可以使用 !=

  1. p!= aVarContainingMoreHTML

Jade 同样是设计师友好的,它可以使 JavaScript 更直接更富表现力。比如下面的赋值语句是相等的,同时表达式还是通常的 JavaScript:

  1. - var foo = 'foo ' + 'bar'
  2. foo = 'foo ' + 'bar'

Jade 会把 ifelse ifelseuntilwhileunless 同别的优先对待, 但是你得记住它们还是普通的 JavaScript:

  1. if foo == 'bar'
  2. ul
  3. li yay
  4. li foo
  5. li worked
  6. else
  7. p oh no! didnt work

循环

尽管已经支持 JavaScript 原生代码,Jade 还是支持了一些特殊的标签,它们可以让模板更加易于理解,其中之一就是 each, 这种形式:

  1. each VAL[, KEY] in OBJ

一个遍历数组的例子 :

  1. - var items = ["one", "two", "three"]
  2. each item in items
  3. li= item

渲染为:

  1. <li>one</li>
  2. <li>two</li>
  3. <li>three</li>

遍历一个数组同时带上索引:

  1. items = ["one", "two", "three"]
  2. each item, i in items
  3. li #{item}: #{i}

渲染为:

  1. <li>one: 0</li>
  2. <li>two: 1</li>
  3. <li>three: 2</li>

遍历一个数组的键值:

  1. obj = { foo: 'bar' }
  2. each val, key in obj
  3. li #{key}: #{val}

将会渲染为:<li>foo: bar</li>

Jade 在内部会把这些语句转换成原生的 JavaScript 语句,就像使用 users.forEach(function(user){, 词法作用域和嵌套会像在普通的 JavaScript 中一样:

  1. each user in users
  2. each role in user.roles
  3. li= role

如果你喜欢,也可以使用 for :

  1. for user in users
  2. for role in user.roles
  3. li= role

条件语句

Jade 条件语句和使用了(-) 前缀的 JavaScript 语句是一致的,然后它允许你不使用圆括号,这样会看上去对设计师更友好一点,
同时要在心里记住这个表达式渲染出的是 常规 JavaScript:

  1. for user in users
  2. if user.role == 'admin'
  3. p #{user.name} is an admin
  4. else
  5. p= user.name

和下面的使用了常规 JavaScript 的代码是相等的:

  1. for user in users
  2. - if (user.role == 'admin')
  3. p #{user.name} is an admin
  4. - else
  5. p= user.name

Jade 同时支持 unless, 这和 if (!(expr)) 是等价的:

  1. for user in users
  2. unless user.isAnonymous
  3. p
  4. | Click to view
  5. a(href='/users/' + user.id)= user.name

模板继承

Jade 支持通过 block 和 extends 关键字来实现模板继承。 一个块就是一个 Jade 的 block ,它将在子模板中实现,同时是支持递归的。

Jade 块如果没有内容,Jade 会添加默认内容,下面的代码默认会输出 block scriptsblock content, 和 block foot.

  1. html
  2. head
  3. h1 My Site - #{title}
  4. block scripts
  5. script(src='/jquery.js')
  6. body
  7. block content
  8. block foot
  9. #footer
  10. p some footer content

现在我们来继承这个布局,简单创建一个新文件,像下面那样直接使用 extends,给定路径(可以选择带 .jade 扩展名或者不带). 你可以定义一个或者更多的块来覆盖父级块内容, 注意到这里的 foot 块 没有 定义,所以它还会输出父级的 "some footer content"。

  1. extends extend-layout
  2. block scripts
  3. script(src='/jquery.js')
  4. script(src='/pets.js')
  5. block content
  6. h1= title
  7. each pet in pets
  8. include pet

同样可以在一个子块里添加块,就像下面实现的块 content 里又定义了两个可以被实现的块 sidebar 和 primary,或者子模板直接实现 content

  1. extends regular-layout
  2. block content
  3. .sidebar
  4. block sidebar
  5. p nothing
  6. .primary
  7. block primary
  8. p nothing

前置、追加代码块

Jade允许你 替换 (默认)、 前置 和 追加 blocks. 比如,假设你希望在 所有 页面的头部都加上默认的脚本,你可以这么做:

  1. html
  2. head
  3. block head
  4. script(src='/vendor/jquery.js')
  5. script(src='/vendor/caustic.js')
  6. body
  7. block content

现在假设你有一个Javascript游戏的页面,你希望在默认的脚本之外添加一些游戏相关的脚本,你可以直接append上代码块:

  1. extends layout
  2. block append head
  3. script(src='/vendor/three.js')
  4. script(src='/game.js')

使用 block append 或 block prepend 时 block 是可选的:

  1. extends layout
  2. append head
  3. script(src='/vendor/three.js')
  4. script(src='/game.js')

包含

Includes 允许你静态包含一段 Jade, 或者别的存放在单个文件中的东西比如 CSS, HTML 非常常见的例子是包含头部和页脚。 假设我们有一个下面目录结构的文件夹:

  1. ./layout.jade
  2. ./includes/
  3. ./head.jade
  4. ./tail.jade

下面是 layout.jade 的内容:

  1. html
  2. include includes/head
  3. body
  4. h1 My Site
  5. p Welcome to my super amazing site.
  6. include includes/foot

这两个包含 includes/head 和 includes/foot 都会读取相对于给 layout.jade 参数filename 的路径的文件, 这是一个绝对路径,不用担心Express帮你搞定这些了。Include 会解析这些文件,并且插入到已经生成的语法树中,然后渲染为你期待的内容:

  1. <html>
  2. <head>
  3. <title>My Site</title>
  4. <script src="/javascripts/jquery.js">
  5. </script><script src="/javascripts/app.js"></script>
  6. </head>
  7. <body>
  8. <h1>My Site</h1>
  9. <p>Welcome to my super lame site.</p>
  10. <div id="footer">
  11. <p>Copyright>(c) foobar</p>
  12. </div>
  13. </body>
  14. </html>

前面已经提到,include 可以包含比如 HTML 或者 CSS 这样的内容。给定一个扩展名后,Jade 不会把这个文件当作一个 Jade 源代码,并且会把它当作一个普通文本包含进来:

  1. html
  2. head
  3. //- css and js have simple filters that wrap them in
  4. <style> and <script> tags, respectively
  5. include stylesheet.css
  6. include script.js
  7. body
  8. //- "markdown" files will use the "markdown" filter
  9. to convert Markdown to HTML
  10. include introduction.markdown
  11. //- html files have no filter and are included verbatim
  12. include content.html

Include 也可以接受块内容,给定的块将会附加到包含文件 最后 的块里。 举个例子,head.jade 包含下面的内容:

  1. head
  2. script(src='/jquery.js')

我们可以像下面给include head添加内容, 这里是添加两个脚本.

  1. html
  2. include head
  3. script(src='/foo.js')
  4. script(src='/bar.js')
  5. body
  6. h1 test

在被包含的模板中,你也可以使用yield语句。yield语句允许你明确地标明include的代码块的放置位置。比如,假设你希望把代码块放在scripts之前,而不是附加在scripts之后:

  1. head
  2. yield
  3. script(src='/jquery.js')
  4. script(src='/jquery.ui.js')

由于被包含的Jade会按字面解析并合并到AST中,词法范围的变量的效果和直接写在同一个文件中的相同。这就意味着include可以用作partial的替代,例如,假设我们有一个引用了user变量的user.jade`文件:

  1. h1= user.name
  2. p= user.occupation

接着,当我们迭代users的时候,只需简单地加上include user。因为在循环中user变量已经被定义了,被包含的模板可以访问它。

  1. users = [{ name: 'Tobi', occupation: 'Ferret' }]
  2. each user in users
  3. .user
  4. include user

以上代码会生成:

  1. <div class="user">
  2. <h1>Tobi</h1>
  3. <p>Ferret</p>
  4. </div>

user.jade引用了user变量,如果我们希望使用一个不同的变量user,那么我们可以直接定义一个新变量user = person,如下所示:

  1. each person in users
  2. .user
  3. user = person
  4. include user

Mixins

Mixins 在编译的模板里会被 Jade 转换为普通的 JavaScript 函数。 Mixins 可以带参数,但不是必需的:

  1. mixin list
  2. ul
  3. li foo
  4. li bar
  5. li baz

使用不带参数的 mixin 看上去非常简单,在一个块外:

  1. h2 Groceries
  2. mixin list

Mixins 也可以带一个或者多个参数,参数就是普通的 JavaScript 表达式,比如下面的例子:

  1. mixin pets(pets)
  2. ul.pets
  3. - each pet in pets
  4. li= pet
  5. mixin profile(user)
  6. .user
  7. h2= user.name
  8. mixin pets(user.pets)

会输出像下面的 HTML:

  1. <div class="user">
  2. <h2>tj</h2>
  3. <ul class="pets">
  4. <li>tobi</li>
  5. <li>loki</li>
  6. <li>jane</li>
  7. <li>manny</li>
  8. </ul>
  9. </div>

产生输出

假设我们有下面的 Jade 源码:

  1. - var title = 'yay'
  2. h1.title #{title}
  3. p Just an example

当 compileDebug 选项不是 false, Jade 会编译时会把函数里加上 __.lineno = n;, 这个参数会在编译出错时传递给 rethrow(), 而这个函数会在 Jade 初始输出时给出一个有用的错误信息。

  1. function anonymous(locals) {
  2. var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" };
  3. var rethrow = jade.rethrow;
  4. try {
  5. var attrs = jade.attrs, escape = jade.escape;
  6. var buf = [];
  7. with (locals || {}) {
  8. var interp;
  9. __.lineno = 1;
  10. var title = 'yay'
  11. __.lineno = 2;
  12. buf.push('<h1');
  13. buf.push(attrs({ "class": ('title') }));
  14. buf.push('>');
  15. buf.push('' + escape((interp = title) == null ? '' : interp) + '');
  16. buf.push('</h1>');
  17. __.lineno = 3;
  18. buf.push('<p>');
  19. buf.push('Just an example');
  20. buf.push('</p>');
  21. }
  22. return buf.join("");
  23. } catch (err) {
  24. rethrow(err, __.input, __.filename, __.lineno);
  25. }
  26. }

当 compileDebug 参数是 false, 这个参数会被去掉,这样对于轻量级的浏览器端模板是非常有用的。结合 Jade 的参数和当前源码库里的 ./runtime.js 文件,你可以通过 toString() 来编译模板而不需要在浏览器端运行整个 Jade 库,这样可以提高性能,也可以减少载入的 JavaScript 数量。

  1. function anonymous(locals) {
  2. var attrs = jade.attrs, escape = jade.escape;
  3. var buf = [];
  4. with (locals || {}) {
  5. var interp;
  6. var title = 'yay'
  7. buf.push('<h1');
  8. buf.push(attrs({ "class": ('title') }));
  9. buf.push('>');
  10. buf.push('' + escape((interp = title) == null ? '' : interp) + '');
  11. buf.push('</h1>');
  12. buf.push('<p>');
  13. buf.push('Just an example');
  14. buf.push('</p>');
  15. }
  16. return buf.join("");
  17. }

Makefile 的一个例子

通过执行 make, 下面的 Makefile 例子可以把 pages/*.jade 编译为 pages/*.html 。

  1. JADE = $(shell find pages/*.jade)
  2. HTML = $(JADE:.jade=.html)
  3. all: $(HTML)
  4. %.html: %.jade
  5. jade < $< --path $< > $@
  6. clean:
  7. rm -f $(HTML)
  8. .PHONY: clean

这个可以和 watch(1) 命令起来产生像下面的行为:

  1. $ watch make

命令行的 Jade


  1. 使用: jade [options] [dir|file ...]
  2. 选项:
  3. -h, --help 输出帮助信息
  4. -v, --version 输出版本号
  5. -o, --out <dir> 输出编译后的 HTML <dir>
  6. -O, --obj <str> JavaScript 选项
  7. -p, --path <path> 在处理 stdio 时,查找包含文件时的查找路径
  8. -P, --pretty 格式化 HTML 输出
  9. -c, --client 编译浏览器端可用的 runtime.js
  10. -D, --no-debug 关闭编译的调试选项(函数会更小)
  11. -w, --watch 监视文件改变自动刷新编译结果
  12. Examples:
  13. # 编译整个目录
  14. $ jade templates
  15. # 生成 {foo,bar}.html
  16. $ jade {foo,bar}.jade
  17. # 在标准IO下使用jade
  18. $ jade < my.jade > my.html
  19. # 在标准IO下使用jade, 同时指定用于查找包含的文件
  20. $ jade < my.jade -p my.jade > my.html
  21. # 在标准IO下使用jade
  22. $ echo "h1 Jade!" | jade
  23. # foo, bar 目录渲染到 /tmp
  24. $ jade foo bar --out /tmp

注意: 从 v0.31.0 的 -o 选项已经指向 --out-O 相应做了交换

教程

许可

Jade使用MIT许可证。

项目主页

jade-lang.com

Jade —— 源于 Node.js 的 HTML 模板引擎的更多相关文章

  1. node.js中的模板引擎jade、handlebars、ejs

    使用node.js的Express脚手架生成项目默认是jade模板引擎,jade引擎实在是太难用了,这么难用还敢设为默认的模板引擎,过分了啊!用handlebars模板引擎写还说的过去,但笔者更愿意使 ...

  2. node.js 使用ejs模板引擎时后缀换成.html

    这是一个小技巧,看着.ejs的后缀总觉得不爽,使用如下方法,可以将模板文件的后缀换成我们习惯的.html. 1.在app.js的头上定义ejs: 代码如下: var ejs = require('ej ...

  3. 小白学习VUE第二课:环境搭建 VUE Node.js VSCode template模板

    环境搭建 VUE Node.js VSCode template模板: 首先安装node:http://www.runoob.com/nodejs/nodejs-install-setup.html ...

  4. JavaScript模板引擎artTemplate.js——如何引入模板引擎?

    artTeamplate.js在github上的地址:artTemplate性能卓越的js模板引擎 引入模板引擎,就是引入外部javascript啦,并且artTemplate.js不依赖其他第三方库 ...

  5. JavaScript模板引擎artTemplate.js——为什么使用模板引擎?

    作为一个工作一年的菜鸟,在公司做了几个外包项目,也接触到了不同形式的web开发.其实也没多少,就是javaweb开发和HTML5移动开发,这两者在页面展示的时候的解决方案还是有所不同的. 1.vo+e ...

  6. Node.js和Chrome V8 引擎了解

    说起Node就不得不先介绍一个Chrome V8 引擎. 随着Web相关技术的发展,JavaScript所要承担的工作也越来越多,早就超越了“表单验证”的范畴,这就更需要快速的解析和执行JavaScr ...

  7. 说说如何用js实现一个模板引擎

    本文同步更新在: https://github.com/whxaxes/blog/issues/4 ,在 github 看文章显示效果会更好一些. 前言 不知不觉就很长时间没造过什么轮子了,以前一直想 ...

  8. doT.js——前端javascript模板引擎问题备忘录

    我手里维护的一个项目,遇到一个问题:原项目的开发人员在Javascript中,大量的拼接HTML,导致代码极丑,极难维护.他们怎么能够忍受的了这么丑陋.拙劣的代码呢,也许是他们的忍受力极强,压根就没想 ...

  9. vue.js与后台模板引擎“双花括号”冲突时的解决办法

    后台渲染模板如swig,也使用“{{ }}“作为渲染,与前端vue的产生冲突,此时只要在新建Vue对象时,添加delimiters: ['${', '}'],就搞定了,代码如下 <!DOCTYP ...

随机推荐

  1. 【MySQL】初识数据库及简单操作

    一.数据库概述 1.1 什么是数据(Data) 描述事物的符号记录称为数据,描述事物的符号既可以是数字,也可以是文字.图片,图像.声音.语言等,数据由多种表现形式,它们都可以经过数字化后存入计算机. ...

  2. 如何高效的学习 TensorFlow 代码?

    https://www.zhihu.com/question/41667903 Linux[公共基础]:TensorFlow的主要运行平台之一就是Linux,但是正式版对Windows的支持日趋完善, ...

  3. 对 JSON 数据进行序列化和反序列化

    如何:对 JSON 数据进行序列化和反序列化 2017/03/30 作者 JSON(JavaScript 对象符号)是一种高效的数据编码格式,可用于在客户端浏览器和支持 AJAX 的 Web 服务之间 ...

  4. Linux的历史发展及应用

    Linux的基本介绍: Linux的历史: 操作系统,英语Operating System简称为OS.说道操作系统就需要先讲一讲Unix,UNIX操作系统,是一个强大的多用户.多任务操作系统,支持多种 ...

  5. 每日一练ACM 2019.04.13

    2019.04.13 第1002题:A+B Proble Ⅱ Problem DescriptionI have a very simple problem for you. Given two in ...

  6. Codeforces Round #532 (Div. 2) F 线性基(新坑) + 贪心 + 离线处理

    https://codeforces.com/contest/1100/problem/F 题意 一个有n个数组c[],q次询问,每次询问一个区间的子集最大异或和 题解 单问区间子集最大异或和,线性基 ...

  7. Linux挂载NAS 网络附属存储

    在工作中经常听到NAS,比如做数据交换,将数据从DB2数据库,导入到ORACLE数据库,采用BCP的方式,首先将DB2导出为文件,再从文件导入到ORACLE.那么中间需要一个很大的存储空间来保存从DB ...

  8. java(二)Web部分

    2.1.1讲一下http get和post请求的区别? GET和POST请求都是http的请求方式,用户通过不同的http的请求方式完成对资源(url)的不同操作.GET,POST,PUT,DELET ...

  9. 因为曾经装过Mysql导致再次装时windows无法启动MySQL服务报错1067的解决方法

    找到这里 MySQL右击属性 检查这里的可执行文件的路径是否正确,因为我这里显示的是原先的文件夹所以会一直启动失败,修改一下 这里你去百度经验 windows服务修改可执行文件路径 网址https:/ ...

  10. 关于Selenium WebDriver的geckodriver

    下载Selenium的最新版本地址:http://selenium-release.storage.googleapis.com/index.html 友情提示:如果一直下载不了,可能是浏览器与下载工 ...