vue3.x lodash在項目中管理封裝指令的優(yōu)雅使用
vue3.x directives
vue
指令是一種特殊的 vue.js
特性,用于在 DOM
元素上添加特定的行為或功能。指令通過在元素上使用特定的指令名稱和參數(shù)來實現(xiàn),可以用于操作 DOM
、響應(yīng)事件、綁定數(shù)據(jù)等。今天簡述一下如何在項目中優(yōu)雅的管理、封裝一些常用的指令。
后面代碼基本上會逐行進(jìn)行注釋,以便于大家閱讀。
管理指令
統(tǒng)一管理
- 統(tǒng)一包管理:通過創(chuàng)建
directives
文件夾,我們可以將所有與指令相關(guān)的文件集中在一個位置,使其更易于查找和維護(hù)。這種統(tǒng)一的包管理結(jié)構(gòu)有助于組織和管理指令相關(guān)的代碼。 - 模塊化指令:在
directives/modules
文件夾中,我們?yōu)槊總€指令創(chuàng)建一個獨立的文件夾。這種模塊化的結(jié)構(gòu)使每個指令的邏輯和功能被封裝在一個獨立的文件中,方便單獨管理和維護(hù)。每個指令文件夾中的出口文件index.ts
可以用于導(dǎo)出指令邏輯,使其在項目中得以統(tǒng)一注冊和使用。 - 規(guī)范化命名:指令文件夾的命名需要言簡意賅,能夠清晰表達(dá)指令的用途。通過規(guī)范化的命名,可以使項目中的指令更易于理解和識別,提高代碼的可讀性和可維護(hù)性。
- 可擴展性:通過這種管理方式,我們可以輕松地添加新的指令。只需在 directives/modules 文件夾中創(chuàng)建一個新的指令文件夾,并在其中編寫相應(yīng)的指令邏輯即可。這種結(jié)構(gòu)使項目具有良好的可擴展性,方便我們根據(jù)需要添加、修改或刪除指令。
· ├── directives ├──├── index.ts ├──├── modules ├──├──├── some directive ├──├──├──├── index.ts type.ts ...
統(tǒng)一注冊
每個指令都使用 index.ts
文件統(tǒng)一暴露一個 CustomDirectiveFC
類型的函數(shù),并且在根目錄的 index.ts
中自動搜集 modules
文件夾中的所有文件并注冊這些指令。
公共類型(type.ts)
import type { Directive } from 'vue' import type { App } from 'vue' export type { DebounceBindingOptions } from './modules/debounce/type' export type { ThrottleBindingOptions } from './modules/throttle/type' export type CustomDirectiveFC<T, K> = () => Directive<T, K> export interface DirectiveModules extends Object { default: CustomDirectiveFC<unknown, unknown> } export type AppType = App<Element>
搜集、注冊指令
利用 import.meta.glob
方法(如果是 webpack
則是使用 require.context
),獲取所有指令文件夾的路徑。然后,遍歷這些文件夾,找到包含 index.ts
文件的位置。在每個 index.ts
文件中,你可以導(dǎo)入 CustomDirectiveFC
函數(shù)。通過這種方式,你可以自動搜集所有指令,并進(jìn)行注冊。
警告
該方式會搜集 modules
中所有的文件夾,并且以文件名稱作為指令名稱。如果是多個單詞,請使用小寫單詞并以 -
連接。
import type { DirectiveModules, CustomDirectiveFC } from '@/directives/type' export const combineDirective = < T extends Record<string, DirectiveModules>, K extends keyof T, >( directiveModules: T, ) => { const directives = Object.keys(directiveModules).reduce((pre, curr) => { const fc = directiveModules[curr]?.default if (typeof fc === 'function') { pre[curr] = fc return pre } else { throw new Error('directiveModules[curr] is not function') } }, {} as Record<K, CustomDirectiveFC<unknown, unknown>>) return directives }
import { combineDirective } from './helper/combine' import { forIn } from 'lodash-es' import type { App } from 'vue' import type { DirectiveModules } from '@/directives/type' /** * * 初始化全局自定義指令 * * 該方法會將 modules 下每個文件夾視為一個指令 * 并且會將文件夾名稱識別為指令名稱 * 每個文件下的 index.ts 文件視為每個指令的入口(也就是指令的處理邏輯, 需要暴露出一個 Directive 類型的對象) */ export const setupDirectives = (app: App<Element>) => { // 獲取 modules 包下所有的 index.ts 文件 const directiveRawModules: Record<string, DirectiveModules> = import.meta.glob('@/directives/modules/**/index.ts', { eager: true, }) // 將所有的包提取出來(./modules/[file-name]/index.ts) const directivesModules = combineDirective(directiveRawModules) // 提取文件名(./modules/copy/index.ts => copy) const regexExtractDirectiveName = /(?<=modules\/).*(?=\/index\.ts)/ // 匹配合法指令名稱 const regexDirectiveName = /^([^-]+-)*[^-]+$/ forIn(directivesModules, (value, key) => { const dname = key.match(regexExtractDirectiveName)?.[0] if (typeof dname === 'string' && regexDirectiveName.test(dname)) { app.directive(dname, value?.()) } else { console.error(`[setupDirectives] ${dname} is not a valid directive name`) } }) }
在 main.ts
文件中導(dǎo)入并且調(diào)用 setupDirectives
方法,即可完成自定義指令的搜集與注冊。然后即可在項目全局中使用。
自定義指令
準(zhǔn)備工作我們已經(jīng)完成了,現(xiàn)在只需要開發(fā)自定義指令即可?,F(xiàn)在我們來封裝幾個常用指令熱熱手。
v-throttle
實現(xiàn)
import type { ThrottleSettings } from 'lodash-es' import type { AnyFC } from '@/types/modules/utils' export interface ThrottleBindingOptions { func: AnyFC trigger?: string wait?: number options?: ThrottleSettings }
import { throttle } from 'lodash-es' import { on, off } from '@use-utils/element' import type { ThrottleBindingOptions } from './type' import type { AnyFC } from '@/types/modules/utils' import type { DebouncedFunc } from 'lodash-es' import type { CustomDirectiveFC } from '@/directives/type' const throttleDirective: CustomDirectiveFC< HTMLElement, ThrottleBindingOptions > = () => { let throttleFunction: DebouncedFunc<AnyFC> | null return { beforeMount: (el, { value }) => { const { func, trigger = 'click', wait = 500, options } = value if (typeof func !== 'function') { throw new Error('throttle directive value must be a function') } throttleFunction = throttle(func, wait, Object.assign({}, options)) on(el, trigger, throttleFunction) }, beforeUnmount: (el, { value }) => { const { trigger = 'click' } = value if (throttleFunction) { throttleFunction.cancel() off(el, trigger, throttleFunction) } throttleFunction = null }, } } export default throttleDirective
使用
<template> <p>我執(zhí)行了{(lán){ count }}次</p> <p>該方法 1s 內(nèi)僅會執(zhí)行一次</p> <button v-throttle="{ func: handleClick, trigger: 'click', wait: 1000, options: {}, }" > 節(jié)流按鈕 </button> </template> <script setup lang="ts"> const count = ref(0) const handleClick = () => { count.value++ } </script>
v-debounce
實現(xiàn)
import type { DebounceSettings } from 'lodash-es' import type { AnyFC } from '@/types/modules/utils' export interface DebounceBindingOptions { func: AnyFC trigger?: string wait?: number options?: DebounceSettings }
import { debounce } from 'lodash-es' import { on, off } from '@use-utils/element' import type { DebounceBindingOptions } from './type' import type { AnyFC } from '@/types/modules/utils' import type { DebouncedFunc } from 'lodash-es' import type { CustomDirectiveFC } from '@/directives/type' const debounceDirective: CustomDirectiveFC< HTMLElement, DebounceBindingOptions > = () => { let debounceFunction: DebouncedFunc<AnyFC> | null return { beforeMount: (el, { value }) => { const { func, trigger = 'click', wait = 500, options } = value if (typeof func !== 'function') { throw new Error('debounce directive value must be a function') } debounceFunction = debounce(func, wait, Object.assign({}, options)) on(el, trigger, debounceFunction) }, beforeUnmount: (el, { value }) => { const { trigger = 'click' } = value if (debounceFunction) { debounceFunction.cancel() off(el, trigger, debounceFunction) } debounceFunction = null }, } } export default debounceDirective
使用
<template> <p>我執(zhí)行了{(lán){ count }}次</p> <p>該方法將延遲 1s 執(zhí)行</p> <button v-throttle="{ func: handleClick, trigger: 'click', wait: 1000, options: {}, }" > 防抖按鈕 </button> </template> <script setup lang="ts"> const count = ref(0) const handleClick = () => { count.value++ } </script>
自定義指令目錄結(jié)構(gòu)
· ├── directives ├──├── index.ts type.ts ├──├── modules ├──├──├── throttle ├──├──├──├── index.ts type.ts ├──├──├── debounce ├──├──├──├── index.ts type.ts
按照上述步驟以后,你將會得到這樣的一個目錄結(jié)構(gòu)。
最后
所有的代碼源碼都來自于 Ray Template,可以自行點擊查看源碼
以上就是vue3.x lodash在項目中管理封裝指令的優(yōu)雅使用的詳細(xì)內(nèi)容,更多關(guān)于vue3.x lodash管理封裝指令的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
element?ui富文本編輯器的使用效果與步驟(quill-editor)
富文本編輯器在任何項目中都會用到,在Element中我們推薦vue-quill-editor組件,下面這篇文章主要給大家介紹了關(guān)于element?ui富文本編輯器的使用效果與步驟(quill-editor)的相關(guān)資料,需要的朋友可以參考下2022-10-10Vue如何實現(xiàn)文件預(yù)覽和下載功能的前端上傳組件
在Vue.js項目中,使用ElementUI的el-upload組件可以輕松實現(xiàn)文件上傳功能,通過配置組件參數(shù)和實現(xiàn)相應(yīng)的方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09詳解Vue前端生產(chǎn)環(huán)境發(fā)布配置實戰(zhàn)篇
這篇文章主要介紹了詳解Vue前端生產(chǎn)環(huán)境發(fā)布配置實戰(zhàn)篇,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05vue $set 實現(xiàn)給數(shù)組集合對象賦值
這篇文章主要介紹了vue $set 實現(xiàn)給數(shù)組集合對象賦值方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07