我做的事情显然是错误的,但无法向我自己解释。
目标是收听点击事件(START,first)。如果用户单击“开始”,则第二个单击侦听器应该已准备就绪,但只有在单击特定元素时才会触发。如果第二次单击发生在外部,则应再次删除第二次单击事件侦听器。
听起来很简单,这是我的问题:
script
开火?
document.body.addEventListener('click'
var Blubb = function(element){
this.element = element;
document.addEventListener('make-ready', this.makeBlubbReady.bind(this), false);
};
Blubb.prototype.makeBlubbReady = function(){
var options = {one: true, two: false };
this.element.classList.remove('disabled');
this.element.addEventListener('click', (function(){this.go(options)}).bind(this), false);
document.body.addEventListener(
'click',
(function(event){
console.log('This shouldn\'t be ready before clicking "start"');
if(event.target == this.element) {
return;
}
this.element.removeEventListener('click', this.go)
}).bind(this),
false
);
};
Blubb.prototype.go = function(options){
console.log('Blubb go, options.one: ', options.one);
};
document.querySelector('.first').addEventListener('click', function(){
new Blubb(document.querySelector('.second'));
document.dispatchEvent(new CustomEvent('make-ready', {}));
}, false)
.second.disabled {
display: none;
}
接下来几乎和上面一样。只是为了解释1.问题。为什么<div class="first">START</div>
<br />
<div class="second disabled">BLUBB</div>
只在身体上设置事件监听器时记录console
?我期望在3
上设置事件监听器,它也只是等待获得点击事件..
this.element
var Blubb = function(element){
this.element = element;
document.addEventListener('make-ready', this.makeBlubbReady.bind(this), false);
};
Blubb.prototype.makeBlubbReady = function(){
var options = {one: true, two: false };
this.element.classList.remove('disabled');
console.log('1');
this.element.addEventListener('click', (function(){
console.log('2');
this.go(options)
}).bind(this), false);
document.body.addEventListener('click', (function(){
console.log('3');
}).bind(this),
false
);
};
Blubb.prototype.go = function(options){
console.log('Blubb go, options.one: ', options.one);
};
document.querySelector('.first').addEventListener('click', function(){
new Blubb(document.querySelector('.second'));
document.dispatchEvent(new CustomEvent('make-ready', {}));
}, false)
.second.disabled {
display: none;
}
答案 0 :(得分:1)
您的代码的问题在于您使用bind
将类的引用绑定到侦听器,但是bind
每次使用时都会创建侦听器的新引用。因此,您将无法在以后删除侦听器。要解决此问题,您必须将侦听器引用保存到变量中以供以后使用。您还将侦听器绑定到文档,因此它会立即执行,以防止您将绑定包装到setTimeout
或将useCapture
选项设置为true
。
此外,您应该考虑使您的类成为单例或销毁前一个实例,因为多个实例会因为文档上的侦听器而相互影响。
以下是使用上述技术的类的示例:
var Blubb = (function(doc) {
var defaults = {
one: true,
two: false
},
disabledClass = 'disabled',
instance = null;
function Blubb(element, options) {
if (instance) {
instance.destroy();
};
this.element = element;
this.options = Object.assign({}, defaults, options);
this.element.classList.remove(disabledClass);
this.removeListener = setupListener.call(this);
instance = this;
}
function setupListener() {
var listener = onClick.bind(this);
doc.addEventListener('click', listener, true);
return function() {
doc.removeEventListener('click', listener, true);
}
}
function onClick(event) {
if (event.target === this.element) {
this.go(this.options);
} else {
this.destroy();
}
}
Blubb.prototype.go = function(options) {
console.log('Blubb go, options: ', options);
}
Blubb.prototype.destroy = function() {
this.element.classList.add(disabledClass);
this.element = null;
instance = null;
this.removeListener();
}
return Blubb;
})(document);
// setup
document.querySelector('.first').addEventListener('click', function() {
new Blubb(document.querySelector('.second'));
}, false)
.second.disabled {
display: none;
}
.first,
.second {
background: #eee;
cursor: pointer;
}
<div class="first">START</div>
<br />
<div class="second disabled">BLUBB</div>
编辑:您还可以使用useCapture
绑定侦听器,而不是将其包装到setTimeout
中。我编辑了上面的代码段。