淺談 Web 中前後端模板引擎的使用
後端 MVC
說起模板渲染,樓主首先接觸的其實並不是前端模板引擎,而是後端。後端 MVC 模式中,一般從 Model 層中讀取資料,然後將資料傳到 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 層的其實就是個叫做 $pageArray 的 JSON 資料。而 MVC 模式也是非常容易理解,然後再看看下面這張圖。
以前的 WEB 專案大多會採用這種後臺 MVC 模式,這樣做有利於 SEO,並且與前端請求介面的方式相比,少了個 HTTP 請求,理論上載入速度可能會稍微快些。但是缺點也非常明顯,前端寫完靜態頁面,要讓後臺去「套模板」,每次前端稍有改動,後臺對應的模板頁面同時也需要改動,非常麻煩。頁面中如果有複雜的 JS,前端寫還是後端寫?前端寫的話,沒有大量的資料,除錯不方便,後端寫的話... 所以樓主看到的 PHPer 通常都會 JS。
前端模板
AJAX 的出現使得前後端分離成為可能。後端專注於業務邏輯,給前端提供介面,而前端通過 AJAX 的方式向後端請求資料,然後動態渲染頁面。
我們假設介面資料如下:
[{name: "apple"}, {name: "orange"}, {name: "peach"}]
假設渲染後的頁面如下:
<div>
<ul class="list">
<li>apple</li>
<li>orange</li>
<li class="last-item">peach</li>
</ul>
</div>
前端模板引擎出現之前,我們一般會這麼做:
<div></div>
<script>
// 假設介面資料
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>
其實樓主個人也經常這麼幹,看上去簡單方便,但是這樣做顯然有缺點,將 HTML 程式碼(View 層)和 JS 程式碼(Controller 層)混雜在了一起,UI 與邏輯程式碼混雜在一起,閱讀起來會非常吃力。一旦業務複雜起來,或者多人維護的情況下,幾乎會失控。而且如果需要拼接的 HTML 程式碼裡有很多引號的話(比如有大量的 href 屬性,src 屬性),那麼就非常容易出錯了(這樣幹過的應該深有體會)。
這個時候,前端模板引擎出現了,Underscore 的 _.template 可能是最簡單的前端模板引擎了(可能還上升不到引擎的高度,或者說就是個前端模板函式)。我們先不談 _.template 的實現,將以上的程式碼用其改寫。
<div></div>
<script src="//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>
// 模擬資料
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 程式碼,只需要改模板即可。這樣做的優點很明顯,前端 UI 和邏輯程式碼不再混雜,閱讀體驗良好,改動起來也方便了許多。
前後端分離最大的缺點可能就是 SEO 無力了,畢竟爬蟲只會抓取 HTML 程式碼,不會去渲染 JS。(PS:現在的 Google 爬蟲已經可以抓取 AJAX 了 Making AJAX applications crawlable ,具體效果未知)
Node 中間層
單純的後端模板引擎(後端 MVC)以及前端模板引擎方式都有一定的侷限性,Node 的出現讓我們有了第三種選擇,讓 Node 作為中間層。
具體如何操作?簡單地說就是讓一門後臺語言(比如 Java?PHP?)單純提供渲染頁面所需要的介面,Node 中間層用模板引擎來渲染頁面,使得頁面直出。這樣一來,後臺提供的介面,不僅 Web 端可以使用,APP,瀏覽器也可以呼叫,同時頁面 Node 直出也不會影響 SEO,並且前後端也分離,不失為一種比較完美的方案。