JavaScript for循环内按钮点击事件仅响应最后一次迭代值问题
问题根源
该问题与变量提升无关,核心原因有两点:
- 所有动态生成的按钮内联
onclick事件都统一调用全局作用域下的addBtn函数,没有绑定当前列表项的专属数据 - 每次for循环迭代都会覆盖重写全局
addBtn函数,前一次迭代定义的函数逻辑会被直接丢弃。循环结束后全局addBtn仅保留最后一次迭代的赋值,其闭包引用的索引值i对应数组最后一位元素,因此点击任意按钮都只会输出最后一项的食材名称。
另外原代码的按钮标签内多写了一个多余的},属于语法错误,需要一并删除。
修复方案
方案1:保留内联事件写法,直接传参(改动最小)
只需要在循环外统一定义一次addBtn,生成模板时直接把当前项的食材名作为参数传入事件调用即可,无需在循环内反复重写函数:
// 循环外单次定义函数,接收食材名参数 const addBtn = (ingredient) => { console.log(ingredient); } fetch('https://www.themealdb.com/api/json/v1/1/list.php?i=list') .then(res => res.json()) .then(res => { for (let i = 0; i < res.meals.length; i++) { const ingredientName = res.meals[i].strIngredient; // 传入当前项的食材名,移除标签多余的} ingredientList.innerHTML += `<li>${ingredientName} <button onclick="addBtn('${ingredientName}')">Add</button> </li>`; } } );
方案2:动态创建元素绑定事件(推荐,无全局函数污染)
避免使用内联onclick,生成DOM元素时直接给按钮绑定事件,利用let的块级作用域特性,每个按钮的事件回调都能拿到对应迭代的食材数据:
fetch('https://www.themealdb.com/api/json/v1/1/list.php?i=list') .then(res => res.json()) .then(res => { for (let i = 0; i < res.meals.length; i++) { const ingredientName = res.meals[i].strIngredient; // 创建DOM节点而非拼接innerHTML const li = document.createElement('li'); li.append(ingredientName); const addBtn = document.createElement('button'); addBtn.textContent = 'Add'; // 单独给当前按钮绑定点击事件 addBtn.addEventListener('click', () => { console.log(ingredientName); }) li.append(addBtn); ingredientList.append(li); } } );
注意:如果用
var声明循环变量i,方案2需要额外做闭包处理,用let声明则自带块级作用域,无需额外处理。
内容的提问来源于stack exchange,提问作者Huttok
相关产品推荐
相关产品推荐

