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轉譯這裏我就將官網的一覽貼了過來而後每一個提供一個例子:
先看一下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>' %>
返回:
<h1>hello world</h1>
使用<%- %>:
該模板語法不會轉譯html字符串
<%- '<h1>hello world</h1>' %>
返回:
<h1>hello world</h1>
<%# %>的使用
該標籤不會在最終的結果中出現,做爲模板中的註釋:
<%# '<h1>hello world</h1>' %>
返回的結果:
<%% %>的使用.
該操做返回的是模板字符串(string):
<%% if(id){ %> <%% } %>
返回的結果:
<% if(id){ %> <% } %>
ejs渲染的API主要有三個分別是:
區別是:
ejs內部是有緩存系統的它會將模板字符串解析爲一個數據結構後續的操做將不會在此解析模板.
compile就是返回了內部已經處理好模板字符串的函數,在有大量數據重複使用這套模板的時候就會帶來性能提高,而對於render
和renderFile
來講須要在選項中設置cache
爲true
,對於render
方法還須要指定filename
選項.
這裏也是照搬官網的:
include
使用絕對路徑引入時會以此爲根路徑.echo
和print
)用於在模板語法內打印輸出內容.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
方法提供選項中包含filename
和cache
屬性就能夠以filename
進行命名而後掛載在ejs內部的緩存對象上.
可是各個文章描述的及其模糊,我查看render
和compile
的源碼後也沒有發現顯式使用緩存的選項存在,不過依然找到了一個可使用緩存後的函數的方法.
// 不要此次的結果,使用緩存 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...