詳解vue的數(shù)據(jù)劫持以及操作數(shù)組的坑
TL;DR
給data添加新屬性的時候vm.$set(vm.info,'newKey','newValue')
data上面屬性值是數(shù)組的時候,需要用數(shù)組的方法操作數(shù)組,而不能通過index或者length屬性去操作數(shù)組,因為監(jiān)聽不到屬性操作的動作。
安裝和初使用vue
vue是構(gòu)建用戶界面的漸進式框架。所謂的漸進式:vue + components + vue-router + vuex + vue-cli可以根據(jù)需要選擇相應的功能。
來串命令mkdir vue-apply;cd vue-apply;npm init -y;npm i vue。
來一個html文件如下,瀏覽器瞄下~,瀏覽器控制臺vm.msg=0再看下
<div id="app">{{msg}}</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
// template加上之后會替換掉#app這個標簽
// template:'<h1>en</h1>',
data:{msg:'msg'}
})
vm.msg = 'msg'
</script>
說說mvvm mvc
mvc其實是model view Model傳統(tǒng)所有邏輯在controller,難以維護。用戶輸入 => 控制器 => 數(shù)據(jù)改變,如果數(shù)據(jù)變了需要獲取dom,操作屬性,再渲染到視圖上。
mvvm其實是model view viewModel數(shù)據(jù)變化驅(qū)動視圖。數(shù)據(jù)變了,不需要你獲取dom,然后改變dom的內(nèi)容。這邊數(shù)據(jù)變了,vm負責監(jiān)聽,視圖那邊自動發(fā)生變化。最明顯的是不需要document.querySelector之類的了。
vm的實質(zhì)
上面說了vm負責讓數(shù)據(jù)變了,視圖能自動發(fā)生變化。這么神奇魔術(shù)背后的原理是Object.defineProperty。其實就是屬性的讀取和設(shè)置操作都進行了監(jiān)聽,當有這樣的操作的時候,進行某種動作。來一個demo玩下。
// 對obj上面的屬性進行讀取和設(shè)置監(jiān)聽
let obj = {
name:'huahua',
age:18
}
function observer(obj){
if(typeof obj === 'object'){
for (const key in obj) {
defineReactive(obj,key,obj[key])
}
}
}
// get的return的值才是最終你讀取到的值。所以設(shè)的值是為讀取準備的。
// set傳的參數(shù)是設(shè)置的值,注意這里不要有obj.name = newVal 這樣又觸發(fā)set監(jiān)聽,會死循環(huán)的。
function defineReactive(obj,key,value){
Object.defineProperty(obj,key,{
get:function(){
console.log('你在讀取')
// happy的話這邊可以value++,這樣你發(fā)現(xiàn)讀取的值始終比設(shè)置的大一個,因為return就是讀取到的值
return value
},
set:function(newVal){
console.log('數(shù)據(jù)更新了')
value = newVal
}
})
}
observer(obj)
obj.age = 2
console.log(obj.age)
在瀏覽器執(zhí)行的時候,控制臺隨手也可以obj.name="hua1"類似的操作,發(fā)現(xiàn)都監(jiān)聽到了。但是如果更深一步,obj.name={firstname:'hua',lastname:'piaoliang'};obj.name.lastname='o'就不能監(jiān)聽到屬性修改了。因為并沒有將新的賦值對象監(jiān)聽其屬性。所以函數(shù)需要改進。
需要在defineReactive的第一行加上observer(value)。設(shè)置值的時候如果是對象的話,也需要將這個對象數(shù)據(jù)劫持。同理,set那邊也需要加這行。
function defineReactive(obj,key,value){
// 注意這里?。。。。。?!
observer(value)
Object.defineProperty(obj,key,{
get:function(){
return value
},
set:function(newVal){
// 注意這里!?。。。。?!
observer(newVal)
console.log('數(shù)據(jù)更新了')
value = newVal
}
})
}
繼續(xù),如果obj.name=[1,2,3];obj.name.push(4)發(fā)現(xiàn)又沒有通知了,這是因為Object.defineProperty不支持監(jiān)聽數(shù)組變化。所以需要重寫數(shù)組上面的方法。話說,最近看了個文章,理論上也可以監(jiān)聽數(shù)組,但是性能消耗和收益不成正比,所以,vue就沒去實現(xiàn)了。
// 把數(shù)組上大部分方法重寫了,這里不一一列舉。但是如果你 [1,2].length--,這是捕捉不到的
let arr = ['push','slice','split']
arr.forEach(method=>{
let oldPush = Array.property[method]
Array.property[method] = function(value){
console.log('數(shù)據(jù)更新')
oldPush.call(this,value)
}
})
vue使用的時候注意的坑
正如上面的解釋,vue2.0的底層約莫是這個邏輯,所以使用需要注意的點:
因為是一開始就數(shù)據(jù)劫持了。所以后來如果新綁定屬性,是沒有數(shù)據(jù)劫持的。如果需要調(diào)用 vm.$set(vm.info,'newKey','newValue'),vm是vue的實例。
當屬性值是數(shù)組,數(shù)組變化的時候,跟蹤不到變化。因為數(shù)組雖然是對象,但是Object.defineProperty不支持數(shù)組,所以vue改寫了數(shù)組的所有方法,當調(diào)用數(shù)組方法的時候,就調(diào)動變動事件。但是不能通過屬性或者索引控制數(shù)組,比如length,index。
總結(jié):data上,綁定所有屬性避免后期加新屬性。如果是數(shù)組,只能通過數(shù)組方法修改數(shù)組。如下例子,控制臺vm.arr--發(fā)現(xiàn)視圖并不會變化,vm.arr.push(4)就能變化
<div id="app">{{msg}}{{arr}}</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
// template加上之后會替換掉#app這個標簽
// template:'<h1>en</h1>',
data:{msg:'msg',arr:[1,2,3]}
})
vm.msg = 'msg'
</script>
以上所述是小編給大家介紹的vue的數(shù)據(jù)劫持以及操作數(shù)組的坑詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
詳解Vue項目中出現(xiàn)Loading chunk {n} failed問題的解決方法
這篇文章主要介紹了詳解Vue項目中出現(xiàn)Loading chunk {n} failed問題的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09

