簡介
組合式API,是Vue 3的新功能,主要是將組件的邏輯關(guān)注點(diǎn),收集在一起,提高邏輯代碼的復(fù)用率,方便復(fù)雜組件邏輯功能的理解與維護(hù)。
實(shí)現(xiàn)上,通過setup組件選項(xiàng),整合邏輯功能,并返回,在組件模板直接使用。setup與methods、data、computed等是向下兼容的。
需要注意的是: 在setup中不能使用this,會(huì)找不到組件的實(shí)例,因?yàn)?code>setup選項(xiàng)是在組件創(chuàng)建前執(zhí)行的。methods、data、computed定義的屬性、方法均無法在setup中被獲取。
接下來我們通過一個(gè)簡單的示例來了解組合式API的關(guān)注點(diǎn)分離、邏輯功能復(fù)用;
示例
示例: 一個(gè)計(jì)數(shù)器,每次遇到偶數(shù)的時(shí)候,加入列表進(jìn)行展示;可排序翻轉(zhuǎn)、可修改列表數(shù)據(jù)。

邏輯功能:
- 基于步幅的累加
- 列表數(shù)據(jù)更新(添加)
- 列表數(shù)據(jù)排序&翻轉(zhuǎn)
- 列表數(shù)據(jù)的修改
實(shí)現(xiàn)
<script>export default { ///定義組件屬性 props: { initialCount: { type: Number, required: false, default: 0, }, step: { type: Number, default: 1 } }, data() { return { count: this.initialCount,//功能1 stepValue : this.step,//功能1 captureValues: [],//功能2、3、4 }; }, methods: { increment() {//功能1 this.count += this.stepValue; }, sortCaptureValues() {//功能2 this.captureValues.sort((a, b) => a > b).reverse(); }, updateCaptureValues() {//功能3 if (this.isEven) { this.captureValues.push(this.count); } }, changeCaptureValues() {//功能4 this.captureValues = this.captureValues.map((a) => a * 10); }, }, computed: { isEven() {//功能3 return this.count % 2 == 0; }, }, watch: { count(newVal, oldVal) { this.updateCaptureValues();//功能3 }, }, onmounted() { console.log("??"); },};</script>
可以看到組件中功能實(shí)現(xiàn)是分散在不同的組件選項(xiàng)中,當(dāng)功能很多很復(fù)雜的時(shí)候,代碼的可讀性也會(huì)大大降低。多個(gè)組件間,相同邏輯功能復(fù)用不易。 Vue 2 中,雖然可通過mixins解決,但mixins容易出現(xiàn)命名沖突等問題。
setup 實(shí)現(xiàn)
接下來,我們基于組合式API來實(shí)現(xiàn),代碼如下:
<script>import { ref, computed, watch } from "vue";export default { ///定義組件屬性 props: { initialCount: { type: Number, required: false, default: 0, }, step: { type: Number, default: 1, }, }, setup(props) { ///功能1:基于步幅的累加 const count = ref(props.initialCount); const stepValue = ref(props.step); const increment = () => (count.value += stepValue.value); ///功能2: 列表數(shù)據(jù)更新(添加) const captureValues = ref([]); const isEven = computed(() => count.value % 2 === 0); const updateCaptureValues = () => { console.log(isEven); if (isEven.value === true) { captureValues.value.push(count.value); } }; ///功能3: 列表數(shù)據(jù)排序&翻轉(zhuǎn) const sortCaptureValues = () => { captureValues.value.sort((a, b) => a > b).reverse(); }; ///功能4:列表數(shù)據(jù)的修改 const changeCaptureValues = () => { captureValues.value = captureValues.value.map((a) => a * 10); }; ///監(jiān)聽count watch(count, updateCaptureValues); return { count, stepValue, increment, isEven, captureValues, updateCaptureValues, sortCaptureValues, changeCaptureValues, }; },};</script>
可以清楚的看到代碼邏輯功能更加聚焦,可讀性增強(qiáng)。 需要注意的是,組件中的數(shù)據(jù)需要通過ref變?yōu)轫憫?yīng)式的。
功能復(fù)用
基于setup的實(shí)現(xiàn)方式,我們可將功能提取到獨(dú)立的js文件中,以便其他組件復(fù)用。
///文件路徑: src/composables/useIncrementimport {ref,computed} from 'vue'///功能1:基于步幅的累加export default function useIncrement(initialCount,step) { const count = ref(initialCount) const stepValue = ref(step) const increment = () => count.value += stepValue.value return { count, stepValue, increment }} ///功能2: 列表數(shù)據(jù)更新(添加)export function useUpdateValues(count) { const captureValues = ref([]); const isEven = computed(() => count.value % 2 === 0); const updateCaptureValues = () => { if (isEven.value === true) { captureValues.value.push(count.value); } }; return { captureValues, updateCaptureValues, }}///功能3: 列表數(shù)據(jù)排序&翻轉(zhuǎn)export function useSortValues(values) { const sortCaptureValues = () => { values.value.sort((a, b) => a > b).reverse(); }; return { sortCaptureValues }}///功能4:列表數(shù)據(jù)的修改export function useChangeValues(values,base) { const changeCaptureValues = () => { values.value = values.value.map((a) => a * base); }; return { changeCaptureValues }}
再將提取的功能函數(shù)引入到我們Counter組件中:
<script>import {watch,onMounted} from "vue";import useIncrement, {useUpdateValues,useSortValues,useChangeValues} from "../composables/useIncrement";export default { ///定義組件屬性 props: /*...*/ setup(props) { ///累加 const {count, stepValue, increment} = useIncrement(props.initialCount, props.step) ///添加到列表 const {captureValues,updateCaptureValues} = useUpdateValues(count) ///排序數(shù)據(jù) const {sortCaptureValues} = useSortValues(captureValues) ///改變數(shù)據(jù) const { changeCaptureValues } = useChangeValues(captureValues,10) ///監(jiān)聽count watch(count, updateCaptureValues); ///生命周期 onMounted(()=>console.log("已掛載組件")) return { count, stepValue, increment, captureValues, updateCaptureValues, sortCaptureValues, changeCaptureValues, }; },};</script>
這樣其他的組件就可以復(fù)用提取功能了,比如:SimpleCounter組件復(fù)用基于步幅的累加功能。
<template> <button @click="increment" > {{count}}</button></template><script>import useIncrement from "../composables/useIncrement";export default { setup(props) { return { ...useIncrement(0,2) // 增幅為2,初始值為0,的計(jì)數(shù)器 } }}</script>
或者使用<script setup>單文件組件中使用組合式API的語法糖:
<template> <button @click="increment" > {{count}}</button></template><script setup>import useIncrement from "../composables/useIncrement";const {count, increment} = useIncrement(0,2) // 增幅為2 ,初始值為0,的計(jì)數(shù)器</script>
參考資料
https://v3.cn.vuejs.org/guide/composition-api-introduction.html