【问题标题】:Why two event listeners are triggered instead of one?为什么会触发两个事件侦听器而不是一个?
【发布时间】:2018-10-02 20:10:08
【问题描述】:

我有一个元素,它有两个根据他的类名触发的事件监听器。在 click 事件期间,他的 className 正在发生变化,并且这个另一个类有自己不同的事件侦听器。每次点击应该交替触发两个事件。

在第一次点击监听器调用函数editClub,但所有接下来的点击调用两个函数。我不知道为什么会触发删除类事件。也许是因为在每个事件函数 callListeners 执行后,一个对象上有多个监听器?但应该只触发一次。后来我写了 removeListeners 函数,它删除了所有现有的监听器,并让她在 callListeners 函数之前调用。但是每次点击都会执行editClub函数。我的代码有什么问题?

function callListeners() 
{
    if ( document.getElementsByClassName('editBtn') )
    {
        let x = document.getElementsByClassName('editBtn');
        for ( let i = 0; i < x.length; i++ )
        {
            x[i].addEventListener('click', editClub);
        }
    }

    if ( document.getElementsByClassName('saveBtn') )
    {
        let x = document.getElementsByClassName('saveBtn');
        for ( let i = 0; i < x.length; i++ )
        {
            x[i].addEventListener('click', saveClub);
        }
    }
}

function editClub(event) 
{
    event.preventDefault();
    this.setAttribute('src','img/\icon_save.png');
    this.setAttribute('class','saveBtn');
    //removeListeners();           <-- here I placed removeListeners function
    callListeners();
}

function saveClub(event) 
{
    event.preventDefault();
    this.setAttribute('src', 'img/\icon_edit.png');
    this.setAttribute('class', 'editBtn');
     //removeListeners();              <-- here I placed removeListeners function
    callListeners();
}

【问题讨论】:

    标签: javascript dom-events


    【解决方案1】:

    当点击事件发生时,您似乎没有删除类,因此在第一次点击后,元素同时具有这两个类。

    【讨论】:

    • 看起来是这样,但为什么呢? setAttribute 函数应该覆盖类属性中的所有类。
    【解决方案2】:

    仅仅改变一个元素的类不会改变之前设置的事件监听器。除非您明确删除它们,否则它们将仍然存在,或者元素本身被破坏。而且您会接到多个电话,因为您不断添加新的侦听器而不删除旧的侦听器。

    您可以在每次点击时移除旧的监听器并添加新的监听器

    function editClub(){
      this.removeEventListener("click",editClub);
      this.addEventListener("click",saveClub);
    }
    function saveClub(){
      this.removeEventListener("click",saveClub);
      this.addEventListener("click",editClub);
    }
    

    但这有点乏味。相反,您可以在像document 这样的静态父对象上设置delegated event listener。这样做允许在单击任一按钮时调用单个事件侦听器。然后在那个监听器中,你可以检查元素的类,并为它执行适当的函数:

    function clubAction(event){
      //get a reference to the element clicked
      var element = event.target;
    
      //call the appropriate function
      //or just do the work here
      if(element.classList.contains("editClub")){
        editClub.call(element,event);
      } else if(element.classList.contains("saveClub")) {
        saveClub.call(element,event);
      }
    }
    
    document.addEventListener("click",clubAction);
    

    classList 是一个属性,可让您对元素的类进行获取、设置、删除和其他操作。


    演示

    function clubAction(event) {
      var element = event.target;
      if (element.classList.contains("editClub")) {
        editClub.call(element,event);
      } else if (element.classList.contains("saveClub")) {
        saveClub.call(element,event);
      }
    }
    
    document.addEventListener("click", clubAction);
    
    function editClub(event) {
      event.preventDefault();
      this.classList.remove('editClub');
      this.classList.add('saveClub');
      this.innerText = "Save";
    }
    
    function saveClub(event) {
      event.preventDefault();
      this.classList.add('editClub');
      this.classList.remove('saveClub');
      this.innerText = "Edit";
    }
    .saveClub {
      background:#0F0;
    }
    
    .editClub {
      background:#FF0;
    }
    <button class="saveClub">Save</button>
    <button class="editClub">Edit</button>

    【讨论】:

    • 感谢您对委派听众的全面回复和解释。我以前不知道这种方法,但它很棒。我在元素上有很多监听器,它们是动态添加或删除的。现在它更方便了。
    猜你喜欢
    • 1970-01-01
    • 2016-07-17
    • 2023-03-11
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2015-12-18
    相关资源
    最近更新 更多