在一個(gè)函數(shù)中,改變了data中的數(shù)據(jù),在函數(shù)中查看是修改成功的,但是頁(yè)面中并沒有刷新。
尤大的解釋:由于性能的代價(jià)與獲得的用戶體驗(yàn)不成正比,故vue2.0的實(shí)現(xiàn)中放棄了這個(gè)特性。在vue3.0中,使用proxy替代了Object.defineProperty()
數(shù)組變更檢測(cè)注意事項(xiàng):
由于JS的限制,以下兩種情況,vue不能檢測(cè)以下數(shù)組的變動(dòng)
- 當(dāng)利用索引直接修改數(shù)組的某一項(xiàng)時(shí)
- 直接修改數(shù)組的長(zhǎng)度時(shí)
示例:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是響應(yīng)性的
vm.items.length = 2 // 不是響應(yīng)性的
也就是說(shuō),直接設(shè)置數(shù)組的某一項(xiàng)時(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")
}
}
});
// 修改屬性的值時(shí)能夠觸發(fā)set
person.age = 12 // 觸發(fā)了set
->觸發(fā)了set
->12
person.age
->12
// 將屬性的值設(shè)置為一個(gè)數(shù)組,當(dāng)通過(guò)索引值修改數(shù)組的某一項(xià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è)置為一個(gè)對(duì)象,當(dāng)修改對(duì)象中某屬性的值時(shí)無(wú)法觸發(fā)set
person.age = { first: 1 }
->觸發(fā)了set
->{first: 1}
person.age.first = 2 // 未觸發(fā)set
->2
通過(guò)上述例子可以觀察得出:
當(dāng)該屬性的值為一個(gè)數(shù)組時(shí),通過(guò)索引修改數(shù)組某一項(xiàng)的值或使用數(shù)組的某些方法修改數(shù)組并不能觸發(fā)set;當(dāng)屬性的值為一對(duì)象時(shí),直接修改對(duì)象中屬性的值時(shí)也無(wú)法觸發(fā)set。
解決方法:
-
Vue.set:Vue.set(vm.items, indexOfItem, newValue) -
vm.$set(vm.items, indexOfItem, newValue)也可以使用vm.$set實(shí)例方法,該方法是全局方法Vue.set的一個(gè)別名 vm.items.splice(indexOfItem, 1, newValue)- 運(yùn)用
this.$forceUpdate()強(qiáng)制刷新。
示例:
<!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()只能對(duì)屬性進(jìn)行劫持,需要遍歷對(duì)象的每個(gè)屬性,若屬性值也是對(duì)象,則需要深度遍歷。而Proxy直接代理對(duì)象,不需要遍歷操作。 - 新增屬性時(shí),需要重新遍歷對(duì)象,對(duì)其新增屬性在使用
Object.define()進(jìn)行劫持。
參考鏈接:
VUE中數(shù)組更新后,頁(yè)面沒有動(dòng)態(tài)刷新問題
vue為什么不能檢測(cè)數(shù)組的變化