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