背景
除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
自定义指令基本用法
vue2全局注册
main.js文件
Vue.directives('focus',{
bind(el, binding, vnode) {
el.focus()
}
})
vue2局部注册
export default {
data () {
return {
name:'我是名字',
}
},
directives:{
test:{
// 指令的定义
inserted: function (el, binding) {
// el为绑定元素,可以对其进行dom操作
console.log(binding) // binding 一个对象,包含很多属性
},
bind: function (el, binding, vnode) {
el.innerHTML =binding.value
}
}
}
}
vue2生命周期
- bind:只调用一次,指令第一次绑到元素调用,用于初始化
- inserted:被绑定元素插入父节点时调用
- update:所在组件vnode更新调用
- componentUpdate:指令在组件的vnode及子组件的vnode全部更新完调用
- ubind:只调用一侧,指令解绑
vue3全局注册
main.js文件
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.directive('focus', {
created(el, binding) {
el.style.backgroundColor = binding.value.color;
console.log(el, binding.value.color);
//<input type="text" style="background-color: red;"> 'red'
}
})
app.mount('#app')
vue3局部注册
<template>
<input type="text" v-focus="{ color: 'red' }" />
</template>
<script setup>
const vFocus = {
created(el, binding) {
el.style.backgroundColor = binding.value.color;
console.log(el, binding.value.color);
//<input type="text" style="background-color: red;"> 'red'
},
};
</script>
vue3生命周期
- created 元素初始化的时候
- beforeMount 指令绑定到元素后调用 只调用一次
- mounted 元素插入父级dom调用
- beforeUpdate 元素被更新之前调用
- update 这个周期方法被移除 改用updated
- beforeUnmount 在元素被移除前调用
- unmounted 指令被移除后调用 只调用一次
使用场景
防抖
防抖:在第一次触发事件时,不立即执行函数,在某个特定的时间之后执行,下一次触发重新计数,计数结束执行函数。可以实现输入框的onchange事件
Vue.directive('debounce', {
inserted: function (el, binding) {
let timer, flag;
el.addEventListener('click', () => {
if (!flag) {
flag = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
typeof binding.value === 'function' && binding.value();
flag = false;
}, 2000) //可通过指令传值设置计时时间
}
})
}
})
节流
节流(throttle):就是指连续触发事件但是在 n 秒中只执行一次函数。
/** 发送验证码 **/
Vue.directive('throttle', {
inserted: function (el, binding) {
let timer, flag;
el.addEventListener('click', () => {
if (!flag) {
flag = true;
typeof binding.value === 'function' && binding.value();
timer && clearTimeout(timer);
timer = setTimeout(() => {
flag = false;
}, 2000)
}
})
}
})
图片懒加载
具体实现代码
<template>
<div>
<div class="lazy">
<div class="lazy-li"> <img v-lazyLoad="imgAddress" alt="" /></div>
<div class="lazy-li"> <img v-lazyLoad="imgAddress" alt="" /></div>
</div>
</div>
</template>
<script>
export default {
directives: { // 局部自定义指令
LazyLoad:{
// IntersectionObserver可以获取到当前的位置信息
let lazyImageObserver = new IntersectionObserver((entries, observer) => {
console.log(observer)
entries.forEach((entry, index) => {
console.log(index)
let lazyImage = entry.target;
// 相交率,默认是相对于浏览器视窗
if(entry.intersectionRatio > 0) {
lazyImage.src = binding.value;
// 当前图片加载完之后需要去掉监听
lazyImageObserver.unobserve(lazyImage);
}
})
})
lazyImageObserver.observe(el);
}
},
data(){
return{
}
},
methods:{
}
}
</script>
按钮权限
核心代码
// <button v-permission="'1'">权限按钮1</button>
// main.js
/** 判断是否有权限
export function checkArray (key) {
let arr = ['1', '2']
let index = arr.indexOf(key)
if (index > -1) {
return true // 有权限
} else {
return false // 无权限
}
}
**/
Vue.directive("permission", {
inserted (el, binding) {
let permission = binding.value; // 获取到 v-permission的值
if (permission) {
// checkArray用来判断是否有权限
let hasPermission = checkArray(permission);
if (!hasPermission) { // 没有权限 移除Dom元素
el.parentNode && el.parentNode.removeChild(el);
}
}
}
});