指令即 v- 的形式,除了内置指令例如 v-model、v-show 以外,vue 允许注册
自定义
的指令。自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。
- 防抖: n 秒后再执行该事件,若在 n 秒内被重复触发,则重新计时
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
1、在 src 文件夹下新建 utils 文件夹,用来存放公共方法或者 js 文件,utils 中新建一个 common.js 的文件,此处写防抖或节流函数。
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true表示立即执行,false表示非立即执行
*/
export function debounce(func , wait , immediate = true){
// 定义一个timeout计时器
let timeout
return function (){
// 如果 timer 有值,代表有执行过定时器,就将定时器清除
if(timeout) clearTimeout(timeout)
// 默认立即执行方法,延后执行的话,会让人感觉有卡顿
if(immediate){
// 定义现在是否能执行
let now = !timeout
if(now) func.apply(this, arguments)
// 不论timeout有没有值,都重新给timeout新添加一个定时器
// 等待wait时间后,将timeout设为null,代表可以继续执行次function
timeout = setTimeout(() => {
timeout = null
}, wait)
}else{
// 如果不是立即执行此函数,则在等待wait时间后执行方法
timeout = setTimeout(()=>{
func.apply(this, arguments)
}, wait)
}
}
}
2、然后在src目录下新建一个 directives 目录,里面再创建一个 index.js,用来存放项目中的全局指令。
directives 下的 index.js 先引入 Vue 构造器和 debounce 函数,然后创建 Vue 的全局指令,在 bind 钩子函数中获取到 dom 元素el,并为其增加 click 事件监听器和经过 debounce 处理后的函数。
import Vue from 'vue'
import { debounce } from '@/utils/common'
// 定义一个名为 debounce 的指令
Vue.directive('debounce', {
// 绑定的值为 el,和 binding
// binding 的值为指令绑定的值,binding 中有哪些值,可以去 vue 官网中查看自定义指令
bind(el, binding){
let execFunc
// 在函数传参与不传参调用的时候,打印出来的 binding.value 是不同的
// v-debounce="getCount" 时,binding.value 是函数
// v-debounce="getCount(index)" 时,binding.value 是 getCount(index) 的返回值,为 undefinded
// 所以传参时调用需要包一层,如 v-debounce="[() => {getCount(index)}]",这样取 [binding.value][0] 即为所需函数
console.log(binding.value)
if(binding.value instanceof Array){
// 函数传参
const [func , time = 500] = binding.value
execFunc = debounce(func, time)
}else{
// 函数不传参
console.log('函数不传参')
execFunc = debounce(binding.value, 500)
}
el.addEventListener('click', execFunc)
}
})
3、 全局注册
在 main.js 主入口中,引入 directives 中的内容,即完成
全局
自定义指令的注册。
import '@/directives'
4、使用
注册完成后,即可在需要应用防抖的地方使用自定义指令。
需要注意的是,使用v-debounce=“getCount(param)”这种写法时,相当于将this.getCount(param)的函数执行结果返还给了binding.value,导致后面报错。所以如果应用防抖的函数里面需要传参,应该在函数外面再包裹一层,如包裹成数组或者对象。
示例:v-debounce=”[() => { getCount(4) }, 500]”
(1)传参使用方式(如果不这么写的话,会返回函数执行完之后的返回值。):
<el-button v-debounce="[$ev => { getCount($ev, 4)}, 500 ]">传参,且获取事件的测试</el-button>
<el-button v-debounce="[() => { getCount(4)}, 500 ]">传参,不获取事件的测试</el-button>
(2)不传参使用方式:
<el-button v-debounce="getCount">不传参测试</el-button>
参考:
自定义指令 | Vue.js