標籤:情況 lstat 大括弧 地球 lis 文章 hello 下載 .com
最近要做一個小項目,不管是使用angularjs還是reactjs,都覺得大材小用了。其實我可能只需要引入一個jquery,但想到jquery對dom的操作,對於早已習慣了雙向繫結模式的我,何嘗不是一種痛苦。
聽過這樣一句話:“技術沒有缺席,只有姍姍來遲”,很多技術自己不知道,並非沒有。今天我想介紹的就是一個簡單的js模板引擎artTemplate,讓我們揚帆起航吧~
一、概述
artTemplate 是新一代 javascript 模板引擎,它採用先行編譯方式讓效能有了質的飛躍,並且充分利用 javascript 引擎特性,使得其效能無論在前端還是後端都有極其出色的表現。
二、我的痛點
我們先來看一段代碼,當我用ajax從後台拿到一堆json資料,要填充進頁面的時候,可能會這麼做:
| 123456789101112 |
$.ajax({ type: ‘GET‘, url: ‘/server/list.json‘, success: function(data) { var lists = ‘‘; for(var i=0;i<data.content.rows.length;i++){ lists += ‘<li><div class="lititle">‘+data.content.rows[i].leaveRuleName+‘(共計 ‘+data.content.rows[i].durationStr+‘)</div><div class="timer"><span>開始時間:‘+data.content.rows[i].startTime+‘</span><span>結束時間:‘+data.content.rows[i].endTime+‘</span></div><div class="btns"><p><a href="#" class="button button-round blue">‘+data.content.rows[i].customApprovalStatus+‘</a></p></div><div class="info">剛剛申請</div></li>‘; } $(‘#myList‘).append(lists); }, error: function(xhr, type) {//此處省略}}) |
html代碼:
| 1 |
<ul class="list-container" id="myList"></ul> |
這段代碼,功能上可能並沒有什麼問題。但是我們來看lists變數,這裡面的資訊已經爆炸了,html結構以及data填充,寫完我就不想維護了。
正應了那句話:“此時我寫的代碼,只有我和天知道。半個月後,恐怕只有天知道了!”
三、處理痛點
這豈止是一場噩夢,簡直就是在挖坑埋雷??。好了,不再矯情了,我們換artTemplate來試試,代碼可能是這樣:
注意:記得提前引入template.js哦~
| 12345678 |
$.ajax({ type: ‘GET‘, url: ‘/server/list.json‘, success: function(data) { $(‘#myList‘).append(template(‘myListTpl‘, { lists: data.content.rows})); }, error: function(xhr, type) {//此處省略}}) |
html代碼:
| 12345678910111213141516 |
<script type="text/html" id="myListTpl"> {{each lists}} <li data-id="{{$value.id}}"> <div class="lititle">{{$value.overtimeRuleName}}(共計 {{$value.durationStr}})</div> <div class="timer"> <span>開始時間:{{$value.startTime}}</span> <span>結束時間:{{$value.endTime}}</span> </div> <div class="btns"> <p><a href="#" class="button button-round {{!$value.isEnsure?‘blue‘:($value.isEffective?‘green‘:‘red‘)}}">{{!$value.isEnsure?‘待確認‘:($value.isEffective?‘已確認‘:‘已失效‘)}}</a></p> </div> <div class="info">{{$value.applyTime | timeFormat}}申請</div> </li> {{/each}}</script><ul class="list-container" id="myList"></ul> |
注意:script中的type=”text/html”
這段代碼很清晰,我們建立了myListTpl作為模板,裡面的html結構清晰,變數包在了雙大括弧中。那麼lists中的值是怎麼來的,細心的你可能看到了這個:
| 1 |
$(‘#myList‘).append(template(‘myListTpl‘, { lists: data.content.rows})); |
對,我們用template去先行編譯模板,同時將資料塞進了lists中。就這樣,js中不需要很複雜的邏輯,html也儲存了原有的結構。
~嗡~嗡,嗯,整個世界都清靜了!
四、用法樣本
artTemplate用起來很簡單,我們來逐一舉例說明:
1.template(id,data),向id模板傳入資料。
| 12345678 |
<script id="test" type="text/html"><h1>{{title}}</h1><ul> {{each list as value i}} <li>索引 {{i + 1}} :{{value}}</li> {{/each}}</ul></script> |
js代碼:
| 123456 |
var data = { title: ‘標籤‘, list: [‘文藝‘, ‘部落格‘, ‘攝影‘, ‘電影‘, ‘民謠‘, ‘旅行‘, ‘吉他‘]};var html = template(‘test‘, data);document.getElementById(‘content‘).innerHTML = html; |
2.template.compile(source,options),先行編譯模板資料。
| 1234567891011121314 |
<script>var source = ‘<ul>‘+ ‘{{each list as value i}}‘+ ‘<li>索引 {{i + 1}} :{{value}}</li>‘+ ‘{{/each}}‘+ ‘</ul>‘; var render = template.compile(source);var html = render({ list: [‘攝影‘, ‘電影‘, ‘民謠‘, ‘旅行‘, ‘吉他‘]}); document.getElementById(‘content‘).innerHTML = html;</script> |
上面兩種方式,屬於簡單的資料渲染,實際應用中我們可能會碰到比較複雜的操作,下面細說。
3.template.helper(name,callback),在模板中使用自訂方法。
某種情況下,我們需要對資料做一下預先處理,類似angularjs中的filter操作,那怎麼辦呢?
| 123 |
<script id="test" type="text/html">{{time | timeFormat}}</script> |
| 1234 |
template.helper(‘timeFormat‘,function(date){ var result = Common.formateTime(date); return result;}); |
如上所示,我們調用了template.helper方法,將自訂方法放在回呼函數中,那麼資料是不是可以進行處理了呢。這裡我的情境是對時間資料做了格式化處理,我希望他顯示成“1小時前,剛剛”之類的文案。
4.template.config(name,value),更改引擎的預設配置。
5.include可嵌套子模板。
| 123456789101112 |
<div id="content"></div><script id="test" type="text/html"><h1>{{title}}</h1>{{include ‘list‘}}</script><script id="list" type="text/html"><ul> {{each list as value i}} <li>索引 {{i + 1}} :{{value}}</li> {{/each}}</ul></script> |
js代碼:
| 123456 |
var data = {title: ‘嵌入子模板‘,list: [‘文藝‘, ‘部落格‘, ‘攝影‘, ‘電影‘, ‘民謠‘, ‘旅行‘, ‘吉他‘]};var html = template(‘test‘, data);document.getElementById(‘content‘).innerHTML = html; |
重點在於:
將id為list的模板包含進來,很簡單,這裡就不細說了。
6.轉義
| 12345 |
<div id="content"></div><script id="test" type="text/html"><p>不轉義:{{#value}}</p><p>預設轉義: {{value}}</p></script> |
js代碼:
| 12345 |
var data = { value: ‘<span style="color:#F00">hello world!</span>‘};var html = template(‘test‘, data);document.getElementById(‘content‘).innerHTML = html; |
我們只需要加上“#”號,模板預設就不轉義啦。
7.在頁面上列印你的資料。
當然,你還可以這麼玩:
| 123 |
<script id="test" type="text/html">{{print a b c}}</script> |
js代碼:
| 12345678 |
var html = ‘‘;var data = {a: ‘hello‘,b: ‘--world‘,c: ‘--!!!‘};html = template(‘test‘, data);document.write(html); |
基本用法就這些了,是不是覺得很簡單呢,那就趕快試試吧!
五、原理剖析
當然,我們並不會只停留在會用的層次上面,模板引擎又是如何工作的呢?
artTemplate 模板編譯器會根據一些簡單的規則提取好所有模板變數,聲明在渲染函數頭部,這個函數類似:
| 12345678910 |
var render = function($data){var content = $data.content,$out = ‘‘;$out += ‘<h3>‘;if(typeof content === ‘string‘){$out += content;}$out += ‘</h3>‘;return $out;}; |
這個自動產生的函數就如同一個手工編寫的 javascript 函數一樣,同等的執行次數下無論 CPU 還是記憶體佔用都有顯著減少,效能近乎極限。
值得一提的是:artTemplate 很多特性都基於先行編譯實現,如沙箱規範與自訂文法等。
雖然每個引擎從模板文法、文法解析、變數賦值、字串拼接的實現方式各有所不同,但關鍵的渲染原理仍然是動態執行 javascript 字串。
嗯,點到為止吧。如果想深入瞭解,去下載個template.js,看看源碼吧。
六、負荷測試與調試
在 chrome 下渲染效率測試中分別是知名引擎 Mustache 與 micro tmpl 的 25 、 32 倍。
除了效能優勢外,調試功能也值得一提。模板調試器可以精確定位到引發渲染錯誤的模板語句,解決了編寫模板過程中無法調試的痛苦,讓開發變得高效,也避免了因為單個模板出錯導致整個應用崩潰的情況發生。樣本如下:
| 12345678 |
<script id="test" type="text/html"><ul>{{each list}}{{/each}} {{window.alert=null}}</ul></script> |
js代碼:
| 123 |
var html = ‘‘;html = template(‘test‘, {});document.write(html); |
list變數並沒有賦值,模板引擎會將錯誤拋出,方便定位與查錯。
七、意外收穫
原本我以為artTemplate會是最快的,結果又發現了doT,很好,你已經成功引起了我的注意。
正如大家所見,js模板引擎五花八門,如果每個引擎寫一篇文章,我想幾年內我應該不用幹其他事了(我才不會這麼無聊呢??)。so,不要糾結到底使用哪個模板引擎。請記住,適合自己的才是最好的。
八、總結
按照學習思路,從上到下有了這篇文章。之所以想要詳細的去寫一篇關於模板引擎的文章,主要是想彌補心裡的內疚。其實早在2014年我就有聽說過artTemplate,但卻只止步於聽過的程度。
當地球人都在用的時候,我還沒有開始,當大家已經去追逐天邊的雲彩,我才反應過來。
血淋淋的教訓,謹以此獻給和我有同樣遭遇以及感受的人們,任何時間請不要停下學習的腳步,哪怕晚了,但至少你努力過。
掌握js模板引擎