删除点击事件问题

时间:2018-02-23 08:47:16

标签: javascript

我做的事情显然是错误的,但无法向我自己解释。

目标是收听点击事件(START,first)。如果用户单击“开始”,则第二个单击侦听器应该已准备就绪,但只有在单击特定元素时才会触发。如果第二次单击发生在外部,则应再次删除第二次单击事件侦听器。

听起来很简单,这是我的问题:

  1. 点击“开始”时为什么script开火?
  2. 我怎样才能完成我所解释的内容?
  3. 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;
    }

1 个答案:

答案 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中。我编辑了上面的代码段。