Node.js的Web模板引擎ejs的入門使用教程
Node 開源模板的選擇很多,但推薦像我這樣的老人去用 EJS,有 Classic ASP/PHP/JSP 的經(jīng)驗(yàn)用起 EJS 來的確可以很自然,也就是說,你能夠在 <%...%> 塊中安排 JavaScript 代碼,利用最傳統(tǒng)的方式 <%=輸出變量%>(另外 <%-輸出變量是不會(huì)對(duì) & 等符號(hào)進(jìn)行轉(zhuǎn)義的)。安裝 EJS 命令如下:
npm install ejs
JS 調(diào)用
JS 調(diào)用的方法主要有兩個(gè):
ejs.compile(str, options); // => Function ejs.render(str, options); // => str
實(shí)際上 EJS 可以游離于 Express 獨(dú)立使用的,例如:
var ejs = require(''), str = require('fs').readFileSync(__dirname + '/list.ejs', 'utf8'); var ret = ejs.render(str, { names: ['foo', 'bar', 'baz'] }); console.log(ret); 見 ejs.render(),第一個(gè)參數(shù)是 模板 的字符串,模板如下。 <% if (names.length) { %> <ul> <% names.forEach(function(name){ %> <li foo='<%= name + "'" %>'><%= name %></li> <% }) %> </ul> <% } %>
names 成了本地變量。
選項(xiàng)參數(shù)
第二個(gè)參數(shù)是數(shù)據(jù),一般是一個(gè)對(duì)象。而這個(gè)對(duì)象又可以視作為選項(xiàng),也就是說數(shù)據(jù)和選擇都在同一個(gè)對(duì)象身上。
如果不想每次都都磁盤,可需要緩存模板,設(shè)定 options.filename 即可。例如:
var ejs = require('../') , fs = require('fs') , path = __dirname + '/functions.ejs' , str = fs.readFileSync(path, 'utf8'); var users = []; users.push({ name: 'Tobi', age: 2, species: 'ferret' }) users.push({ name: 'Loki', age: 2, species: 'ferret' }) users.push({ name: 'Jane', age: 6, species: 'ferret' }) var ret = ejs.render(str, { users: users, filename: path }); console.log(ret);
inculde 指令
而且,如果要如
<ul> <% users.forEach(function(user){ %> <% include user/show %> <% }) %> </ul>
般插入公共模板,也就是引入文件,必須要設(shè)置 filename 選項(xiàng)才能啟動(dòng) include 特性,不然 include 無從知曉所在目錄。
模板:
<h1>Users</h1> <% function user(user) { %> <li><strong><%= user.name %></strong> is a <%= user.age %> year old <%= user.species %>.</li> <% } %> <ul> <% users.map(user) %> </ul>
EJS 支持編譯模板。經(jīng)過模板編譯后就沒有 IO 操作,會(huì)非常快,而且可以公用本地變量。下面例子 user/show 忽略 ejs 擴(kuò)展名:
<ul> <% users.forEach(function(user){ %> <% include user/show %> <% }) %> </ul>
自定義 CLOSE TOKEN
如果打算使用 <h1>{{= title }}</h1> 般非 <%%>標(biāo)識(shí),也可以自定義的。
var ejs = require('ejs'); ejs.open = '{{'; ejs.close = '}}';
ejs.filters.last = function(obj) { return obj[obj.length - 1]; };
<p><%=: users | last %></p>
<html> <head> <script src="../ejs.js"></script> <script id="users" type="text/template"> <% if (names.length) { %> <ul> <% names.forEach(function(name){ %> <li><%= name %></li> <% }) %> </ul> <% } %> </script> <script> onload = function(){ var users = document.getElementById('users').innerHTML; var names = ['loki', 'tobi', 'jane']; var html = ejs.render(users, { names: names }); document.body.innerHTML = html; } </script> </head> <body> </body> </html>
對(duì)了,有網(wǎng)友爆料說,jQ 大神 John 若干年前寫過 20 行的模板,汗顏,與 EJS 相似但短小精悍!
簡(jiǎn)單實(shí)用的js模板引擎
不足 50 行的 js 模板引擎,支持各種 js 語(yǔ)法:
<script id="test_list" type="text/html"> <%= for(var i = 0, l = p.list.length; i < l; i++){ var stu = p.list[i]; =%> <tr> <td<%=if(i==0){=%> class="first"<%=}=%>><%==stu.name=%></td> <td><%==stu.age=%></td> <td><%==(stu.address || '')=%></td> <tr> <%= } =%> </script>
“<%= xxx =%>”內(nèi)是 js 邏輯代碼,“<%== xxx =%>”內(nèi)是直接輸出的變量,類似 php 的 echo 的作用?!皃”是調(diào)用下面 build 方法時(shí)的 k-v 對(duì)象參數(shù),也可以在調(diào)用 “new JTemp” 時(shí)設(shè)置成別的參數(shù)名
調(diào)用:
$(function(){ var temp = new JTemp('test_list'), html = temp.build( {list:[ {name:'張三', age:13, address:'北京'}, {name:'李四', age:17, address:'天津'}, {name:'王五', age:13} ]}); $('table').html(html); });
上面的 temp 生成以后,可以多次調(diào)用 build 方法,生成 html。以下是模板引擎的代碼:
var JTemp = function(){ function Temp(htmlId, p){ p = p || {};//配置信息,大部分情況可以缺省 this.htmlId = htmlId; this.fun; this.oName = p.oName || 'p'; this.TEMP_S = p.tempS || '<%='; this.TEMP_E = p.tempE || '=%>'; this.getFun(); } Temp.prototype = { getFun : function(){ var _ = this, str = $('#' + _.htmlId).html(); if(!str) _.err('error: no temp!!'); var str_ = 'var ' + _.oName + '=this,f=\'\';', s = str.indexOf(_.TEMP_S), e = -1, p, sl = _.TEMP_S.length, el = _.TEMP_E.length; for(;s >= 0;){ e = str.indexOf(_.TEMP_E); if(e < s) alert(':( ERROR!!'); str_ += 'f+=\'' + str.substring(0, s) + '\';'; p = _.trim(str.substring(s+sl, e)); if(p.indexOf('=') !== 0){//js語(yǔ)句 str_ += p; }else{//普通語(yǔ)句 str_ += 'f+=' + p.substring(1) + ';'; } str = str.substring(e + el); s = str.indexOf(_.TEMP_S); } str_ += 'f+=\'' + str + '\';'; str_ = str_.replace(/\n/g, '');//處理?yè)Q行 var fs = str_ + 'return f;'; this.fun = Function(fs); }, build : function(p){ return this.fun.call(p); }, err : function(s){ alert(s); }, trim : function(s){ return s.trim?s.trim():s.replace(/(^\s*)|(\s*$)/g,""); } }; return Temp; }();
核心是將模板代碼轉(zhuǎn)變成了一個(gè)拼接字符串的 function,每次拿數(shù)據(jù) call 這個(gè) function。
因?yàn)橹饕墙o手機(jī)(webkit)用的,所以沒有考慮字符串拼接的效率問題,如果需要給 IE 使用,最好將字符串拼接方法改為 Array.push() 的形式。
ejs模板布局 layout
1. 如果不愿意使用默認(rèn)的layout.ejs,可自行指定。例如:
res.render("index",{"title":"test","layout":"main"}); // 或 res.render("index",{"title":"test","layout":"main.ejs"});
2. 如果不愿意使用layout,則可以設(shè)置layout為false,例如:
res.render("index",{"layout":false});
3. 如果不想每個(gè)請(qǐng)求都單獨(dú)設(shè)置一次??梢允褂萌衷O(shè)置:
app.set("view options",{ "layout":false });
4. ejs 里,默認(rèn)的閉合標(biāo)記是 <% .. %>,我們也可以定義自己的標(biāo)簽。例如:
app.set("view options",{ "open":"{{", "close":"}}" });
5. 局部布局
在web應(yīng)用中,經(jīng)常會(huì)需要重復(fù)顯示某個(gè)內(nèi)容,例如:用戶評(píng)論功能,需要重復(fù)顯示出每一條用戶的評(píng)論,這個(gè)時(shí)候,我們可以通過循環(huán)來實(shí)現(xiàn)。但是也可以使用【局部模版】( partial)來實(shí)現(xiàn)。例如:
首先我們建一個(gè)局部的模版 ./views/comment.ejs:
<div class="comment_item"> <div class="comment_user"><%=comment.user%></div> <div class="comment_content"><%=comment.content%></div> </div>
注意:這里是 comment.xxxx
然后在./views/index.ejs中,通過partial調(diào)用comment
this is <%=title%>! <br/> <%- partial("comment", comments)%>
注意:這里是 partial("comment.ejs", comments); <-- 單詞要用復(fù)數(shù)。
最后是在router中,調(diào)用index.ejs。
app.get("/",function(req,res){ res.render("index",{"title":"test","layout":false,"comments":[ {"user":"gainover","content":"test1"}, {"user":"zongzi","content":"test2"}, {"user":"maomao","content":"test3"} ]}); });
注意:代碼里的 comments 和 index.ejs的 comments變量名稱一致,而partial所調(diào)用的comment.ejs中,則采用 comment 的單數(shù)形式。
在列表顯示時(shí),我們通常會(huì)遇到的場(chǎng)景是,對(duì)第一個(gè)元素或者最后一個(gè)元素加以特殊顯示。在partial中,我們可以通過express內(nèi)置的變量來判斷當(dāng)前對(duì)象是否是第一個(gè)元素或者最后一個(gè)元素,例如:
<div class="comment_item<%if(firstInCollection){%> firtitem <%}%>"> <div class="comment_user"><%=comment.user%></div> : <div class="comment_content"><%=comment.content%></div> </div>
這樣第一條評(píng)論的 class 里就會(huì)多一個(gè)firstitem。
類似的內(nèi)置變量還有:
(1)firstInCollection 如果是數(shù)組的第一個(gè)元素,則為true
(2)indexInCollection 當(dāng)前元素在數(shù)組里的索引
(3)lastInCollection 如果是數(shù)組的最后一個(gè)元素,則為true
(4)collectionLength 數(shù)組的長(zhǎng)度
最后是partial調(diào)用模版時(shí)的路徑查找問題:
(1)partial("edit") 會(huì)查找同目錄下的edit.ejs文件。
(2)partial("../message") 會(huì)查找上一級(jí)目錄的message.ejs文件。
(3)partial("users") 會(huì)查找 users.ejs文件,如果不存在users.ejs, 則會(huì)查找 /users/index.ejs文件。
(4)<%= users %> 會(huì)對(duì)內(nèi)容進(jìn)行轉(zhuǎn)義,想不轉(zhuǎn)義,可以用 <%- users %>
相關(guān)文章
websocket結(jié)合node.js實(shí)現(xiàn)雙向通信的示例代碼
本文主要介紹了websocket結(jié)合node.js實(shí)現(xiàn)雙向通信的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02nodejs中操作mysql數(shù)據(jù)庫(kù)示例
這篇文章主要介紹了nodejs中操作mysql數(shù)據(jù)庫(kù)示例,本文演示了如何在NodeJS中創(chuàng)建創(chuàng)建mysql連接、mysql數(shù)據(jù)庫(kù)、插入數(shù)據(jù)、查詢數(shù)據(jù)等功能,需要的朋友可以參考下2014-12-12詳解通過源碼解析Node.js中cluster模塊的主要功能實(shí)現(xiàn)
這篇文章主要介紹了詳解通過源碼解析Node.js中cluster模塊的主要功能實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05實(shí)戰(zhàn)node靜態(tài)文件服務(wù)器的示例代碼
本篇文章主要介紹了實(shí)戰(zhàn)node靜態(tài)文件服務(wù)器的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03nodejs獲取微信小程序帶參數(shù)二維碼實(shí)現(xiàn)代碼
這篇文章主要介紹了nodejs獲取微信小程序帶參數(shù)二維碼實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04nodejs如何在package.json中設(shè)置多條啟動(dòng)命令
這篇文章主要介紹了nodejs如何在package.json中設(shè)置多條啟動(dòng)命令,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03基于promise.js實(shí)現(xiàn)nodejs的promises庫(kù)
promise是JavaScript實(shí)現(xiàn)優(yōu)雅編程的一個(gè)非常不錯(cuò)的輕量級(jí)框架。該框架可以讓你從雜亂的多重異步回調(diào)代碼中解脫出來,并把精力集中到你的業(yè)務(wù)邏輯上。2014-07-07