自定义指令

介绍

内置指令(v-model等)

自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

一个指令的定义对象可以提供几种钩子函数 (都是可选的):


import type { Directive, DirectiveBinding } from "vue";
const myDirective : Directive = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(elHTMLElement, bindingDirectiveBinding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, bindingDirectiveBinding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, bindingDirectiveBinding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, bindingDirectiveBinding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, bindingDirectiveBinding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, bindingDirectiveBinding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, bindingDirectiveBinding, vnode, prevVnode) {}
}

钩子参数

指令的钩子会传递以下几种参数:

  • el:指令绑定到的元素。这可以用于直接操作 DOM。

  • binding:一个对象,包含以下属性。

    • value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2
    • oldValue:之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用。
    • arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"
    • modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }
    • instance:使用该指令的组件实例。
    • dir:指令的定义对象。
  • vnode:代表绑定元素的底层 VNode。

  • prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

插件全局注册指令使用

插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。

    import type { App, Plugin } from "vue";
import copy from "./modules/cope";//复制指令模板
const directivesList: any = {
	copy
};
// 插件注册全局自定义指令
const directives: Plugin = {
	install: (app: App) => {
		Object.keys(directivesList).forEach(key => {
			app.directive(key, directivesList[key]);
		});
	}
};
export default directives;

//main.ts 使用插件
app.use(directives)

常用指令

v-cope 复制粘贴指令

import type { Directive, DirectiveBinding } from "vue";
import { ElMessage } from "element-plus";
interface ElType extends HTMLElement {
	copyData: string | number;
}
const copy: Directive = {
	// 在绑定元素的父组件
	// 及他自己的所有子节点都挂载完成后调用
	mounted(el: ElType, binding: DirectiveBinding) {
		el.copyData = binding.value;// v-cope="value"传进来的值
		el.addEventListener("click", handleClick);
	},
	updated(el: ElType, binding: DirectiveBinding) {
		el.copyData = binding.value;// 值改变重新赋值
	},
	// 绑定元素的父组件卸载前调用
	beforeUnmount(el: ElType) {
		el.removeEventListener("click", handleClick);
	}
};

function handleClick(this: any) {
	let copyFont = this.copyData.toLocaleString();
	let textFont = null;
	// 仿知乎掘金 复制一两个字则不添加版权信息 超过一定长度的文字 就添加版权信息
	if (copyFont.length > 10) {
		textFont = `
				${copyFont} 
				--------------------------------三八线--------------------------------
				联系方式:QQ825437313
				外貌:10不存1,187cm是吧?200斤?减肥计划开始!!
				来源: 爱会凋零,花会枯萎! 
				著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。`;
	} else {
		textFont = copyFont; // 没超过十个字 则采用被复制的内容。
	}
	navigator.clipboard.writeText(textFont)//复制粘贴
		.then(() => {
			ElMessage({
				type: "success",
				message: "复制成功"
			});
		})
		.catch(() => {
			ElMessage({
				type: "error",
				message: "复制失败"
			});
		});
}
export default copy;


// 使用 <el-button v-copy="copeData">点击复制</el-button>
const copeData = ref<string>("我是被复制的内容 🍒 🍉 🍊");