Vue3 組合式函數(shù)Composable最佳實(shí)戰(zhàn)
引言
截至目前,Composable(組合式函數(shù))應(yīng)該是在VUE 3應(yīng)用程序中組織業(yè)務(wù)邏輯最佳的方法。
它讓我們可以把一些小塊的通用邏輯進(jìn)行抽離、復(fù)用,使我們的代碼更易于編寫(xiě)、閱讀和維護(hù)。
由于這種編寫(xiě)VUE代碼的方式相對(duì)較新,因此您可能想知道編寫(xiě)組合式函數(shù)的最佳實(shí)踐是什么呢?本系列教程可以作為您和您的團(tuán)隊(duì)在進(jìn)行組合式開(kāi)發(fā)過(guò)程中的參考指南。
我們將涵蓋以下內(nèi)容:
- 1.如何通過(guò)選項(xiàng)對(duì)象參數(shù)使您的組合更加可配置; ?? 本篇主題
- 2.使用ref和unref使我們的參數(shù)更加靈活;
- 3.如何使你的返回值更有用;
- 4.為什么從接口定義開(kāi)始可以使你的組合式函數(shù)更強(qiáng)大;
- 5.如何使用異步代碼而無(wú)需“等待” - 使您的代碼更易于理解;
不過(guò),首先,我們需要確保我們對(duì)組合式函數(shù)的理解是一致的。我們先花點(diǎn)時(shí)間解釋一下什么是組合式函數(shù)。
什么是Composable-組合式函數(shù)?
根據(jù)官方文檔說(shuō)明,在 Vue 應(yīng)用的概念中,“組合式函數(shù)”是一個(gè)利用 Vue 組合式 API 來(lái)封裝和復(fù)用有狀態(tài)邏輯的函數(shù)。
這就意味著,任何有狀態(tài)邏輯,并且使用了響應(yīng)式處理的邏輯都可以轉(zhuǎn)換成組合式函數(shù)。這和我們平時(shí)抽離封裝的公共方法還是有一些區(qū)別的。我們封裝的公共方法往往是無(wú)狀態(tài)的:它在接收一些輸入后立刻返回所期望的輸出。而組合式函數(shù)往往是和狀態(tài)邏輯關(guān)聯(lián)的。
讓我們看看官方給出的useMouse
這個(gè)組合式函數(shù):
import { ref, onMounted, onUnmounted } from 'vue' // 按照慣例,組合式函數(shù)名以“use”開(kāi)頭 export function useMouse() { // 被組合式函數(shù)封裝和管理的狀態(tài) const x = ref(0) const y = ref(0) // 組合式函數(shù)可以隨時(shí)更改其狀態(tài)。 function update(event) { x.value = event.pageX y.value = event.pageY } // 一個(gè)組合式函數(shù)也可以?huà)炜吭谒鶎俳M件的生命周期上 // 來(lái)啟動(dòng)和卸載副作用 onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update)) // 通過(guò)返回值暴露所管理的狀態(tài) return { x, y } }
我們把狀態(tài)定義為refs
,當(dāng)鼠標(biāo)移動(dòng)的時(shí)候我們更新這個(gè)狀態(tài)。通過(guò)返回x
和y
,我們可以在任何組件中使用它們,甚至我們還可以把多個(gè)組合式函數(shù)嵌套使用。
當(dāng)我們?cè)诮M件中使用時(shí)
<template> X: {{ x }} Y: {{ y }} </template> <script setup> import { useMouse } from './useMouse'; const { x, y } = useMouse(); </script>
如您所見(jiàn),通過(guò)使用useMouse
我們可以輕松的復(fù)用這個(gè)邏輯。僅僅很少的代碼,我們就可以在組件中獲取鼠標(biāo)坐標(biāo)狀態(tài)。
現(xiàn)在我們對(duì)組合式函數(shù)有了相同的認(rèn)識(shí),讓我們看一下可以幫助我們編寫(xiě)更好的組合式函數(shù)的第一個(gè)方法吧。
選項(xiàng)對(duì)象參數(shù)
大部分組合式函數(shù)都會(huì)有一個(gè)或兩個(gè)必須的參數(shù),然后有一系列可選的參數(shù)來(lái)幫助進(jìn)行一些額外的配置。在配置組合式函數(shù)時(shí),我們可以將一系列的可選配置放到一個(gè)選項(xiàng)對(duì)象參數(shù)中,而不是一長(zhǎng)串參數(shù)的形式。
// 使用選項(xiàng)對(duì)象參數(shù)形式 const title = useTitle('A new title', { titleTemplate: '>> %s <<' }); // Title is now ">> A new title <<" // 使用多參數(shù)形式 const title = useTitle('A new title', '>> %s <<'); // Title is now ">> A new title <<"
選項(xiàng)對(duì)象參數(shù)的形式可以給我們帶來(lái)一些便利:
- 首先,我們不必記住參數(shù)的正確順序,特別是參數(shù)很多的時(shí)候。雖然現(xiàn)在我們可以通過(guò)Typescript和編輯器提示功能來(lái)避免這類(lèi)問(wèn)題,但是通過(guò)這種方式仍然是有差別的。使用Javascript對(duì)象,參數(shù)的順序就不那么重要了。(當(dāng)然,這也要求我們的函數(shù)定義需要清晰明了,我們后面會(huì)談)
- 其次,代碼更可讀取,因?yàn)槲覀冎涝撨x項(xiàng)的作用是什么。
- 第三,代碼擴(kuò)展性更好,以后添加新的選項(xiàng)要容易得多。這既適用于為組合式函數(shù)本身添加新選項(xiàng),又適用于嵌套使用時(shí)參數(shù)傳遞。
因此,使用對(duì)象參數(shù)更加友好,但是我們?cè)撊绾蝸?lái)實(shí)現(xiàn)呢?
在組合式函數(shù)中的實(shí)現(xiàn)
現(xiàn)在讓我們看下如何在組合式函數(shù)中使用選項(xiàng)對(duì)象參數(shù)。我們來(lái)給上面的useMouse
進(jìn)行一些擴(kuò)展:
export function useMouse(options) { const { asArray = false, throttle = false, } = options; // ... };
useMouse
本身沒(méi)有必傳參數(shù),所以我們直接給它增加一個(gè)options
參數(shù)來(lái)進(jìn)行一些額外的配置。通過(guò)解構(gòu),我們可以訪問(wèn)所有的選傳參數(shù),并且為每個(gè)參數(shù)設(shè)置了默認(rèn)值,這就避免了有些不需要額外配置的調(diào)用時(shí)沒(méi)有傳入可選參數(shù)的情況。
現(xiàn)在讓我們來(lái)看兩個(gè)VueUse上面的組合式函數(shù)是如何使用這個(gè)模式的。VueUse是一個(gè)服務(wù)于Vue3的組合式函數(shù)的常用工具集,它的初衷就是將一切原本并不支持響應(yīng)式的JS API變得支持響應(yīng)式,省去程序員自己寫(xiě)相關(guān)代碼。
我們先來(lái)看useTitle
,然后再看一下useRefHistory
是如何實(shí)現(xiàn)的。
舉例-useTitle
useTitle
的作用非常簡(jiǎn)單,就是用來(lái)更新頁(yè)面的標(biāo)題。
const title = useTitle('Initial Page Title'); // Title: "Initial Page Title" title.value = 'New Page Title'; // Title: "New Page Title"
它也有幾個(gè)選擇參數(shù),來(lái)促進(jìn)額外的靈活性。我們可以傳入titleTemplate
作為模版,并且通過(guò)observe
來(lái)將其設(shè)置稱(chēng)為具備觀察性(內(nèi)部通過(guò)MutationObserver實(shí)現(xiàn)):
const title = useTitle('Initial Page Title', { titleTemplate: '>> %s <<', observe: true, }); // Title: ">> Initial Page Title <<" title.value = 'New Page Title'; // Title: ">> New Page Title <<"
當(dāng)我們查看它的源碼的時(shí)候可以看到以下處理
export function useTitle(newTitle, options) { const { document = defaultDocument, observe = false, titleTemplate = '%s', } = options; // ... }
useTitle
包含一個(gè)必傳的參數(shù),以及一個(gè)可選參數(shù)對(duì)象。正如我們上面描述的那樣,它完全是按照這個(gè)模式來(lái)實(shí)現(xiàn)的。
接下來(lái),讓我們看一下一個(gè)更復(fù)雜的組合式函數(shù)是如何使用選項(xiàng)對(duì)象模式的。
舉例-useRefHistory
useRefHistory
可以幫助我們追蹤一個(gè)響應(yīng)式變量的所有更改,可以讓我們輕松的執(zhí)行撤銷(xiāo)和恢復(fù)的操作。
// Set up the count ref and track it const count = ref(0); const { undo } = useRefHistory(count); // Increment the count count.value++; // Log out the count, undo, and log again console.log(counter.value); // 1 undo(); console.log(counter.value); // 0
它支持設(shè)置許多不同的配置選擇
{ deep: false, flush: 'pre', capacity: -1, clone: false, // ... }
如果想知道這些選項(xiàng)參數(shù)的完整列表和對(duì)應(yīng)的功能,可以去查看相關(guān)文檔,在此不再贅述。
我們可以將選項(xiàng)對(duì)象作為第二個(gè)參數(shù)傳遞,以進(jìn)一步配置該組合函數(shù)的行為,與我們上一個(gè)示例相同:
export function useRefHistory(source, options) { const { deep = false, flush = 'pre', eventFilter, } = options; // ... }
我們可以看到它內(nèi)部?jī)H僅解構(gòu)出了一部分參數(shù)值,這是因?yàn)?code>useRefHistory內(nèi)部依賴(lài)了useManualHistory
這個(gè)組合式函數(shù),其他的選項(xiàng)參數(shù)將在后面透?jìng)鹘ouseManualHistory
時(shí)進(jìn)行展開(kāi)合并。
// ... const manualHistory = useManualRefHistory( source, { // Pass along the options object to another composable ...options, clone: options.clone || deep, setSource, }, ); // ...
這也和我們前面說(shuō)到的內(nèi)容相符:組合式函數(shù)可以嵌套使用。
小結(jié)
本文是“組合式函數(shù)最佳實(shí)踐”的第一部分。我們研究了如何通過(guò)選項(xiàng)對(duì)象參數(shù)提升組合式函數(shù)的靈活性。無(wú)須擔(dān)心參數(shù)順序不對(duì)導(dǎo)致的問(wèn)題,并且可以靈活進(jìn)行配置項(xiàng)的增加擴(kuò)展。我們不僅僅研究了這個(gè)模式本身,我們還通過(guò)VueUse中的useTitle
和useRefHistory
來(lái)學(xué)習(xí)了如何實(shí)現(xiàn)此模式。它們略有不同,但是這個(gè)模式本身就是很簡(jiǎn)單的,我們通過(guò)它能做到也是有限的。
下一篇我們將介紹如何通過(guò)ref和unref使我們的參數(shù)更加靈活
// Works if we give it a ref we already have const countRef = ref(2); useCount(countRef); // Also works if we give it just a number const countRef = useRef(2);
這增加了靈活性,使我們能夠在應(yīng)用程序中的更多情況下使用我們的組合。
以上就是Vue3 組合式函數(shù)Composable最佳實(shí)戰(zhàn)的詳細(xì)內(nèi)容,更多關(guān)于Vue3 Composable的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Vue3 Ref獲取真實(shí)DOM學(xué)習(xí)實(shí)戰(zhàn)
- vue中this.$refs.name.offsetHeight獲取不到值問(wèn)題
- vue3+ts數(shù)組去重方及reactive/ref響應(yīng)式顯示流程分析
- VueJs中的shallowRef與shallowReactive函數(shù)使用比較
- 一文搞懂VueJs中customRef函數(shù)使用
- VueJs中toRef與toRefs函數(shù)對(duì)比詳解
- Vue?2中實(shí)現(xiàn)CustomRef方式防抖節(jié)流
- Vue3組合式函數(shù)Composable實(shí)戰(zhàn)ref和unref使用
相關(guān)文章
vue-seamless-scroll 實(shí)現(xiàn)簡(jiǎn)單自動(dòng)無(wú)縫滾動(dòng)且添加對(duì)應(yīng)點(diǎn)擊事件的簡(jiǎn)單整理
vue-seamless-scroll是一個(gè)基于Vue.js的簡(jiǎn)單無(wú)縫滾動(dòng)組件, 基于requestAnimationFrame實(shí)現(xiàn),配置多滿(mǎn)足多樣需求,目前支持上下左右無(wú)縫滾動(dòng),單步滾動(dòng),及支持水平方向的手動(dòng)切換功能,本節(jié)介紹,vue添加 vue-seamless-scroll實(shí)現(xiàn)自動(dòng)無(wú)縫滾動(dòng)的效果,并對(duì)應(yīng)添加點(diǎn)擊事件2023-01-01vue 實(shí)現(xiàn)左右拖拽元素并且不超過(guò)他的父元素的寬度
這篇文章主要介紹了vue 實(shí)現(xiàn)左右拖拽元素并且不超過(guò)他的父元素的寬度,需要的朋友可以參考下2018-11-1117個(gè)vue常用的數(shù)組方法總結(jié)與實(shí)例演示
這篇文章主要介紹了vue中常用的數(shù)組方法,包括:VUE數(shù)組轉(zhuǎn)換字符串,VUE數(shù)組遍歷,VUE數(shù)組過(guò)濾,VUE數(shù)組查詢(xún),VUE數(shù)組排序等功能,需要的朋友可以參考下2022-12-12vue3父子組件通信之子組件修改父組件傳過(guò)來(lái)的值
這篇文章主要介紹了vue3父子組件通信之子組件修改父組件傳過(guò)來(lái)的值,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-05-05Vue?keepAlive實(shí)現(xiàn)不同的路由共用一個(gè)組件component的緩存問(wèn)題(推薦)
這篇文章主要介紹了Vue?keepAlive實(shí)現(xiàn)不同的路由共用一個(gè)組件component的緩存問(wèn)題,實(shí)現(xiàn)方式使用Vue?keepAlive實(shí)現(xiàn)頁(yè)面緩存,需要的朋友可以參考下2022-08-08VUE中setTimeout和setInterval自動(dòng)銷(xiāo)毀案例
這篇文章主要介紹了VUE中setTimeout和setInterval自動(dòng)銷(xiāo)毀案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Vue中nprogress頁(yè)面加載進(jìn)度條的方法實(shí)現(xiàn)
這篇文章主要介紹了Vue中nprogress頁(yè)面加載進(jìn)度條的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11