!!!指令都是v- 开头!!!
什么是自定义指令?
Vue[框架]给我们提供了许多指令,例如v-if 、v-else、 v-html、v-show、v-text、v-model、v-bind等等,这些指令都是固定的,并不能任意满足我们.当你需要对普通DOM元素进行底层操作,这个时候就会用到自定义指令(我们需要一个指令而框架还没有提供,就需要我们自己定义,称为“自定义指令”)。
指令对象提供了哪些钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind:只调用一次,指令与元素解绑时调用。
钩子函数可以传入哪些参数?
el:指令所绑定的元素,可以用来直接操作 DOM。binding:一个对象,包含以下 property:
name:指令名,不包括v-前缀。value:指令的绑定值,例如:v-my-directive="1 + 1"中,绑定值为2。oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如v-my-directive="1 + 1"中,表达式为"1 + 1"。arg:传给指令的参数,可选。例如v-my-directive:foo中,参数为"foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar中,修饰符对象为{ foo: true, bar: true }。vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用。 !!!! 除了el之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的dataset来进行。
注册方法
注意:当同一个元素及使用了全局指令和局部指令对统一属性进行操作的时候,会优先使用局部自定义指令,这里采用就近原则,局部指令会优先于全局指令对统一属性操作的调用。
- 全局注册
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus',
{
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
- 局部注册
directives: { focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
部分自定义指令代码实现
- 图片加载不出来,设置默认头像
Vue.directive('errorImg', {
inserted(el, binding) {
// console.log(el, 666)
// 元素加载执行的时候出现错误 就会触发这个事件 表示 资源加载失败
el.onerror = function() {
// 如果图片加载失败 就显示 默认图片 加载成功不用管
el.src = binding.value
}
}
})
- 通过自定义指令显示excel文件导出按钮是否显示
Vue.directive("arrow", {
inserted(el, binding) {
console.log(1111);
// 通过自定义指令显示excel文件导出按钮是否显示
// 通过传过来的showBtn,然后再points数组中查找,如果有就表示按钮有权限,没有就不显示按钮,没有权限
setTimeout(() => {
var points = store.state.user.userInfo.roles.points;
var flag = points.includes(binding.value);
if (!flag) {
//不显示====需要将按钮移除===不能自杀,需要父节点移除自己
el.parentNode.removeChild(el);
}
}, 1000);
},
});
- 鼠标放上显示被隐藏的元素 在tips标签
import Vue from 'vue'
// 鼠标放上显示对应的内容
Vue.directive('showTips', {
// el {element} 当前元素
componentUpdated (el) {
const curStyle = window.getComputedStyle(el, '') // 获取当前元素的style
const textSpan = document.createElement('span') // 创建一个容器来记录文字的width
// 设置新容器的字体样式,确保与当前需要隐藏的样式相同
textSpan.style.fontSize = curStyle.fontSize
textSpan.style.fontWeight = curStyle.fontWeight
textSpan.style.fontFamily = curStyle.fontFamily
// 将容器插入body,如果不插入,offsetWidth为0
document.body.appendChild(textSpan)
// 设置新容器的文字
textSpan.innerHTML = el.innerText
// 如果字体元素大于当前元素,则需要隐藏
if (textSpan.offsetWidth > el.offsetWidth) {
// 给当前元素设置超出隐藏
el.style.overflow = 'hidden'
el.style.textOverflow = 'ellipsis'
el.style.whiteSpace = 'nowrap'
// 鼠标移入
el.onmouseenter = function (e) {
// 创建浮层元素并设置样式
const vcTooltipDom = document.createElement('div')
vcTooltipDom.style.cssText = `
max-width:400px;
max-height: 400px;
overflow: auto;
position:absolute;
top:${e.clientY + 5}px;
left:${e.clientX}px;
background: rgba(0, 0 , 0, .6);
color:#fff;
border-radius:5px;
padding:10px;
display:inline-block;
font-size:12px;
z-index:19999
`
// 设置id方便寻找
vcTooltipDom.setAttribute('id', 'vc-tooltip')
// 将浮层插入到body中
document.body.appendChild(vcTooltipDom)
// 浮层中的文字
document.getElementById('vc-tooltip').innerHTML = el.innerText
}
// 鼠标移出
el.onmouseleave = function () {
// 找到浮层元素并移出
const vcTooltipDom = document.getElementById('vc-tooltip')
vcTooltipDom && document.body.removeChild(vcTooltipDom)
}
}
// 记得移除刚刚创建的记录文字的容器
document.body.removeChild(textSpan)
},
// 指令与元素解绑时
unbind () {
// 找到浮层元素并移除
const vcTooltipDom = document.getElementById('vc-tooltip')
vcTooltipDom && document.body.removeChild(vcTooltipDom)
}
})
使用
可以直接在需要的地方使用他(v-),
// v-arrow="'edit1'" 直接在这里使用 即可 edit1是自定义的 可以随便设置
//自定义的都是v-开头
//v-自定义指令的名称 这个名称必须要和你注册的时候 定义的名称一致
<el-button
v-arrow="'edit1'"
type="text"
size="small"
>编辑</el-button>