天天看點

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

最近工作挺忙,avalon隻能斷斷續續的寫下去了,大概看了下angular的源碼,看到小一半就比較難堅持了,是塊硬骨頭,慢慢啃吧

不過angular的的文檔中用詞還是很優雅:

HTML編譯器

指令

編譯

連結

過濾器

注入器

控制器

管道

      等等…看起來覺得老進階,其實avalon也間接的部分實作,原理也不是很複雜

avalon版本更新很快,新版的加入了AMD規範的子產品加載器,還修複了很多BUG,不過相信短期内實作的核心還是不會變化,是以我依然以現在的版本分析為主

<a></a>

視圖背後的代碼就是控制器,在mvvm中就是vm視圖模型,它的主要工作就是構造模型,并把模型與回調方法一并發送到視圖,視圖可以看作作用到模版HTML上的投影

是以在編譯階段,我們的控制器就會把使用者定義的資料模型給構造出來

avalon中的modelFactory工廠方法構造出的model對象其實就是真正的控制器了,至于構造出來的控制器如何注入到視圖上的,等以後分析到HTML編譯器雙向綁定吧

model 本來是系統内部定義的一個臨時對象,将控制器和avalon的作用域對象給關聯起來

接上一節

收集使用者定義的scope在過濾的時候做了2個處理

收集控屬性賦監與計算屬性,是為了在初始化scpoe中的代碼未處理的方法

周遊監控屬性收集器,給初始化的空model對應的方法指派

這裡注意各重點,指派的的時候實際是調用的accessor方法,因為set get給轉換過了

accessor 源碼

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

其實源碼注釋很清楚了,我們歸納下執行的流程

判斷參數是調用set還是get方法

stopRepeatAssign //阻止重複指派,是這factory.apply(0, deps);重置上下文的時候處理的

監控數組處理

更新json  //收集原始的定義

notifySubscribers  //更新依賴,就是目前的操作會觸發與之相關

model.$events 觸發訂閱的自定義事件

notifySubscribers  其實就是關鍵的執行點,執行目前作用域所依賴的所有的,這個在雙向綁定的時候就可以仔細讨論了

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

監控屬性涉及使用者定義的處理,是以要做很多關聯的處理

流程:

收集依賴關系

處理用于定義的get方法

更新json

傳回定義函數的結果

Publish 對象是将函數曝光到此對象上,友善通路器收集依賴

fn.nick 就是對應的計算屬性方法名稱,在過濾的時候 accessor.nick = name;附上的

同樣執行了accessor方法,由于沒有傳遞參數,實際上就是在處理收集依賴關系了

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

collectSubscribers方法

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

很明顯的處理,取出開始push到的Publish的處理回調,取出依賴清單,合并

ensure 法隻有目前數組不存在此元素時隻添加它

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

所有此時的 subscibers關聯就有值了

最後執行定義的get方法,更新json

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

注意的一點

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

這裡又涉及到取值的問題,是以又會關對應的執行各自的accessor

是以這裡會進行一次收集依賴了

在轉換的完畢model後,會給model增加訂閱的特性與一些屬性

model.$json = json;  //純淨的js對象,所有通路器與viewModel特有的方法屬性都去掉

增加事件訂閱

model.$events = {}; //VB對象的方法裡的this并不指向自身,需要使用bind處理一下

model.watch=Observable.watch=Observable.watch.bind(model);//用于監聽ViewModel中的某屬性變化,它将新值與舊值都傳給回調

model.unwatch=Observable.unwatch=Observable.unwatch.bind(model);//解除安裝$watch綁定的回調

model.fire=Observable.fire=Observable.fire.bind(model); //觸發$watch指定的回調

ViewModel的ID,友善通過avalon.models[$id]通路

model.$id = generateID();

判斷是否為模型中的原始資料

model.hasOwnProperty 方法

最後傳回工廠轉化後的model對象

avalon.define

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

其實這裡有一種重點

輕量級前端MVVM架構avalon - 控制器引子:編譯期處理監控屬性 處理計算屬性:主方法入口那麼有個精妙的思路:

作者再次把定義的模型給執行了一遍,用意呢?

請看

在定義的VM中的方法中,如果再次通路vm.xxx屬性,

這時候内部引用不對了 VM還是指向原來的普通JS對象,而不是真正的VM是以需要apply一次,改變

我們 factory.apply(0, deps); //重置它的上下文

是以把方法執行一次把内部引用換給model

因為轉換了模型關系,是以監控屬性與計算屬性都會有對應的set get操作了,相對應的上下文也變成了vm了

stopRepeatAssign return 阻止了,防止重複指派

avalon.models[name] = model; 挂到了全局的models中,方面以後使用

本文轉自艾倫 Aaron部落格園部落格,原文連結:http://www.cnblogs.com/aaronjs/p/3166694.html,如需轉載請自行聯系原作者