【Vue】1548- 我相信這是 Vue3 復用代碼的正確姿勢!

在vue2中代碼復用一般是 mixins[1] 混入來實現(xiàn)但使用 mixins 進行代碼復用會有一些問題
vue3雖然對 mixins 進行了保留但不再推薦使用。
mixins 問題
不清晰的數(shù)據(jù)來源:當使用了多個 mixin 時,實例上的數(shù)據(jù)屬性來自哪個 mixin 變得不清晰,這使追溯實現(xiàn)和理解組件行為變得困難。
命名空間沖突:多個來自不同作者的 mixin 可能會注冊相同的屬性名,造成命名沖突。
隱式的跨 mixin 交流:多個 mixin 需要依賴共享的屬性名來進行相互作用,這使得它們隱性地耦合在一起。
當然這些問題對于的程序員來說都是可以避免的,但最好的方法是換一種更好的方式。
在 vue3 中復用代碼
目前作者的認知里寫 sfc 進行代碼復用依然需要使用 mixins 來實現(xiàn)。
所以這里說的是使用 Composition API 組織代碼的情況下(vue2.7 也已經(jīng)支持)
先了解下什么是組合式 API?
組合式 API (Composition API) 是一系列 API 的集合,使我們可以使用函數(shù)而不是聲明選項的方式書寫 Vue 組件。它是一個概括性的術(shù)語,涵蓋了以下方面的 API:
響應(yīng)式 API[2]:例如 ref()和reactive(),使我們可以直接創(chuàng)建響應(yīng)式狀態(tài)、計算屬性和偵聽器。生命周期鉤子[3]:例如 onMounted()和onUnmounted(),使我們可以在組件各個生命周期階段添加邏輯。依賴注入[4]:例如 provide()和inject(),使我們可以在使用響應(yīng)式 API 時,利用 Vue 的依賴注入系統(tǒng)。
這段話完全來自官網(wǎng) 更多的內(nèi)容還是需要看官網(wǎng)
為什么要有組合式 API?
這里官方文檔列出了幾點:更好的邏輯復用 、更靈活的代碼組織 、更好的類型推導 、更小的生產(chǎn)包體積。這里已經(jīng)出現(xiàn)了本文關(guān)注的重點即 更好的邏輯復用 我們來看下官方的說明
組合式 API 最基本的優(yōu)勢是它使我們能夠通過組合函數(shù)[5]來實現(xiàn)更加簡潔高效的邏輯復用。在選項式 API 中我們主要的邏輯復用機制是 mixins,而組合式 API 解決了 mixins 的所有缺陷[6]。
兩個結(jié)論 1. 組合式 API 解決了mixins 的所有缺陷 2. 能夠通過組合函數(shù)來實現(xiàn)更加簡潔高效的邏輯復用。
什么是“組合式函數(shù)” ?
在 Vue 應(yīng)用的概念中,“組合式函數(shù)”(Composables) 是一個利用 Vue 的組合式 API 來封裝和復用有狀態(tài)邏輯的函數(shù)。
一般會以 use 開頭進行函數(shù)命名,放到 composables 目錄中,其他約定[7]。
組合函數(shù)內(nèi)部可以使用 組合式api,一個組合式函數(shù)可以調(diào)用一個或多個其他的組合式函數(shù)。
這使得我們可以像使用多個組件組合成整個應(yīng)用一樣,用多個較小且邏輯獨立的單元來組合形成復雜的邏輯。
當時我看到這里時候其實有個疑問 為什么要強調(diào)是有狀態(tài)邏輯的函數(shù)(有狀態(tài)函數(shù)是指函數(shù)內(nèi)部有自己的狀態(tài)更改),這個問題先留著,看完代碼示例自會理解。
一個例子
抽離后臺管理列表共用的邏輯,示例只是列表相關(guān)邏輯封裝,你甚至可以將增刪改查的邏輯封裝進去。
usePage.js
import { reactive, ref } from 'vue'
// 一個用于重置對象字段為原始值的函數(shù)
import { resetObjToPrimitiveType } from '@/utils/tool'
/**
* @description usePage 接收一個 opts 參數(shù),返回列表所需數(shù)據(jù)
* @param {Object} opts.searchForm - 默認查詢參數(shù)
* @param {Function} opts.getListApi - 獲取列表數(shù)據(jù)的接口
* @param {Function} opts.customQueryParameters - 自定義查詢參數(shù)
* @param {Function} opts.getListFunc - 執(zhí)行完 getList 成功后執(zhí)行的邏輯 有一個opts參數(shù)
* @param {Function} opts.resetFunc - 執(zhí)行完 reset 后執(zhí)行的邏輯
* @param {Function} opts.sizeChangeFunc - 執(zhí)行完 sizeChange 后執(zhí)行的邏輯
* @param {Function} opts.currentChangeFunc - 執(zhí)行完 currentChange 后執(zhí)行的邏輯
*/
export const usePage = (opts) => {
// searchForm 由外部傳入,內(nèi)部傳入導出的數(shù)據(jù)無法推導類型即無法知道對象里有什么也會失去代碼提示
const {
searchForm = {},
getListApi,
customQueryParameters = () => {},
getListFunc = (opts) => {},
resetFunc = () => {},
sizeChangeFunc = () => {},
currentChangeFunc = () => {}
} = opts
const reset = () => {
Object.assign(searchForm, resetObjToPrimitiveType(searchForm))
resetFunc()
handleCurrentChange(1)
}
const page = reactive({
pageSize: 10,
pageNo: 1,
total: 0
})
const tableData = ref([])
const getList = () => {
const opts = {
...page,
...searchForm,
...customQueryParameters()
}
getListApi(opts).then((res) => {
if (res.code === 0) {
tableData.value = res.data?.rows || []
page.total = res.data?.total || 0
getListFunc(opts)
}
})
}
const handleSizeChange = (size) => {
page.pageSize = size
sizeChangeFunc()
getList()
}
const handleCurrentChange = (cur) => {
page.pageNo = cur
currentChangeFunc()
getList()
}
return {
searchForm,
reset,
page,
tableData,
handleSizeChange,
handleCurrentChange
}
}
復制代碼
組件內(nèi)使用
import { reactive, ref, computed } from 'vue'
import { usePage } from '@/composables/usePage'
import testModel from '@/model/test'
// 查詢參數(shù)
const searchForm = reactive({
createEndTime: '',
createStartTime: ''
})
// 接收 查詢參數(shù)、獲取列表的接口 返回 列表所需要的數(shù)據(jù)、分頁參數(shù)、分頁函數(shù)等
const { reset, page, tableData, handleSizeChange, handleCurrentChange } = usePage({
searchForm,
getListApi: testModel.getList
})
// 首次獲取數(shù)據(jù)使用 reset方式即可 tableData 的數(shù)據(jù)自動更新
reset()
復制代碼
組合式函數(shù)其實就是一個函數(shù)接收一些參數(shù)返回一些東西,將邏輯進行封裝、共用。
如果函數(shù)依賴 store、router 等
import {useStore} from 'vuex'
import {computed} from 'vue'
export const useTest = () => {
// 獲取store
const store = useStore()
const getOrgById = (id) => {
// 使用
const orgObj = computed(() => store.state.orgObj)
return orgObj.value[id]
}
return {
getOrgById
}
}
復制代碼
總結(jié)
說明 vue2 使用 mixins 進行代碼復用所帶來的問題,引出了vue3如何進行代碼復用。
介紹 組合式 API (Composition API) 以及為什么需要 組合式 API, 什么是 組合式函數(shù) 通過一個例子讓大家了解了 組合式函數(shù) 的用法。
Composition API 與 組合式函數(shù) 用來解決 vue2 mixins 帶來的問題只是附帶,它可以做更多做的更好。
同時也是一把雙刃劍,取決于使用的人。就像有的人可以把代碼寫的一塌糊涂有的人卻可以把代碼寫的像詩一樣!
關(guān)于本文
作者:唐詩
https://juejin.cn/post/7160480314089799710
