聲明(míng)響應式狀态
選用(yòng)選項式 API 時(shí),會(huì)用(yòng) data 選項來(lái)聲明(míng)組件的響應式狀态。此選項的值應爲返回一個對(duì)象的函數。Vue 将在創建新組件實例的時(shí)候調用(yòng)此函數,并将函數返回的對(duì)象用(yòng)響應式系統進行包裝。此對(duì)象的所有頂層屬性都會(huì)被代理(lǐ)到(dào)組件實例 (即方法和(hé)生命周期鈎子中的 this) 上(shàng)。
js
export default {
data() {
return {
count: 1
}
},
// `mounted` 是生命周期鈎子,之後我們會(huì)講到(dào)
mounted() {
// `this` 指向當前組件實例
console.log(this.count) // => 1
// 數據屬性也(yě)可以被更改
this.count = 2
}
}
在演練場中嘗試一下(xià)
這(zhè)些(xiē)實例上(shàng)的屬性僅在實例首次創建時(shí)被添加,因此你(nǐ)需要确保它們都出現(xiàn)在 data 函數返回的對(duì)象上(shàng)。若所需的值還未準備好(hǎo),在必要時(shí)也(yě)可以使用(yòng) null、undefined 或者其他(tā)一些(xiē)值占位。
雖然也(yě)可以不在 data 上(shàng)定義,直接向組件實例添加新屬性,但(dàn)這(zhè)個屬性将無法觸發響應式更新。
Vue 在組件實例上(shàng)暴露的内置 API 使用(yòng) $ 作(zuò)爲前綴。它同時(shí)也(yě)爲内部屬性保留 _ 前綴。因此,你(nǐ)應該避免在頂層 data 上(shàng)使用(yòng)任何以這(zhè)些(xiē)字符作(zuò)前綴的屬性。
響應式代理(lǐ) vs. 原始值
在 Vue 3 中,數據是基于 JavaScript Proxy(代理(lǐ)) 實現(xiàn)響應式的。使用(yòng)過 Vue 2 的用(yòng)戶可能(néng)需要注意下(xià)面這(zhè)樣的邊界情況:
js
export default {
data() {
return {
someObject: {}
}
},
mounted() {
const newObject = {}
this.someObject = newObject
console.log(newObject === this.someObject) // false
}
}
當你(nǐ)在賦值後再訪問 this.someObject,此值已經是原來(lái)的 newObject 的一個響應式代理(lǐ)。與 Vue 2 不同的是,這(zhè)裏原始的 newObject 不會(huì)變爲響應式:請(qǐng)确保始終通過 this 來(lái)訪問響應式狀态。
聲明(míng)方法
要爲組件添加方法,我們需要用(yòng)到(dào) methods 選項。它應該是一個包含所有方法的對(duì)象:
js
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
// 在其他(tā)方法或是生命周期中也(yě)可以調用(yòng)方法
this.increment()
}
}
Vue 自(zì)動爲 methods 中的方法綁定了(le)永遠指向組件實例的 this。這(zhè)确保了(le)方法在作(zuò)爲事(shì)件監聽器或回調函數時(shí)始終保持正确的 this。你(nǐ)不應該在定義 methods 時(shí)使用(yòng)箭頭函數,因爲箭頭函數沒有自(zì)己的 this 上(shàng)下(xià)文(wén)。
js
export default {
methods: {
increment: () => {
// 反例:無法訪問此處的 `this`!
}
}
}
和(hé)組件實例上(shàng)的其他(tā)屬性一樣,方法也(yě)可以在模闆上(shàng)被訪問。在模闆中它們常常被用(yòng)作(zuò)事(shì)件監聽器:
template
<button @click="increment">{{ count }}</button>
在演練場中嘗試一下(xià)
在上(shàng)面的例子中,increment 方法會(huì)在 <button> 被點擊時(shí)調用(yòng)。
DOM 更新時(shí)機
當你(nǐ)更改響應式狀态後,DOM 會(huì)自(zì)動更新。然而,你(nǐ)得注意 DOM 的更新并不是同步的。相反,Vue 将緩沖它們直到(dào)更新周期的 “下(xià)個時(shí)機” 以确保無論你(nǐ)進行了(le)多少次狀态更改,每個組件都隻更新一次。
若要等待一個狀态改變後的 DOM 更新完成,你(nǐ)可以使用(yòng) nextTick() 這(zhè)個全局 API:
import { nextTick } from 'vue'
export default {
methods: {
increment() {
this.count++
nextTick(() => {
// 訪問更新後的 DOM
})
}
}
}
深層響應性
在 Vue 中,狀态都是默認深層響應式的。這(zhè)意味着即使在更改深層次的對(duì)象或數組,你(nǐ)的改動也(yě)能(néng)被檢測到(dào)。
js
export default {
data() {
return {
obj: {
nested: { count: 0 },
arr: ['foo', 'bar']
}
}
},
methods: {
mutateDeeply() {
// 以下(xià)都會(huì)按照期望工(gōng)作(zuò)
this.obj.nested.count++
this.obj.arr.push('baz')
}
}
}
你(nǐ)也(yě)可以直接創建一個淺層響應式對(duì)象。它們僅在頂層具有響應性,一般僅在某些(xiē)特殊場景中需要。
有狀态方法
在某些(xiē)情況下(xià),我們可能(néng)需要動态地創建一個方法函數,比如創建一個預置防抖的事(shì)件處理(lǐ)器:
js
import { debounce } from 'lodash-es'
export default {
methods: {
// 使用(yòng) Lodash 的防抖函數
click: debounce(function () {
// ... 對(duì)點擊的響應 ...
}, 500)
}
}
不過這(zhè)種方法對(duì)于被重用(yòng)的組件來(lái)說是有問題的,因爲這(zhè)個預置防抖的函數是 有狀态的:它在運行時(shí)維護着一個内部狀态。如果多個組件實例都共享這(zhè)同一個預置防抖的函數,那麽它們之間将會(huì)互相影響。
要保持每個組件實例的防抖函數都彼此獨立,我們可以改爲在 created 生命周期鈎子中創建這(zhè)個預置防抖的函數:
js
export default {
created() {
// 每個實例都有了(le)自(zì)己的預置防抖的處理(lǐ)函數
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// 最好(hǎo)是在組件卸載時(shí)
// 清除掉防抖計(jì)時(shí)器
this.debouncedClick.cancel()
},
methods: {
click() {
// ... 對(duì)點擊的響應 ...
}
}
}
網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發