You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用循环添加事件监听时,如何正确访问触发事件的元素本身?

问题:循环创建按钮点击事件总是指向最后一个元素

当使用循环批量创建按钮并绑定点击事件后,所有按钮点击后都会隐藏最后一个按钮,而非自身。尝试使用this或self也无法解决这个问题。

原始代码

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <template id="button-template">
        <button></button>
    </template>

    <script src="./bug.js"></script>
</body>
</html>

JS代码

const button_template = document.getElementById("button-template")

for(let i = 0; i < 10; i++) {
    clone = button_template.content.cloneNode(true)
    btn = clone.querySelector("button")

    btn.addEventListener("click", () => {
        btn.style.display = "None"
    })

    btn.innerHTML = i.toString()

    document.querySelector("body").appendChild(clone)
    console.log("something")
}

问题原因

  1. 全局变量污染:clone和btn未用let/const声明,属于全局变量。循环结束后,btn始终指向最后一个创建的按钮,箭头函数捕获的是这个全局变量的引用,导致所有点击事件都操作最后一个按钮。
  2. 箭头函数的this指向:箭头函数没有独立的this,它的this继承自外层作用域,因此用this无法获取当前点击的按钮元素。

修复方案

方案一:用const声明局部变量,绑定当前迭代的按钮

const button_template = document.getElementById("button-template")

for(let i = 0; i < 10; i++) {
    // 用const声明局部变量,每个循环迭代生成独立作用域
    const clone = button_template.content.cloneNode(true)
    const btn = clone.querySelector("button")

    btn.addEventListener("click", () => {
        btn.style.display = "none" // CSS属性值需小写
    })

    btn.innerHTML = i.toString()
    document.querySelector("body").appendChild(clone)
}

每个循环迭代会创建新的作用域,箭头函数会捕获当前迭代的btn变量,而非最后一个全局变量。

方案二:使用普通函数,通过this访问当前元素

const button_template = document.getElementById("button-template")

for(let i = 0; i < 10; i++) {
    const clone = button_template.content.cloneNode(true)
    const btn = clone.querySelector("button")

    // 普通函数作为事件监听时,this指向触发事件的按钮
    btn.addEventListener("click", function() {
        this.style.display = "none"
    })

    btn.innerHTML = i.toString()
    document.querySelector("body").appendChild(clone)
}

普通函数的this在事件触发时会自动指向当前点击的元素,无需额外处理。

方案三:通过事件对象的target属性获取当前元素

const button_template = document.getElementById("button-template")

for(let i = 0; i < 10; i++) {
    const clone = button_template.content.cloneNode(true)
    const btn = clone.querySelector("button")

    btn.addEventListener("click", (e) => {
        // e.target指向触发事件的元素
        e.target.style.display = "none"
    })

    btn.innerHTML = i.toString()
    document.querySelector("body").appendChild(clone)
}

事件对象e的target属性始终指向触发事件的具体元素,不受函数类型和变量作用域影响。


内容的提问来源于stack exchange,提问作者AchoDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:16:11