一、引入
談及Vue中的數據雙向綁定,我們自然而然的想到是通過v-model指令實現的。但具體是怎么實現的呢?下面就介紹一下。
二、v-model語法糖是什么?原理是什么?
v-model語法糖是vue多個基礎語法(屬性綁定 和事件綁定)的簡寫。
原理:給表單元素input綁定通過"v-bind:"綁定value屬性的數據msg,再給表單元素input添加監聽value值改變的事件@input,給msg重新賦值。
代碼:
<!-- <input type="text" v-model="msg"> --> <input :value="msg" type="text" @input="msg=$event.target.value">
三、雙向數據綁定的原理?
vue中數據雙向綁定通過v-model實現,雙向綁定指的是視圖和內存中的數據進行雙向綁定。(通過Object.defineProperty和給元素注冊事件)
表單元素改變數據的原理:
- 實現數據驅動視圖
- 需要先定義一個data對象將其中msg屬性的值顯示到視圖中。想要通過Object.defineProperty來監測其值得變化是不可能實現的,因為使用他的同時需要給對象賦值並監聽,而data對象中已經有了這個屬性並綁定到了頁面中顯示,無法再重新定義該屬性。這就需要新建一個空對象vm,通過給vm定義屬性並監測來實現這個功能。
- Object.defineProperty調用時的第三個參數為對象配置項,其中的get()方法為vm的msg屬性值被獲取時觸發的回調函數。set()方法為vm的msg屬性值被設置時觸發的回調函數,set()函數的參數為msg屬性的新值。
- 實現視圖驅動數據
通過給表單元素注冊input事件,將表單元素中的value值賦給vue.msg
<!-- 1. 把數據渲染到表單元素中 -->
<!-- 2. 當你修改數據的時候,表單元素的值發生改變,視圖需要更新 -->
<!-- 3. 當你使用表單元素的時候,你在修改元素的值,對應的數據也要發生改變 -->
<h5></h5>
<input type="text">
<script>
// const vm = new Vue({data:{msg:'hi vue'}}) vm.msg = '數據'
// 使用用定義可以監聽(觀察)的屬性的。
const vm = {}
const data = { msg: 'hi vue' }
// 獲取dom
const h5 = document.querySelector('h5')
const input = document.querySelector('input')
// 1. 默認渲染
h5.innerHTML = data.msg
input.value = data.msg
// 2.1 監聽 data中的msg的值改變 觀察 data中的msg的值改變 最終監聽的是vm的msg屬性變化
// 2.2 如果 數據改變 修改視圖
// 三個參數 給誰定義一個屬性 屬性的名稱 對象配置項(get 獲取屬性值 set 設置屬性值)
Object.defineProperty(vm, 'msg', {
get() {
// 當獲取msg屬性值時觸發
// console.log('get')
return data['msg']
},
set(newValue) {
// 當設置msg屬性值時觸發
// console.log('set')
// console.log(newValue)
// 數據改變
data['msg'] = newValue
// 修改視圖
h5.innerHTML = newValue
input.value = newValue
}
})
// 3. 監聽 表單元素 的值改變事件 修改數據即可(上面已經實現數據驅動視圖)
input.oninput = function(){
// console.log(this.value)
vm.msg = this.value
}
</script>
總體描述:
-
Vue內部會把data中的數據通過defineProperty方法轉化為set和get的監控方式
-
當data中的數據發生變化時,會觸發對應的set或者get
-
修改屬性值的時候,觸發set方法
-
訪問屬性值的時候,觸發get方法
-
-
監控數據變化的目的還是為了更新頁面(僅僅更新數據變化對應的DOM節點:盡可能少的更新DOM)
-
但是完成上述要求需要底層虛擬DOM的支持
四、什么是虛擬DOM?
瀏覽器更新DOM比較耗時,為了節省時間,需要盡可能少的更新DOM。虛擬DOM是對真實DOM的一種描述;其組成部分虛擬節點也描述了真實的DOM節點,本質上就是普通對象
// VNODE 虛擬節點:描述了真實的DOM節點,本質上就是普通對象
{
tagName: 'div'
attrs: { class: "active", id: "info"}
content: "hello"
}
-
虛擬DOM也會形成一個樹狀結構,描述了真實的DOM樹(形成虛擬DOM樹和真實DOM樹的對應關系)
-
如果數據發生變化,那么就會觸發虛擬DOM數的對比(diff算法,過程發生在內存中)
-
對比的結果是:有變化的虛擬節點的集合
-
上述虛擬節點需要轉化為真實的DOM節點(下面是虛擬下面是虛擬節點轉換為真實節點的過程)
var div = document.createElement(vnode.tagName) div.setAttibute(key, value) div.innerHTML = vnode.content
- 最終會把真實的節點更新到頁面
雙向數據綁定運用虛擬DOM的進一步解釋說明:
在使用defineProperty進行到set()時,會采用虛擬DOM來跟新視圖;虛擬DOM有新、舊兩份數據存儲在內存中,每次監測到數據改變時,計算機會通過diff算法對比兩份數據的區別,得到有變化的虛擬節點的集合,並將它們轉換為真實的DOM節點更新到頁面中。
采用上面方式的原因就是瀏覽器解析完整DOM樹的時間、性能消耗,要遠比內存對比數據再進行局部渲染的消耗大得多。內存處理數據的速度要比瀏覽器快的多。
