前端MVVM框架avalon揭祕 - HTML編譯器

MVVM試圖更加清晰的講用戶界面(UI)開發從應用程序的業務邏輯與行爲中心分離,由於,不少這樣的模式的實現都須要利用聲明式數據綁定來實現講View(視圖)工做從其餘層分離css

因此出現了一大堆自定義的聲明式的語法:html

如:Avalonnode

  1. 做用域綁定(ms-controller, ms-important)
  2. 模板綁定(ms-include)
  3. 數據填充(ms-text, ms-html)
  4. 類名切換(ms-class, ms-hover, ms-active)
  5. 事件綁定(ms-on,……)
  6. 顯示綁定(ms-visible)
  7. 插入綁定(ms-if)
  8. 雙工綁定(ms-duplex,原來的ms-model)
  9. 樣式綁定(ms-css)
  10. 數據綁定(ms-data)
  11. 布爾屬性綁定(ms-checked, ms-selected, ms-readonly, ms-disabled, ms-enabled)
  12. 字符串屬性綁定(ms-title, ms-src, ms-href……)
  13. 萬能屬性綁定(ms-attr)
  14. 萬能綁定(ms-bind)
  15. 數組循環綁定(ms-each)
  16. 對象循環綁定(ms-with)
    等等………

顧名思義,自定義聲明語法,那麼遊覽器自己是不能識別的,那麼如何遊覽器能過識別自定義的HTML語法,它能讓你講行爲關係到HTML元素或者屬性上,甚至能讓你創造具備自定義行爲的新元素呢,咱們暫且講這個過程稱之爲「HTML編譯」吧。數組

咱們先看一段HTML代碼瀏覽器

<div id='box' ms-controller="box">

    <div style=" background: #a9ea00;" ms-css-width="w" ms-css-height="h"  ms-click="click"></div>

    <p>{{ w }} x {{ h }}</p>
    <p>W: <input type="text" ms-model="w" data-event="change"/></p>
    <p>H: <input type="text" ms-model="h" /></p>

</div>
    avalon.define("box", function(vm) {
        vm.w = 100;
        vm.h = 100;
        vm.click = function() {
            vm.w = parseFloat(vm.w) + 10;
            vm.h = parseFloat(vm.h) + 10;
        }
    })
    avalon.scan(document.getElementById('box'));

HTML結構中充斥了大量的ms開頭的自定義標籤,還有{}插值表達式。。等等ruby

聲明1:

ms-controller="box"

avalon提供ms-controller, ms-important來指定VM在視圖的做用範圍。好比有兩個VM,它們都有一個firstName屬性,在DIV中,若是咱們用 ms-controller="VM1", 那麼對於DIV裏面的{{firstName}}就會解析成VM1的firstName中的值。app

聲明2:

ms-css-width="w" ms-css-height="h" 

用來處理樣式框架

聲明3:

ms-click="click"

avalon經過ms-on-click或ms-click進行事件綁定,並在IE對事件對象進行修復,並統一了全部瀏覽器對return false的處理dom

 

其實就是把部分的行爲操做提高到了dom上了,而後有框架在後臺給你處理好,經過加入各類自定義的屬性可讓任何的HTML元素都實現這樣的行爲函數

 

具體看源碼的執行流程:

總的來講就是匹配每一給節點上的屬性,經過匹配分配到指定的bindingHandlers處理函數上,以後的處理本章不暫時不涉及

//掃描入口
avalon.scan = function(elem, vmodel)

//掃描子節點
function scanNodes(parent, vmodels, callback) 

//開始掃描
function scanTag(elem, vmodels)

//掃描文本
function scanText(textNode, vmodels)

//掃描表達式
function scanExpr(str)

//掃描屬性節點
function scanAttr(el, vmodels)

//抽取綁定
function executeBindings(bindings, vmodels)

//抽取文本綁定
function extractTextBindings(textNode)

 

看看命名就大概能猜出函數的做用了

1.入口函數  avalon.scan

avalon.scan

默認從文本的根documentElement開始,若是傳遞了第一個elem,那麼就是指定了掃描的做用域了,相似 jQuery( selector, [ context ] )

 

2. 執行掃描 scanTag

avalon.scan
  • 依次要檢測是當前元素上是否有ms-skip,ms-important,ms-controller屬性,用於最開始的處理
  • 若是ms-controller存在就取出vm視圖模型對象
  • 清除這個自定義屬性
  • 執行sacnAttr 屬性掃描

 

3. 掃描屬性節點 scanAttr

avalon.scan

attributes 屬性返回包含被選節點屬性的 NamedNodeMap。

若是在文檔中設置了屬性值,則 specified 屬性返回 true.

是不是avalon的HTML指示 "ms-"開頭

若是還指定了參數

能找到對應的處理函數

bindings 保存參數

 

4. 執行綁定 executeBindings

avalon.scan

找到對應的類型的bindingHandlers方法,傳入數據與vm對象,實現處理

移除數據綁定,防止被二次解析

 

5. 掃描子節點 scanNodes

avalon.scan

其實就循環處理子節點列表了,注意要過濾空文本類型

若是是元素節點就遞歸循環scanTag方法

若是是文本節點就scanText

 

6. 掃描文本 scanText

avalon.scan

 

7.抽出文本綁定 extractTextBindings

avalon.scan

文本解析是個比較複雜的東西,能夠匹配不少種狀況,因此須要加入不少解析的規則

scanExpr 就是掃描的表達式的匹配

documentFragment 先把這個結構讓到文檔碎片中,性能處理

 

8. 表達式匹配scanExpr

avalon.scan

代碼很長,可是處理的東西確很簡單的

好比:

"{{ w }} x {{ h }}" 一個插值表達式,那麼應該如何解析

分析這個表達式,解析能夠分三塊
1.  {{ w }} 

2    x 

3   {{ h }}

左右兩邊都是vm視圖全部關聯的屬性,中間x就是求值

那麼解析的規則,分解3個部分,組成處理數據

tokens 就有3個組成對象

  1. expr: true
  2. filters: undefined
  3. value: " w "
  1. expr: false
  2. value: " x "
  1. expr: true
  2. filters: undefined
  3. value: " h "

解析後分解成綁定的數據

 

而後就是一次循環了, 遇到條件stopScan就終止了

 

因此總結scan無非就幹了一件事,掃描到指定的行爲,發送數據給處理函數

相關文章
相關標籤/搜索