在Vue中,我們通常使用computed屬性來計算一個值,這樣我們可以方便地在模板中使用這個值。但是有時候,我們會遇到這樣的問題:computed里面的數據打印出來變化了,但是視圖里面沒有變化。本文將會深入探討這個問題。
一、什么是computed屬性
Vue中computed屬性是計算屬性,它在Vue實例中用于計算一個值。computed的值是只讀的,它們依賴于其他屬性的值,并且只有在依賴的值發生改變時才會重新求值。
例如,我們可以使用computed屬性計算兩個數字的和:
<template>
<div>{{ result }}</div>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
return this.num1 + this.num2;
},
},
};
</script>
在上面的例子中,result是一個只讀的computed屬性,它依賴于num1和num2兩個屬性,只有當這兩個屬性發生變化時,result才會重新計算。
二、computed屬性的計算過程
計算computed屬性的過程是一個異步的過程,Vue會在下一次事件循環中計算computed屬性。這是為了避免不必要的計算,提升性能。
下面的例子演示了computed屬性的計算過程:
<template>
<div>{{ result }}</div>
<button @click="changeNum">Change Num</button>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
console.log("computed");
return this.num1 + this.num2;
},
},
methods: {
changeNum() {
this.num1++;
},
changeNumSync() {
this.num2++;
},
},
};
</script>
在上面的例子中,當我們點擊Change Num按鈕時,num1屬性會加1,這會導致result屬性發生變化,因此Vue會在下一次事件循環中計算result屬性。我們可以在瀏覽器的控制臺中看到"computed"這個輸出。
三、computed屬性不更新的原因
因為computed屬性的計算過程是異步的,所以如果computed屬性依賴的屬性發生變化時,如果Vue在下一次事件循環之前檢測到了這個變化并更新了computed屬性,那么視圖就會自動更新。
但是,如果computed屬性依賴的屬性發生變化后,Vue沒有在下一次事件循環之前檢測到這個變化,computed屬性就不會更新,視圖也就不會更新。
下面的例子演示了computed屬性不更新的情況:
<template>
<div>{{ result }}</div>
<button @click="changeNum">Change Num</button>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
console.log("computed");
return this.num1 + this.num2;
},
},
methods: {
changeNum() {
this.num1++;
this.$nextTick(() => {
console.log(this.result);
});
},
},
};
</script>
在上面的例子中,我們在changeNum方法中加了一個$nextTick方法,這個方法會在下一次事件循環中執行。在$nextTick方法中,我們打印了result屬性的值。這個值會比實際的值晚一步。這是因為在num1的值發生變化后,Vue沒有在下一次事件循環之前檢測到這個變化,computed屬性沒有更新,result的值也就沒有更新。
四、解決computed屬性不更新的方法
我們可以使用以下方法解決computed屬性不更新的問題:
4.1 使用watch監聽屬性變化
我們可以使用watch監聽num1和num2屬性的變化,并在變化時強制重新計算computed屬性。這樣,即使Vue沒有在下一次事件循環之前檢測到屬性的變化,computed屬性也會更新。
<template>
<div>{{ result }}</div>
<button @click="changeNum">Change Num</button>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
console.log("computed");
return this.num1 + this.num2;
},
},
watch: {
num1: {
handler() {
this.$forceUpdate();
},
},
num2: {
handler() {
this.$forceUpdate();
},
},
},
methods: {
changeNum() {
this.num1++;
},
},
};
</script>
在上面的例子中,我們使用watch監聽了num1和num2屬性的變化,并在變化時強制重新計算computed屬性。這樣,即使Vue沒有在下一次事件循環之前檢測到屬性的變化,computed屬性也會更新。
4.2 使用key讓Vue重新渲染組件
當Vue檢測到組件的key發生變化時,它會銷毀當前的組件并重新創建一個新的組件,這樣就能夠強制computed屬性重新計算。
<template>
<div :key="num1">{{ result }}</div>
<button @click="changeNum">Change Num</button>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
console.log("computed");
return this.num1 + this.num2;
},
},
methods: {
changeNum() {
this.num1++;
},
},
};
</script>
在上面的例子中,我們使用:num1作為組件的key,這樣當num1變化時,Vue會重新渲染組件,computed屬性也會重新計算。
4.3 手動調用$forceUpdate方法
$forceUpdate方法會強制組件重新渲染,在重新渲染時,computed屬性也會重新計算。
<template>
<div>{{ result }}</div>
<button @click="changeNum">Change Num</button>
</template>
<script>
export default {
data() {
return {
num1: 1,
num2: 2,
};
},
computed: {
result() {
console.log("computed");
return this.num1 + this.num2;
},
},
methods: {
changeNum() {
this.num1++;
this.$forceUpdate();
},
},
};
</script>
在上面的例子中,當num1的值發生變化時,我們手動調用了$forceUpdate方法,這會強制組件重新渲染,在重新渲染時,computed屬性也會重新計算。
五、小結
本文深入探討了在Vue中使用computed屬性時出現的computed里面的數據打印出來變化了,但是視圖里面沒有變化的問題。我們從computed屬性的計算過程、computed屬性不更新的原因和解決方法三個方面進行了詳細的闡述。最終,我們提出了使用watch監聽屬性變化、使用key讓Vue重新渲染組件和手動調用$forceUpdate方法三種解決方法。