VM 主要做了兩件微小的事情:
- 從 M 到 V 的映射(Data Binding),這樣可以大量節省你人肉來 update View 的代碼(將數據綁定到view)
- 從 V 到 M 的事件監聽(DOM Listeners),這樣你的 Model 會隨着 View 觸發事件而改變 (view改變的時候改變數據)
1、M 到 V 實現
做到這件事的第一步是形成類似於:
// template var tpl = '<p>{{ text }}</p>'; // data var data = { text: 'This is some text' }; // magic process template(tpl, data); // '<p>This is some text</p>'
中間的 magic process 是模板引擎所做的事情,已經有非常多種模板引擎可供選擇
當然你比較喜歡造輪子的話也可以自己實現一個
無論是 Angular 的 $scope,React 的 state 還是 Vue 的 data 都提供了一個較為核心的 model 對象用來保存模型的狀態;它們的模板引擎稍有差別,不過大體思路相似;拿到渲染后的 string 接下來做什么不言而喻了(中間還有很多處理,例如利用 model 的 diff 來最小量更新 view )。
但是僅僅是這樣並不夠,我們需要知道什么時候來更新 view( 即 render ),一般來說主要的 VM 做了以下幾種選擇:
- VM 實例初始化時
- model 動態修改時
其中初始化拿到 model 對象然后 render 沒什么好講的;model 被修改的時候如何監聽屬性的改變是一個問題,目前有以下幾種思路:
- 借助於 Object 的 observe 方法
- 自己在 set,以及數組的常用操作里觸發 change 事件
- 手動 setState(),然后在里面觸發 change 事件
知道了觸發 render 的時機以及如何 render,一個簡單的 M 到 V 映射就實現了。
2、V 到 M 實現
從 V 到 M 主要由兩類( 雖然本質上都是監聽 DOM )構成,一類是用戶自定義的 listener, 一類是 VM 自動處理的含有 value 屬性元素的 listener
第一類類似於你在 Vue 里用 v-on 時綁定的那樣,VM 在實例化得時候可以將所有用戶自定義的 listener 一次性代理到根元素上,這些 listener 可以訪問到你的 model 對象,這樣你就可以在 listener 中改變 model
第二類類似於對含有 v-model 與 value 元素的自動處理,我們期望的是例如在一個輸入框內
<input type="text" v-model="message" />
輸入值,那么我與之對應的 model 屬性 message 也會隨之改變,相當於 VM 做了一個默認的 listener,它會監聽這些元素的改變然后自動改變 model,具體如何實現相信你也明白了