博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Jade —— 源于 Node.js 的 HTML 模板引擎
阅读量:5952 次
发布时间:2019-06-19

本文共 13359 字,大约阅读时间需要 44 分钟。

54

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

jade

试玩

你可以在网上。

特性

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

其它实现

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

安装

npm install jade

浏览器支持

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

make jade.js

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

make jade.min.js

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

下面的模板

p Hello #{name}

会被翻译成下面的函数:

function anonymous(locals, attrs, escape, rethrow) { var buf = []; with (locals || {}) { var interp; buf.push('\n

Hello ' + escape((interp = name) == null ? '' : interp) + '\n

'); } return buf.join(""); }

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

function anonymous(locals, attrs, escape, rethrow) { var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; var buf = []; with (locals || {}) { var interp; buf.push('\n

Hello ' + escape((interp = name) == null ? '' : interp) + '\n

'); } return buf.join(""); }

API

var jade = require('jade');// Compile a functionvar fn = jade.compile('string of jade', options); fn(locals);

选项

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

标签

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

html

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

标签也是可以有 id 的:

div#container

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

怎么加 class 呢?

div.user-details

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

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

div#foo.bar.baz

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

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

#foo.bar

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

标签文本

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

p wahoo!

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

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

p  | foo bar baz  | rawr rawr  | super cool  | go jade go

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

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

#user #{name} <#{email}>

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

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

p \#{something}

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

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

- var html = "" | !{html}

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

label  | Username:  input(name='user[name]')

或者直接使用标签文本:

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

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

html  head    title Example    script      if (foo) {        bar();      } else {        baz();      }

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

p.  foo asdf  asdf   asdfasdfaf   asdf  asd.

会被渲染为:

foo asdfasdf asdfasdfaf asdfasd.

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

p .

渲染为:

.

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

foo\bar

使用:

p.  foo\\bar

注释

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

// just some paragraphsp foop bar

渲染为:

foo

bar

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

//- will not output within markupp foop bar

渲染为:

foo

bar

块注释

块注释也是支持的:

body  //    #content      h1 Example

渲染为:

  

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

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

渲染为:

  

内联

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

ul  li.first    a(href='#') foo  li    a(href='#') bar  li.last    a(href='#') baz

块展开

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

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

Case

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

html  body    friends = 10    case friends when 0 p you have no friends when 1 p you have a friend default p you have #{friends} friends

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

friends = 5html  body    case friends when 0: p you have no friends when 1: p you have a friend default: p you have #{friends} friends

属性

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

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

当一个值是 undefined 或者 null 属性  会被加上,

所以呢,它不会编译出 'something="null"'.

div(something=null)

Boolean 属性也是支持的:

input(type="checkbox", checked)

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

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

多行同样也是可用的:

input(type='checkbox',  name='agreement',  checked)

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

input(type='checkbox'  name='agreement'  checked)

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

input(  type='checkbox'  name='agreement'  checked)

冒号也是支持的:

rss(xmlns:atom="atom")

假如我有一个 user 对象 { id: 12, name: 'tobi' }

我们希望创建一个指向 /user/12 的链接 href, 我们可以使用普通的 JavaScript 字符串连接,如下:

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

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

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

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

body(class=bodyClasses)

HTML

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

html  body    | 

Title

|

foo bar baz

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

html  body.    

Title

foo bar baz

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

Title

foo bar baz

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

html  body    h1 User #{name}

Doctypes

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

!!!

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

!!! 5

!!! html

doctype html

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

doctype Basicdoctype basic

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

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

渲染后:

 

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

var doctypes = exports.doctypes = {  '5': '',  'xml': '
', 'default': '', 'transitional': '', 'strict': '', 'frameset': '', '1.1': '', 'basic': '', 'mobile': '' };

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

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

过滤器

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

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

渲染为:

Woah! jade and markdown, very cool we can even link to stuff

代码

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

- var foo = 'bar';

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

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

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

- if (foo)  ul    li yay li foo li worked - else p oh no! didnt work

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

- if (items.length)  ul    - items.forEach(function(item){ li= item - })

所以你想要的!

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

- var foo = 'bar'= fooh1= foo

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

p!= aVarContainingMoreHTML

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

- var foo = 'foo ' + 'bar'foo = 'foo ' + 'bar'

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

if foo == 'bar'  ul    li yay li foo li worked else p oh no! didnt work

循环

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

each VAL[, KEY] in OBJ

一个遍历数组的例子 :

- var items = ["one", "two", "three"]each item in items li= item

渲染为:

  • one
  • two
  • three
  • 遍历一个数组同时带上索引:

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

    渲染为:

  • one: 0
  • two: 1
  • three: 2
  • 遍历一个数组的键值:

    obj = { foo: 'bar' }each val, key in obj  li #{key}: #{
    val}

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

    Jade 在内部会把这些语句转换成原生的 JavaScript 语句,就像使用 users.forEach(function(user){

    , 词法作用域和嵌套会像在普通的 JavaScript 中一样:

    each user in users  each role in user.roles    li= role

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

    for user in users  for role in user.roles    li= role

    条件语句

    Jade 条件语句和使用了(-) 前缀的 JavaScript 语句是一致的,然后它允许你不使用圆括号,这样会看上去对设计师更友好一点,

    同时要在心里记住这个表达式渲染出的是 常规 JavaScript:

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

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

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

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

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

    模板继承

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

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

    html  head    h1 My Site - #{title}    block scripts script(src='/jquery.js') body block content block foot #footer p some footer content

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

    extends extend-layoutblock scripts  script(src='/jquery.js')  script(src='/pets.js')block content  h1= title  each pet in pets    include pet

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

    extends regular-layoutblock content  .sidebar block sidebar p nothing .primary block primary p nothing

    前置、追加代码块

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

    html  head    block head      script(src='/vendor/jquery.js')      script(src='/vendor/caustic.js')  body    block content

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

    extends layoutblock append head  script(src='/vendor/three.js')  script(src='/game.js')

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

    extends layoutappend head  script(src='/vendor/three.js')  script(src='/game.js')

    包含

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

    ./layout.jade./includes/  ./head.jade  ./tail.jade

    下面是 layout.jade 的内容:

    html  include includes/head    body    h1 My Site p Welcome to my super amazing site. include includes/foot

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

          My Site    

    My Site

    Welcome to my super lame site.

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

    html  head    //- css and js have simple filters that wrap them in        

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

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

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

    html  include head    script(src='/foo.js')    script(src='/bar.js')  body    h1 test

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

    head  yield  script(src='/jquery.js')  script(src='/jquery.ui.js')

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

    h1= user.namep= user.occupation

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

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

    以上代码会生成:

    Tobi

    Ferret

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

    each person in users  .user    user = person    include user

    Mixins

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

    mixin list  ul    li foo li bar li baz

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

    h2 Groceriesmixin list

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

    mixin pets(pets)  ul.pets    - each pet in pets li= pet mixin profile(user) .user h2= user.name mixin pets(user.pets)

    会输出像下面的 HTML:

    tj

    • tobi
    • loki
    • jane
    • manny

    产生输出

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

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

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

    function anonymous(locals) { var __ = { lineno: 1, input: "- var title = 'yay'\nh1.title #{title}\np Just an example", filename: "testing/test.js" }; var rethrow = jade.rethrow; try { var attrs = jade.attrs, escape = jade.escape; var buf = []; with (locals || {}) { var interp; __.lineno = 1; var title = 'yay' __.lineno = 2; buf.push('
    '); buf.push('' + escape((interp = title) == null ? '' : interp) + ''); buf.push(''); __.lineno = 3; buf.push('

    '); buf.push('Just an example'); buf.push('

    '); } return buf.join(""); } catch (err) { rethrow(err, __.input, __.filename, __.lineno); } }

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

    function anonymous(locals) { var attrs = jade.attrs, escape = jade.escape; var buf = []; with (locals || {}) { var interp; var title = 'yay' buf.push('
    '); buf.push('' + escape((interp = title) == null ? '' : interp) + ''); buf.push(''); buf.push('

    '); buf.push('Just an example'); buf.push('

    '); } return buf.join(""); }

    Makefile 的一个例子

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

    JADE = $(shell find pages/*.jade)HTML = $(JADE:.jade=.html)all: $(HTML)%.html: %.jade jade < $< --path $< > $@ clean: rm -f $(HTML) .PHONY: clean

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

    $ watch make

    命令行的 Jade

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

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

    教程

    • cssdeck interactive 
    • cssdeck interactive 

    许可

    Jade使用MIT许可证。

    项目主页

    转载于:https://www.cnblogs.com/zhangycun/p/10304209.html

    你可能感兴趣的文章
    线程互互斥锁
    查看>>
    KVM虚拟机&openVSwitch杂记(1)
    查看>>
    win7下ActiveX注册错误0x80040200解决参考
    查看>>
    《.NET应用架构设计:原则、模式与实践》新书博客--试读-1.1-正确认识软件架构...
    查看>>
    网址收藏
    查看>>
    2013 Linux领域年终盘点
    查看>>
    大学生暑期实践活动---关注少数民族孤寡老人
    查看>>
    linux学习之查看程序端口占用情况
    查看>>
    linux下配置安装OpenJDK+Tomcat
    查看>>
    相逢在栀枝花开的季节
    查看>>
    Ajax实现直链(点击量统计)
    查看>>
    linux下git自动补全命令
    查看>>
    Ubuntu14.04LTS更新源
    查看>>
    Linux报“Unknown HZ value! (288) Assume 100”错误
    查看>>
    mysql多实例实例化数据库
    查看>>
    Sql 字符串长度不足补0
    查看>>
    我的友情链接
    查看>>
    golang xml和json的解析与生成
    查看>>
    小弟的新书《Ext JS权威指南》终于出版了
    查看>>
    好吧好吧,就在这里消磨时间
    查看>>