我在使用某些JavaScript代码时遇到了一些问题。 我想要做的是将事件侦听器添加到数组中的元素。
问题是,在运行代码之后,只有数组中的最后一个元素才能使eventlistener正常工作,其余的元素都会返回错误。
我假设这是因为我正在使用for循环和eventlisteners的逻辑。 什么是达到预期结果的有效方法?
function addSlider(config) {
var controls = `
<div id="next"> next </div>
<div id="previous"> previous </div>`;
var S_wrapper = config.wrapper;
var controls_html = document.createElement("div");
controls_html.setAttribute("id", "ctrl");
controls_html.innerHTML = controls;
var arrayData = config.wrapper.split(",");
for (i = 0; i < arrayData.length; i++) {
(function(index) {
document.querySelector(arrayData[i]).appendChild(controls_html);
var parent = document.querySelector(arrayData[index]);
console.log(i, index, arrayData[index], parent);
document.querySelector(arrayData[index]).addEventListener("mouseover", function(){
this.querySelector("#ctrl").style.display = "block";
})
document.querySelector(arrayData[index]).addEventListener("mouseout", function(){
this.querySelector("#ctrl").style.display = "none";
})
})(i);
}
}
答案 0 :(得分:1)
有几个问题:
您在每次循环迭代中将相同的div移动到新的父级。您的controls_html
不是 HTML,它是对HTMLDivElement
对象的引用。这一行:
document.querySelector(arrayData[i]).appendChild(controls_html);
从它拥有的任何父级(最初没有,但在第一个循环后它是前一个循环中的元素)移动到新父级。
如果您希望在每个父级中都有新的div
,则每次都需要创建一个新的div
。
您在多个元素上使用相同的ID ctrl
。这是无效的,ID必须是唯一的。之后,当您使用#ctrl
时,您将获得浏览器选择给您的任何元素(这是未指定的行为,尽管根据我的经验,它始终是第一个)。
所以我们需要处理这两个问题。采用最小化更改方法,我们将div创建移动到循环中并将索引添加到ID中:
function addSlider(config) {
var controls = `
<div id="next"> next </div>
<div id="previous"> previous </div>`;
var S_wrapper = config.wrapper;
var arrayData = config.wrapper.split(",");
for (i = 0; i < arrayData.length; i++) {
(function(index) {
var div = document.createElement("div");
div.setAttribute("id", "ctrl" + index);
div.innerHTML = controls;
var parent = document.querySelector(arrayData[index]);
parent.appendChild(div);
parent.addEventListener("mouseover", function() {
this.querySelector("#ctrl" + index).style.display = "block";
})
parent.addEventListener("mouseout", function() {
this.querySelector("#ctrl" + index).style.display = "none";
})
})(i);
}
}
但是我退一步看看更广泛的画面。例如,mouseover
和mouseout
都会冒泡,因此您可以在父元素上挂钩,并使用单个处理程序处理它。根本没有理由提供这个身份证;我们可以使用类或类似物识别子div,并且仅在parent
内搜索它。您可以使用Array#forEach
替换循环及其中的函数。那种事。
旁注:我注意到你正在使用模板文字(你要分配给controls
的东西),这是ES2015(又名“ES6”)中引入的一个功能,但没有使用任何一个其他ES2015功能。所以只是在你没有意识到的情况下标记它......
答案 1 :(得分:0)
PS:我将回答您当前代码中的问题,而不是谈论设计/重构(其他人已对此进行了评论)
您的主要问题是使用id而不是类。请记住,文档中只能存在一个id,否则无法引用它们。
此外,您还在重用controls_html
元素,您应该为要添加的每个元素创建一个新元素。 (再次,此情况)
我创建了一个fiddle,其中包含代码的工作副本
function addSlider(config) {
var controls = `
<div class="next"> next </div>
<div class="previous"> previous </div>`;
var S_wrapper = config.wrapper;
var arrayData = config.wrapper.split(",");
for (i = 0; i < arrayData.length; i++) {
(function(index) {
var controls_html = document.createElement("div");
controls_html.setAttribute("class", "ctrl");
controls_html.style.display = 'none';
controls_html.innerHTML = controls;
document.querySelector(arrayData[index]).appendChild(controls_html);
var parent = document.querySelector(arrayData[index]);
document.querySelector(arrayData[index]).addEventListener("mouseover", function() {
this.querySelector(".ctrl").style.display = "block";
})
document.querySelector(arrayData[index]).addEventListener("mouseout", function() {
this.querySelector(".ctrl").style.display = "none";
})
})(i);
}
}
addSlider({
wrapper: '#a,#b,#c'
})
<div id="a">
1
</div>
<div id="b">
2
</div>
<div id="c">
3
</div>