请手写去抖和节流两个通用函数
2019-07-03 本文已影响0人
LeoMelody
这篇文章是手写实现xxx功能部分的第二篇,后续会陆续更新其他的。
考察点: 去抖和节流的理解以及应用场景
去抖和节流
去抖和节流是前端非常常用的工具方法。去抖可以保证一个操作不会不停地触发而节流可以保证在一段时间内一个操作只能触发一次。
节流应用场景
节流应用场景最多就是页面上的事件处理了。比如鼠标滑动事件的监听,页面滚动事件的监听等等。
这里就拿页面滚动这个例子来说。这里我们实现一个常见的读书的那种web页面的头部导航条。效果可以看这里
相应实例代码:
// HTML
<body>
<div id="nav"></div>
<div id="wrap"></div>
</body>
// CSS
#wrap {
background: red;
width: 300px;
height: 3300px;
margin: 0 auto;
}
#nav {
height: 10px;
background: greenyellow;
position: fixed;
top: 0;
left: 0;
width: 1px;
}
// JS
;(function() {
// 获取屏幕高度和宽度 之所以用这个高度,是因为这个height = screenHeight + 滚动到底部是的window.scrollY
// 计算出可滚动的高度
const height = document.documentElement.scrollHeight
const width = document.documentElement.scrollWidth
const screenHeight = document.documentElement.clientHeight
const scrollHeight = height - screenHeight
const nav = document.querySelector('#nav')
window.addEventListener('scroll', function(e) {
let currentHeight = window.scrollY
nav.style.width = currentHeight/scrollHeight * width + 'px'
})
})()
但是这种实现方式会非常频繁的修改DOM,这时候节流函数就体现处它的价值了。在这里,我直接就写节流函数的通用方法
// 节流函数
const throttle = function(fn, timer = 500) {
let setTimeoutTimer
return function() {
if (setTimeoutTimer) return
// 这行代码是为了方便在Vue这类框架中使用节流函数
fn && fn.call(this, ...arguments)
setTimeoutTimer = setTimeout(() => {
setTimeoutTimer = null
}, timer)
}
}
// 用法:将触发时间修改为50ms触发一次
window.addEventListener('scroll', throttle(function(e) {
let currentHeight = window.scrollY
nav.style.width = currentHeight/scrollHeight * width + 'px'
}, 50))
上面还有提到在Vue这类框架中用到这个节流函数的用法,我用setInterval模拟事件触发,一个简单的demo
let vue = {
data: {
name: 'wyh'
},
say(x) {
console.log(this.data.name + x)
}
}
let fn = throttle(vue.say, 500)
setInterval(() => {
fn.call(vue, 'x')
}, 100)
去抖应用场景
个人认为去抖在平常开发中要用的更多,最常见的场景就是动态输入搜索(类似百度)这类功能的开发。这里就不做无去抖的效果展示了
去抖通用函数
function debounce(fn, timer = 500) {
let debounceTimer
return function() {
if (debounceTimer) {
clearTimeout(debounceTimer)
}
// 参数缓存
let args = arguments
debounceTimer = setTimeout(() => {
fn && fn.call(this, ...args)
}, timer)
}
}
实例场景
// html
<input type="text" id="input" />
// javascript
;(function() {
const i = document.querySelector('#input')
// 模拟Vue环境
let vue = {
data: {
searchStr: ''
},
/**
* 模拟搜索方法
*/
search() {
console.log(`正在以${this.data.searchStr}为检索值进行搜索`)
}
}
let searchFn = debounce(vue.search)
i.addEventListener('input', function(e) {
// 模拟v-model
vue.data.searchStr = i.value
searchFn.call(vue)
})
})()
效果 记得打开下面的console看