打造屬于自己的MVVM框架: 2.模版渲染引擎

上一篇介紹了MVVM的基本知識(shí),本篇講針對(duì)MVVM的模版渲染引擎進(jìn)行介紹,不但從原理上對(duì)模版引擎的渲染原理進(jìn)行剖析,而且有會(huì)相應(yīng)的實(shí)現(xiàn)代碼。

源碼請(qǐng)戳
原文請(qǐng)戳

什么是模版渲染引擎

還是先來(lái)看一下上一篇有關(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);

頁(yè)面效果:

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樹(shù)上,就完成了整個(gè)指令渲染工作,而這個(gè)流程,就是前端模版渲染引擎的主要任務(wù)。

怎么做一個(gè)簡(jiǎn)單的渲染引擎

其實(shí)稱(chēng)為引擎還真有點(diǎn)夸張,充其量它只不過(guò)是一個(gè)解析的邏輯流程,在整個(gè)過(guò)程中有三個(gè)部分:

  • 模版,即Html
  • 渲染源,即viewModel
  • 所謂的引擎,一段解析流程的,由knockoutjs負(fù)責(zé)

現(xiàn)在我們來(lái)自己試著實(shí)現(xiàn)一下這個(gè)模版引擎。

1.模版

為了在渲染是保留原模版,我采用template標(biāo)簽去畫(huà)Html模版,因?yàn)椋?/p>

  • template標(biāo)簽可以放在任意位置
  • template標(biāo)簽?zāi)J(rèn)display: none

基于以上優(yōu)點(diǎn),個(gè)人覺(jué)得template標(biāo)簽太適合做模版了,難怪會(huì)稱(chēng)為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)容取出來(lá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ì)代碼略長(zhǎng),就不在這里貼了,可以去我的repo里去查看)

4.渲染完成

渲染完成后,將最終的結(jié)果插入到body上。

    $('body').append($(result));

5.總結(jié)

這一節(jié)主要介紹了前端模版引擎的工作原理,同時(shí)也分享了我自己的代碼。但模版引擎僅僅只起到了單向綁定的效果(即viewModl->view),要想體現(xiàn)MVVM的優(yōu)勢(shì),那就必須得實(shí)現(xiàn)雙向綁定,那就必須的介紹MVVM中的核心對(duì)象observable了,下一篇會(huì)介紹如何實(shí)現(xiàn)observable。

源碼請(qǐng)戳
原文請(qǐng)戳

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,167評(píng)論 0 29
  • MVVM(Model View ViewModel)是一種基于MVC的設(shè)計(jì),開(kāi)發(fā)人員在HTML上寫(xiě)一些Bindin...
    Pursue閱讀 3,141評(píng)論 0 10
  • MVVM中對(duì)Bingding的解析只能算viewModel->view的單項(xiàng)綁定,但MVVM絕不僅僅只有單向綁定,...
    Pursue閱讀 774評(píng)論 4 6
  • 每天一百多人的門(mén)診工作量,對(duì)于出門(mén)診的醫(yī)生就是折磨,看病要麻利,詢(xún)問(wèn)病史要簡(jiǎn)要擊中要害,不讓病人集堆,下班時(shí)...
    慈桉閱讀 440評(píng)論 0 1
  • 看清自己的我,很悲傷…… 在別人感情世界里面指點(diǎn)、談?wù)?,閑聊的我,一個(gè)人的時(shí)候,充滿(mǎn)了落寞....
    堂堂工閱讀 162評(píng)論 0 0

友情鏈接更多精彩內(nèi)容