原地址:https://github.com/hanzichi/underscore-analysis/issues/25
前言
這篇文章本來不打算寫的新蟆,實(shí)話說樓主對前端模板的認(rèn)識還處在非常初級的階段玉控,但是為了整個 源碼解讀系列 的完整性捕发,在深入 Underscore _.template 方法源碼后腻惠,覺得還是有必要記下此文衷恭,為了自己備忘也好腾夯,為了還沒用上前端模板引擎的同學(xué)的入門也好校套。(熟悉模板引擎的可以幫樓主看看文中有沒有 BUG ..)
后端 MVC
說起模板渲染价脾,樓主首先接觸的其實(shí)并不是前端模板引擎,而是后端笛匙。后端 MVC 模式中侨把,一般從 Model 層中讀取數(shù)據(jù),然后將數(shù)據(jù)傳到 View 層渲染(渲染成 HTML 文件)妹孙,而 View 層秋柄,一般都會用到模板引擎,比如樓主項目中用到的 PHP 的 smarty 模板引擎蠢正。隨便上段代碼感受一下骇笔。
<div>
<ul class="well nav nav-list" style="height:95%;">
{{foreach from=$pageArray.result item=leftMenu key=key name=leftMenu}}
<li class="nav-header">{{$key}}</li>
{{foreach from=$leftMenu key=key2 item=item2}}
<li><a target="main" href='{{$item2}}'>{{$key2}}</a></li>
{{/foreach}}
{{/foreach}}
</ul>
</div>
傳入 View 層的其實(shí)就是個叫做 $pageArray 的 JSON 數(shù)據(jù)。而 MVC 模式也是非常容易理解,推薦看下阮一峰老師的 談?wù)凪VC模式笨触,然后再看看下面這張圖懦傍。
以前的 WEB 項目大多會采用這種后臺 MVC 模式,這樣做有利于 SEO芦劣,并且與前端請求接口的方式相比粗俱,少了個 HTTP 請求,理論上加載速度可能會稍微快些虚吟。但是缺點(diǎn)也非常明顯源梭,前端寫完靜態(tài)頁面,要讓后臺去「套模板」稍味,每次前端稍有改動,后臺對應(yīng)的模板頁面同時也需要改動荠卷,非常麻煩模庐。頁面中如果有復(fù)雜的 JS,前端寫還是后端寫油宜?前端寫的話掂碱,沒有大量的數(shù)據(jù),調(diào)試不方便慎冤,后端寫的話... 所以樓主看到的 PHPer 通常都會 JS疼燥。
前端模板
AJAX 的出現(xiàn)使得前后端分離成為可能。后端專注于業(yè)務(wù)邏輯蚁堤,給前端提供接口醉者,而前端通過 AJAX 的方式向后端請求數(shù)據(jù),然后動態(tài)渲染頁面披诗。
我們假設(shè)接口數(shù)據(jù)如下:
[{name: "apple"}, {name: "orange"}, {name: "peach"}]
假設(shè)渲染后的頁面如下:
<div>
<ul class="list">
<li>apple</li>
<li>orange</li>
<li class="last-item">peach</li>
</ul>
</div>
前端模板引擎出現(xiàn)之前撬即,我們一般會這么做:
<div></div>
<script>
// 假設(shè)接口數(shù)據(jù)
var data = [{name: "apple"}, {name: "orange"}, {name: "peach"}];
var str = "";
str += '<ul class="list">';
for (var i = 0, len = data.length; i < len; i++) {
if (i !== len - 1)
str += "<li>" + data[i].name + "</li>";
else
str += '<li class="last-item">' + data[i].name + "</li>";
}
str += "</ul>";
document.querySelector("div").innerHTML = str;
</script>
其實(shí)樓主個人也經(jīng)常這么干,看上去簡單方便呈队,但是這樣做顯然有缺點(diǎn)剥槐,將 HTML 代碼(View 層)和 JS 代碼(Controller 層)混雜在了一起,UI 與邏輯代碼混雜在一起宪摧,閱讀起來會非常吃力粒竖。一旦業(yè)務(wù)復(fù)雜起來,或者多人維護(hù)的情況下几于,幾乎會失控蕊苗。而且如果需要拼接的 HTML 代碼里有很多引號的話(比如有大量的 href 屬性,src 屬性)孩革,那么就非常容易出錯了(這樣干過的應(yīng)該深有體會)岁歉。
這個時候,前端模板引擎出現(xiàn)了,Underscore 的 _.template 可能是最簡單的前端模板引擎了(可能還上升不到引擎的高度锅移,或者說就是個前端模板函數(shù))熔掺。我們先不談 _.template 的實(shí)現(xiàn),將以上的代碼用其改寫非剃。
<div></div>
<script src="http://cdn.bootcss.com/underscore.js/1.8.3/underscore.js"></script>
<script type="text/template" id="tpl">
<ul class="list">
<%_.each(obj, function(e, i, a){%>
<% if (i === a.length - 1) %>
<li class="last-item"><%=e.name%></li>
<% else %>
<li><%=e.name%></li>
<%})%>
</ul>
</script>
<script>
// 模擬數(shù)據(jù)
var data = [{name: "apple"}, {name: "orange"}, {name: "peach"}];
var compiled = _.template(document.getElementById("tpl").innerHTML);
var str = compiled(data);
document.querySelector("div").innerHTML = str;
</script>
這樣一來置逻,如果前端需要改 HTML 代碼,只需要改模板即可备绽。這樣做的優(yōu)點(diǎn)很明顯券坞,前端 UI 和邏輯代碼不再混雜,閱讀體驗良好肺素,改動起來也方便了許多恨锚。
前后端分離最大的缺點(diǎn)可能就是 SEO 無力了,畢竟爬蟲只會抓取 HTML 代碼倍靡,不會去渲染 JS猴伶。(PS:現(xiàn)在的 Google 爬蟲已經(jīng)可以抓取 AJAX 了 Making AJAX applications crawlable,具體效果未知)
Node 中間層
單純的后端模板引擎(后端 MVC)以及前端模板引擎方式都有一定的局限性塌西,Node 的出現(xiàn)讓我們有了第三種選擇他挎,讓 Node 作為中間層。
具體如何操作捡需?簡單地說就是讓一門后臺語言(比如 Java办桨?PHP?)單純提供渲染頁面所需要的接口站辉,Node 中間層用模板引擎來渲染頁面呢撞,使得頁面直出。這樣一來庵寞,后臺提供的接口狸相,不僅 Web 端可以使用,APP捐川,瀏覽器也可以調(diào)用脓鹃,同時頁面 Node 直出也不會影響 SEO,并且前后端也分離古沥,不失為一種比較完美的方案瘸右。
總結(jié)
本文簡單介紹了模板引擎在前后端的使用,下文我們回到 Underscore岩齿,重點(diǎn)分析下 _.template 的使用方式以及源碼原理太颤。