EJS學習指南

基本概念

ejs的基本概念十分簡單,一個html = 模板 + 數據,和傳統的php字符串模板拼接很是類似.javascript

例如咱們有一個列表該列表展現一組新聞,理想中的狀態以下:php

<article>
    <h2>新聞1</h2>
    <h2>新聞2</h2>
    <h2>新聞3</h2>
    <h2>新聞4</h2>
    <h2>新聞5</h2>
</article>

若是數據是異步獲取的,咱們能夠利用for循環拼接字符串來實現內部的多個h2而後再追加到html中.css

let data = [],result = '';
    
for (i=0,len = data.length;i<len;i++){
    
    result += '<h1>'+data[i]+'</h1>>';
    
}

可是ejs更像是以下的樣子(僞代碼):html

/**
 * @param {string} template 字符串模板
 * @param {object} data 模板須要的數據
 */
function ejs(template,data) {
    
    return template(data);
}

也就是說ejs須要一個字符串模板,和一個data也就是咱們的數據源.java

template是字符串模板基於html語法可是ejs提供了特殊符號用於控制咱們傳入的數據如何填充到html中.node

安裝

這裏就不說起了你能夠去官網下載也可使用npm進行安裝.git

我使用的版本是2.6.1是目前的最新版本,網上的不少文章實際上有些已通過時了,由於API有些變更.github

ejs中文文檔中有較新的API一覽.express

使用

ejs分爲兩個版本一個是CommonJs版本,另一個是AMD規範的版本.npm

後面的測試基本都是在瀏覽器中運行,我沒有使用requireJs直接使用script引入的ejs:

<script type="text/javascript" src="./node_modules/ejs/ejs.js"></script>

ejs會將自身掛載到window對象上,因此你只要console.log(ejs)控制檯有輸出就說明安裝成功了.

渲染單個數據

ejs.render('<h1><%= data %></h1>',{data:123});

返回:

<h1>123</h1>

render方法只須要兩個參數,和以前說的同樣第一個爲模板字符串,而二個爲數據源.

ejs使用html做爲模板的基礎語言,因此你不須要進行學習任何額外的語法,須要瞭解的就是ejs給咱們提供的幾個模板語法.

那麼<%= %>目前看來就是輸出數據,ejs所作的僅僅是用123來替換掉<%= data %>而已.

渲染多個數據

在ejs提供的語法中能夠直接使用javascript因此你能夠很是容易理解使用複雜邏輯如何完成渲染的,咱們來看一個具體的例子:

const template = `

<article>
    <%  news.forEach(item=>{ %>
        <h2><%= item %></h2>
    <%  }) %>
</article>

`;


const data = {

    news:['新聞1','新聞2','新聞3']

};

const htmlString = ejs.render(template,data);

返回的內容:

<article>
    
        <h2>新聞1</h2>
    
        <h2>新聞2</h2>
    
        <h2>新聞3</h2>
    
</article>

實際上去除掉ejs提供了模板語法,內容就是這個樣子的:

news.forEach(item=>{
    '<h2>'+item+'</h2>'
})

也就是說<% %>的符號不會產生實際的輸出,可是能夠放置javascript代碼用於控制中間代碼塊的執行流程.

有條件的渲染數據

const template = `

<article>
    <% data.forEach(item=>{ %>
        <% if(item.sexCode){ %>

            <h2><%= item.name+'的性別是女' %></h2>

        <% } else { %>

            <h2><%= item.name+'的性別是男' %></h2>

        <% } %>
    <% }) %>
</article>

`;


const data = {

    data:[
        {
            name:'小明',
            sexCode:0
        }
        ,
        {
            name:'小紅',
            sexCode:1
        }
    ]

};

const htmlString = ejs.render(template,data);

輸出:

<article>
    
        

            <h2>小明的性別是男</h2>

        
    
        

            <h2>小紅的性別是女</h2>

        
    
</article>

這個例子稍顯複雜,可是他告訴咱們幾點有價值的內容:

  • <% %>用於存放javascript代碼片斷是肯定無疑的事情了,甚至在這個例子中咱們還執行了嵌套操做.
  • <%= %>實際上把內容看成表達式執行後再輸出的,至少它有執行表達式的能力

本質

  • <% %>用於執行其中的javascript代碼
  • <%= %>會對其中的javascript代碼html轉譯

其餘的模板語法

這裏我就將官網的一覽貼了過來而後每一個提供一個例子:

  1. <% '腳本' 標籤,用於流程控制,無輸出。
  2. <%_ 刪除其前面的空格符
  3. <%= 輸出數據到模板(輸出是轉義 HTML 標籤)
  4. <%- 輸出非轉義的數據到模板
  5. <%# 註釋標籤,不執行、不輸出內容
  6. <%% 輸出字符串 '<%'
  7. %> 通常結束標籤
  8. -%> 刪除緊隨其後的換行符
  9. _%> 將結束標籤後面的空格符刪除

先看一下2,8,9這三個.

以前個人幾個例子中包含了不少空格和換行緣由是由於使用的是默認的輸出格式,例如咱們以前使用這個例子:

<article>
        
            

                <h2>小明的性別是男</h2>

            
        
            

                <h2>小紅的性別是女</h2>

            
        
    </article>

來看一下修改後的效果.

使用刪除空格符號:

<article>
    <%_ data.forEach(item=>{ _%>
        <%_ if(item.sexCode){ _%>

            <h2><%= item.name+'的性別是女' _%></h2>

        <%_ } else { %>

            <h2><%= item.name+'的性別是男' _%></h2>

        <%_ } _%>
    <%_ }) _%>
</article>

輸出的內容:

<article>


                <h2>小明的性別是男</h2>


                <h2>小紅的性別是女</h2>

    </article>

能夠看到確實少了一些內容,可是實際上空隙是由換行符號引發的,此次咱們來刪除尾部的換行符號:

<article>
    <% data.forEach(item=>{ -%>
        <% if(item.sexCode){ -%>

            <h2><%= item.name+'的性別是女' -%></h2>

        <% } else { -%>

            <h2><%= item.name+'的性別是男' -%></h2>

        <% } -%>
    <% }) -%>
</article>

輸出的內容:

<article>
                    
                <h2>小明的性別是男</h2>

                                
                <h2>小紅的性別是女</h2>

                        </article>

雖然行數減小了不過格式亂掉了.

注意:若是不想保留換行和空格能夠把方法的選項參數中的rmWhitespace設置爲true.

<%- %>的使用

默認狀況下在<%= %>之間的html字符串會被作轉譯處理:

<%= '<h1>hello world</h1>' %>

返回:

&lt;h1&gt;hello world&lt;/h1&gt;

使用<%- %>:

該模板語法不會轉譯html字符串

<%- '<h1>hello world</h1>' %>

返回:

<h1>hello world</h1>

<%# %>的使用

該標籤不會在最終的結果中出現,做爲模板中的註釋:

<%# '<h1>hello world</h1>' %>

返回的結果:

<%% %>的使用.

該操做返回的是模板字符串(string):

<%% if(id){ %>
<%% } %>

返回的結果:

<% if(id){ %>
<% } %>

API

ejs渲染的API主要有三個分別是:

  • compile(str, options)
  • render(str, data, options)
  • renderFile(filename, data, options,callback(err,str)) 在瀏覽器端無效

區別是:

  • render 傳入模板字符串和數據返回結果
  • compile 返回一個模板函數,對這個函數傳入數據獲取結果
  • rednerFile 從文件中獲取模板

ejs內部是有緩存系統的它會將模板字符串解析爲一個數據結構後續的操做將不會在此解析模板.

compile就是返回了內部已經處理好模板字符串的函數,在有大量數據重複使用這套模板的時候就會帶來性能提高,而對於renderrenderFile來講須要在選項中設置cachetrue,對於render方法還須要指定filename選項.

選項參數

這裏也是照搬官網的:

  1. cache 緩存編譯後的函數,須要提供 filename
  2. filename 被 cache 參數用作鍵值,同時也用於 include 語句
  3. context 函數執行時的上下文環境
  4. compileDebug 當爲 false 時不編譯調試語句
  5. client 返回獨立的編譯後的函數
  6. delimiter 放在角括號中的字符,用於標記標籤的開與閉
  7. debug 將生成的函數體輸出
  8. _with 是否使用 with() {} 結構。若是爲 false,全部局部數據將存儲在 locals 對象上。
  9. localsName 若是不使用 with ,localsName 將做爲存儲局部變量的對象的名稱。默認名稱是 locals
  10. rmWhitespace 刪除全部可安全刪除的空白字符,包括開始與結尾處的空格。對於全部標籤來講,它提供了一個更安全版本的 -%> (在一行的中間並不會剔除標籤後面的換行符)。
  11. escape 爲 <%= 結構設置對應的轉義(escape)函數。它被用於輸出結果以及在生成的客戶端函數中經過 .toString() 輸出。(默認轉義 XML)。
  12. root include使用絕對路徑引入時會以此爲根路徑.
  13. outputFunctionName 指定一個函數名稱(例如echoprint)用於在模板語法內打印輸出內容.
  14. async 當爲true時ejs內部的渲染都將爲異步,內部使用(await/async).

測試緩存對於性能的影響,使用的模板和數據以下:

const template = `
    <article>
        <% data.forEach(item=>{ %>
            <% if(item.sexCode){ %>

                <h2><%= item.name+'的性別是女' %></h2>

            <% } else { %>

                <h2><%= item.name+'的性別是男' %></h2>

            <% } %>
        <% }) %>
    </article>

    `;


const data = {

    data: [
        {
            name: '小明',
            sexCode: 0
        }
        ,
        {
            name: '小紅',
            sexCode: 1
        }
    ]

};

我使用render連續跑1000次使用的時間爲480ms.

使用compile進行測試:

const demo = ejs.compile(template);


console.time('start');

let i = 0, len = 1000;

while (i < len) {
    demo(data);
    i++;
}

console.timeEnd('start');

最後的結果爲15ms,能夠看到性能提高是很是明顯的.

測試outputFunctionName選項.

const data = {
    content:'hello world'
};


const result = ejs.render(`<h1><% echo(content) %></h1>`,data,{
    outputFunctionName:'echo'
});

console.log(result)

輸出:

<h1>hello world</h1>

測試async選項.

const data = {
    content:'hello world'
};


const result = ejs.render(`<h1><%= content %></h1>`,data,{
    async:true
});

result.then((result)=>{
    console.log(result);
})

輸出:

<h1>hello world</h1>

瀏覽器端使用默認緩存

網上的各類文章中都提到了ejs擁有內部緩存,給render方法提供選項中包含filenamecache屬性就能夠以filename進行命名而後掛載在ejs內部的緩存對象上.

可是各個文章描述的及其模糊,我查看rendercompile的源碼後也沒有發現顯式使用緩存的選項存在,不過依然找到了一個可使用緩存後的函數的方法.

// 不要此次的結果,使用緩存
ejs.render(template,data,{
    filename: 'test',
    cache:true
});

// 獲取緩存後的函數
const cacheFun = ejs.cache.get('test');

console.time('start');

let i = 0, len = 1000;

while (i < len) {
    cacheFun(data);
    i++;
}

console.timeEnd('start');

最後使用的時間爲15ms和使用compile的速度一致.

我的猜想內部緩存功能是爲了服務端渲染使用的或者爲了配合express使用,沒有向瀏覽器端提供很好的支持.

注意:ejs.clearCache()方法能夠清空內部的緩存.

高級操做

包含其餘模板

在通常的開發中咱們常常將網頁切割爲多個部分,例如最簡單的切割就是將頁面分爲導航欄`主體區域`頁尾三個部分.

在使用的時候常常變化的是主體區域,而頁尾不常常變化,可是不少頁面須要一樣的頁尾,這個時候咱們就能夠將頁尾單獨拿出來作成一個模板.

ejs中可使用include命令來插入其餘的模板.(注意只能在服務端中操做)

新建兩個文件:

header.ejs:

<h2>

    <%= content %>

</h2>

footer.ejs:

<h2>

    <%= content %>

</h2>

咱們編寫如下代碼:

const ejs = require('ejs');

const template =
    `
    <%- include('./header',{content:'我是頁頭'}) %>
    <article>
        我是內容區域
    </article>
    <%- include('./footer',{content:'我是頁腳'}) %>
    `;

console.log(ejs.render(template,{
    filename:'whatthefuck' // 這個操做中須要一個名稱,和路徑無關
}));

輸出:

<h2>
    我是頁頭
</h2>
<article>
    我是內容區域
</article>
<h2>
    我是頁腳
</h2>

有其餘須要的朋友能夠去查看ejs的github或者中文官網,惟一的額外信息也就這裏有了.

參考

https://blog.csdn.net/xjl2713...

https://www.jianshu.com/p/81e...

https://blog.csdn.net/zhangxi...

https://www.cnblogs.com/yedey...

https://segmentfault.com/a/11...

https://ejs.bootcss.com/

https://github.com/mde/ejs

相關文章
相關標籤/搜索