傳送門:https://github.com/xiangyuecn/BuildHTMLhtml
html作點小功能(什麼都沒有),若是是要手動生成html這種操做,容易把代碼搞得亂七八糟,若是使用模板並解析成html,就會簡單不少。前端
演示:https://xiangyuecn.github.io/BuildHTML/c++
如下內容copy自READMEgit
這段代碼是之前在多個項目中使用的(包括PC端、移動端、還有Android、IOS Hybrid App),代碼簡單輕巧,但功能一點都不簡單。100行代碼不到,Uglify壓縮後1k大小(可選移除_eval後0.8k)。github
演示地址:https://xiangyuecn.github.io/BuildHTML/正則表達式
方法1:把代碼直接複製到你項目的公共js文件中使用。數組
方法2:將代碼文件引用到你的頁面中<script src="buildhtml.js"></script>
瀏覽器
引入代碼後有兩個函數可用:BuildHTML
、BuildHTMLArray
,基本使用流程:緩存
<script type="text/template" class="tp_action"> <div> {name}第一次使用模板,請多多指教。({:slogan}){{::html}} </div> </script> <script> var tp_action=$(".tp_action").html(); </script>
var data={name:"豆豆",slogan:"<span style='color:green;font-size:12px'>面向大海春暖花開</span>"}; var html=BuildHTML(tp_action,data); data.html="{fn:BuildHTMLArray.index}"; var list=[data,data,data]; html+=BuildHTMLArray(tp_action,list);
$("body").append(html);
HTML模板內經過嵌入特定的語法來實現內容的自動生成。性能優化
全部嵌入的代碼可讀寫o對象(爲啥用o,o=object,一個字母簡短啊),o對象爲當前傳入的數據對象(對象能夠是object、數字、文本...);多個嵌入代碼塊之間若是須要傳遞變量數據,能夠放入o對象中。
模板嵌入語法支持兩類:
此語法會在{}語法以前執行,可實現:
此語法支持三種寫法:
定義多行文本變量,無返回值;通常用於內置模板定義。
變量名稱會賦值給o[變量名],好比{{_tp_=多行文本}}
,最終結果:o._tp_="多行文本"
當即執行多行代碼,並將返回的內容當作純文本處理,若是有html會被轉義,好比:{{:var i="<div>";i}}
結果爲<div>
。
注意:若是存在倒數第二行代碼,代碼結尾須要帶
;
。
其餘地方無此要求,畢竟解析js代碼格式是一件複雜的事情,加分號結尾省事的多。
當即執行多行代碼,並原樣返回內容;這個和{{:}}語法一致,只是這個對返回結果不會轉義,用於返回html。好比:{{::var i="<div>";i}}
結果爲<div>
。
此語法求整個代碼在一行,多行請使用前置處理語法。
此語法支持4種寫法:
執行一段代碼,返回純文本,若是有html會被轉義。好比{fn:o.num=1;''} {fn:1+o.num}和{fn:var n=1+o.num;n}
結果爲2和2
這個和{fn:}語法一致,只是這個對返回結果不會轉義,用於返回html。
讀取o對象的屬性值,返回純文本,若是有html會被轉義。好比:{name}
表示取o.name
做爲返回值並轉義。
屬性後面能夠跟複雜的表達式。好比:{num-100?'有':'無'}
表示執行表達式o.num-100?'有':'無'
做爲返回值並轉義。
此語法是基於{fn:}語法,只是自動在代碼前面加了
o.
,簡化了對對象屬性的獲取。
這個和{屬性}語法一致,只是這個對返回結果不會轉義,用於返回html。
此語法是基於{fn::}語法,只是自動在代碼前面加了
o.
,簡化了對對象屬性的獲取。
tp:html模板字符串。
obj:數據對象。
返回值:html結果。
tp:html模板字符串。
list:對象數組。
check:fn(item,index),檢查函數,item爲當前遍歷到的對象,index爲item在list中的索引,返回false能夠中止遍歷。
當前遍歷的索引。
var tp=[ '<div txt="{txt}" style="display:{disable?"none":"僞裝空白"}">' ,' 表達式文本:{txt}' ,' 表達式html:{:txt}' ,' 表達式html:{:txt.replace(/div/g,"p")}' ,' 函數返回純文本:{fn:var d="加"+o.html;Date.now()+d}' ,' 函數返回html:{fn::o.html}' ,' 函數+內置模板(嵌套):{fn::BuildHTML(o._tp_,o)}' ,' 函數+內置模板+列表(嵌套循環):' ,' {fn::BuildHTMLArray(o._tp_,o.childs)}' ,'</div>' ,'定義內置模板(無返回值):{{_tp_=' ,' <div>' ,' <span>{name}</span>' ,' </div>' ,'}}' ,'執行代碼返回文本:{{:o.name' ,' +"<p>"' ,'}}' ,'執行代碼返回html:{{::var p="<p>";' ,' o.name+p' ,'}}' ,'執行代碼返回文本:{{:' ,' var c=0;' ,' for(var i=0;i<1000;i++){' ,' if(i%3)c++;' ,' };' ,' c' ,'}}!哈' ].join('\n'); BuildHTML(tp,{ disable:false ,txt:"內容<div>" ,html:'<i>html</i>' ,name:"小視頻<i>" ,childs:[{name:"土豆<i>"},{name:"愛奇藝"}] });
<div txt="內容<div>" style="display:僞裝空白"> 表達式文本:內容<div> 表達式html:內容<div> 表達式html:內容<p> 函數返回純文本:1528680191658加<i>html</i> 函數返回html:<i>html</i> 函數+內置模板(嵌套): <div> <span>小視頻<i></span> </div> 函數+內置模板+列表(嵌套循環): <div> <span>土豆<i></span> </div> <div> <span>愛奇藝</span> </div> </div> 定義內置模板(無返回值): 執行代碼返回文本:小視頻<i><p> 執行代碼返回html:小視頻<i><p> 執行代碼返回文本:666!哈
BuildHTML用Uglify壓縮後1k大小,若是你對列表使用無多少要求,能夠把對列表解析優化部分移除,而後變成了0.8k。
移除方法:刪除代碼後段_eval部分,把代碼中兩處引用_eval(x)()的代碼改爲eval(x)便可,結果:損失了eval解析緩存,僅僅影響列表性質的模板解析速度,由於沒有緩存了,每次都要調用重量級的eval或Function。
最先版本是隻支持{}語法,{{}}前置處理語法是後面加的,最老版本只有不到20行代碼,不過也很好用。
_eval緩存是在{{}}語法以後加的,主要針對列表這種反覆調用相同模板的性能優化,通過兩次優化測試:
第一次、所有把模板解析成一個函數並緩存此函數,之後每次調用都使用此函數,省去了解析過程。結果:列表性能大幅提高,只使用一次的模板解析性能降低明細,svn提交記錄:
BuildHtml升級成編譯成函數模式,列表build效率大幅提高,測試:將近50倍,單個build速度降低3倍
第二次、eval增長緩存,列表性能大幅提高,但比解析成函數慢一倍,不過總體很強勁(證明了:正則表達式替換開銷與函數執行開銷慢不了多少),svn提交記錄:
BuildHtml從新優化,只改造eval部分,其他不動,列性build能比函數化的慢一倍,但比原始的快20倍,單個build和原始差很少,相對來講比函數化的強 測試結果: 原始 2842.516ms 3365.878ms eval緩存 124.680ms 3725.948ms 函數化 60.350ms 8512.252ms 測試代碼: for(var i=0;i<10000;i++){ BuildHtml(tp); } console.timeEnd(1); console.time(1); for(var i=0;i<10000;i++){ BuildHtml('<div class="{cls+'+Math.random()+'}">{html+'+Math.random()+'}{fn:FormatDate()+'+Math.random()+'}</div>'); } console.timeEnd(1);