我今天一直在关闭关闭的很多,并且已经查看了很多类似的问题。我还没有能找到一个触及我遇到的完全相同的问题,以及如何修复它。大多数答案似乎与jQuery有关,但关于闭包如何工作有一些很棒的答案。我知道我的问题在哪里。我尝试了许多不同的闭包示例而没有运气。
我有一组代表3个校园的数据。每个校区都有一些建筑物。第一个for循环遍布校园。嵌套for循环遍历当前园区中的建筑物并将点击事件绑定到它(这允许我以编程方式平移和缩放传单地图。)
我创建了一个非常简化的JSFiddle来代表我尝试做的事情,这表明了这个问题。只有最后一个校园的建筑物#34;组保留点击事件。
这是来自JS Fiddle的JS代码。 http://jsfiddle.net/scwutpno/3/
var campuses = {
"campus1": {
"buildings": {
"building1": {
"id": 1
},
"building2": {
"id": 2
},
"building3": {
"id": 3
}
},
"name": "Campus 1"
},
"campus2": {
"buildings": {
"building1": {
"id": 4
},
"building2": {
"id": 5
},
"building3": {
"id": 6
}
},
"name": "Campus 2"
},
"campus3": {
"buildings": {
"building1": {
"id": 7
},
"building2": {
"id": 8
},
"building3": {
"id": 9
}
},
"name": "Campus 3"
}
};
var buildingLinksContainer = document.getElementById("building-list");
function buildExternalLinks() {
for (var campus in campuses) {
var container,
item;
if (buildingLinksContainer !== null) {
buildingLinksContainer.innerHTML += '<div class="building-links" id="' + campus + '-buildings">' +
'<div class="building-links__campus-name">' + campuses[campus].name + '</div></div>';
container = document.getElementById(campus + '-buildings');
}
for (var building in campuses[campus].buildings) {
item = container.appendChild(document.createElement('li'));
item.innerHTML = 'Building ' + campuses[campus].buildings[building].id;
item.addEventListener("click", function () {
alert('clicked!');
});
}
}
}
buildExternalLinks();
我已尝试将点击事件置于自我调用的关闭状态,但我不认为里面的数据是点击事件。有问题。它是应用click事件的节点。我不知道如果因为我使用嵌套for循环,我需要某种嵌套闭包概念吗?
很想知道这个问题是如何解决的。我已经通过在for循环中使用闭包来克服它一次,但是这个嵌套for循环让我感到难过。
答案 0 :(得分:1)
问题在于,每次附加到&#34; buildingLinksContainer&#34;时,您的代码都会重写DOM。元件。每当您的代码附加到&#34; buildingLinksContainer&#34;的内部HTML与&#34; + =&#34;时,DOM就是从头开始创建的。以前在其中包含事件监听器的所有元素&#34; buildingLinksContainer&#34;被创建为没有任何事件监听器的新元素。
仅在最后一次迭代中,当DOM未被拆除后,事件监听器才会坚持下去。并且由于在最后一次迭代中只创建了最后三个li元素,因此只有它们具有事件侦听器。
罪魁祸首:
buildingLinksContainer.innerHTML += '<div class="building-links" id="' + campus + '-buildings">' +
'<div class="building-links__campus-name">' + campuses[campus].name + '</div></div>';
我已经以一种有效的方式重写了您的解决方案(获得更好的性能和标记奖励)
var buildingLinksContainer = document.getElementById("building-list");
function buildExternalLinks(campuses, rootElement) {
var ul = document.createElement('ul'),
li = document.createElement('li'),
h1 = document.createElement('h1'),
list = document.createDocumentFragment();
for(var campus in campuses) {
if(campuses.hasOwnProperty(campus)) {
var c = ul.cloneNode(false);
c.classList.add('building-links');
c.setAttribute('id', campus+'-buildings');
var name = h1.cloneNode(false);
name.appendChild(document.createTextNode(campuses[campus].name));
c.appendChild(name);
for(var building in campuses[campus].buildings) {
if(campuses[campus].buildings.hasOwnProperty(building)) {
var b = li.cloneNode(false);
var text = 'Building ' + campuses[campus].buildings[building].id;
b.appendChild(document.createTextNode(text));
b.addEventListener('click', function(event) {
alert(event.target.innerHTML);
});
c.appendChild(b);
}
}
}
list.appendChild(c);
}
rootElement.appendChild(list);
}
buildExternalLinks(campuses, buildingLinksContainer);
我还更新/分发了您的JSFiddle。
答案 1 :(得分:0)
+=
只是x = x + y
之类的快捷方式。设置buildingLinksContainer.innerHTML += ...
时,您实际上会重新创建该元素的整个内容。 全部删除了之前的内容,包括附加到元素的事件。然后一个新的字符串被设置为DOM,并且在解析它时,不再有任何事件。
快速解决方法是使用insertAdjacentHTML()
代替innerHTML
,如下所示:
buildingLinksContainer.insertAdjacentHTML('beforeend',
'<div class="building-links" id="' + campus + '-buildings">' +
'<div class="building-links__campus-name">' +
campuses[campus].name +
'</div></div>'
);
答案 2 :(得分:0)
使用事件委派仅将事件侦听器添加到 building-list 元素
document.querySelector('#building-list').addEventListener('click', function(evt){
var clickedElement = evt.target;
//just use the clickedElement variable to get the element that was clicked
//ex: you can get the id from it or whatever you want
});