本文學習了完整的**在最下面會展示
有關於圖形化的程式設計,我們往往會採用mvvm的模式來進行程式設計,將頁面抽象成資料可以讓程式設計變得更好把握,網頁前端也是如此,頻繁的dom操作勢必造成邏輯上的混亂,當專案特別龐大的時候,比如開發前端excel時,乙個單元格合併操作會造成大量dom元素的變更,刪除行和新增行也會造成dom的大量變更,造成邏輯上的混亂,維護和開發就會變得非常困難,因此,我們程式設計師只要修改和頁面ui繫結的資料 (物件,陣列,list一類的存在於記憶體中的資料結構),然後通過程式去對映在介面上,這樣的開發才能更好的維護。
首先先看個案例。
var student = ;
observe(student);
student.age = 24;
console.log('student.age is '+student.age);
我們定義了乙個物件,呼叫了乙個js函式,並且修改了age的值,但是在列印時並沒有改變,這證明js是通過get,set方法來修改值的,js提供了一層包裝,而提供編寫get,set函式的方法我這裡採用object.defineproperty(data, item , ;object.defineproperty(student,"proxyname",,
mdn解釋
object.defineproperty()
方法會直接在乙個物件上定義乙個新屬性,或者修改乙個物件的現有屬性,並返回此物件。
這樣我們就知道在set的時候是可以呼叫我們自定義方法的,這就為 js 物件的值改變時去更改介面樣式提供了支援。
當然,使用者是不會用proxyname來操作name的,使用者的寫法肯定還是student.name = newvalue;但如果把object.defineproperty的第二個引數換成name,是會造成棧溢位的,**如下。
原因是無限遞迴了。
我們的目標自然也不是給某乙個特定的物件的特定的值加set,而是任意物件的全部object屬性新增set。(function屬性是不需要新增set的。)
**如下
function observe(data) ,
set: function(newval)
})})
}var student = ;
var cat = ;
observe(student);
observe(cat);
student.name = "newname";
cat.color = "black";
這樣使用者在用自己的物件時不會有任何的不一樣,但是在修改時可以加入我們的邏輯,我們可以在set時做髒值檢查來修改前端的ui介面。
接下來我們思考使用者至少需要提供給我們什麼資料,經過思考得知使用者至少給乙個dom元素和乙個值,這就夠了。如下所示
function mymvvm(options)
new mymvvm()
接下來編寫髒值檢查邏輯,髒值的儲存應該是乙個陣列,陣列中放著乙個物件的全部屬性的髒值,也就是乙個鍵值對的形式來表示髒值。髒值就是dom元素的value,新值就是js物件的值。watch就是用於髒值檢查的物件。
option就是使用者傳遞給我們的資料物件,也就是上面的new mymvv(),nodevalue就是繫結的值這裡是val,node就是和nodevalue繫結的dom元素了就是上面的
function watcher(option, nodevalue ,node)
watcher.prototype.dirtyvaluecheck = function(newval)
}
function sub()
sub.prototype = ,
trigger: function(newval) )
}};sub.target = null;
sub就是容器,迴圈遍歷檢查髒值,這個邏輯應該在observe中去呼叫,並且是在set中去使用。
function observe(data)
return val;
},set: function(newval)
})})
}
總的來說就是當使用者傳遞的資料發生了修改會呼叫set,set呼叫sub的trigger然後遍歷裡面的watch,如果出現髒值就要利用dom去修改ui介面,這就完成了模型繫結view的能力。
那麼接下來就是如何新增watch了,watch就是提供node和value的乙個容器,node的**自然是html中的document,而value的**就是使用者提供的乙個物件了。那就需要去遍歷dom樹了,然後把和使用者提供的資料有繫結關係的node新增到sub中就可以了。對於插值表示式來說也是一樣的。
//compile
function compile(option)
compile.prototype.init = function ()
let childnodes = fragment.childnodes;
array.from(childnodes).foreach(node => })}
//實現插值表示式
interpolationrender(node,this);
})//經過轉化後的介面新增到節點下面就可以了
}function bingmodelview(node,attr,binddata)
})}function interpolationrender(node,binddata)\}/;
let text = node.textcontent;
if (reg.test(text))
}
這樣就完成了雙向繫結最為基礎的功能,還有很多功能沒有實現,也有非常多的細節沒有考慮到,以後會逐漸的完善。
下面附上完整的**
mvvm.html
winston_mvvm.js
function sub()
sub.prototype = ,
trigger: function(newval) )
}};sub.target = null;
function observe(data)
return val;
},set: function(newval)
})})
}//watcher
function watcher(option, nodevalue ,node)
watcher.prototype.dirtyvaluecheck = function(newval)
}//compile
function compile(option)
compile.prototype.init = function ()
let childnodes = fragment.childnodes;
array.from(childnodes).foreach(node => })}
//實現插值表示式
interpolationrender(node,this);
})//經過轉化後的介面新增到節點下面就可以了
vue資料雙向繫結的簡單實現
對資料雙向繫結一直都是半知半解,今天就打算自己寫個簡單的實現。可能有理解不到位甚至是錯誤的地方,如果有人發現的話可以指正 謝謝 資料的雙向繫結,即檢視和資料之間 html js var oinput document.getelementbyid input var ooutput document...
實現雙向繫結
ng和vue都有雙向資料繫結。vue是資料劫持,ng是藏之檢測 一 vue雙向資料繫結 訪問器屬性是物件中的一種特殊屬性,它不能直接在物件中設定,而必須通過 defineproperty 方法單獨定義。此例實現的效果是 隨文字框輸入文字的變化,span 中會同步顯示相同的文字內容 在js或控制台顯式...
前端主流框架雙向繫結實現原理簡述
angular的屬性繫結語法為 attr porperty,事件繫結語法為 event fn。雙向繫結的使用存在兩種場景 1 在表單中雙向繫結使用 ngmodel porperty,但同時得設定name屬性。其等價於繫結屬性 value property 繫結事件 input porperty.va...