自定义指令
关于Vue中指令的详细介绍可以查看Vue文档,这里主要记录如何实现一个符合需求的自定义指令。
tips: 自定义指令主要用于对DOM元素进行操作。
需求: 实现一个完全覆盖页面上指定区域的遮罩,遮罩不能影响除指定区域外的其他元素,且可以动态切换此遮罩的开启、关闭。
思考: 利用自定义指令实现,获取指令绑定元素的宽高,若该元素有子元素,需要包含其所有子元素;根据指令绑定值,动态创建/销毁遮罩元素。
钩子函数
一个指令定义对象可以提供如下几个可选的钩子函数
bind
: 只调用一次,指令第一次绑定到元素时调用。(可以做一些一次性的初始化设置)inserted
: 被绑定元素插入父节点时调用 ,仅保证父节点存在,但不一定已被插入文档中(在此创建并插入DOM元素)。update
: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。(可以通过比较更新前后的值来做一些操作)componentUpdated
: 指令所在组件的 VNode 及其子 VNode 全部更新后调用 (组件内所有DOM元素都已更新,可以获取指令所在元素包含子元素在内的全部高度)unbind
: 只调用一次,指令与元素解绑时调用(可以在此移除/销毁不再需要的DOM元素)。
钩子函数参数
全部参数信息可见文档
实现
可以在项目目录src/directives下新建mask目录,文件结构如下
├─src
├─directives
│ ├─mask
│ │ index.js
│ │ mask.js
- mask.js中导出包含钩子函数的对象
查看代码
js
// 创建并插入遮罩
function insertMaskEl(el) {
const parentNode = el.parentNode
const fragment = document.createDocumentFragment()
el.mask = document.createElement(el.tagName)
parentNode.style.position = 'relative'
// 样式可以通过添加类名统一添加,也可以直接改变元素style属性
el.mask.classList.add('mask-wrapper')
fragment.appendChild(el.mask)
parentNode.appendChild(fragment)
}
// 移除并销毁遮罩
function removeMaskEl(el) {
el.mask && el.parentNode.removeChild(el.mask)
}
export default {
inserted(el, binding, vnode) {
// 根据指令的绑定值切换遮罩的状态
if (binding.value) {
insertMaskEl(el)
} else {
removeMaskEl(el)
}
},
// 指令值变更时,更新遮罩
update(el, binding) {
if (binding.value !== binding.oldValue) {
insertMaskEl(el)
}
},
// DOM元素完全更新,此处可获取到指令所在组件完整的高度
componentUpdated(el, binding) {
if (el.mask) {
el.mask.style.height = el.getBoundingClientRect().height.toFixed(1) + 'px'
}
},
unbind(el) {
removeMaskEl(el)
}
}
css
/* 遮罩样式,全局指令需要将样式写在公共的样式文件中 */
.mask-wrapper {
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 99;
opacity: 0;
}
- index.js中注册指令
js
import Vue from 'vue'
// 全局注册
Vue.directive('mask', mask)
src/main.js中导入文件:可以单独导入@/src/directives/mask,也可以和其他自定义指令一起导入。
使用
js
<template>
<div v-mask="showMask">
<div></div>
<p></p>
</div>
</template>
export default {
data() {
return {
showMask: false // 为true时显示遮罩
}
}
}