首页 > 解决方案 > addEventListener 被忽略

问题描述

我有一个将元素添加到下拉列表的循环。添加了元素,我想添加一个在用户单击其中一个元素时发生的事件。所以我正在添加一个这样的事件监听器。

for (var i = 0; cities.length > i; i++) {
        if (cities[i].toLowerCase().indexOf(value.toLowerCase()) !== -1 && citiesList <= 10) {
            citiesList ++;
            dropdown.classList.add('show');
            dropdown.innerHTML += '<a class="dropdown-item" id="dropdown_item-' + i + '" href="#">' + cities[i] + '</a>';
            var item = document.getElementById('dropdown_item-' + i);
            item.addEventListener("click", function(){ console.log("test") });
            console.log(item);
        }
    }

但是,当我单击元素时,即使 console.log 正确记录了该项目,事件也不会触发,并且当我通过控制台手动添加侦听器时它可以工作。我尝试使用超时功能,但没有占上风。

标签: javascriptloopslistener

解决方案


当您+=使用innerHTML容器时,容器的内容会完全从它们的 HTML 标记中重新解析。其他任何内容(例如不在 HTML 标记中的事件侦听器)都将丢失。改为使用insertAdjacentHTML

Element 接口的 insertAdjacentHTML() 方法将指定的文本解析为 HTML 或 XML,并将生成的节点插入到 DOM 树中的指定位置。它不会重新解析正在使用的元素,因此不会破坏该元素内的现有元素。这避免了额外的序列化步骤,使其比直接的 innerHTML 操作快得多。

dropdown.insertAdjacentHTML('beforeend', '<a class="dropdown-item" id="dropdown_item-' + i + '" href="#">' + cities[i] + '</a>');

也就是说,看起来您可能只是为元素提供了一个 ID,以便您可以选择它并随后将侦听器附加到它。动态 ID 是一个非常糟糕的主意 - 如果是 ID 的原因,最好使用以下方法创建元素createElement

const a = document.createElement('a');
a.className = "dropdown-item";
a.textContent = cities[i];
a.addEventListener("click", function() {
  console.log("test")
});
dropdown.appendChild(a);

请记住,给定您当前的代码,这i将等于cities.length循环结束后。如果您i在侦听器回调中引用,如果您希望它引用i用于该特定迭代的,您需要一个块范围的i代替:更改

for (var i = 0; cities.length > i; i++) {

for (let i = 0; cities.length > i; i++) {

(或者,甚至更好,使用Array.prototype.forEach或类似的东西,而不是手动弄乱索引)


推荐阅读