參考:剖析vue原理&實現雙向繫結mvvm和vue.js雙向繫結的實現原理
1、通過object.defineproperty(obj, prop, descriptor)劫持物件的屬性讀寫,其中obj是要在上面定義屬性的物件,prop是要定義或修改的屬性名稱,descriptor是屬性的描述符。描述符中可選get和set鍵值。get是屬性的getter方法,返回屬性值;set為setter方法,接受唯一引數,並將該引數的值賦值給屬性,get和set的預設值均為undefined。
2、雙向繫結的簡單實現。
當通過input進行輸入時,obj.txt的值會相應更新;當通過控制台改變obj.txt的值時,setter會改變view,從而實現了view=>model,model=>view的雙向繫結。不過這種簡單繫結不會真正執行obj.txt = e.target.value,obj永遠為{},如果在set方法中賦值obj.txt = e.target.value,則會造成無限迴圈。為解決這個問題,將object.defineproperty()封裝為乙個函式,即可在其中儲存狀態obj.txt,修改如下:
上面就是乙個最簡單的雙向繫結,但要實現類似於vue的功能還需要繼續改進。
3、model=>view繫結
function compile(node, vm)}時,將該位置替換為vm下data對應屬性的值。
vm通過new關鍵字宣告,建構函式vue中將el確定的節點及vm自身傳入nodetofragment函式,之後再將當前子節點替換為nodetofragment函式返回的documentfragment物件。nodetofragment函式將當前節點的子節點逐個傳入編譯函式compile,並將編譯好的節點新增到documentfragment物件返回。編譯函式compile()判斷當前節點型別,節點為元素時,判斷是否有v-model屬性,並替換input.value,當節點為文字時,利用正規表示式判斷是否含有花括號,並查詢花括號內對應的值替換該節點。
存在的問題:
function compile(node, vm),
set: function (newvalue)
});});
}function compile(node, vm)
此時改變input的值時,span也會改變;通過console改變vm.input時,span也會改變。但當在console中輸入vm.input時會出現無限迴圈的情況:
這是由於在getter中會反覆呼叫自身,下面對observe進行改進,將object.defineproperty從函式中單獨取出,構成乙個閉包。
function defineproperty(vm, key, val),
set: function (newvalue)
val = newvalue;
}});
}function observe(data, vm));
}
修改後vm.input的值就能正確改變和返回了。但此時view的變化是通過setter手動新增的,而且只能是元素形式的節點,如果節點是}模板字串則無法動態改變。解決辦法是採用訂閱/發布模式進行修改,對每個節點繫結乙個觀察者watcher,對每個資料繫結乙個分發者dep,資料改變時,呼叫分發者的通知方法,通知每個觀察者進行相應的改變。
5、訂閱/發布模式(subscribe&publish)
採用訂閱/發布模式對**進行修改。首先定義觀察者watcher,並在編譯函式compile()中對每個節點新增觀察著watcher,當接收到分發者指令時,呼叫update方法更新檢視。接下來定義訊息分發者dep,dep維護觀察者陣列,當值發生變化時,通知各觀察者呼叫update方法。完整**如下:
//第三部分
function watcher(vm, node, name, nodetype)
watcher.prototype =
if (this.nodetype === 'input')
},get: function()
}function dep()
dep.prototype = ,
notify: function());
}}//第二部分
function defineproperty(vm, key, val)
return val;
},set: function (newvalue)
val = newvalue;
dep.notify();
}});
}function observe(data, vm));
}//第一部分
function compile(node, vm));
node.value = vm[name];
node.removeattribute('v-model');
new watcher(vm, node, name, "input");}}
if (child = node.firstchild)
}if(node.nodetype === 3)\}/;
if(reg.test(node.nodevalue))
}}function nodetofragment(node, vm)
return flag;
}function vue(options)
var vm = new vue(
});
Javascript 學習筆記
如果在生成的html裡面有事件需要傳遞帶特殊字元的引數,處理如下 singletext 輸入 1.singletext value.escapehtml 為 將html編碼 2.singletext value.escapehtml inspect 為 3.在 jsdebugtext innerht...
javascript學習筆記
視窗操作 1改變視窗的位置 window.location 2視窗的歷史操作 previous 3建立新的視窗 window.open url 視窗名稱 視窗特徵字元 細節 不能換行寫 視窗特徵 width,height,yes,no munubar,status,scrollbars,resiza...
javaScript學習筆記
2018 12 26 標題 var num1 10 var num2 0 var result num1 num2 console.log result infinity 表示超出了js的數值範圍 類似高數里的整數除以無窮小的數,得到無窮大的結果。var num1 a var num2 3 或其它n...