做自(zì)由與創造的先行者

響應式基礎

Vue.js中文(wén)手冊

聲明(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)發
下(xià)一篇:計(jì)算(suàn)屬性
上(shàng)一篇:模闆語法