JavaScript石头剪刀布游戏:选择展示与胜负渲染实现方案问询
石头剪刀布JS功能实现方案
两种动态渲染方式的选择结论
优先选创建DOM节点后追加元素的方案,比拼接innerHTML更适合你的场景,原因如下:
- 你已经在
SELECTIONS数组里存储了对应选项的icon DOM引用,直接克隆节点追加不需要重复写img的src、alt属性,减少冗余代码 - 动态添加类名时直接操作DOM的
classListAPI,不需要在字符串里做复杂的类名拼接,避免出现漏空格、属性写错的低级bug - 不会破坏原有选择按钮上的图标元素(直接移动原有DOM会导致按钮上的图标消失,克隆节点不存在这个问题)
- 不存在innerHTML拼接带来的XSS风险,后续要给结果图标加自定义属性、交互事件时,操作DOM节点比改字符串灵活太多
两种方式在你这个小规模渲染场景下性能没有明显差异,但DOM追加方案的可维护性、出错率都远优于innerHTML拼接,是最优选择。
现有代码的前置问题修复
你的原有代码有3个会导致功能异常的bug,需要先修正:
SELECTIONS中剪刀选项的beats属性配置错误,原代码写的是赢剪刀,实际应该赢布addSelectionReult函数名拼写错误(少了s,正确为addSelectionResult),且函数内部无法访问makeSelection作用域下的yourWinner、computerWinner变量,需要调整传参- 直接引用原有按钮的icon节点会导致原按钮图标丢失,需要做深克隆处理
完整可运行实现代码
const selectionButtons = document.querySelectorAll('[data-selection]') const finalColumn = document.querySelector('[data-final-column]') // 修复剪刀的胜负逻辑配置 const SELECTIONS = [ { name: 'rock', icon: document.querySelector('#uRock'), beats: 'scissors' }, { name: 'paper', icon: document.querySelector('#uPaper'), beats: 'rock' }, { name: 'scissors', icon: document.querySelector('#uScissors'), beats: 'paper' } ] selectionButtons.forEach(selectionButton => { selectionButton.addEventListener('click', () =>{ const selectionName = selectionButton.dataset.selection const selection = SELECTIONS.find(selection => selection.name === selectionName) makeSelection(selection) }) }) function makeSelection(selection) { const computerSelection = randomSelection(); const yourWinner = isWinner(selection, computerSelection) const computerWinner = isWinner(computerSelection, selection) // 按顺序先插入电脑选择(左侧)、再插入玩家选择(右侧),传入归属方参数方便加类名 addSelectionResult(computerSelection, computerWinner, 'computer') addSelectionResult(selection, yourWinner, 'player') } function addSelectionResult(selection, isCurrentWinner, side) { const div = document.createElement('div') div.classList.add('result-selection') // 深克隆原有图标节点,不影响按钮上的原图标 const resultIcon = selection.icon.cloneNode(true) // 按照规则给图标加对应类名 if (side === 'computer') { resultIcon.classList.add(isCurrentWinner ? 'winner' : 'computerLost') } if (side === 'player') { resultIcon.classList.add(isCurrentWinner ? 'winner' : 'playerLost') } // 追加图标到结果容器 div.appendChild(resultIcon) finalColumn.after(div) } function isWinner(selection, opponentSelection){ return selection.beats === opponentSelection.name } function randomSelection() { const randomIndex = Math.floor(Math.random() * SELECTIONS.length) return SELECTIONS[randomIndex] }
实现效果说明
代码运行后完全符合你的需求:
- 点击选择按钮后自动获取对应选项的图标
- 结果区按左电脑、右玩家的顺序展示双方选择
- 类名完全匹配规则:电脑获胜则电脑图标加
winner、玩家图标加playerLost;玩家获胜则玩家图标加winner、电脑图标加computerLost - 最终生成的DOM结构和你给出的参考HTML完全一致
内容的提问来源于stack exchange,提问作者Kade Campbell
相关产品推荐
相关产品推荐

