vue2.x通过指令实现v-debounce和v-throttle防抖节流的实现,亲测可用。

在vue2.x中,防抖和节流一般是通过引入防抖函数debounce和节流函数throtte,对事件回调进行一层包裹,然后在模板中绑定包裹后的事件回调,这样每个需要用的地方都需要进行防抖,节流函数的导入,事件回调的包裹,比较麻烦。通过摸索,有以下两种方法。

重写Vue.protyoep.$on方法

通过重写Vue.prototype.$on方法,统一对xx事件进行防抖和节流,(没试过,应该可行)

伪代码如下:

javascript 复制代码
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:事件.毫秒数

html 复制代码
<input @click="fn" v-debounce:click.300 v-debounce:change.300 />

实现细节

javascript 复制代码
/**
 * 防抖函数
 * @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)
          }
        }
      }
    }
  }
})
相关推荐
计算机毕设定制辅导-无忧学长8 小时前
《基于SpringBoot青年公寓出租管理系统的设计与实现》
java·vue.js·spring boot·青年公寓出租管理系统
宿6749 小时前
vue3-config
前端·javascript·vue.js
ShineWinsu12 小时前
对于 Vue 3:从为什么学 Vue,到声明式渲染与数据响应式的解析
前端·javascript·vue.js
leoZ23114 小时前
第 6 篇:SchemaForm 渲染器核心实现
前端·javascript·vue.js·人工智能·神经网络·机器学习·自然语言处理
CoderYanger14 小时前
前端基础——JavaScript(基础语法)(下篇)
java·开发语言·前端·javascript·程序人生·面试·职场和发展
还是大剑师兰特14 小时前
vue项目浏览器版本判别,低于IE11跳转到新页面
前端·javascript·vue.js
想吃火锅100514 小时前
【leetcode】42.接雨水js
开发语言·javascript·ecmascript
雪芽蓝域zzs16 小时前
第十六节:递归组件实现无限层级折叠侧边栏菜单
开发语言·javascript·ecmascript
BillKu17 小时前
vue3 字符串排序 localeCompare,确保排序为 “B01“, “B10“, “B2“
前端·javascript·vue.js
Nayana17 小时前
《Web 到 HarmonyOS》-- 第一课:前端经验哪些能带走
vue.js·harmonyos