前端MVVM框架設計及實現(一)

最近抽出點時間想弄個dom模塊化的模板引擎,不過如今這種都是MVVM自帶的,索性就想本身造輪子寫一個簡單的MVVM框架了javascript

借鑑的天然仍是從正美的avalon開始了,我記得仍是去年6月寫過一個系列的avalon源碼分析的,不過那時候0.7版本,不夠健全,如今已經好太多了css

 

框架是面向一個領域,提供一套解決方案,那麼咱們用前端的MVVM能爲咱們帶來什麼便利?html

  • 關注點分離
  • 操做數據即操做DOM
  • 動態模板

關注點分離是MVVM與身俱來的,操做數據即操做DOM,是VM中的訪問器帶來的,動態模板是流程綁定實現的。 前端

關於MV*的討論太多了,這裏不在討論,咱們重點就是分析如何實現前端MVMM框架 java

Avalon 地址 https://github.com/RubyLouvre/avalon git

 


學會MVVM須要先會哪些東西?github

1. javascript語言基礎(做用域,原型鏈,閉包等等)設計模式

2. 簡單設計模式,基本的數據結構數組

3. 閱讀或者寫過jQuery源碼數據結構

爲何要這樣說呢,由於avalon就是這些東東的綜合體!

 


我是以avalon爲藍本,按照做者是思路模仿實現的,固然avalon的代碼有4000多行,新手若是去學習的話估計無從下手,也力不從心

爲何呢?簡單的說實現的手段有點另類,寫的代碼有點狂野(請原諒我不知道如何形容),不過用戶體驗卻是不錯!

簡單的看下代碼結構

<div ms-controller="box">
     <div style=" background: #a9ea00;" ms-css-width="w" ms-click="click"></div>
     <p>{{ w }}p>
 </div>
 <script>
     avalon.define("box", function(vm) {
         vm.w = 100;
         vm.click = function() {
             vm.w = parseFloat(vm.w) + 10;
         }
     })
 </script>

針對這個代碼結構,咱們要明白:

 

1:爲何要自定義大量標記(聲明式綁定)

這就是MVVM 最原始的意義,數據邏輯展示分離。表現就是 數據 js邏輯代碼 htmlcss展示

因此再HTML里加結構是天然而然的事情,若是html都用js生成,那就跟mvvm搭不上邊

 

2:avalon.define裏面爲何不須要操做dom?

在MVVM中,數據是核心,因爲VM與V之間的雙向綁定,操做了VM中的數據(固然只能是監控屬性),就會同步到DOM,咱們透過DOM事件監控用戶對DOM的改動,也會同步到VM。

 


本章咱們就實現第一步:搭建基本的分層結構,實現雙向通知機制

初版實現:300行代碼,請對照分析看源碼 https://github.com/JsAaron/aaMVVM

針對上面2個問題,咱們看看如何才能作到操做數據即操做dom呢?

簡單的說一下實現是思路:你們能夠down下git的aaMVVM對照下,比原版的4000行代碼友愛多了!

 

咱們知道在MVVM中,M只是一個過客,它與其餘表示業務狀態的東西融入VM(ViewModel)中。ViewModel是一個狀態的集合,固然還拖家帶口監控着大量的回調

因此ViewModel就承載的幾乎全部的功能,在avalon中ViewModel就包含全部的數據與方法的定義,溝通着V與M,起到承上啓下的做用~

 


視圖模型如何與數據跟視圖關聯起來?

經過avalon.define定義的vm中的屬性與方法都與對應的html結構中的標記有映射關係,因此改變vm中的數據與之關聯的dom就會自動刷新

分析下

vm.w = 100

當模型的數據改變爲100時,對應的視圖中div的寬度爲100, 文本<p>100</p>  ,可見修改一個數據在同一個控制器內與之關聯的2個映射動做都將會修改

一個是css操做,一個是text賦值

從這個操做咱們能夠大膽推測下vm.v中應該有一個列表,記錄了當前控制器下對應的映射操做(多個)

爲了實現set與get方法,avalon也相似emberjs,採用了Object.defineProperty

我用最簡單的代碼模擬下實現


也就是說

vm.w = 100  即要修改style也要修改p,就是一對多的關聯方式

因此在avalon中針對每個監控屬性,都會生成set與get的訪問控制器,那麼在每個監控屬性的訪問控制器裏面都會有一個

accessor[subscribers] = [] //訂閱者數組,這樣的東東來存放與之相關的依賴

image

當咱們觸發  vm.w = 100時,就會觸發w:set方法,取出accessor[subscribers]中的依賴,從而各執執行,這樣就實現了依賴執行了

對應的方法:自動更新自身的依賴

//通知依賴於這個訪問器的訂閱者更新自身
function notifySubscribers(accessor) {
    var list = accessor[subscribers]
    if (list && list.length) {
        var args = [].slice.call(arguments, 1)
        for (var i = list.length, fn; fn = list[--i];) {
            var el = fn.element
            fn.handler(fn.evaluator.apply(0, fn.args || []), el, fn)
        }
    }
}

 


上面只是簡單的思路,真正實現的時候真要作到大而全的框架,考慮的問題可不是那麼簡單的事

1 框架是怎麼解釋聲明式綁定的語法

2 如何把解析後的語法生成對應的處理句柄

3 用戶的定義如何生成vm模型

4 如何收集這些依賴

5 如何自動更新依賴映射

 

GitHub上會同步更新最新的實現,。。。敬請關注~

Fork https://github.com/JsAaron/aaMVVM

相關文章
相關標籤/搜索