在vue2.x中,防抖和节流一般是通过引入防抖函数debounce
和节流函数throtte
,对事件回调进行一层包裹,然后在模板中绑定包裹后的事件回调,这样每个需要用的地方都需要进行防抖,节流函数的导入,事件回调的包裹,比较麻烦。通过摸索,有以下两种方法。
重写Vue.protyoep.$on方法
通过重写Vue.prototype.$on方法,统一对xx事件进行防抖和节流,(没试过,应该可行)
伪代码如下:
const oldOn = Vue.prototype.$on
Vue.prototype.$on = function(...args){
const event = args[0]
let fn = args[1]
if(某某条件){
fn = debounce(fn)
// fn = throttle(fn)
}
oldOn.call(this,fn)
}
通过指令包裹vnode的存放回调
使用方法,只需要在组件或者dom元素上对需要防抖或者节流的事件添加以下指令即可
v-debounce:事件.毫秒数
<input @click="fn" v-debounce:click.300 v-debounce:change.300 />
实现细节
/**
* 防抖函数
* @param {*} fn
* @param {*} wait 防抖间隔
* @param {*} immediate 立即执行
* @returns
*/
function debounce(fn, wait = 300, immediate = true) {
let t = null
let canChangeImmdiate = !!immediate
if (typeof fn !== "function") {
throw new TypeError("debounce 第一个参数必须是函数")
}
return function debounceFn(...args) {
t && clearTimeout(t)
if (immediate) {
if (!t) {
fn.apply(this, args)
immediate = false
}
} else {
t = setTimeout(() => {
fn.apply(this, args)
if (canChangeImmdiate) {
immediate = true
t = null
}
}, wait)
}
}
}
// 直接添加在组件或者元素上 v-debounce:click.300 v-debounce:change.300 300ms
// vue2.6.x在update中,vue2.7.x在insertd钩子中起作用
Vue.directive("debounce", {
update(el, bind, vnode) {
// 默认给click事件添加防抖
const { value: fn, arg = "click", modifiers } = bind
const { immediate = false } = modifiers
const modNumKeys = Object.keys(modifiers).filter((key) => !isNaN(+key))
const wait = modNumKeys.length > 0 ? modNumKeys[0] : 300
if (vnode.componentInstance) {
// 组件
for (const [evtName, handlers] of Object.entries(vnode.componentInstance._events)) {
if (arg == evtName) {
vnode.componentInstance._events[evtName] = handlers.map((handler) =>
debounce(handler, wait, immediate)
)
}
}
} else {
// dom元素
for (const [evtName, handler] of Object.entries(vnode.data.on)) {
if (evtName == arg) {
if (Array.isArray(vnode.data.on[arg].fns)) {
vnode.data.on[arg].fns = vnode.data.on[arg].fns.map((fn) =>
debounce(fn, wait, immediate)
)
} else {
console.log(wait, immediate)
vnode.data.on[arg].fns = debounce(vnode.data.on[arg].fns, wait, immediate)
}
}
}
}
}
})