如何用JS数组存储游戏名与URL 修复按钮首次点击加载失效问题
网页游戏列表加载功能修复与实现方案
一、游戏信息数组结构实现
使用对象数组存储游戏元信息是可维护性最高的方案,无需把URL硬编码在按钮id属性中,后续增删游戏只需要修改数组即可,不需要编写重复的HTML标签。
- 基础数组结构:整个游戏列表用
[]包裹为数组,每个数组项是{}格式的对象,分别用两个字段存储游戏名和加载地址
// 游戏列表数组,新增游戏直接按格式追加数组项即可 const gameList = [ { name: "Run 3", url: "https://theadvancedsociety-tam.tbt.mx/tam-run3/" }, { name: "Slope Game", url: "https://bigfoot9999.github.io/Slope-Game/" } ]
如果需要按游戏分类管理,可以扩展数组结构,给每个分类建单独项,嵌套存储对应分类下的游戏,后续优化版代码会提供对应实现。
二、现有交互bug根因与修复
问题根因
你遇到的两个交互异常来自三处逻辑错误:
- 首次点击无响应:点击按钮触发
reply_click时,仅为页面第一个按钮绑定了二次点击的onclick事件,没有执行任何加载逻辑,必须点击第二次才会触发加载动作。 - 按钮加载地址不匹配:
document.querySelector('button')只会匹配页面中排在最前面的第一个按钮,无论点击哪个按钮,事件绑定、样式修改操作都只会作用在第一个按钮上;同时存储弹窗引用的win变量定义在函数内部,多次点击会生成多个独立的弹窗引用,加上闭包缓存的url值,最终出现点击按钮和加载地址不对应的问题。 - 样式无效:代码中写的背景色值
#00000是无效十六进制色值,少一位字符,正确纯黑色值为#000000。
最小修复版本(保留原有手写HTML结构)
只需要修改JS逻辑和HTML内的事件传参,不需要重构现有页面结构:
- 修改为以下JS代码:
// 全局存储弹窗引用,所有按钮共用同一个弹窗实例 let gameWindow = null; function reply_click(activeBtn) { const targetUrl = activeBtn.id; if (!targetUrl) return; if (gameWindow && !gameWindow.closed) { // 已打开弹窗则直接聚焦,替换iframe加载地址 gameWindow.focus(); const gameIframe = gameWindow.document.querySelector('iframe'); if (gameIframe) gameIframe.src = targetUrl; } else { // 未打开弹窗则新建窗口,注入iframe gameWindow = window.open(); gameWindow.document.body.style.margin = '0'; gameWindow.document.body.style.height = '100vh'; const gameIframe = gameWindow.document.createElement('iframe'); gameIframe.style.border = 'none'; gameIframe.style.width = '100%'; gameIframe.style.height = '100%'; gameIframe.style.margin = '0'; gameIframe.src = targetUrl; gameWindow.document.body.appendChild(gameIframe); } // 仅修改当前点击按钮的样式 activeBtn.style.background = '#000000'; activeBtn.style.color = '#ffffff'; }
- 修改HTML内的按钮事件传参,把
this.id改为直接传入按钮DOM对象this:
<div class="gameslist"> <h1>Action Games</h1> <button id="https://theadvancedsociety-tam.tbt.mx/tam-run3/" onClick="reply_click(this)">Run 3</button><br> <button id="https://bigfoot9999.github.io/Slope-Game/" onClick="reply_click(this)">Slope Game</button><br> <h1>Puzzle & Strategy Games</h1> <h1>Skill Games</h1> <h1>Retro</h1> <h1>Shooter Games</h1> <h1>Other</h1> </div>
优化版本(配合数组自动渲染列表)
基于前面提到的数组结构,实现自动渲染全部分类和游戏按钮,后续加游戏只需要改数组,不需要写HTML:
// 带分类的游戏列表数组 const gameList = [ { category: "Action Games", games: [ { name: "Run 3", url: "https://theadvancedsociety-tam.tbt.mx/tam-run3/" }, { name: "Slope Game", url: "https://bigfoot9999.github.io/Slope-Game/" } ] }, { category: "Puzzle & Strategy Games", games: [] }, { category: "Skill Games", games: [] }, { category: "Retro", games: [] }, { category: "Shooter Games", games: [] }, { category: "Other", games: [] } ] let gameWindow = null; // 页面加载完成后自动渲染所有游戏列表 window.addEventListener('load', () => { const listContainer = document.querySelector('.gameslist'); gameList.forEach(categoryItem => { // 渲染分类标题 const title = document.createElement('h1'); title.textContent = categoryItem.category; listContainer.appendChild(title); // 渲染分类下的所有游戏按钮 categoryItem.games.forEach(gameItem => { const btn = document.createElement('button'); btn.textContent = gameItem.name; btn.dataset.url = gameItem.url; // 绑定按钮点击事件 btn.addEventListener('click', function() { const targetUrl = this.dataset.url; if (gameWindow && !gameWindow.closed) { gameWindow.focus(); gameWindow.document.querySelector('iframe').src = targetUrl; } else { gameWindow = window.open(); gameWindow.document.body.style.margin = '0'; gameWindow.document.body.style.height = '100vh'; const gameIframe = gameWindow.document.createElement('iframe'); gameIframe.style.border = 'none'; gameIframe.style.width = '100%'; gameIframe.style.height = '100%'; gameIframe.src = targetUrl; gameWindow.document.body.appendChild(gameIframe); } this.style.background = '#000000'; this.style.color = '#ffffff'; }) listContainer.appendChild(btn); listContainer.appendChild(document.createElement('br')); }) }) })
对应HTML只需要保留列表容器即可:
<div class="gameslist"></div>
内容的提问来源于stack exchange,提问作者Bigfoot9999
相关产品推荐
相关产品推荐

