自定义指令directives
在项目特别是后台管理类的项目中使用的尤其多(个人经验),每个人编写的自定义指令也各不相同,一个人的时候还没啥感觉,在多人合作的项目中统一编码规范就变得很有必要了,这样看着舒服的同时也更方便后期维护。
题外话: 强烈推荐使用 vueuse,该库由vue核心成员开发,封装了各种常用hooks,能够省很多不必要的开发时间,且其中的封装hooks思想也很值得学习参考
最终效果如下图所示
1. directives
自定义指令创建及类型参数声明
在src/directives
目录下新建 index.ts
及 types.ts
分别用于自定义指令directives
的注册及全局指令参数声明。另新建目录modules
用于存放各种不同的指令实现代码。
// index.ts
import type { App } from 'vue';
import type { DirectiveOptions, Keys } from './types';
export default async function directives(app: App) {
// 项目是用 vite 创建,import.meta.glob 用于导入 /modules 下所有指令实现代码
const files = import.meta.glob('./modules/*.ts');
for (const key in files) {
const file: any = await files[key]();
if (file) {
const direct = file.default as DirectiveOptions<Keys>;
app.directive(direct.name, direct.directive);
}
}
}
// types.ts
import type { Directive } from 'vue';
type EventTypes = 'click' | 'input';
export interface ELType extends HTMLElement {
__fn__: () => any;
}
export interface Directives {
vFocus: Directive; // 聚焦
vDebounce: Directive<
any,
{
type?: EventTypes;
delay?: number;
callback: (...args: any[]) => void;
}
>; // 防抖
}
export type Keys = keyof Directives;
// 指令名转小写
type LowerDirectiveName<T extends Keys> = T extends `v${infer V}`
? Lowercase<V>
: never;
// 指令对象类型
export interface DirectiveOptions<T extends Keys> {
name: LowerDirectiveName<T>;
directive: Directives[T];
}
注:types.ts
导出接口声明Directives
主要用于在vue组件的ComponentCustomProperties
中作声明使用。
聚焦指令(v-focus)实现
import type { DirectiveOptions } from '../types';
const focusDirective: DirectiveOptions<'vFocus'> = {
name: 'focus',
directive: {
mounted: (el: HTMLInputElement) => el.focus(),
},
};
export default focusDirective;
防抖指令(v-debounce)代码实现
// modules/debounce.ts
import { useDebounceFn } from '@vueuse/core'
import type { DirectiveOptions, ELType } from '../types';
const focusDirective: DirectiveOptions<'vDebounce'> = {
name: 'debounce',
directive: {
mounted: (el: ELType, { value }, vnode) => {
const { type = 'input', delay, callback } = value;
el.__fn__ = useDebounceFn(callback.bind(vnode), delay ?? 300);
el.addEventListener(type, el.__fn__);
},
beforeUnmount: (el: ELType, { value }) => {
el.removeEventListener(value.type || 'input', el.__fn__);
},
},
};
export default focusDirective;
2. 注册自定义指令directives
在入口文件 main.ts
中引入并注册即可
// main.ts
import { createApp } from 'vue';
import directives from './directives';
const app = createApp(App);
app.use(directives);
app.mount('#app');
3. 为.vue
文件添加自定义指令类型声明
// global-properties.d
import type { Component } from 'vue';
import type { Filter } from '../src/filters/types';
import type { Directives } from '@/directives/types';
declare module 'vue' {
// 在这里直接继承 Directives 即可
interface ComponentCustomProperties extendsComponent, Directives {
$filters: Filter;
}
}
注:别忘了将该文件加入tsconfig.json
的include配置项中,否则在.vue
文件的template
中使用将不会出现类型提示。
在线代码可查看:vue-sy-admin
简易模板可查看:vue-vite-template