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ù)性。
- 可擴(kuò)展性:通過這種管理方式,我們可以輕松地添加新的指令。只需在 directives/modules 文件夾中創(chuàng)建一個新的指令文件夾,并在其中編寫相應(yīng)的指令邏輯即可。這種結(jié)構(gòu)使項目具有良好的可擴(kuò)展性,方便我們根據(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-10
Vue如何實現(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-05
vue $set 實現(xiàn)給數(shù)組集合對象賦值
這篇文章主要介紹了vue $set 實現(xiàn)給數(shù)組集合對象賦值方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

