前言
本篇文章先介绍一下插件库 underscore.js里面的两个方法,然后根据个人需要封装项目需求的防抖节流
函数
_.debounce(function, wait, [immediate])
插件库封装的防抖函数,里面有3个参数分别是
function是将要被执行防抖的函数wait是防抖间隔时间单位毫秒immediate参数为true的时候第一次触发传入的function立即执行
_.throttle(function, wait, [options])
插件库封装的节流函数分别是
-
function是将要被执行节流的函数 -
wait是节流间隔时间单位毫秒 -
options参数有两个 如果传{leading: false}的会禁用第一次首先执行如果传{leading: false}则会禁用最后一次执行
两种函数如果想取消就调用 .cancel()方法
封装
防抖函数
介绍
时间相应函数在一段时间后才执行,如果在这段时间内再次调用,则重新计算执行时间 当预定时间没有再次调用该函数,则执行函数 (类似属于王者荣耀的回城,频繁点击会时终止回城操作,只有等待响应的时间才会触发完成回城操作)
应用场景
- scroll事件滚动触发
- 搜索框输入查询
- 表单验证
- 按钮提交时间
- 浏览器窗口缩放,resize事件
封装
因为 underscore.js 包实在是太大了如果只用这个两个方法会当用户进入首次进入页面的时候加载时间会加载时间过长导致用户体验非常不好所以自己学着封装函数
1function debounce(func, wait, immediate) {
2 //声明定时器,和返回参数
3 var timeout, result
4 //声明返回函数
5 let decounced = function () {
6 //获取执行事件的this方便用来改变传入的func的this指向
7 let _this = this
8 //获取执行函数的e的时间事件对象像
9 let args = arguments
10 //重点:如果频繁触发事件就会先停止并重置定时器只有等待wait时间不执行时间才能触发被执行行发func这样就达到了防抖效果
11 timeout && clearTimeout(timeout)
12 //判断如果immediate是true就走立刻执行的函数
13 if (immediate) {
14 //加一个执行立刻执行判断逻辑,当第一次执行次函数 timeout 为 underfined 时取反
15 let callNow = !timeout
16 //在给timeout 赋值一个定时器 让其wait时间以后清除自己这样 timeout 又为空 取反callNow又为true 才能执行传入的函数
17 timeout = setTimeout(() => {
18 timeout = null
19 }, wait);
20 // callNow因为第一次没有定时器所以取反为true 这时就调用 传入执行的func 但如果定时定时器没被销毁则不触发传入的执行函数
21 if (callNow) result = func.apply(_this, args)
22 } else {//如果没有就执行默认的防抖函数
23 //定义等待wait时间去执行定时器
24 timeout = setTimeout(() => {
25 //调用原生js的apply改变this指向并赋值传递的参数用来获取事件e的对象
26 func.apply(_this, args)
27 }, wait);
28 }
29 return result
30 }
31 //封装停止防抖操作cancek方法
32 decounced.cancel = function () {
33 //暂停并重置定时器
34 clearTimeout(timeout)
35 //清除定时器
36 timeout = null
37 }
38 return decounced
39}
40}
节流函数
介绍
如果你持续触发事件,每隔一段时间,只执行一次事件 (类似属于吃鸡的98k射击,频繁点击开火可是98k只会按照固定开枪间隔进行开火)
应用场景
- DOM元素的拖拽功能的实现
- 射击游戏
- 计算鼠标移动的距离
- 监听scroll滚动事件
封装
因为这里我觉的目前项目不需要太复杂的节流函数所以我封装了相对简单的防抖函数
1 function thorttle(func, wait) {
2 //声明_this 和 args 下面更改this指向和获取传入func函数
3 let _this, args;
4 let old = 0;
5 return function () {
6 _this = this
7 args = arguments
8 //当触发第一次函数的时候获取一下当期的时间戳
9 let now = new Date().valueOf();
10 //重点:判断如果当前的时间 减去 上一次操作的时间戳 大于 传入的时间戳 wait 才执行 传入的func
11 if (now - old > wait) {
12 //因为第一次 old的时间戳为0 所以立刻执行传入的函数,
13 func.apply(_this, args)
14 //执行完毕以后记录当前的时间戳并赋值给 odl(判断变量)
15 old = now
16
17 }
18 }
19 }