准备工作
在开始编写自定义指令之前,请确保你已经安装了Vue3和TypeScript,并且能够创建Vue项目。
自定义指令示例
复制指令
复制指令用于实现点击元素后将其内容复制到剪贴板的功能。
/**
* v-copy
* 复制某个值至剪贴板
* 接收参数:string类型/Ref<string>类型/Reactive<string>类型
*/
import type { Directive, DirectiveBinding } from "vue";
import { ElMessage } from "element-plus";
interface ElType extends HTMLElement {
copyData: string | number;
__handleClick__: any;
}
const copy: Directive = {
mounted(el: ElType, binding: DirectiveBinding) {
el.copyData = binding.value;
el.addEventListener("click", handleClick);
},
updated(el: ElType, binding: DirectiveBinding) {
el.copyData = binding.value;
},
beforeUnmount(el: ElType) {
el.removeEventListener("click", el.__handleClick__);
}
};
async function handleClick(this: any) {
if (!navigator.clipboard) {
const input = document.createElement("input");
input.value = this.copyData.toLocaleString();
document.body.appendChild(input);
input.select();
document.execCommand("Copy");
document.body.removeChild(input);
} else {
await navigator.clipboard.writeText(this.copyData);
}
ElMessage({
type: "success",
message: "复制成功"
});
}
export default copy;
防抖指令
防抖指令用于延迟执行某个函数,常用于输入框搜索等场景。
/**
* v-debounce
* 按钮防抖指令,可自行扩展至input
* 接收参数:function类型
*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {
__handleClick__: () => any;
}
const debounce: Directive = {
mounted(el: ElType, binding: DirectiveBinding) {
if (typeof binding.value !== "function") {
throw "callback must be a function";
}
let timer: NodeJS.Timeout | null = null;
el.__handleClick__ = function () {
if (timer) {
clearInterval(timer);
}
timer = setTimeout(() => {
binding.value();
}, 500);
};
el.addEventListener("click", el.__handleClick__);
},
beforeUnmount(el: ElType) {
el.removeEventListener("click", el.__handleClick__);
}
};
export default debounce;
节流指令
节流指令用于限制函数的执行频率,常用于滚动加载等场景。
/*
需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。
思路:
1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮
2、将需要触发的方法绑定在指令上
使用:给 Dom 加上 v-throttle 及回调函数即可
<button v-throttle="debounceClick">节流提交</button>
*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {
__handleClick__: () => any;
disabled: boolean;
}
const throttle: Directive = {
mounted(el: ElType, binding: DirectiveBinding) {
if (typeof binding.value !== "function") {
throw "callback must be a function";
}
let timer: NodeJS.Timeout | null = null;
el.__handleClick__ = function () {
if (timer) {
clearTimeout(timer);
}
if (!el.disabled) {
el.disabled = true;
binding.value();
timer = setTimeout(() => {
el.disabled = false;
}, 1000);
}
};
el.addEventListener("click", el.__handleClick__);
},
beforeUnmount(el: ElType) {
el.removeEventListener("click", el.__handleClick__);
}
};
export default throttle;
注册自定义指令
在Vue应用的入口文件中,注册自定义指令以便在整个应用中使用。
// directives/index.ts
import { App } from "vue";
import copy from "./modules/copy";
import debounce from "./modules/debounce";
import throttle from "./modules/throttle";
const directivesList: any = {
copy,
debounce,
throttle,
};
const directives = {
install: function (app: App<Element>) {
Object.keys(directivesList).forEach(key => {
// 注册所有自定义指令
app.directive(key, directivesList[key]);
});
}
};
export default directives;
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import directives from "@/directives/index";
const app = createApp(App);
app.use(directives).mount("#app");
总结
通过本文的介绍,我们学习了如何结合Vue3和TypeScript编写自定义指令,并实现了复制、防抖、节流等几种常见的自定义指令。自定义指令的使用能够让我们更好地控制DOM元素的行为,提高开发效率,降低代码重复度。在实际项目中,可以根据需求编写更多更复杂的自定义指令,以满足不同的业务场景。
希望本文能够帮助到你,欢迎探索更多关于Vue3和TypeScript的技术内容!