JavaScript學習筆記 自己實現雙向繫結

2021-08-17 22:00:20 字數 2815 閱讀 7980

參考:剖析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...