vue3結(jié)合ts從零實(shí)現(xiàn)vueuse的useRouteQuery方法
本文將使用vue3
與ts
從零實(shí)現(xiàn)一個(gè)類vueuse
的useRouteQuery
方法,接受基本相同的參數(shù)(移除了router與route參數(shù)),并解決vueuse
的useRouteQuery
方法存在的一些問(wèn)題。
使用 vueuse 的 useRouteQuery 碰到的問(wèn)題
問(wèn):為什么不使用vueuse
的提供的useRouteQuery
方法?
答:因?yàn)樵谑褂?code><KeepAlive>?;畹捻?yè)面級(jí)組件之間切換時(shí),在所有組件中使用vueuse
的useRouteQuery
方法定義的變量都會(huì)更新。
例如:打開(kāi)A頁(yè)面(?;?后,修改page為2,假設(shè)url現(xiàn)在為/pageA?page=2
,然后切換到B頁(yè)面,A頁(yè)面將會(huì)觸發(fā)watch
且page
將會(huì)更新為默認(rèn)值,并且每次修改B頁(yè)面的query都會(huì)觸發(fā)A頁(yè)面的query更新。代碼如下。
import { useRouteQuery } from '@vueuse/router' import { watch } from 'vue' // 頁(yè)面A (KeepAlive) const page = useRouteQuery('page', 1, { transform: Number }) watch(page, (value) => { console.log('page A', value) }) // 頁(yè)面B (KeepAlive) const pageSize = useRouteQuery('pagesize', 10, { transform: Number }) watch(pageSize, (value) => { console.log('page B', value) })
查看vueuse
的useRouteQuery
的源碼后發(fā)現(xiàn)它是根據(jù)router
對(duì)象去保存query
信息的,因此每次url
的query
變化時(shí),所有已存在的相關(guān)變量都會(huì)更新。
從零實(shí)現(xiàn)一個(gè) useRouteQuery
思考:
- 監(jiān)聽(tīng)
route.query
的變化,在值變化時(shí)更新響應(yīng)式變量的值; - 監(jiān)聽(tīng)響應(yīng)式變量的變化,在值變化時(shí)修改
route.query
的值; - 在
route.query
變化時(shí),判斷是否是當(dāng)前頁(yè)面,不是則跳過(guò)更新過(guò)程。
1. 簡(jiǎn)易實(shí)現(xiàn)
import { watch, ref, type Ref } from 'vue' import { useRoute, useRouter } from 'vue-router' type IQuery = string | number | string[] | null | undefined /** * 獲取當(dāng)前頁(yè)面的query * @param name * @param defaultValue * @param options * @returns */ export const useRouteQuery = <T extends IQuery, K extends IQuery = T>( name: string, defaultValue?: T, options: { transform?: (value: any) => K mode?: 'push' | 'replace' isEncodeURIComponent?: boolean } = {} ) => { const { mode = 'push', transform = (value) => value, isEncodeURIComponent = false } = options const route = useRoute() const router = useRouter() const currentPath = route.path const query = ref(defaultValue) as Ref<T | K> watch( () => route.query[name], (value) => { // 不是當(dāng)前頁(yè)面時(shí)不更新 if (route.path !== currentPath) { return } if (value === undefined) { query.value = defaultValue as T return } if (!isEncodeURIComponent) { query.value = transform(value) return } query.value = transform(decodeURIComponent(value as string)) }, { immediate: true }) watch(query, (value) => { const { params, query: oldQuery, hash } = route router[mode]({ params, query: { ...oldQuery, [name]: isEncodeURIComponent ? encodeURIComponent(value as string) : value }, hash }) }) return query }
實(shí)際使用過(guò)后,我們會(huì)發(fā)現(xiàn)以上實(shí)現(xiàn)存在一些問(wèn)題:
多個(gè)變量同步修改時(shí),route.query
上只會(huì)保留最后一個(gè)修改的響應(yīng)式變量,代碼如下;
import { useRouteQuery } from '@/hooks/useRouteQuery' const disabled = useRouteQuery('disabled', 0) const title = useRouteQuery('title', '') disabled.value = 1 title.value = 'test' // 預(yù)想:?disabled=1&title=test // 實(shí)際:?title=test
特殊值undefined
、null
經(jīng)過(guò)encodeURIComponent
處理后會(huì)轉(zhuǎn)換為字符串格式,因此還會(huì)帶在route.query
上,如“?diabled=null&title=undefined”。
2. 完整實(shí)現(xiàn)
解決方案:
- 通過(guò)在函數(shù)外定義一個(gè)隊(duì)列來(lái)保存所有需要更新的值,并異步更新
route.query
; - 特殊值不使用
encodeURIComponent
方法轉(zhuǎn)義。
import { nextTick, watch, ref, type Ref } from 'vue' import { useRoute, useRouter } from 'vue-router' type IQuery = string | number | string[] | null | undefined // 用來(lái)保存所有的query const queriesQueue = new Map<string, Record<string, IQuery>>() /** * 獲取當(dāng)前頁(yè)面的query * @param name * @param defaultValue * @param options * @returns */ export const useRouteQuery = <T extends IQuery, K extends IQuery = T>( name: string, defaultValue?: T, options: { transform?: (value: any) => K mode?: 'push' | 'replace' isEncodeURIComponent?: boolean } = {} ) => { const { mode = 'push', transform = (value) => value, isEncodeURIComponent = false } = options const route = useRoute() const router = useRouter() const currentPath = route.path const query = ref(defaultValue) as Ref<T | K> watch( () => route.query[name], (value) => { if (route.path !== currentPath) { return } if (value === undefined) { query.value = defaultValue as T return } if (!isEncodeURIComponent) { query.value = transform(value) return } query.value = transform(decodeURIComponent(value as string)) }, { immediate: true }) const setQueryQueue = (value: IQuery) => { const currentPageQueries = queriesQueue.get(currentPath) || {} // 特殊值不轉(zhuǎn)義 if (value === null || value === undefined) { currentPageQueries[name] = value } else { currentPageQueries[name] = isEncodeURIComponent ? encodeURIComponent(value as string) : value } queriesQueue.set(currentPath, currentPageQueries) } watch(query, (value) => { setQueryQueue(value as IQuery) // 異步更新 nextTick(() => { // 獲取當(dāng)前頁(yè)面所有的query const currentPageQueries = queriesQueue.get(currentPath) || {} const { params, query: oldQuery, hash } = route router[mode]({ params, query: { ...oldQuery, ...currentPageQueries }, hash }) }) }) return query }
到此這篇關(guān)于vue3結(jié)合ts從零實(shí)現(xiàn)vueuse的useRouteQuery方法的文章就介紹到這了,更多相關(guān)vue實(shí)現(xiàn)vueuse的useRouteQuery內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談vue的props,data,computed變化對(duì)組件更新的影響
本篇文章主要介紹了淺談vue的props,data,computed變化對(duì)組件更新的影響,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01vue3新擬態(tài)組件庫(kù)開(kāi)發(fā)流程之table組件源碼分析
這篇文章主要介紹了vue3新擬態(tài)組件庫(kù)開(kāi)發(fā)流程——table組件源碼,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04vue實(shí)現(xiàn)購(gòu)物車拋物線小球動(dòng)畫效果的方法詳解
這篇文章主要介紹了vue實(shí)現(xiàn)購(gòu)物車拋物線小球動(dòng)畫效果的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了vue.js實(shí)現(xiàn)拋物線動(dòng)畫效果購(gòu)物車功能相關(guān)原理與操作注意事項(xiàng),需要的朋友可以參考下2019-02-02avue-crud多級(jí)復(fù)雜的動(dòng)態(tài)表頭的實(shí)現(xiàn)示例
Avue.js?是基于現(xiàn)有的element-ui庫(kù)進(jìn)行的二次封裝,本文主要介紹了avue-crud多級(jí)復(fù)雜的動(dòng)態(tài)表頭,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12vue.js實(shí)現(xiàn)格式化時(shí)間并每秒更新顯示功能示例
這篇文章主要介紹了vue.js實(shí)現(xiàn)格式化時(shí)間并每秒更新顯示功能,結(jié)合實(shí)例形式分析了vue.js時(shí)間格式化顯示與基于定時(shí)器進(jìn)行實(shí)時(shí)更新的相關(guān)操作技巧,需要的朋友可以參考下2018-07-07vue+openlayers+nodejs+postgis實(shí)現(xiàn)軌跡運(yùn)動(dòng)效果
使用postgres(postgis)數(shù)據(jù)庫(kù)以及nodejs作為后臺(tái),vue和openlayers做前端,openlayers使用http請(qǐng)求通過(guò)nodejs從postgres數(shù)據(jù)庫(kù)獲取數(shù)據(jù),這篇文章主要介紹了vue+openlayers+nodejs+postgis實(shí)現(xiàn)軌跡運(yùn)動(dòng),需要的朋友可以參考下2024-05-05vue中用qrcode庫(kù)將超鏈接生成二維碼圖片的示例代碼
生成二維碼是一種常見(jiàn)的需求,無(wú)論是用于商業(yè)宣傳還是個(gè)人分享,二維碼都可以提供快速方便的方式來(lái)傳遞信息,在Vue框架中,我們可以使用qrcode庫(kù)來(lái)輕松地生成二維碼,本篇博文將介紹如何安裝qrcode庫(kù),并通過(guò)一個(gè)實(shí)際例子來(lái)展示如何生成二維碼,需要的朋友可以參考下2023-12-12