近来摸鱼吃东西时想要复制个内容,下意识的用了左手去cv十分不便,突然想到Vue中提供的自定义指令,作为Vue中最常使用的内容之一,方便的指令是开发过程中不可或缺的方法,于是便将自己2.x项目中的自定义指定进行了下升级。顺道重新复习下相关知识,如果这篇文章对你有帮助自是不胜荣幸。
1.什么是自定义指令?
所谓自定义指令其实就是指令当中的一个分支用法,那么什么是指令呢?
我们平常开发中使用的 v-if、v-show、v-for、v-model... 等都是Vue内置的核心指令,既内置指令。通过这些内置指令我们可以对dom进行底层操作。而自定义就是Vue为了满足我们开发者的个性化需求而提供的API,通过它可以更方便的完成需求开发。
2.使用自定义指令
那么如何使用自定义指令呢?想像内置指令一样使用自定义指令自然是离不开注册再使用。同样的注册指令也分为全局注册和局部注册,全局注册的指令可以在任何组件中直接使用,局部注册的指令只能在注册的地方使用。
2.1 钩子函数
不管是Vue的内置指令还是自定义指令,都有类似于组件的生命周期,我们可以在不同的生命周期完成不同的逻辑操作,并绑定到组件元素上,这样就完成了自定义指令的生成。
一个自定义指令对象可以提供如下几个钩子函数 (均为可选):
created:在绑定元素的 attribute 或事件监听器被应用之前调用。在指令需要附加在普通的v-on事件监听器调用前的事件监听器中时,这很有用。beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用。mounted:在绑定元素的父组件被挂载后调用。beforeUpdate:在更新包含组件的 VNode 之前调用。updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用。beforeUnmount:在卸载绑定元素的父组件之前调用unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次。
钩子函数的参数 (即 el、binding、vnode 和 prevVnode)
具体参数信息可移步至Vue3官方文档
2.2 全局注册
Vue提供了一个 directive 方法给我们注册自定义指令,和组件的全局注册一样,我们在main.js中注册了一个全局自定义指令后,自定义指令可在项目中所有组件内使用。
/*main.js*/
import { createApp } from 'vue'
import App from './App.vue'
import copy from "../src/util/copy";
const app = createApp(App);
// 注册一个全局自定义指令 `v-focus`
app.directive('focus', {
// 当被绑定的元素挂载到 DOM 中时……
mounted(el) {
// 聚焦元素
el.focus()
}
})
注册成功后便可在组件中使用了
<input type="text" v-focus />
2.3 局部注册
Vue提供了配置项 directives ,可以让我们在组件中通过 directives 选项进行局部注册。
/*组件内部局部注册*/
<template>
<input type="text" v-focus />
</template>
<script>
export default {
setup() {},
directives: {
focus: {
mounted(el, bindings, vnode, preVnode) {
console.log("节点已挂载完成");
el.focus();
}
}
}
}
</script>
这样一来通过自定义指令 v-focus 就可以实现,当某个元素挂载完成后可以自定获取焦点这个功能。
当然自定义指令自然不止这点用处,在我们的开发中有许多比较常见的需求,便可以通过自定义指令完成,比如一键复制粘贴、输入框防抖、图片懒加载等等便不一一列举,下面通过全局注册来自定义一个常用指令吧。
3.常用自定义指令示例
以一键复制为例,首先先确定需求与思路逻辑。
需求:实现一键复制当前文本,可通过Ctrl+V或者鼠标右键完成粘贴。
实现思路:
- 创建
textarea标签,设置readOnly属性移出可视区 - 将要复制的值赋给
textarea标签的value属性,并插入到body - 选中
textarea的值并复制 - 将
body中插入的textarea移除 - 在第一次调用时绑定事件,在解绑时移除事件
全局注册自定义指令
/* main.js */
import {
createApp
} from 'vue'
import App from './App.vue'
import router from "./router";
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import copy from "../src/util/copy"; // 引入copy方法文件
const app = createApp(App);
app.use(router)
app.use(ElementPlus, {
size: 'small',
zIndex: 3000
})
copy(app) // 传入app实例
app.mount('#app')
一键复制逻辑代码:
/* util/copy.js */
import { ElMessage } from "element-plus";
export default app => {
const copy = {
mounted(el, { value }) {
el.$value = value;
el.handler = () => {
console.log("要复制的内容是:", value);
if (!el.$value) {
return ElMessage({
message: "空的!空的!空的!",
type: "warning"
});
}
// 动态创建 textarea 标签
const textarea = document.createElement("textarea");
// 将textarea设为只读,并移出可视区域
textarea.readOnly = "readonly";
textarea.style.position = "absolute";
textarea.style.left = "-9999px";
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = el.$value;
// 将textarea插入到body,选中并复制
document.body.appendChild(textarea);
textarea.select();
const result = document.execCommand("Copy");
if (result) {
ElMessage({
message: "复制成功!",
type: "success"
});
}
// 移除textarea
document.body.removeChild(textarea);
};
el.addEventListener("click", el.handler);
},
// 传值更新的时触发
updated(el, { value }) {
el.$value = value;
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener("click", el.handler);
}
};
app.directive("copy", copy); // 为实例注册方法
};
组件中使用自定义指令:
<template>
<div>
问:<el-input v-model="text1"></el-input>
<el-button v-copy="text1">复制</el-button>
</div>
<div>
答: <el-input v-model="text2"></el-input>
<el-button @click="pasteEvent(text1)">赋值</el-button>
</div>
</template>
<script>
import { ElMessage } from "element-plus";
import { ref } from "@vue/runtime-core";
export default {
setup() {
const text1 = ref("隐约雷鸣,阴霾天空。但盼风风雨来,能留你在此");
let text2 = ref("");
const pasteEvent = value => {
const text = value.split("。");
text2.value = `${text[0]},即使天无雨,我亦留此地`;
ElMessage({
message: "粘贴成功!",
type: "success"
});
};
return {
text1,
text2,
pasteEvent
};
}
};
</script>
实现效果:
以上就是Vue3中自定义指令的用法,如有问题欢迎指正~