转载自 几个问题
事件委托
- Walk the dog
- Pay bills
- Make dinner
- Code for one hour
做一下操作来将事件绑定到元素
document.addEventListener('DOMContentLoaded', function() {
let app = document.getElementById('todo-app');
let items = document.getElementByClassName('item');
for(let item of items) {
item.addEventListener('click', function () {
alert('you clicked on item: ' + item.innerHtml)
})
}
})
如果item有1000个,那就要用事件委托
下面是事件委托的代码
document.addEventListener('DOMContetentLoaded', function() {
let app = document,getElementById('too-app');
app.addEventListener('click', function (e) {
if (e.target && e.target.nodeName === "LI") {
let item = e.target;
alert("you clicked on item:" + item.innerHTML)
}
})
})
在循环中使用闭包
闭包基本上是内部函数可以访问其范围之外的变量。
编写一个函数,该函数将遍历整数列表,并在延迟3秒后打印每个元素的索引。
const arr = [10,12,15,21];
arr.map((v,i)=> {
setTimeout(function() {
console.log(i)
}, 3000)
})
使用for循环 - var
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
setTimeout(function (i) {
return function () {
console.log(i)
}
}(i), 3000)
}
使用for循环 - let
const arr = [10, 12, 15, 21];
for (let i = 0; i < arr.length; i++) {
setTimeout(function () {
console.log(i)
}, 3000)
}
事件的节流和防抖
节流
如果咱们不让点击事件一个时间段内重复触发,就可以用节流, 就是控制频率
定时器函数实现:
如果第一次执行,直接放行, 如果存在定时器就退出函数, 否则就执行定时器
const throttle = (fn,intervel) {
let isFirst = true,
timer = null;
return function () {
let arg = arguments, _me = this;
if (isFirst) {
fn.apply(_me, args);
isFirst = false;
}
if (timer) {
return false
}
timer = setTimout(() => {
window.clearTimeout(timer);
timer = null;
fn.apply(_me, args);
},intervel)
}
}
利用时间差, 若这一次执行的时间 减去 上一次的执行时间 大于某个时间
function throttle(fn, interval) {
let last = 0;
return function () {
let _me = this;
let args = arguments;
let now = +new Date();
if (now - last >= interval) {
last = now;
fn.apply(_me, args);
}
}
}
防抖
防止手抖点击多次只有最后一次生效
function debounce(fn, delay) {
let timer = null;
return function () {
let _me = this;
let args = arguments;
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
fn.apply(_me, args)
}, delay)
}
}
用throttle来优化Debounce
如果用户操作的频率十分频繁,不等debounce设置的delay时间结束就进行下一次操作,于是每一次debounce都会为该用户生成新的计时器,回调函数被延迟了不计无数次。频繁的延迟会导致用户迟迟得不到响应。
所以我们借力throttle的思想优化debounce, ---- delay时间内,我可以为你重新生成定时器,但只要delay时间到了,我必须要给用户一个响应。
// 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)