在一個函數(shù)中,改變了data中的數(shù)據(jù)伴奥,在函數(shù)中查看是修改成功的写烤,但是頁面中并沒有刷新。
尤大的解釋:由于性能的代價與獲得的用戶體驗不成正比拾徙,故vue2.0的實現(xiàn)中放棄了這個特性洲炊。在vue3.0中,使用proxy
替代了Object.defineProperty()
數(shù)組變更檢測注意事項:
由于JS的限制尼啡,以下兩種情況暂衡,vue不能檢測以下數(shù)組的變動
- 當(dāng)利用索引直接修改數(shù)組的某一項時
- 直接修改數(shù)組的長度時
示例:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是響應(yīng)性的
vm.items.length = 2 // 不是響應(yīng)性的
也就是說,直接設(shè)置數(shù)組的某一項時玄叠,雖然改變了數(shù)組的值古徒,但視圖上顯示的仍然為數(shù)組之前的值,數(shù)據(jù)的響應(yīng)式失效了读恃。
vue的數(shù)據(jù)劫持是利用Object.defineProperty()
的get,set
方法隧膘,但是get,set
是有限制的。示例:
var person = {};
Object.defineProperty( person, {
age: {
defaultValue: 11,
get: function () {
return this.defaultValue;
},
set: function (val) {
this.defaultValue = val;
console.log("觸發(fā)了set")
}
}
});
// 修改屬性的值時能夠觸發(fā)set
person.age = 12 // 觸發(fā)了set
->觸發(fā)了set
->12
person.age
->12
// 將屬性的值設(shè)置為一個數(shù)組寺惫,當(dāng)通過索引值修改數(shù)組的某一項或使用數(shù)組的某些方法修改數(shù)組時不能觸發(fā)set
person.age = [2,3,4] // 觸發(fā)了set
->觸發(fā)了set
->(3) [2, 3, 4]
person.age[2] = 5 // 未觸發(fā)set
->5
person.age
->(3) [2, 3, 5]
person.age.push(5) // 未觸發(fā)set
->4
person.age
->(4) [2, 3, 4, 5]
// 將屬性的值設(shè)置為一個對象疹吃,當(dāng)修改對象中某屬性的值時無法觸發(fā)set
person.age = { first: 1 }
->觸發(fā)了set
->{first: 1}
person.age.first = 2 // 未觸發(fā)set
->2
通過上述例子可以觀察得出:
當(dāng)該屬性的值為一個數(shù)組時,通過索引修改數(shù)組某一項的值或使用數(shù)組的某些方法修改數(shù)組并不能觸發(fā)set西雀;當(dāng)屬性的值為一對象時萨驶,直接修改對象中屬性的值時也無法觸發(fā)set。
解決方法:
-
Vue.set
:Vue.set(vm.items, indexOfItem, newValue)
-
vm.$set(vm.items, indexOfItem, newValue)
也可以使用vm.$set
實例方法艇肴,該方法是全局方法Vue.set
的一個別名 vm.items.splice(indexOfItem, 1, newValue)
- 運用
this.$forceUpdate()
強制刷新腔呜。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li v-for='(item,index) in list' :key='index'>{{item}}</li>
</ul>
<button @click='change'>按鈕</button>
</div>
</body>
</html>
<script src="./lib/vue-2.6.10.js"></script>
<script>
var vm = new Vue({
el:'#app',
data:{
list:[
1,2,3,4,5
]
},
methods: {
change(){
this.list[0] = 2
// Vue.set(vm.list,0,2)
vm.list.splice(0,1,2)
// this.$forceUpdate()
console.log(this.list);
}
},
})
</script>
proxy
-
Object.define()
只能對屬性進行劫持叁温,需要遍歷對象的每個屬性,若屬性值也是對象核畴,則需要深度遍歷膝但。而Proxy
直接代理對象,不需要遍歷操作谤草。 - 新增屬性時跟束,需要重新遍歷對象,對其新增屬性在使用
Object.define()
進行劫持丑孩。
參考鏈接: