MVVM框架最顯著的特點就是虛擬dom和響應式的數據、我們以Vue為例,分別實現data、computed、created、methods以及虛擬dom。
這一章我們先實現簡單的響應式,修改數據之后在控制臺打印。
我們將該框架命名為MiniVue。
首先我們需要創建MiniVue的類(src/core/index.js)
創建完類之后我們需要創建一個js(src/core/init.js)給這個類的原型添加初始化事件,用來初始化data、computed等內容
然后在類中混入_init 方法并在構造方法中調用_init方法
接著我們來實現一個數據代理的一部分
?當前的代理我們使用Object.defineProperty來實現,這個類方法有一個很大的缺點,就是在定義數組時,通過下標修改數據和新增刪除數據時不會觸發,vue2中的解決方法就是重寫這些方法,這里我們也按照vue2的方式來實現。
我們在src中添加proxy.js,并添加代理方法(src/core/proxy.js)
/*** 代理數據* @param {*} vm * @param {*} data * @param {*} namespace 主要控制當前data是哪一個 name 還是 object.name 訪問跟下面的屬性就是 '' */
export function constructProxy(vm, data, namespace) {let proxyObj = {}// 我們需要判斷data的類型if(data instanceof Array) { // 需要先判斷Array類型} else if (data instanceof Object) { // 判斷Object類型proxyObj = proxyObject(vm, data)} else {throw new Error('data must be an object or array')}return proxyObj
}
在響應式系統里面我們只代理Object和Array類型,如果不是就拋出錯誤
接下來我們來實現Object類型的代理?proxyObject 方法 (src/core/proxy.js)
/*** 代理Object數據* @param {*} vm * @param {*} data */
function proxyObject(vm, data) {// 創建代理對象let proxyObj = {}for(let key in data) {Object.defineProperty(proxyObj, key, {get() {return data[key]},set(newValue) {console.log(`正在修改:${key} 值為:${data[key]}`)data[key] = newValue}})// 為MiniVue的根實例添加屬性Object.defineProperty(vm, key, {get() {return data[key]},set(newValue) {console.log(`正在修改根:${key} 值為:${data[key]}`)data[key] = newValue}})}return proxyObj
}
然后我們在初始化方法中去代理data (src/core/init.js)
/*** 實現init方法* @param {Object} options */
function init(options) {console.log(`options: ${options}`)// 初始化dataif(options && options.data) {this._data = constructProxy(this, options.data, "")}// 初始化computed// 初始化methods// 初始化created// 掛載dom
}
這樣一個簡單的代理就完成了,我們創建一個入口文件并實例化這個MiniVue來看效果
在控制臺查看MiniVue實例的屬性 然后修改_data 中的數據
我們通過圖片內容可以看到:
1.我們可以看到實例中最外層有name 和 description ,這說明我們已經為MiniVue實例的根實例添加了屬性
2.我們可以看到_data 中也添加了屬性
3.修改根節點的name 后 _data.name 也會發生了變化,并且監控到了修改行為
章節總結:
1.創建MiniVue類,創建init.js 給原型添加_init方法
2.在方法中實現data、computed、created、methods以及虛擬dom
3.創建proxy.js, 入口方法中判斷數據類型 如果不是Object 或者 Array 直接拋出異常
4.代理Object類型時, 創建代理對象,并且給實例的根屬性也添加代理