尝试优化某些JS的UX,包括使用事件委托和限制-但似乎无法结合使用这些方法。 我正在寻找一种监听事件(滚动,鼠标移动等),识别元素然后调用相关函数(限制)的方法。
我已经尝试了各种方法,包括尝试添加包装器/中间函数(处理程序)以传递多个函数-但是最终结果是相同的……我最终从Throttle函数中获得了任何回报。
我设法上班的唯一方法是产生一个多油门功能,在该功能中,我希望重复使用每个要油门的功能手动重复油门功能。
function mythrottle() {
var timer1, timer2;
return function() {
var now = Date.now();
var last1 = timer1;
var last2 = timer2;
if(!last1) { timer1 = now; callback1(); return; }
if(!last2) { timer2 = now; callback2(); return; }
if(last1 + 500 > now) { return; }
timer1 = now; callback1();
if(last2 + 1500 > now) { return; }
timer2 = now; callback2();
}
}
function callback1(){
console.log("callback 1 firing");
}
function callback2(){
console.log("callback 2 firing");
}
window.addEventListener('scroll', mythrottle());
理想情况下,我想要; 1)每个事件一个事件监听器 2)过滤/限定事件的能力(单击按钮或链接或跨度等) 3)然后使用特定函数(取决于过滤器/限定符)调用油门函数,并传递函数和延迟 4)节流阀延迟处理事件(立即着火,然后等待)
这将避免我当前要做的事情,即复制并为每个单独的东西准备好几个小块(并且我必须用限定符/过滤器包装每个!)。
答案 0 :(得分:0)
有很多方法可以完成您想做的事情。无论如何,要使其动态工作(添加/删除/配置回调),您需要一个状态。这就是为什么我将所有内容都包装在一个类中的原因。
将分别跟踪每个回调(以使每个请求具有不同的延迟)。实例化之后,您可以添加更多的回调和/或事件。显然,可以扩展/改进此示例,但是我认为这是一个好的开始,它应该满足您的所有要求。
如果您对以下代码有任何疑问,请随时提出,我们将很乐意回答。
// -- THROTTLER --
class Throttler {
constructor(args) {
this.queue = [];
this.throttle = typeof args.throttle === "number" ? args.throttle : 500; // GLOBAL THROTTLE
this.threshold = typeof args.threshold === "number" ? args.threshold : 50; // GLOBAL THRESHOLD
// BIND METHODS
this.addCallback = this.addCallback.bind(this);
this.addEvent = this.addEvent.bind(this);
this.handler = this.handler.bind(this);
if (Array.isArray(args.queue)) {
// SETUP INITIAL CALLBACKS
args.queue.forEach(this.addCallback);
}
if (Array.isArray(args.events)) {
// SETUP INITIAL EVENTS
args.events.forEach(this.addEvent);
}
}
addCallback(cb) {
if (typeof cb === "function") {
this.queue.push({
throttle: this.throttle,
threshold: this.threshold,
callback: cb,
timer: null,
ref: Date.now(),
elapsed: 0
});
} else if (typeof cb === "object") {
this.queue.push({
throttle: cb.debounce ? undefined : this.throttle,
threshold: this.threshold,
...cb,
timer: null,
ref: Date.now(),
elapsed: 0
});
}
}
addEvent(eventName) {
// ATTACH HANDLER
window.addEventListener(eventName, this.handler);
}
handler(e) {
this.queue.forEach((elem) => {
const NOW = Date.now();
if (typeof elem.throttle === "number") { // THROTTLE
elem.elapsed += NOW - elem.ref;
elem.ref = NOW;
if (elem.elapsed >= elem.throttle) {
// EXECUTE CALLBACK
if (typeof elem.callback === "function") {
if (typeof elem.selector !== "string" || (typeof e.target.matches === "function" && e.target.matches(elem.selector))) {
if (typeof elem.eventName !== "string" || e.type === elem.eventName) {
elem.callback(e);
}
}
}
// RESET COUNTER
elem.elapsed = 0;
}
// KILL TIMER
elem.timer && clearInterval(elem.timer);
// RE-CREATE TIMER
elem.timer = setTimeout(() => {
// RESET COUNTER
elem.elapsed = 0;
// RESET TIMER
elem.timer = null;
}, elem.threshold);
} else if (typeof elem.debounce === "number") { // DEBOUNCE
// KILL TIMER
elem.timer && clearInterval(elem.timer);
// RE-CREATE TIMER
elem.timer = setTimeout(() => {
// EXECUTE CALLBACK
if (typeof elem.callback === "function") {
if (typeof elem.selector !== "string" || (typeof e.target.matches === "function" && e.target.matches(elem.selector))) {
if (typeof elem.eventName !== "string" || e.type === elem.eventName) {
elem.callback(e);
}
}
}
// RESET TIMER
elem.timer = null;
}, elem.debounce);
}
});
}
}
// --- USAGE ---
// INSTANTIATE THROTTLER
const myThrottler = new Throttler({
throttle: 1500,
events: ['scroll', 'mousemove'],
queue: [callback1, callback2]
});
// ADD ANOTHER EVENT
myThrottler.addEvent('resize');
// ADD CONDITIONAL CALLBACK
myThrottler.addCallback({
callback: callback3,
selector: '*',
eventName: 'mousemove'
});
// ADD CUSTOM DELAY DEBOUNCED CALLBACK
myThrottler.addCallback({
callback: callback4,
debounce: 2000
});
// ADD CUSTOM DELAY THROTTLED CALLBACK
myThrottler.addCallback({
callback: callback5,
throttle: 3000
});
// --- CALLBACKS ---
function callback1() {
console.log("CB 1");
}
function callback2() {
console.log("CB 2");
}
function callback3() {
console.log("CB 3");
}
function callback4() {
console.log("CB 4");
}
function callback5() {
console.log("CB 5");
}