javascript - 未将侦听器添加到创建的 div
问题描述
所以我有以下名为 addPanels() 的函数,它为每个具有“手风琴”类的元素添加一个事件侦听器
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 似乎只将侦听器添加到具有类 ACCORDION 且未从 API 加载的元素(它们已经在 HTML 中)。为什么会这样?
解决方案
因为在添加侦听器时,您的新元素并不存在。
api.routines.getRoutines().done
指定一个应该在未来某个时间点运行的回调函数——我们不知道什么时候会运行。因此,当该 API 开始其进程时,addPanels();
会立即调用 next,它会设置事件处理程序,但getRoutines()
尚未完成,因此您最终只能在getRoutines()
完成之前存在的面板上设置处理程序。这就是异步处理的工作原理。
要解决此类问题,您需要使用事件委托,即在从一开始就存在的对象上设置事件处理程序,然后通过事件冒泡捕获由后代元素发起的事件。处理事件后,您检查事件的来源并查看它是否符合您想要的条件。这样,创建元素的时间就无关紧要了。
这是一个简化的示例:
// 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; }
推荐阅读
- functional-programming - 使用迭代器时的类型感知映射
- rust - 如何通过结构内容返回对迭代器的适当生命周期引用?
- eclipse - 无论打开哪种语言,有没有办法在缩进后进行换行?
- java - 运行嵌入在 Java 中的 Pig
- c# - 仅在 float[] 样本数组的末尾删除或修剪零 0
- amazon-web-services - AWS EMR Hive 在查询 S3 存储桶时失败,并出现 execption 'java.io.FileNotFoundException: No such file or directory:'
- c# - 如何使用 C# 中的 Docker.dotnet 库连接到远程 docker 守护进程?
- ios - SJVideoPlayer 不播放视频显示黑屏
- dart - 如何根据父元素调整图像大小?
- mysql - MySQL更新整个字符串的一部分?