Vue.js 中的組合式 API 代表了我們構建和組織組件方式的重大轉變。它為傳統的選項式 API 提供了一種更靈活、更強大的替代方案,尤其適用于復雜的應用程序。本章將深入探討組合式 API 的核心概念:setup
函數、ref
和reactive
,為你構建更可維護、更可重用的 Vue 組件打下堅實的基礎。我們將探索這些元素如何協同工作,以實現更功能化、更可組合的組件邏輯。
理解?setup
?函數
setup
?函數是 Vue 組件中使用 Composition API 的入口點。它用于定義響應式數據、計算屬性、方法和生命周期鉤子。與 Options API 不同,在 Options API 中這些元素定義在組件定義的單獨部分中,而?setup
?函數允許你以更邏輯和連貫的方式組織它們。
setup
?的作用
setup
?函數充當組件模板與其底層邏輯之間的橋梁。它在組件創建?之前?執行,并提供對組件的?props
?和?context
?的訪問。setup
?函數必須返回一個包含你希望提供給模板的數據、方法和計算屬性的對象。
示例:基本的?setup
?函數
import { ref } from 'vue';export default {props: {initialCount: {type: Number,default: 0}},setup(props, context) {// 使用“ref”創建一個反應變量const count = ref(props.initialCount);// 定義一個方法來增加計數const increment = () => {count.value++;};// 將反應變量和方法暴露給模板return {count,increment};},template: `<div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>`
};
在這個例子中:
- 我們從 Vue 導入?
ref
?函數。 setup
?函數接收?props
?和?context
?作為參數。- 我們使用?
ref
?創建一個響應式變量?count
,并使用?initialCount
?prop 的值進行初始化。 - 我們定義一個方法?
increment
,用于增加?count
?的值。注意,我們通過?.value
?訪問?ref
?的值。 - 我們返回一個包含?
count
?和?increment
?的對象,使其在模板中可用。 - 模板顯示?
count
?的當前值,并提供一個按鈕來增加它。
setup
?參數:props
?和?context
setup
?函數接收兩個參數:
props
: 一個包含組件屬性的對象。需要注意的是,props
?對象是響應式的。如果父組件更新了屬性,setup
?中的?props
?對象將自動更新。context
: 一個提供訪問組件上下文的對象。它暴露了三個屬性:attrs
: 一個包含組件非屬性屬性的對象(相當于 Options API 中的?$attrs
)。slots
: 一個包含組件插槽的對象(相當于 Options API 中的?$slots
)。emit
: 一個允許你從組件中發出自定義事件的函數(在選項 API 中相當于?$emit
)。
示例:使用?context.emit
import { ref } from 'vue';export default {setup(props, context) {const count = ref(0);const increment = () => {count.value++;// Emit a custom event when the count is incrementedcontext.emit('increment', count.value);};return {count,increment};},template: `<div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>`
};
在這個例子中,我們使用?context.emit
?來在每次調用?increment
?方法時發出一個名為?increment
?的自定義事件。事件負載是?count
?的新值。
ref
: 創建響應式引用
ref
?函數是 Composition API 的核心部分。它允許你創建對基本值(數字、字符串、布爾值)和復雜數據類型(對象、數組)的響應式引用。當?ref
?的值發生變化時,Vue 會自動更新 DOM 以反映新值。
如何?ref
?工作
ref
?函數接受一個參數:引用的初始值。它返回一個具有?.value
?屬性的對象,該屬性保存當前值。訪問或修改?ref
?的值需要使用?.value
?屬性。
示例:使用?ref
?與原始值
import { ref } from 'vue';export default {setup() {const message = ref('Hello, Vue!');const updateMessage = () => {message.value = 'Goodbye, Vue!';};return {message,updateMessage};},template: `<div><p>{{ message }}</p><button @click="updateMessage">Update Message</button></div>`
};
在這個例子中:
- 我們創建一個名為?
ref
?的?message
,初始值為"Hello, Vue!"。 - 我們定義一個名為?
updateMessage
?的方法,該方法將?message
?的值更改為"Goodbye, Vue!"。 - 模板顯示?
message
?的當前值。當按鈕被點擊時,updateMessage
?被調用,模板會自動更新以顯示新消息。
示例:使用?ref
?與復雜數據類型
import { ref } from 'vue';export default {setup() {const user = ref({name: 'John Doe',age: 30});const updateUser = () => {user.value.name = 'Jane Doe';user.value.age = 25;};return {user,updateUser};},template: `<div><p>Name: {{ user.name }}</p><p>Age: {{ user.age }}</p><button @click="updateUser">Update User</button></div>`
};
在這個例子中:
- 我們創建一個名為?
ref
?的?user
?引用,其初始值是一個包含?name
?和?age
?屬性的對象。 - 我們定義一個名為?
updateUser
?的方法,用于更新?user
?對象中的?name
?和?age
?屬性。 - 模板顯示?
user
?對象的?name
?和?age
?屬性。當按鈕被點擊時,調用?updateUser
,模板會自動更新以顯示新的用戶信息。
何時使用?ref
使用?ref
?當你需要創建一個單一值的響應式引用,無論是基本類型還是復雜的數據類型。當你需要跟蹤組件中單個值的變化時,它特別有用。
reactive
: 創建響應式對象
reactive
?函數是 Composition API 的另一個重要部分。它允許你創建響應式對象。與?ref
?不同,ref
?創建一個值的響應式?引用?,reactive
?創建一個響應式的?對象?。響應式對象屬性的變化會被 Vue 自動跟蹤,并且 DOM 會相應更新。
reactive
?的工作原理
reactive
?函數接受一個普通的 JavaScript 對象作為參數,并返回該對象的響應式代理。然后你可以直接訪問和修改響應式對象的屬性,而無需像使用?ref
?那樣使用?.value
?屬性。
示例:使用?reactive
import { reactive } from 'vue';export default {setup() {const state = reactive({name: 'John Doe',age: 30});const updateState = () => {state.name = 'Jane Doe';state.age = 25;};return {state,updateState};},template: `<div><p>Name: {{ state.name }}</p><p>Age: {{ state.age }}</p><button @click="updateState">Update State</button></div>`
};
在這個例子中:
- 我們使用?
reactive
?函數創建一個響應式對象?state
。 - 我們定義一個方法?
updateState
,用于更新?state
?對象的?name
?和?age
?屬性。 - 模板顯示?
state
?對象的?name
?和?age
?屬性。當按鈕被點擊時,調用?updateState
,模板會自動更新以顯示新的狀態信息。
深度響應式
reactive
?函數提供深度響應式功能。這意味著在響應式對象中的嵌套屬性的變化也會被 Vue 跟蹤。
示例:深度響應式
import { reactive } from 'vue';export default {setup() {const state = reactive({user: {name: 'John Doe',address: {city: 'New York'}}});const updateCity = () => {state.user.address.city = 'Los Angeles';};return {state,updateCity};},template: `<div><p>Name: {{ state.user.name }}</p><p>City: {{ state.user.address.city }}</p><button @click="updateCity">Update City</button></div>`
};
在這個例子中,即使?city
?是?state
?對象中的嵌套屬性,對它的修改仍然會被 Vue 追蹤,并且模板會相應地更新。
reactive
?的局限性
-
僅適用于對象:?
reactive
?函數僅適用于普通的 JavaScript 對象。它不能用于數字、字符串或布爾值等原始值。對于這些值,你應該使用?ref
。 -
重新賦值導致的響應性丟失:?如果你重新賦值一個響應式對象,你會丟失響應性。例如:
import { reactive } from 'vue';export default {setup() {const state = reactive({ count: 0 });const resetState = () => {// Reactivity is lost here!state = { count: 0 };};return { state, resetState };},template: '<button @click="resetState">Reset</button>' };
在這種情況下,
state
?在重新賦值后不再具有響應性。為了避免這種情況,始終修改響應式對象的屬性,而不是重新賦值對象本身。
何時使用?reactive
當你需要創建具有多個屬性的反應式對象時,使用?reactive
。當你有一個復雜的數據結構需要追蹤變化時,它特別有用。
ref
?與?reactive
:選擇合適的工具
ref
?和?reactive
?都用于在 Composition API 中創建反應式數據,但它們有不同的使用場景。以下是它們的主要區別總結:
特性 | ref | reactive |
---|---|---|
數據類型 | 可與原始類型和對象一起使用 | 僅適用于對象 |
訪問值 | 使用?.value ?來訪問/修改 | 直接訪問/修改屬性 |
響應性 | 創建一個響應式_引用_ | 創建一個響應式_對象_ |
用例 | 單個值、基本類型 | 具有多個屬性的對象 |
一般來說,使用?ref
?表示單個值和基本類型,使用?reactive
?表示具有多個屬性的對象。