Vue3 組合式 API(Composition API) 主要用于在大型組件中提高代碼邏輯的可復(fù)用性。 傳統(tǒng)的組件隨著業(yè)務(wù)復(fù)雜度越來越高,,代碼量會不斷的加大,,整個代碼邏輯都不易閱讀和理解。 Vue3 使用組合式 API 的地方為 setup,。 在 setup 中,,我們可以按邏輯關(guān)注點(diǎn)對部分代碼進(jìn)行分組,然后提取邏輯片段并與其他組件共享代碼,。因此,,組合式 API(Composition API) 允許我們編寫更有條理的代碼。 對比以下兩端代碼: 1,、傳統(tǒng)組件 2,、組合式 API setup 組件setup() 函數(shù)在組件創(chuàng)建 created() 之前執(zhí)行。 setup() 函數(shù)接收兩個參數(shù) props 和 context,。 第一個參數(shù) props,,它是響應(yīng)式的,當(dāng)傳入新的 prop 時,,它將被更新,。 第二個參數(shù) context 是一個普通的 JavaScript 對象,它是一個上下文對象,,暴露了其它可能在 setup 中有用的值,。
以下實(shí)例使用組合 API 定義一個計數(shù)器: 實(shí)例(src/APP.vue)
<template> <div> <p>計數(shù)器實(shí)例: {{ count }}</p> <input @click="myFn" type="button" value="點(diǎn)我加 1"> </div> </template> <script> import {ref, onMounted} from 'vue'; export default { setup(){ //定義初始值為0的變量,,要使用ref方法賦值,直接賦值的話變量改變不會更新 UI let count = ref(0); // 定義點(diǎn)擊事件 myFn function myFn(){ console.log(count); count.value += 1; } // 組件被掛載時,我們用 onMounted 鉤子記錄一些消息 onMounted(() => console.log('component mounted!')); // 外部使用組合API中定義的變量或方法,,在模板中可用,。 return {count,myFn} // 返回的函數(shù)與方法的行為相同 } } </script> 在 Vue 3.0 中,我們可以通過一個新的 ref 函數(shù)使任何響應(yīng)式變量在任何地方起作用,,如下所示: import { ref } from 'vue' let count = ref(0); ref() 函數(shù)可以根據(jù)給定的值來創(chuàng)建一個響應(yīng)式的數(shù)據(jù)對象,,返回值是一個對象,且只包含一個 .value 屬性,。 在 setup() 函數(shù)內(nèi),,由 ref() 創(chuàng)建的響應(yīng)式數(shù)據(jù)返回的是對象,所以需要用 .value 來訪問,。 實(shí)例
import { ref } from 'vue' const counter = ref(0) console.log(counter) // { value: 0 } console.log(counter.value) // 0 counter.value++ console.log(counter.value) // 1 Vue 組合式 API 生命周期鉤子在 Vue2 中,,我們通過以下方式實(shí)現(xiàn)生命周期鉤子函數(shù): 實(shí)例
export default { beforeMount() { console.log('V2 beforeMount!') }, mounted() { console.log('V2 mounted!') } }; 在 Vue3 組合 API 中實(shí)現(xiàn)生命周期鉤子函數(shù)可以在 setup() 函數(shù)中使用帶有 on 前綴的函數(shù): 實(shí)例
import { onBeforeMount, onMounted } from 'vue'; export default { setup() { onBeforeMount(() => { console.log('V3 beforeMount!'); }) onMounted(() => { console.log('V3 mounted!'); }) } }; 下表為 Options API 和 Composition API 之間的映射,包含如何在 setup () 內(nèi)部調(diào)用生命周期鉤子:
因為 setup 是圍繞 beforeCreate 和 created 生命周期鉤子運(yùn)行的,,所以不需要顯式地定義它們,。換句話說,在這些鉤子中編寫的任何代碼都應(yīng)該直接在 setup 函數(shù)中編寫,。 這些函數(shù)接受一個回調(diào)函數(shù),,當(dāng)鉤子被組件調(diào)用時將會被執(zhí)行: 實(shí)例
setup() { ... // 組件被掛載時,我們用 onMounted 鉤子記錄一些消息 onMounted(() => console.log('component mounted!')); ... } 模板引用在使用組合式 API 時,,響應(yīng)式引用和模板引用的概念是統(tǒng)一的,。 為了獲得對模板內(nèi)元素或組件實(shí)例的引用,我們可以像往常一樣聲明 ref 并從 setup() 返回: 實(shí)例
<template> <div ref="root">This is a root element</div> </template> <script> import { ref, onMounted } from 'vue' export default { setup() { const root = ref(null) onMounted(() => { // DOM 元素將在初始渲染后分配給 ref console.log(root.value) // <div>This is a root element</div> }) return { root } } } </script> 以上實(shí)例中我們在渲染上下文中暴露 root,,并通過 ref="root",,將其綁定到 div 作為其 ref。 作為模板使用的 ref 的行為與任何其他 ref 一樣:它們是響應(yīng)式的,,可以傳遞到 (或從中返回) 復(fù)合函數(shù)中,。 v-for 中的用法組合式 API 模板引用在 v-for 內(nèi)部使用時沒有特殊處理。相反,,請使用函數(shù)引用執(zhí)行自定義處理: 實(shí)例
<template> <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }"> {{ item }} </div> </template> <script> import { ref, reactive, onBeforeUpdate } from 'vue' export default { setup() { const list = reactive([1, 2, 3]) const divs = ref([]) // 確保在每次更新之前重置ref onBeforeUpdate(() => { divs.value = [] }) return { list, divs } } } </script> 偵聽模板引用偵聽模板引用的變更可以替代前面例子中演示使用的生命周期鉤子,。 但與生命周期鉤子的一個關(guān)鍵區(qū)別是,watch() 和 watchEffect() 在 DOM 掛載或更新之前運(yùn)行會有副作用,,所以當(dāng)偵聽器運(yùn)行時,,模板引用還未被更新。 實(shí)例
<template> <div ref="root">This is a root element</div> </template> <script> import { ref, watchEffect } from 'vue' export default { setup() { const root = ref(null) watchEffect(() => { // 這個副作用在 DOM 更新之前運(yùn)行,,因此,,模板引用還沒有持有對元素的引用。 console.log(root.value) // => null }) return { root } } } </script> 因此,,使用模板引用的偵聽器應(yīng)該用 flush: 'post' 選項來定義,,這將在 DOM 更新后運(yùn)行副作用,,確保模板引用與 DOM 保持同步,并引用正確的元素,。 實(shí)例
<template> <div ref="root">This is a root element</div> </template> <script> import { ref, watchEffect } from 'vue' export default { setup() { const root = ref(null) watchEffect(() => { console.log(root.value) // => <div>This is a root element</div> }, { flush: 'post' }) return { root } } } </script> |
|