动态生成按钮向嵌套函数传递变量值的问题求助
解决浏览器游戏存档操作按钮的索引绑定问题
你的问题核心是循环中绑定事件时的闭包陷阱:所有按钮的点击函数都共享同一个a变量,当循环结束后a的值已经变成了saves.length,所以不管点哪个按钮,最终拿到的都是最后一个存档的索引,自然无法正确对应到目标存档。下面给你几个原生JavaScript的解决方案,按推荐度排序:
方案1:用ES6的let创建块级作用域(最简单)
把循环里的var a改成let a,这样每次循环都会创建一个独立的块级作用域,每个按钮的点击函数会捕获当前循环的a值,而不是共享同一个变量:
function loadSaveList(){ saves = JSON.parse(localStorage.getItem("game_saves")); // 把var改成let,创建块级作用域 for(let a=0; a < saves.length; a++){ var entry = document.createElement("div"); var buttons = document.createElement("div"); var overwriteB = document.createElement("input"); var deleteB = document.createElement("input"); var loadB = document.createElement("input"); overwriteB.type = "button"; deleteB.type = "button"; loadB.type = "button"; // 直接用当前的a,不用再写返回函数 overwriteB.onclick = function(){ buttonType = 0; saveNum = a; saveAlert(); }; deleteB.onclick = function(){ buttonType = 1; saveNum = a; saveAlert(); }; loadB.onclick = function(){ buttonType = 2; saveNum = a; saveAlert(); }; buttons.appendChild(overwriteB); buttons.appendChild(deleteB); buttons.appendChild(loadB); entry.appendChild(buttons); document.getElementById("saveEntries").appendChild(entry); } }
方案2:用立即执行函数(IIFE)捕获当前索引(兼容旧浏览器)
如果需要兼容不支持ES6的旧环境,可以用立即执行函数为每个循环迭代创建独立的作用域,把当前的a值作为参数传进去:
function loadSaveList(){ saves = JSON.parse(localStorage.getItem("game_saves")); for(var a=0; a < saves.length; a++){ var entry = document.createElement("div"); var buttons = document.createElement("div"); var overwriteB = document.createElement("input"); var deleteB = document.createElement("input"); var loadB = document.createElement("input"); overwriteB.type = "button"; deleteB.type = "button"; loadB.type = "button"; // 用IIFE捕获当前的a值 (function(currentIndex) { overwriteB.onclick = function(){ buttonType = 0; saveNum = currentIndex; saveAlert(); }; deleteB.onclick = function(){ buttonType = 1; saveNum = currentIndex; saveAlert(); }; loadB.onclick = function(){ buttonType = 2; saveNum = currentIndex; saveAlert(); }; })(a); // 把当前的a传进去 buttons.appendChild(overwriteB); buttons.appendChild(deleteB); buttons.appendChild(loadB); entry.appendChild(buttons); document.getElementById("saveEntries").appendChild(entry); } }
方案3:用元素的dataset存储索引(更直观)
把存档索引直接存在按钮的dataset属性里,点击时从按钮上读取,这样不用依赖闭包,逻辑更清晰:
function loadSaveList(){ saves = JSON.parse(localStorage.getItem("game_saves")); for(var a=0; a < saves.length; a++){ var entry = document.createElement("div"); var buttons = document.createElement("div"); var overwriteB = document.createElement("input"); var deleteB = document.createElement("input"); var loadB = document.createElement("input"); overwriteB.type = "button"; deleteB.type = "button"; loadB.type = "button"; // 给每个按钮存当前索引 overwriteB.dataset.saveIndex = a; deleteB.dataset.saveIndex = a; loadB.dataset.saveIndex = a; overwriteB.onclick = function(){ buttonType = 0; saveNum = parseInt(this.dataset.saveIndex); // 读取索引 saveAlert(); }; deleteB.onclick = function(){ buttonType = 1; saveNum = parseInt(this.dataset.saveIndex); saveAlert(); }; loadB.onclick = function(){ buttonType = 2; saveNum = parseInt(this.dataset.saveIndex); saveAlert(); }; buttons.appendChild(overwriteB); buttons.appendChild(deleteB); buttons.appendChild(loadB); entry.appendChild(buttons); document.getElementById("saveEntries").appendChild(entry); } }
另外要注意:你之前把saveNum赋值为一个函数,后续操作里直接用saveNum(比如saves.splice(saveNum, 1))会出错,因为splice需要的是数字索引而非函数。上面的方案里已经把saveNum改成直接存储数字索引,这样后续的overwriteButton、deleteButton、loadButton函数就能正常工作了。
内容的提问来源于stack exchange,提问作者th0r23
相关产品推荐
相关产品推荐

