首先先要知道的是v-model的作用是實作資料的雙向系結,即:

資料在視圖層的雙向回應,
實作思路主要分為兩步:
第一步:資料層到視圖層的回應
將資料回應到視圖層的方式,在vue2使用的是Object.defineProperty()來實作,需要劫持到資料的變化,在資料變化的時候將其渲染到視圖上:
A,首先需要遍歷data的資料,獲取到每個data的屬性
B,其次,獲取到data的每個屬性之后,對屬性進行攔截,
C,在攔截時,需要將其值反映到對應的視圖示簽上,
第C步中又可以分為:
a,獲取到視圖中每個節點的DOM物件,
b,遍歷DOM物件,獲取到每個DOM物件對應的node物件(節點物件),
c,遍歷node物件,獲取到node物件中含有v-model屬性的節點
d,將對應的data的屬性值賦值給node節點的value值上
代碼實作為:
<body>
<div id="app">
名字:<input type="text" v-model="name" value="12"><br>
年齡:<input type="text" v-model="age" value="2323">
<div class="sjkx">
<h1 class="name">模擬v-model</h1>
</div>
</div>
<script>
let data = {
name: '',
age: '',
}
let view = document.getElementById('app')
// 資料反映到視圖方法
function getVmodelNode(view, data) {
// a,獲取到視圖中每個節點的DOM物件,
let allDom = view.getElementsByTagName("*")
let allDomArray = Array.from(allDom)//將偽陣列轉化成陣列
let attributeArray = []
// b,遍歷DOM物件,獲取到每個DOM物件對應的node物件,
allDomArray.forEach(nodeItem => {
//c, 遍歷node物件,過濾獲取到node物件中含有v-model的節點
Array.from(nodeItem.attributes).forEach(item => {
if (item.nodeName === 'v-model') {
//d,將對應的data的屬性值賦值給node節點的value值上
nodeItem.value = data[item.nodeValue]
}
})
})
}
// A,首先需要遍歷data的資料,獲取到每個data的屬性
Object.keys(data).forEach(key => {
// B,其次,獲取到data的每個屬性之后,對屬性進行攔截,
debugger
WebServer(data,key,data[key])
})
function WebServer(data, key, value) {
Object.defineProperty(data, key, {
get() {
return value
},
set(newValue) {
value= newValue
// C,在攔截時,需要將其值反映到對應的視圖示簽上,
getVmodelNode(view,data)
}
})
}
</script>
</body>
第二步:視圖層到資料層的回應,
視圖層回應到資料層的思路:當輸入框的資料發生變化的時候,呼叫函式,將輸入框的值賦值給data對應的屬性上,
實際上就是在第一步的第C步多加了一步:為對應的node物件系結一個input事件,并將node的value賦值給data對應的屬性上,
<body>
<div id="app">
名字:<input type="text" v-model="name" value="12"><br>
年齡:<input type="text" v-model="age" value="2323">
<div class="sjkx">
<h1 class="name">模擬v-model</h1>
</div>
</div>
<script>
let data = {
name: '',
age: '',
}
let view = document.getElementById('app')
// 資料反映到視圖方法
function getVmodelNode(view, data) {
// a,獲取到視圖中每個節點的DOM物件,
let allDom = view.getElementsByTagName("*")
let allDomArray = Array.from(allDom)//將偽陣列轉化成陣列
let attributeArray = []
// b,遍歷DOM物件,獲取到每個DOM物件對應的node物件,
allDomArray.forEach(nodeItem => {
//c, 遍歷node物件,過濾獲取到node物件中含有v-model的節點
Array.from(nodeItem.attributes).forEach(item => {
if (item.nodeName === 'v-model') {
//d,將對應的data的屬性值賦值給node節點的value值上
nodeItem.value = data[item.nodeValue]
//視圖層反映到資料層上,
nodeItem.addEventListener('input',(e)=>{
data[item.nodeValue]=e.target.value
})
}
})
})
}
// A,首先需要遍歷data的資料,獲取到每個data的屬性
Object.keys(data).forEach(key => {
// B,其次,獲取到data的每個屬性之后,對屬性進行攔截,
WebServer(data,key,data[key])
})
function WebServer(data, key, value) {
Object.defineProperty(data, key, {
get() {
return value
},
set(newValue) {
value= newValue
// C,在攔截時,需要將其值反映到對應的視圖示簽上,
getVmodelNode(view,data)
}
})
}
// getVmodelNode(view, data)
</script>
</body>
這就是完整的模擬v-model的代碼了,
順著這個思路,vue中全部的指令原始碼都可以自己搞定,什么bind呀,什么v-text呀,甚至ref都可以自己搞定!!!!!!


轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/298139.html
標籤:其他
上一篇:cgb2107-day09
