pug模板引擎(原jade)

前面的話

  爲何要引入pug,pug有什麼特別之處呢?有一些嵌套層次較深的頁面,可能會出現巢狀嵌套,以下圖所示javascript

  在後期維護和修改時,一不當心少了一個尖括號,或者某個標籤的開始和閉合沒有對應上,就會致使DOM結構的混亂甚至是錯誤。因此,有人發明了HAML,它最大的特點就是使用縮進排列來代替成對標籤。受HAML的啓發,pug進行了javascript的實現。css

  Pug原名不叫Pug,是大名鼎鼎的jade,後來因爲商標的緣由,改成Pug,哈巴狗。其實只是換個名字,語法都與jade同樣。醜話說在前面,Pug有它自己的缺點——可移植性差,調試困難,性能並不出色,但使用它能夠加快開發效率。本文將詳細介紹pug模板引擎html

 

安裝

  使用npm安裝pugjava

$ npm install pug

  但運行pug命令時,提示pug命令未找到jquery

  這時,須要安裝pug命令行工具pug-clinpm

  [注意]必定要全局安裝pug-cli,不然沒法正常編譯json

npm install  pug-cli -g

  再運行pug命令時,正常執行bootstrap

 

命令行

  在學習pug基礎語法以前,首先要了解pug的命令行的使用api

【基礎編譯】數組

  將以下內容輸入文件中,並命名爲index.pug

html
    head
        title aaa
    body

  在命令行中敲入pug index.pug便可實現基礎編譯

  在當前目錄下生成一個index.html,是index.pug編譯後的結果

【sublime兩列設置】

  可是,這樣查看並不方便。下面將sublime設置爲兩列放置,將index.pug和index.html分別放置在左右兩列,方便查看

【自動編譯】

  使用pug -w功能能夠實現自動編譯

  更改index.pug文件並保存後,index.html文件會實時更新爲最新的編譯的文件

【標準版HTML】

  如上所示,默認地,pug編譯出的HTML文件是壓縮版的。若是要編譯標準版的HTML文件,須要設置-P參數

pug index.html -P

【路徑設置】

  若是並不但願在當前目錄下輸入編譯後的HTML文件,而是有自定義目錄的需求,則須要設置-o參數

  以下設置,index.html將輸入到a目錄下面,若是a目錄不存在,則會新建a目錄

pug index.pug -o a

【重命名】

  默認地,編譯後的HTML與pug文件同名。若是須要重命名,則能夠進行以下設置

  經過以下設置,能夠同時設置路徑和名稱

  [注意]這裏的路徑必須提早創建好,不然不會成功

pug <xx.pug> <xx/xx.html>

  最終,test.html文件被保存到templates目錄下

【批量編譯】

  假設,編譯href目錄下全部的pug文件

 

結構語法

  下面介紹關於結構的基礎語法

標籤

【樹狀】

  在默認狀況下,在每行文本的開頭(或者緊跟白字符的部分)書寫這個 HTML 標籤的名稱。使用縮進來表示標籤間的嵌套關係,這樣能夠構建一個 HTML 代碼的樹狀結構  

ul
  li Item A
  li Item B
  li Item C

【內聯】

  爲了節省空間, Pug 嵌套標籤提供了一種內聯式語法

a: img

【自閉合】

  Pug知道哪些元素是自閉合的,也能夠經過在標籤後加上 / 來明確聲明此標籤是自閉合的

img
input
img/
input/

【DOCTYPE】

   HTML5的DOCTYPE書寫以下

doctype html

  也能夠自定義一個 doctype 字面值 

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

 

內容

   Pug 提供了三種經常使用的方式來放置內容

【管道文本】

  這是最簡單的向模板添加純文本的方法。只須要在每行前面加一個 | 字符,這個字符在類 Unix 系統下經常使用做「管道」功能,所以得名

| 純文本固然也能夠包括 <strong>HTML</strong> 內容。
p
  | 但它必須單獨起一行。

【標籤內文本】

  這其實是最多見的狀況,文本只須要和標籤名隔開一個空格便可

p 純文本固然也能夠包括 <strong>HTML</strong> 內容。

【嵌入大段文本】

  有時可能想要寫一個大段文本塊。好比嵌入腳本或者樣式。只需在標籤後面接一個 .便可

  [注意]不要有空格

script.
  if (usingPug)
    console.log('這是明智的選擇。')
  else
    console.log('請用 Pug。')

 

屬性

  標籤屬性和 HTML 語法很是類似,它們的值就是普通的 JavaScript 表達式。能夠用逗號做爲屬性分隔符,也能夠不加逗號

a(href='baidu.com') 百度
= '\n'
a(class='button' href='baidu.com') 百度
= '\n'
a(class='button', href='baidu.com') 百度

【多行屬性】

  若是有不少屬性,能夠把它們分幾行寫

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

【長屬性】

  若是有一個很長的屬性,而且JavaScript運行時引擎支持ES2015模板字符串,可使用它來寫屬性值

input(data-json=`
  {
    "很是": "長的",
    "數據": true
  }
`)

【特殊字符】

  若是屬性名稱中含有某些奇怪的字符,可能會與 JavaScript 語法產生衝突的話,能夠將它們使用 "" 或者 '' 括起來。還可使用逗號來分割不一樣的屬性

div(class='div-class', (click)='play()')
div(class='div-class' '(click)'='play()')

【轉義屬性】

  默認狀況下,全部的屬性都通過轉義(即把特殊字符轉換成轉義序列)來防止諸如跨站腳本攻擊之類的攻擊方式。若是要使用特殊符號,須要使用 != 而不是 =

  [注意]未經轉義的緩存代碼十分危險。必須正確處理和過濾用戶的輸入來避免跨站腳本攻擊

div(escaped="<code>")
div(unescaped!="<code>")

【布爾值】

  在Pug中,布爾值屬性是通過映射的,這樣布爾值(truefalse)就能接受了。沒有指定值時,默認是true

input(type='checkbox' checked)
= '\n'
input(type='checkbox' checked=true)
= '\n'
input(type='checkbox' checked=false)
= '\n'
input(type='checkbox' checked=true.toString())

【行內樣式】

  style(樣式)屬性能夠是一個字符串(就像其餘普通的屬性同樣)還能夠是一個對象

a(style={color: 'red', background: 'green'})

【類和ID】

  類可使用 .classname 語法來定義,ID 可使用 #idname 語法來定義

  考慮到使用 div 做爲標籤名這種行爲實在是太常見了,因此若是省略掉標籤名稱的話,它就是默認值

a.button
.content
="\n"
a#main-link
#content

 

標籤嵌入

  標籤支持一種標籤嵌入的寫法,形式以下

#[標籤名(標籤屬性)  標籤內容]

  對於內聯標籤來講,這種寫法比較簡單

p.
  這是一個很長很長並且還很無聊的段落,尚未結束,是的,很是很是地長。
  忽然出現了一個 #[strong 充滿力量感的單詞],這確實讓人難以 #[em 忽視]。

【空格調整】

  Pug 默認會去除一個標籤先後的全部空格,而標籤嵌入功能能夠在須要嵌入的位置上處理先後空格

p
  | 若是我不用嵌入功能來書寫,一些標籤好比 strong strong | 和 em em | 可能會產生意外的結果。 p. 若是用了嵌入,在 #[strong strong] 和 #[em em] 旁的空格就會讓我舒服多了。

  

註釋

【單行註釋】

  單行註釋和 JavaScript 相似,可是必須獨立一行

// 一些內容
p foo
p bar

【不輸出註釋】

  只須要加上一個橫槓,就可使用不輸出註釋

//- 這行不會出如今結果裏
p foo
p bar

【塊註釋】

body
  //
    隨便寫多少字
    都不要緊。

【條件註釋】

  Pug 沒有特殊的語法來表示條件註釋(conditional comments)。不過由於全部以 < 開頭的行都會被看成純文本,所以直接寫一個 HTML 風格的條件註釋也是沒問題的

<!--[if IE 8]>
<html lang="en" class="lt-ie9">
<![endif]-->
<!--[if gt IE 8]><!-->
<html lang="en">
<!--<![endif]-->

 

邏輯語法

  如下是關於模板邏輯的語法

JS代碼

【不輸出的代碼】

  用 - 開始一段不直接進行輸出的代碼

- for (var x = 0; x < 3; x++)
  li item

【輸出的代碼】

  用=開始一段帶有輸出的代碼,它應該是能夠被求值的一個JavaScript表達式。爲安全起見,它將被HTML轉義

p
  = '這個代碼被 <轉義> 了!'
p= '這個代碼被 <轉義> 了!'

【不轉義的輸出代碼】

  用 != 開始一段不轉義的,帶有輸出的代碼。這將不會作任何轉義,因此用於執行用戶的輸入將會不安全

p
  != '這段文字 <strong>沒有</strong> 被轉義!'
p!= '這段文字' + ' <strong>沒有</strong> 被轉義!'

 

變量

【內容變量】

  使用=或#{}來進行變量的真實值替換

- var title = "On Dogs: Man's Best Friend";
- var author = "enlore"; - var theGreat = "<span>轉義!</span>"; h1= title p #{author} 筆下源於真情的創做。 p 這是安全的:#{theGreat}

  在 #{ 和 } 裏面的代碼也會被求值、轉義,並最終嵌入到模板的渲染輸出中

- var msg = "not my inside voice";
p This is #{msg.toUpperCase()}

  Pug 足夠聰明來分辨到底哪裏纔是嵌入表達式的結束,因此不用擔憂表達式中有 },也不須要額外的轉義

p 不要轉義 #{'}'}!

  若是須要表示一個 #{ 文本,能夠轉義它,也能夠用嵌入功能來生成

p Escaping works with \#{interpolation}
p Interpolation works with #{'#{interpolation}'} too!

  使用!{}嵌入沒有轉義的文本進入模板中

- var riskyBusiness = "<em>我但願經過外籍教師 Peter 找一位英語筆友。</em>";
.quote
  p 李華:!{riskyBusiness}

  [注意]若是直接使用用戶提供的數據,未進行轉義的內容可能會帶來安全風險

【屬性變量】

  若是要在屬性當中使用變量的話,須要進行以下操做

- var url = 'pug-test.html';
a(href='/' + url) 連接
= '\n'
- url = 'https://example.com/'
a(href=url) 另外一個連接

  若是JavaScript運行時支持 ECMAScript 2015 模板字符串,還可使用下列方式來簡化屬性值

- var btnType = 'info'
- var btnSize = 'lg'
button(type='button' class='btn btn-' + btnType + ' btn-' + btnSize)
= '\n'
button(type='button' class=`btn btn-${btnType} btn-${btnSize}`)

  &attributes 語法能夠將一個對象轉化爲一個元素的屬性列表

div#foo(data-bar="foo")&attributes({'data-foo': 'bar'})
- var attributes = {};
- attributes.class = 'baz';
div#foo(data-bar="foo")&attributes(attributes)

【變量來源】

  變量來源有三種,分別是pug文件內部、命令行參數和外部JSON文件

  一、pug文件內部

  二、命令行參數

  使用--obj參數,就能夠跟隨一個對象形式的參數

  三、外部JSON文件

  使用-O,跟隨一個JSON文件的路徑便可

  這三種方式,pug文件內部的變量優先級最多,而外部JSON文件和命令行傳參優先級相同

  以下所示,外部JSON文件和命令行傳參兩種方式都存在,因爲--obj寫在-w後面,最終以命令行傳參爲準

 

條件

  Pug 的條件判斷的通常形式的括號是可選的,因此能夠省略掉開頭的 -,效果徹底相同。相似一個常規的 JavaScript 語法形式

【if else】

- var user = { description: 'foo bar baz' }
- var authorised = false
#user
  if user.description
    h2.green 描述
    p.description= user.description
  else if authorised
    h2.blue 描述
    p.description.
      用戶沒有添加描述。
      不寫點什麼嗎……
  else
    h2.red 描述
    p.description 用戶沒有描述

  Pug 一樣也提供了它的反義版本 unless

unless user.isAnonymous
  p 您已經以 #{user.name} 的身份登陸。

【switch】

  case 是 JavaScript 的 switch 指令的縮寫,而且它接受以下的形式

- var friends = 10
case friends
  when 0
    p 您沒有朋友
  when 1
    p 您有一個朋友
  default
    p 您有 #{friends} 個朋友

  在某些狀況下,若是不想輸出任何東西的話,能夠明確地加上一個原生的 break 語句

- var friends = 0
case friends
  when 0
    - break
  when 1
    p 您的朋友不多
  default
    p 您有 #{friends} 個朋友

  也可使用塊展開的語法

- var friends = 1
case friends
  when 0: p 您沒有朋友
  when 1: p 您有一個朋友
  default: p 您有 #{friends} 個朋友

 

循環

  Pug 目前支持兩種主要的迭代方式: eachwhile

【each】

  這是 Pug 的首選迭代方式

ul
  each val in [1, 2, 3, 4, 5]
    li= val

  能夠在迭代時得到索引值

ul
  each val, index in ['', '', '']
    li= index + ': ' + val

  可以迭代對象中的鍵值

ul
  each val, index in {1:'',2:'',3:''}
    li= index + ': ' + val

  用於迭代的對象或數組僅僅是個 JavaScript 表達式,所以它能夠是變量、函數調用的結果,又或者其餘

- var values = [];
ul
  each val in values.length ? values : ['沒有內容']
    li= val

  還能添加一個 else 塊,這個語句塊將會在數組與對象沒有可供迭代的值時被執行

- var values = [];
ul
  each val in values
    li= val
  else
    li 沒有內容

  [注意]也可使用 for 做爲 each 的別稱

【while】

  也可使用 while 來建立一個循環

- var n = 0;
ul
  while n < 4
    li= n++

 

混入

  混入是一種容許在 Pug 中重複使用一整個代碼塊的方法

//- 定義
mixin list
  ul
    li foo
    li bar
    li baz
//- 使用
+list
+list

  混入能夠被編譯成函數形式,並傳遞一些參數

mixin pet(name)
  li.pet= name
ul
  +pet('')
  +pet('')
  +pet('')

  混入也能夠把一整個代碼塊像內容同樣傳遞進來

mixin article(title)
  .article
    .article-wrapper
      h1= title
      if block
        block
      else
        p 沒有提供任何內容。

+article('Hello world')

+article('Hello world')
  p 這是我
  p 隨便寫的文章

  混入也能夠隱式地,從「標籤屬性」獲得一個參數 attributes

  也能夠直接用 &attributes 方法來傳遞 attributes 參數

mixin link(href, name)
  a(class!=attributes.class href=href)= name

+link('/foo', 'foo')(class="btn")

  [注意]+link(class="btn") 等價於 +link()(class="btn"),由於 Pug 會判斷括號內的內容是屬性仍是參數。但最好使用後面的寫法,明確地傳遞空的參數,確保第一對括號內始終都是參數列表

  能夠用剩餘參數(rest arguments)語法來表示參數列表最後傳入若干個長度不定的參數

mixin list(id, ...items)
  ul(id=id)
    each item in items
      li= item

+list('my-list', 1, 2, 3, 4)

 

文件包含

  包含(include)功能容許把另外的文件內容插入進來

//- index.pug
doctype html
html
  include includes/head.pug
  body
    h1 個人網站
    p 歡迎來到我這簡陋得不能再簡陋的網站。
    include includes/foot.pug
//- includes/head.pug
head
  title 個人網站
  script(src='/javascripts/jquery.js')
  script(src='/javascripts/app.js')
//- includes/foot.pug
footer#footer
  p Copyright (c) foobar

  被包含的若是不是 Pug 文件,那麼就只會看成文本內容來引入

//- index.pug
doctype html
html
  head
    style
      include style.css
  body
    h1 個人網站
    p 歡迎來到我這簡陋得不能再簡陋的網站。
    script
      include script.js
/* style.css */
h1 {
  color: red;
}
// script.js
console.log('真了不得!');

 

文件繼承

【覆蓋】

  Pug 支持使用 blockextends 關鍵字進行模板的繼承。一個稱之爲「塊」(block)的代碼塊,能夠被子模板覆蓋、替換。這個過程是遞歸的。

  Pug 的塊能夠提供一份默認內容,固然這是可選的

//- layout.pug
html
  head
   meta(charset="UTF-8") title 個人站點
- #{title} block scripts script(src='/jquery.js') body block content block foot #footer p 一些頁腳的內容

  如今來擴展這個佈局:只須要簡單地建立一個新文件,並以下所示用一句 extends 來指出這個被繼承的模板的路徑。如今能夠定義若干個新的塊來覆蓋父模板裏對應的「父塊」。值得注意的是,由於這裏的 foot沒有 被重定義,因此會依然輸出「一些頁腳的內容」

//- pet.pug
p= petName
//- page-a.pug
extends layout.pug

block scripts
  script(src='/jquery.js')
  script(src='/pets.js')

block content
  h1= title
  - var pets = ['貓', '狗']
  each petName in pets
    include pet.pug

  一樣,也能夠覆蓋一個塊並在其中提供一些新的塊。以下所示,content 塊如今暴露出兩個新的塊 sidebarprimary 用來被擴展。固然,它的子模板也能夠把整個 content 給覆蓋掉

//- sub-layout.pug
extends layout.pug

block content
  .sidebar
    block sidebar
      p 什麼都沒有
  .primary
    block primary
      p 什麼都沒有
//- page-b.pug
extends sub-layout.pug

block content
  .sidebar
    block sidebar
      p 什麼都沒有
  .primary
    block primary
      p 什麼都沒有

【擴展】

  Pug 容許去替換(默認的行爲)、prepend(向頭部添加內容),或者 append(向尾部添加內容)一個塊。 假設有一份默認的腳本要放在 head 塊中,並且但願將它應用到 每個頁面,能夠進行以下操做

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

  如今假設有一個頁面,那是一個 JavaScript 編寫的遊戲。但願把一些遊戲相關的腳本也像默認的那些腳本同樣放進去,那麼只要簡單地 append 這個塊:

//- page.pug
extends layout.pug

block prepend head
  script(src='/vendor/three.js')

block append head
  script(src='/game.js')

  當使用 block append 或者 block prepend 時,block 關鍵字是可省略的:

//- page.pug
extends layout.pug

prepend head
  script(src='/vendor/three.js')

append head
  script(src='/game.js')

 

簡易模板

//- index.pug
doctype html
html
    head
        meta(charset="UTF-8")
        title= documentTitle
        each val in srcStyles
            link(href= baseStyle +'/' + val)
    body
        header.hd
            nav.hd-navbar.m-navbar.m-navbar_primary
                .hd-navbar-tel 聯繫方式: #{tel}
            ul.hd-navbar-nav
                each val in mainNavItem
                    li.Hnn-item.m-btn.m-btn_info
                        a(href="#")= val

        section.main
            h1.main-title 個人文檔
            p.main-content.
                這是一個很長很長並且還很無聊的段落,尚未結束,是的,很是很是地長。
                忽然出現了一個 #[strong 充滿力量感的單詞],這確實讓人難以 #[em 忽視]。

        footer.ft
            p Copyright (c) 小火柴的藍色理想

        each val in srcScripts
            script(src=baseScript + '/' + val)
//- data.json
{
    "documentTitle":"測試文檔",
    "tel":"400-888-8888",
    "mainNavItem":['登陸','註冊','關於','幫助'],
    "baseStyle":'style',
    "srcStyles":['bootstrap.css','main.css'],
    "baseScript":'/js',
    "srcScripts":['jquery.js','app.js']
}
相關文章
相關標籤/搜索