听众没有被添加到一个creted div

时间:2018-05-12 20:06:50

标签: javascript jquery html

所以我有以下函数addPanels(),它为每个带有“accordion”类的元素添加一个事件监听器

function addPanels(){
    var acc = document.getElementsByClassName("accordion");
    var i;

    for (i = 0; i < acc.length; i++) {
        acc[i].addEventListener("click", function() {
        var panel = this.nextElementSibling;
        if (panel.style.display === "block") {
            panel.style.display = "none";
        } else {
            panel.style.display = "block";
        }

        var arrow = this.children[0].children[0];

        if (panel.style.display === "block") {
            arrow.src = "Iconos/arrow_up.png";
        } else {
            arrow.src = "Iconos/arrow_down.png";
        }
    });
  } 
}

然后我有了这个:

$(document).ready(function() {
    api.routines.getRoutines().done(function(data) {
       $.each(data, function(i, item){
       var list = document.getElementById("routines_list");
       var acc = document.createElement("div");
       acc.setAttribute("class", "accordion");
       var panel = document.createElement("div");
       panel.setAttribute("class", "panel");
        //more stuff 
      });
    acc.appendChild(panel);
    list.appendChild(acc);  
    // ...
    });
    addPanels(); //WORKS ONLY WITH PREVIOUS ACCORDIONS NOT WITH THE NEW ONE! WHY??

}).fail(function(jqXHR, textStatus, errorThrown) {
    //do sth
    });
});

addPanels似乎只将侦听器添加到没有从API加载的类ACCORDION的元素(它们已经在HTML中)。为什么会这样?

1 个答案:

答案 0 :(得分:1)

因为在添加侦听器时,您的新元素不存在。

api.routines.getRoutines().done指定一个应该在未来某个时间点运行的回调函数 - 我们不知道什么时候会这样。因此,当该API开始执行时,addPanels();会立即调用,它会设置事件处理程序,但getRoutines()尚未完成,因此您最终只会设置处理程序在getRoutines()完成之前存在的面板上。这就是异步处理的工作原理。

要解决此类问题,您需要使用 event delegation ,这是在您从一开始就存在的对象上设置事件处理程序然后捕获事件的时候由后代元素通过事件冒泡启动。处理事件时,您检查事件的来源并查看它是否符合您想要的条件。这样,元素何时被创建无关紧要。

这是一个简化的例子:

// Set up a click event handler on the document (which all descendant element events will bubble up to)
document.addEventListener("click", function(evt){
  console.log("Click event handled!");
 
  // Is the clicked element NOT the document?
  if(evt.target.classList){
    // Check for dynamically created elements that were given
    // the "dynamic" class upon creation (you can use any criteria you want here)
    if(evt.target.classList.contains("dynamic")){
      console.log("Click event for dynamically created element, " + evt.target.nodeName + " handled by document");
    }
  }
});

// Now, we'll create some elements and inject them into the DOM AFTER the event handler
// has been set up. Also, these elements were not specifically set up with event handlers.
var div = document.createElement("div");
div.classList.add("dynamic");
div.textContent = "Click Me";
document.body.appendChild(div);

var btn = document.createElement("input");
btn.classList.add("dynamic");
btn.type = "button";
btn.value = "Click Me!";
document.body.appendChild(btn);
.dynamic { font-weight:bold; color:#800080; }