Vue自定义指令使用记录
最近在研究自定义指令,开始使用的话遇到点小问题。慢慢看大佬的文章也慢慢的理解了。 首先就得掏出大佬封装的方法。后续的话自己写一点也不是问题。首先介绍的是全局指令,局部指令用的地方比较少。
自定义指令的钩子函数(生命周期)
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定被插入文档中)
- update:所在组件的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 钩子中可用。
生命周期应该类似(具体我也不太清楚,欢迎指正)
组件生命 | 自定义指令生命 |
---|---|
created | bind |
mounted | inserted |
BeforUpdate | update |
Update | componentUpdated |
destroy | unbind |
1.首先在src下建立directives/index.js
import Vue from "vue"
// 防抖钩子
Vue.directive('debounce', {
inserted: function(el, binding) {
let timer
el.addEventListener('click', () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
binding.value()
}, 1000)
})
},
})
// 验证input输入
let findEle = (parent, type) => {
return parent.tagName.toLowerCase() === type ? parent : parent.querySelector(type)
}
const trigger = (el, type) => {
const e = document.createEvent('HTMLEvents')
e.initEvent(type, true, true)
el.dispatchEvent(e)
}
Vue.directive('emoji', {
bind: function(el) {
// 正则规则可根据需求自定义
var regRule = /[^\u4E00-\u9FA5|\d|\r\n\s,.?!,。?!…—&$=()-+/*{}[\]]|\s/g;
let $inp = findEle(el, 'input');
el.$inp = $inp;
$inp.handle = function() {
let val = $inp.value;
$inp.value = val.replace(regRule, '');
trigger($inp, 'input');
}
$inp.addEventListener('keyup', $inp.handle);
},
unbind: function(el) {
el.$inp.removeEventListener('keyup', el.$inp.handle);
},
})
// 添加水印
function addWaterMarker(str, parentNode, font, textColor) {
// 水印文字,父元素,字体,文字颜色
var can = document.createElement('canvas')
parentNode.appendChild(can);
can.width = 200;
can.height = 150;
can.style.display = 'none';
var cans = can.getContext('2d');
cans.rotate((-20 * Math.PI) / 180);
cans.font = font || '16px Microsoft JhengHei';
cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)';
cans.textAlign = 'left';
cans.textBaseline = 'Middle';
cans.fillText(str, can.width / 10, can.height / 2);
parentNode.style.backgroundImage = 'url(' + can.toDataURL('image/png') + ')';
}
Vue.directive('waterMarker', {
bind: function(el, binding) {
addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor);
}
})
// 长按事件
Vue.directive('longpress', {
bind: function(el, binding) {
if (typeof binding.value !== 'function') {
throw 'callback must be a function'
}
// 定义变量
let pressTimer = null
// 创建计时器( 2秒后执行函数 )
let start = (e) => {
if (e.type === 'click' && e.button !== 0) {
return
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
handler()
}, 2000)
}
}
// 取消计时器
let cancel = () => {
if (pressTimer !== null) {
clearTimeout(pressTimer)
pressTimer = null
}
}
// 运行函数
const handler = (e) => {
binding.value(e)
}
// 添加事件监听器
el.addEventListener('mousedown', start)
el.addEventListener('touchstart', start)
// 取消计时器
el.addEventListener('click', cancel)
el.addEventListener('mouseout', cancel)
el.addEventListener('touchend', cancel)
el.addEventListener('touchcancel', cancel)
},
// 当传进来的值更新的时候触发
componentUpdated(el, {
value
}) {
el.$value = value
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('click', el.handler)
},
})
// 权限校验判断是否展示
function checkArray(key) {
let arr = ['1', '2', '3', '4']
let index = arr.indexOf(key)
if (index > -1) {
return true // 有权限
} else {
return false // 无权限
}
}
// 权限校验
Vue.directive('permission', {
inserted: function(el, binding) {
let permission = binding.value // 获取到 v-permission的值
if (permission) {
let hasPermission = checkArray(permission)
if (!hasPermission) {
// 没有权限 移除Dom元素
el.parentNode && el.parentNode.removeChild(el)
}
}
},
})
2.使用方法(我是全局的自定义指令)
在main.js里面(注意要在new Vue之前)
使用的话直接 v-指令名称就行了
- 有参数 v-指令名="123" 如(v-html="xxx")
- 没参数 v-指令名 如(v-focus)