除了使用内置的 Vue 指令,程序员还可以自定义 Vue 指令,从而☀️复用对 DOM 元素进行操作。使用方式便是 v-“指令名称”
注册自定义指令分为全局注册和局部注册,顾名思义,全局注册的指令注册在 main.js 内且全局可用,局部注册的指令注册在 Vue 组件里且仅当前组件可用
App.vue
<template>
<p v-global>p>
template>
<script>
export default {
name: 'App'
}
script>
main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.directive("global", {
mounted() {
console.log("Global Hello");
},
})
app.mount('#app')
TempTest.vue
<template>
<p v-local>p>
template>
<script>
export default {
name: 'TempTest',
directives: {
local: {
mounted() {
console.log("Local Hello");
},
}
}
}
script>
自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数
myDirective: {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created() {},
// 在元素被插入到 DOM 前调用
beforeMount() {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted() {},
// 绑定元素的父组件更新前调用
beforeUpdate() {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated() {},
// 绑定元素的父组件卸载前调用
beforeUnmount() {},
// 绑定元素的父组件卸载后调用
unmounted() {}
}
el:
指令绑定到的元素。这可以用于直接操作 DOM。
binding:
一个对象,包含以下属性。
vnode:
代表绑定元素的底层 VNode。
prevNode:
之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
<template>
<div v-test:ARG.a.b="'VALUE'">
<h2>测试自定义指令的参数h2>
div>
template>
<script>
export default {
name: 'TempTest',
directives: {
test: {
mounted(el, binging, vnode) {
console.log(el.innerText);
console.log(el.innerHTML);
// 测试自定义指令的参数
// 测试自定义指令的参数
console.log(binging.value);
console.log(binging.arg);
console.log(binging.modifiers);
// VALUE
// ARG
// {a: true, b: true}
console.log(vnode);
// { __v_isVNode: true, __v_skip: true, type: "div", props: null}
}
}
}
}
script>
在动态值、动态参数、修饰符中可以动态绑定的唯有前两种
<template>
<div v-test:[num].a.b="num">div>
template>
<script>
export default {
name: 'TempTest',
data() {
return {
num: 11
}
},
directives: {
test: {
mounted(el, binding) {
console.log(el, binding);
},
}
}
}
script>
对于自定义指令来说,一个很常见的情况是仅仅需要在 mounted 和 updated 上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令
app.directive('color', (el, binding) => {
// 这会在 `mounted` 和 `updated` 时都调用
el.style.color = binding.value
})
v-img
指令当页面加载一个很大的图片时,在未成功加载之前,会在图片位置出现空白区域。v-img 指令会在未加载图片之前,在图片位置显示随机的颜色
<div v-img="'image/logo.gif'">div>
img: {
mounted(el, binding) {
const color = Math.floor(Math.random()*1000000);
el.style.backgroundColor = `#${color}`;
const img = new Image();
img.src = binding.value;
img.onload = () => {
el.style.backgroundImage = `url(${binding.value})`;
}
}
}
v-drag
指令v-drag 支持用鼠标拖拽网页上特定的 DOM 元素移动
<div v-drag>div>
drag(el) {
el.onmousedown = (event) => {
// 获取单点处分别与 div 左边和上边的距离,
// 取值为鼠标位置减去 div 位置
const disX = event.clientX - el.offsetLeft;
const disY = event.clientY - el.offsetTop;
console.log(disX, disY);
// 处理在整个网页区域中移动鼠标的事件
document.onmousemove = (event) => {
// 获取移动后的 div 的位置,
// 取值为鼠标位置减去 disX,disY
const left = event.clientX - disX;
const top = event.clientY - disY;
// 重新设置 DOM 元素的位置
el.style.left = left + 'px';
el.style.top = top + 'px';
}
// 处理整个网页中鼠标弹起和停止移动鼠标的事件
document.onmouseup = (event) => {
document.onmousemove = null;
document.onmouseup = null;
}
}
}
参考资料:
- https://cn.vuejs.org/
- 《精通Vue.js Web前端开发技术详解》