1. 程式人生 > >pug模板引擎(原jade)

pug模板引擎(原jade)

code 包括 常見 nds bootstra 條件判斷 tns business 最簡

前面的話

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

技術分享

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

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

安裝

  使用npm安裝pug

$ npm install pug

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

技術分享

  這時,需要安裝pug命令行工具pug-cli

  [註意]一定要全局安裝pug-cli,否則無法正常編譯

npm install  pug-cli -g

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

技術分享

命令行

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

【基礎編譯】

  將如下內容輸入文件中,並命名為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文件

  1、pug文件內部

技術分享

  2、命令行參數

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

技術分享 技術分享

  3、外部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]
}
技術分享 技術分享

pug模板引擎(原jade)