使用JavaScript的createElement生成多按钮,如何绑定不同点击效果?
解决循环生成按钮点击事件绑定错误的问题
你遇到的核心问题是**var的函数级作用域引发的闭包陷阱**:用var声明的nr和tr在整个printBtn函数内共享,循环结束后,所有按钮的点击事件引用的都是这两个变量的最终值(也就是最后一次循环的"kick"和20)。另外你写的btn.innerHTML.onclick是错误写法,innerHTML是元素的HTML内容字符串,应该直接给btn.onclick赋值函数。
下面是几种可行的解决方案:
方案1:改用let声明变量(最简单)
let是块级作用域,每次循环会创建独立的变量绑定,点击事件会捕获当前循环迭代的变量值:
var joe = { age: 20, moves: [ {name: "punch", power: 10,}, {name: "kick", power: 20,}, ] } function printBtn() { for (var i = 0; i < joe.moves.length; i++) { let btn = document.createElement("button"); var n = document.createTextNode(joe.moves[i].name); var t = document.createTextNode(joe.moves[i].power); // 用let声明,创建块级作用域变量 let nr = joe.moves[i].name let tr = joe.moves[i].power var linebreak = document.createElement("br") btn.appendChild(n); btn.appendChild(linebreak); btn.appendChild(t); document.body.appendChild(btn); btn.style.width = "125px" btn.style.height = "50px" btn.style.fontSize = "12px" // 直接绑定onclick事件 btn.onclick = function readOut() { console.log(nr + " " + tr) } } }
方案2:使用forEach遍历数组
forEach的回调函数会创建独立作用域,天然避免闭包问题:
var joe = { age: 20, moves: [ {name: "punch", power: 10,}, {name: "kick", power: 20,}, ] } function printBtn() { joe.moves.forEach(move => { let btn = document.createElement("button"); var n = document.createTextNode(move.name); var t = document.createTextNode(move.power); var linebreak = document.createElement("br") btn.appendChild(n); btn.appendChild(linebreak); btn.appendChild(t); document.body.appendChild(btn); btn.style.width = "125px" btn.style.height = "50px" btn.style.fontSize = "12px" btn.onclick = function() { console.log(`${move.name} ${move.power}`) } }) }
方案3:用立即执行函数(IIFE)捕获当前值
通过IIFE创建独立作用域,把当前循环的move值传入并保存:
var joe = { age: 20, moves: [ {name: "punch", power: 10,}, {name: "kick", power: 20,}, ] } function printBtn() { for (var i = 0; i < joe.moves.length; i++) { let btn = document.createElement("button"); var n = document.createTextNode(joe.moves[i].name); var t = document.createTextNode(joe.moves[i].power); var linebreak = document.createElement("br") btn.appendChild(n); btn.appendChild(linebreak); btn.appendChild(t); document.body.appendChild(btn); btn.style.width = "125px" btn.style.height = "50px" btn.style.fontSize = "12px" // 用IIFE捕获当前循环的move对象 (function(currentMove) { btn.onclick = function() { console.log(`${currentMove.name} ${currentMove.power}`) } })(joe.moves[i]) } }
HTML部分保持不变:
<button onclick="printBtn();">Go Joe!</button>
内容的提问来源于stack exchange,提问作者Inzhu
相关产品推荐
相关产品推荐

