上一篇介紹了MVVM的基本知識(shí),本篇講針對(duì)MVVM的模版渲染引擎進(jìn)行介紹灵汪,不但從原理上對(duì)模版引擎的渲染原理進(jìn)行剖析败许,而且有會(huì)相應(yīng)的實(shí)現(xiàn)代碼。
什么是模版渲染引擎
還是先來看一下上一篇有關(guān)knockoutjs的Demo:
<p>First name: <strong data-bind="text: firstName"></strong></p>
<p>Last name: <strong data-bind="text: lastName"></strong></p>
var viewModel = {
firstName: "Bert",
lastName: "Bertington"
};
ko.applyBindings(viewModel);
頁面效果:
First name: Bert
Last name: Bertington
在HTML里砰嘁,我們用data-bind: "text: firstName"
作為Binding Instruction,而在JS里的viewModel相當(dāng)于一個(gè)$scope,當(dāng)Dom加載時(shí)件炉,首先會(huì)檢查HTML標(biāo)簽,發(fā)現(xiàn)有Binding Instruction后會(huì)對(duì)DOM進(jìn)行解析般码,此時(shí)根據(jù)具體的指令在viewModel中進(jìn)行解析妻率,將解析后的值渲染到已經(jīng)生成的DOM樹上,就完成了整個(gè)指令渲染工作板祝,而這個(gè)流程宫静,就是前端模版渲染引擎的主要任務(wù)。
怎么做一個(gè)簡單的渲染引擎
其實(shí)稱為引擎
還真有點(diǎn)夸張,充其量它只不過是一個(gè)解析的邏輯流程孤里,在整個(gè)過程中有三個(gè)部分:
- 模版伏伯,即Html
- 渲染源,即viewModel
- 所謂的引擎捌袜,一段解析流程的说搅,由knockoutjs負(fù)責(zé)
現(xiàn)在我們來自己試著實(shí)現(xiàn)一下這個(gè)模版引擎。
1.模版
為了在渲染是保留原模版虏等,我采用template標(biāo)簽去畫Html模版弄唧,因?yàn)椋?/p>
- template標(biāo)簽可以放在任意位置
- template標(biāo)簽?zāi)J(rèn)display: none
基于以上優(yōu)點(diǎn),個(gè)人覺得template標(biāo)簽太適合做模版了霍衫,難怪會(huì)稱為template候引。
<template id="test">
<p>First name: <strong data-bind="text: firstName"></strong></p>
<p>Last name: <strong data-bind="text: lastName"></strong></p>
</template>
將我們要渲染的Html包裹在<template>中,加上id是為了能夠確保唯一敦跌。
2.解析template
利用id我們可以唯一找到template澄干,首先將template里的內(nèi)容取出來,
var clone = document.importNode(document.querySelector('#' + id).content, true);
分離子節(jié)點(diǎn)
var fragmentContent = splitSubRealDoms(clone);
function splitSubRealDoms(fatherDom) {
var subRealDoms = [];
while(fatherDom.firstElementChild) {
var firstElementChild = fatherDom.removeChild(fatherDom.firstElementChild);
subRealDoms.push(firstElementChild);
}
return subRealDoms;
}
3.根據(jù)父節(jié)點(diǎn)的Binding Instruction去渲染子節(jié)點(diǎn)
for(var i = 0;i < fragmentContent.length;i++) {
var result = renderTemplate(fragmentContent[i], viewModel);
}
renderTemplate的方法較為復(fù)雜柠傍,首先會(huì)渲染父節(jié)點(diǎn)麸俘,然后將所有的子節(jié)點(diǎn)當(dāng)作父節(jié)點(diǎn)再次遞歸,直到?jīng)]有子節(jié)點(diǎn)為止惧笛。遞歸后的子節(jié)點(diǎn)集合渲染完后从媚,需要加入到重新加入到父節(jié)點(diǎn)中。遞歸中途需要對(duì)data-bind = instruction: value
進(jìn)行解析徐紧,將得到的value值在viewModel的$scope中静檬,利用eval進(jìn)行解析后綁定到DOM上。(詳細(xì)代碼略長并级,就不在這里貼了拂檩,可以去我的repo里去查看)
4.渲染完成
渲染完成后,將最終的結(jié)果插入到body上嘲碧。
$('body').append($(result));
5.總結(jié)
這一節(jié)主要介紹了前端模版引擎的工作原理稻励,同時(shí)也分享了我自己的代碼。但模版引擎僅僅只起到了單向綁定的效果(即viewModl->view)愈涩,要想體現(xiàn)MVVM的優(yōu)勢望抽,那就必須得實(shí)現(xiàn)雙向綁定,那就必須的介紹MVVM中的核心對(duì)象observable了履婉,下一篇會(huì)介紹如何實(shí)現(xiàn)observable煤篙。