使用Web Component开发井字棋:无法选中shadowRoot内的cell元素
问题描述
我正尝试使用Webpack和Web Component开发一款井字棋游戏。需要选中place-mark组件shadowRoot内带有cell类的div标签,并根据回合计算结果,将其innerText更新为O或X。目前逻辑运行正常,但无法选中正确的组件来更新HTML视图,导致用户无法看到选中区域的当前状态。
简化代码
HTML代码
<div class="board" id="board"> <place-mark data-cell></place-mark> </div>
组件代码
const template = document.createElement("template"); template.innerHTML = `<div class="cell" />`; export default class PlaceMark extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild( template.content.cloneNode(true) ); } } window.customElements.define( "place-mark", PlaceMark );
JS逻辑代码
const X_CLASS = "x"; const CIRCLE_CLASS = "circle"; const cellElements = document.querySelectorAll('[data-cell]'); const board = document.getElementById("board"); let circleTurn; function startGame() { // 修正原语法错误,遍历所有cell元素绑定点击事件 cellElements.forEach(cell => { cell.addEventListener("click", handleClick, { once: true }); }); } function handleClick(e) { // 确保获取到place-mark组件本身(点击可能触发在内部cell上) const placeMarkElement = e.target.closest('[data-cell]') || e.target; const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS; placeMark(placeMarkElement, currentClass); if (checkWin(currentClass)) { endGame(false); } else if (isDraw()) { endGame(true); } else { swapTurns(); setBoardHoverClass(); } } function placeMark(cell, currentClass) { // 访问组件Shadow DOM内的cell元素 const innerCell = cell.shadowRoot.querySelector('.cell'); innerCell.classList.add(currentClass); // 根据回合设置对应文本 innerCell.innerText = currentClass === CIRCLE_CLASS ? 'O' : 'X'; }
关键修正说明
- 修复事件绑定错误:原
startGame函数存在语法问题,改为遍历所有data-cell元素批量绑定点击事件。 - 定位正确组件:点击事件的
target可能是组件内部的celldiv,通过closest('[data-cell]')确保拿到place-mark组件本身。 - 访问Shadow DOM元素:利用
open模式的shadowRoot,通过cell.shadowRoot.querySelector('.cell')获取组件内部的cell元素,实现视图更新。 - 补充文本更新逻辑:原
placeMark函数仅添加样式类,补充设置innerText为O或X,让用户能直观看到选中状态。
如果想更贴合Web Component的封装思想,可以在组件内部添加方法管理标记逻辑:
// 在PlaceMark类中新增方法 setMark(mark) { const cell = this.shadowRoot.querySelector('.cell'); cell.innerText = mark; cell.classList.add(mark === 'O' ? CIRCLE_CLASS : X_CLASS); } // 修改placeMark函数调用组件方法 function placeMark(cell, currentClass) { const mark = currentClass === CIRCLE_CLASS ? 'O' : 'X'; cell.setMark(mark); }
内容的提问来源于stack exchange,提问作者Nazanin Naghavi
相关产品推荐
相关产品推荐

