在 Vue 中使用lodash对事件进行防抖和节流,防止用户重复点击按钮提交
一、防抖函数手动写
防抖函数定义:一个需要频繁触发的函数,在规定时间内只让最后一次生效,前面的不生效
/** * @param {*} fn 包装的事件回调函数 * @param {*} delay 等待时间 */ export function debounce(fn, delay) { // 记录上一次的延时器 var timer = null // 将debounce处理结果当作函数返回 return () => { // 保留调用时的this上下文 let context = this // 保留调用时传入的参数 let args = arguments // 每次事件被触发时,都去清除之前的旧定时器 if (timer) { clearTimeout(timer) } // 重新设置新的延时器 timer = setTimeout(() => { // 解决this指向问题 fn.apply(context, args) }, delay) } } // 用debounce来包装scroll的回调 const better_scroll = debounce(() => console.log('触发了滚动事件'), 1000)
注意:debounce 的问题在于它“太有耐心了”。试想,如果用户的操作十分频繁——他每次都不等 debounce 设置的 delay 时间结束就进行下一次操作,于是每次 debounce 都为该用户重新生成定时器,回调函数被延迟了不计其数次。频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感
用 Throttle 来优化 Debounce
// fn是我们需要包装的事件回调, delay是时间间隔的阈值 function throttle(fn, delay) { // last为上一次触发回调的时间, timer是定时器 let last = 0, timer = null // 将throttle处理结果当作函数返回 return function () { // 保留调用时的this上下文 let context = this // 保留调用时传入的参数 let args = arguments // 记录本次触发回调的时间 let now = +new Date() // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值 if (now - last < delay) { // 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器 clearTimeout(timer) timer = setTimeout(function () { last = now fn.apply(context, args) }, delay) } else { // 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应 last = now fn.apply(context, args) } } } // 用新的throttle包装scroll的回调 const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000) document.addEventListener('scroll', better_scroll)
二、在 Vue 里使用 lodash 中的 Debouncing 和 Throttling
安装
可以通过 yarn 或 npm 安装 lodash。
# Yarn
$ yarn add lodash
# NPM
$ npm install lodash --save
注意:如果我们不想导入lodash
的所有内容,而只导入所需的部分,则可以通过一些Webpack构建自定义来解决问题。 还可以使用lodash.throttle
和lodash.debounce
等软件包分别安装和导入lodash
的各个部分。
throttling 方法
要对事件进行节流处理方法非常简单,只需将要调用的函数包装在lodash的_.throttle
函数中即可。
<template> <button @click="throttledMethod()">Click me as fast as you can!</button> </template> <script> import _ from 'lodash' export default { methods: { throttledMethod: _.throttle(() => { console.log('I get fired every two seconds!') }, 2000) } } </script>
debouncing 方法
尽管节流在某些情况下很有用,但一般情况我们经常使用的是防抖。 防抖实质上将我们的事件分组在一起,并防止它们被频繁触发。 要在Vue组件中使用节流,只需将要调用的函数包装在lodash的_.debounce
函数中。
<template> <button @click="throttledMethod()">Click me as fast as you can!</button> </template> <script> import _ from 'lodash' export default { methods: { throttledMethod: _.debounce(() => { console.log('I only get fired once every two seconds, max!') }, 2000) } } </script>