您如何像jQuery库一样实现延迟? -我知道这个问题已经问过很多次了,但是还没有人见过使用async/await
或ES6样式来实现它。让我知道你是否有想法
//create a jquery like library
class DOM {
constructor(selector){
this.elements = [];
if(!selector){
return;
} else if(selector === 'document' || selector === 'window'){
this.elements = [selector];
} else {
this.elements = Array.from(document.querySelectorAll(selector));
}
}
on(){
console.log('on');
return this;
}
get(){
console.log('get');
return this;
}
delay(ms, callback){
//how to implement this? how to chain result of callback onto next chain?
console.log('delay');
const promise = Promise.resolve();
return promise.then(function(resolve) {
setTimeout(function(){
resolve(this);
}, ms);
});
}
}
const $ = function(selector) {
return new DOM(selector);
}
$('document').on().delay(10000).get()
答案 0 :(得分:2)
您可能根本不需要promise或async/await
,我认为您可以创建一个代理对象来拦截后续调用。
这个想法是,当调用.delay(duration)
时,它将返回一个代理对象而不是类实例。该代理对象将拦截方法调用,为duration
设置超时,然后使用原始的类实例调用该方法。
class J {
constructor(selector) {
this.$element = document.querySelector(selector)
}
delay(duration) {
const proxy = new Proxy(this, {
get: (target, prop) => {
const f = target[prop]
return (...args) => {
setTimeout(() => {
return f.apply(target, [...args])
}, duration)
// return the class instance again, so subsequent call & delay still works
return this
}
}
})
return proxy
}
text(content) {
this.$element.textContent = content
return this
}
}
const $ = selector => new J(selector)
$('#test').text('hello').delay(1000).text('world')
<div id="test"></div>
答案 1 :(得分:1)
您可以维护仍要在所选元素上执行的功能队列。这样,您可以允许链中出现多个延迟,还可以让客户端停止操作。
可以使用代理来“装饰”有意义的方法,以便可以将它们放置在队列中,而不是在计时器仍处于活动状态时执行。
这是看起来如何:
class DOM {
constructor(selector) {
this.elements = typeof selector === "object" ? [selector]
: selector === 'document' || selector === 'window' ? [document]
: Array.from(document.querySelectorAll(selector));
this.delayed = false;
this.queue = [];
const proxy = new Proxy(this, {
get(obj, prop) {
return !["css","show","hide","delay"].includes(prop) || !obj.delayed ? obj[prop]
: function (...args) {
obj.queue.push(() => proxy[prop](...args));
return this;
}
}
});
return proxy;
}
each(cb) {
this.elements.forEach(cb);
return this;
}
css(name, value) {
return this.each(elem => elem.style[name] = value);
}
show() {
return this.css("display", "");
}
hide() {
return this.css("display", "none");
}
on(eventType, cb) {
return this.each(elem => elem.addEventListener(eventType, cb.bind(elem)));
}
delay(ms) {
this.delayed = true;
setTimeout(() => {
this.delayed = false;
while (this.queue.length && !this.delayed) this.queue.shift()();
}, ms);
return this;
}
stop() {
this.queue.length = 0;
return this;
}
}
const $ = selector => new DOM(selector);
const $span = $('#demo').hide();
for (let i = 0; i < 100; i++) {
$span.delay(500).show()
.delay(500).css("color", "red")
.delay(500).css("color", "blue")
.delay(500).hide();
}
$("#stop").on("click", function () {
$span.stop();
$(this).hide();
});
<div>This is a <span id="demo">colorful </span>demo</div>
<button id="stop">Stop</button>