防抖与节流,应用场景有很多,例如:禁止重复提交数据的场景、搜索框输入搜索条件,待输入停止后再开始搜索。



防抖

  • 点击button按钮设置定时器,在规定的时间内再次点击会重置定时器重新计时,在规定的时间没有再次点击才执行相关函数。
  • 规定时间内最后一次点击有效。

节流

  • 点击button按钮执行相关函数。设置定时器,在规定的时间内连续点击均无效,定时器过后,可以再次点击。
  • 规定时间内可点击一次(第一次点击有效)。


案例-防抖

Vue项目中使用自定义指令实现(按钮)防抖功能。

应用场景:搜索框输入搜索条件,待输入停止后再开始搜索。

/*
*  防抖,规定时间内最后一次点击有效。
*  @param {?Number|300} time - 间隔时间,毫秒
*  @param {Function} fn - 执行函数
*  @param {?String|"click"} event - 事件类型 例:"click"
*  @param {Array} binding.value - [fn,event,time]
*  例:<el-button v-debounce="[resetData,`click`,300]">刷新</el-button>
*  也可简写成:<el-button v-debounce="[resetData]">刷新</el-button>
*/
// 注册一个全局自定义指令 `v-debounce`
Vue.directive('debounce', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el, binding) {
    //binding.value,使用自定义指令v-debounce时填写的参数
    //解构赋值,定义了3个变量,将参数(数组)按顺序进行赋值
    let [fn, event = "click", time = 300] = binding.value
    let timer
    el.addEventListener(event, () => {
      //默认监听的事件为click
      //判断计时器是否存在,存在则清除计时器。重新创建计时器,到时间后执行函数fn
      if(timer){
        clearTimeout(timer)
      }
      timer = setTimeout(() => fn(), time)
    })
  }
})


案例-节流

Vue项目中使用自定义指令实现(按钮)节流功能。

应用场景:click事件,禁止重复提交数据的场景。

/*
*  节流,规定时间内可点击一次(第一次点击有效)。
*  @param {?Number|300} time - 间隔时间,毫秒
*  @param {Function} fn - 执行函数
*  @param {?String|"click"} event - 事件类型 例:"click"
*  @param {Array} binding.value - [fn,event,time]
*  例:<el-button v-throttle="[resetData,`click`,300]">刷新</el-button>
*  传递参数则:<el-button v-throttle="[()=>resetData(param),`click`,300]">刷新</el-button>
*/
// 注册一个全局自定义指令 `v-throttle`
Vue.directive('throttle', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function(el, binding) {
    //binding.value,使用自定义指令v-throttle时填写的参数
    //解构赋值,定义了3个变量,将参数(数组)按顺序进行赋值
    let [fn, event = "click", time = 300] = binding.value
    let timer = null;
    el.addEventListener(event, () => {
      //默认监听的事件为click
      //判断计时器是否存在,不存在则执行函数fn,创建计时器
      if (timer == null) {
        fn();
        timer = setTimeout(() => timer = null, time)
      }
    })
  }
})


//方案二
/**
 * 按钮节流
 * 3秒内只有第一次点击有效,防止重复提交数据。
 */
//注册一个全局自定义指令 `v-throttle-disabled`
Vue.directive('throttle-disabled', {
	// 当被绑定的元素插入到 DOM 中时……
	inserted(el, binding) {
		let [event = "click", time = 2 * 1000] = binding.value
		el.addEventListener(event, () => {
			//默认监听click事件
			//当 dom元素el 非禁用状态时 将其设置为禁用状态,同时设置计时器,规定时间后(默认2秒)启用。
			if (!el.disabled) {
				el.disabled = true
				setTimeout(() => {
					el.disabled = false
				}, time)
			}
		})
	}
})


组件中使用

在.vue文件中,data、methods同级的位置,添加如下配置:

,
directives: {
	debounce: {//自定义指令名,v-debounce
		// 指令的定义
    inserted: function(el, binding) {
      //binding.value,使用自定义指令v-throttle时填写的参数
      //解构赋值,定义了3个变量,将参数(数组)按顺序进行赋值
      let [fn, event = "click", time = 300] = binding.value
      let timer = null;
      el.addEventListener(event, () => {
        //默认监听的事件为click
        //判断计时器是否存在,不存在则执行函数fn,创建计时器
        if (timer == null) {
          fn();
          timer = setTimeout(() => timer = null, time)
        }
      })
    }
	}
},


全局引入

新建js文件

在项目中新建 myDirective.js 文件。通过export default暴露出来。

/*
 * @Author: qsdbl
 * @Date: 2022-02-10
 * @Description: 添加全局自定义指令。
 * 防抖,v-debounce。节流,v-throttle、v-throttle-disabled(可能无效)。
 * 示例:<el-button v-throttle="[resetData]">刷新</el-button>,使用默认配置,监听click事件,300毫秒内只会执行一次函数resetData
 * 传递参数:<el-button v-throttle="[()=>resetData(param)]">刷新</el-button>
 */
export default {
	install(Vue, Options) {
		/*
		 *  防抖,规定时间内(默认300毫秒)最后一次点击有效。
		 *  @param {?Number|300} time - 间隔时间,毫秒
		 *  @param {Function} fn - 执行函数
		 *  @param {?String|"click"} event - 事件类型 例:"click"
		 *  @param {Array} binding.value - [fn,event,time]
		 *  例:<el-button v-debounce="[resetData,`click`,300]">刷新</el-button>
		 *  也可简写成:<el-button v-debounce="[resetData]">刷新</el-button>
		 */
		// 注册一个全局自定义指令 `v-debounce`
		Vue.directive('debounce', {
			// 当被绑定的元素插入到 DOM 中时……
			inserted: function(el, binding) {
				//binding.value,使用自定义指令v-debounce时填写的参数
				//解构赋值,定义了3个变量,将参数(数组)按顺序进行赋值
				let [fn, event = "click", time = 300] = binding.value
				let timer
				el.addEventListener(event, () => {
					//默认监听的事件为click
					//判断计时器是否存在,存在则清除计时器。重新创建计时器,到时间后执行函数fn
					if (timer) {
						clearTimeout(timer)
					}
					timer = setTimeout(() => fn(), time)
				})
			}
		})

		/*
		 *  节流,规定时间内可点击一次(第一次点击有效)。
		 *  @param {?Number|300} time - 间隔时间,毫秒
		 *  @param {Function} fn - 执行函数
		 *  @param {?String|"click"} event - 事件类型 例:"click"
		 *  @param {Array} binding.value - [fn,event,time]
		 *  例:<el-button v-throttle="[resetData,`click`,300]">刷新</el-button>
		 *  传递参数则:<el-button v-throttle="[()=>resetData(param),`click`,300]">刷新</el-button>
		 */
		// 注册一个全局自定义指令 `v-throttle`
		Vue.directive('throttle', {
			// 当被绑定的元素插入到 DOM 中时……
			inserted: function(el, binding) {
				//binding.value,使用自定义指令v-throttle时填写的参数
				//解构赋值,定义了3个变量,将参数(数组)按顺序进行赋值
				let [fn, event = "click", time = 300] = binding.value
				let timer = null;
				el.addEventListener(event, () => {
					//默认监听的事件为click
					//判断计时器是否存在,不存在则执行函数fn,创建计时器
					if (timer == null) {
						fn();
						timer = setTimeout(() => timer = null, time)
					}
				})
			}
		})

		/*
		 *  节流方案二,通过禁用html标签,规定时间内可点击一次(第一次点击有效)。
		 *  应用在封装的组件中可能无效。
		 *  @param {?String|"click"} event - 事件类型 例:"click"
		 *  @param {?Number|2000} time - 间隔时间,毫秒
		 *  @param {Array} binding.value - [event,time]
		 *  例:<button v-throttle-disabled="[]">测试按钮</button>
		 */
		//注册一个全局自定义指令 `v-throttle-disabled`
		Vue.directive('throttle-disabled', {
			// 当被绑定的元素插入到 DOM 中时……
			inserted(el, binding) {
				let [event = "click", time = 2 * 1000] = binding.value
				el.addEventListener(event, () => {
					//默认监听click事件
					//当 dom元素el 非禁用状态时 将其设置为禁用状态,同时设置计时器,规定时间后(默认2秒)启用。
					if (!el.disabled) {
						el.disabled = true
						setTimeout(() => {
							el.disabled = false
						}, time)
					}
				})
			}
		})
	}
}

配置main.js文件

在入口文件main.js引入

//引入自定义指令,方便全局使用
import myDirective from '@/static/js/myDirective.js';
Vue.use(myDirective);

使用

这样就可以全局使用myDirective.js里面的自定义指令了,示例:

<button v-debounce="[debounceTest,`click`,3000]">测试按钮-3</button>
<button v-debounce="[()=>debounceTest('hi')]">测试按钮</button>


笔记学习自:51CTO-JackieDYHvue 全局、局部引入

Logo

前往低代码交流专区

更多推荐