2. vue-sy-admin: 基于vue3+TypeScript的自定义指令(directives)的封装及示例

自定义指令directives在项目特别是后台管理类的项目中使用的尤其多(个人经验),每个人编写的自定义指令也各不相同,一个人的时候还没啥感觉,在多人合作的项目中统一编码规范就变得很有必要了,这样看着舒服的同时也更方便后期维护。

题外话: 强烈推荐使用 vueuse,该库由vue核心成员开发,封装了各种常用hooks,能够省很多不必要的开发时间,且其中的封装hooks思想也很值得学习参考

最终效果如下图所示

Snipaste_2023-10-13_12-20-15.png

1. directives自定义指令创建及类型参数声明

src/directives目录下新建 index.tstypes.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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值