繁体   English   中英

querySelectorAll 没有选择 shadowRoot 中的元素

[英]querySelectorAll not selecting elements within shadowRoot

我正在尝试使用WebpackWeb Component创建井字游戏

我需要 select div标签在place-mark组件处的shadowRoot内具有cell class 然后根据另一个 function 计算的 Turn 将innerText更新为 O/X。

逻辑运行正常,但我不能 select 正确的组件来更新 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.addEventListener("click", handleClick, { once: true });});
}

function handleClick(e) {
const cell = e.target;
const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS;
placeMark(cell, currentClass);
  if (checkWin(currentClass)) {
    endGame(false);
  } else if (isDraw()) {
    endGame(true);
  } else {
    swapTurns();
    setBoardHoverClass();
  }
}

function placeMark(cell, currentClass) {
  cell.classList.add(currentClass);
}

如果您需要以上代码的完整版本,这是我的项目:

https://github.com/nazaninsnr/TicTacToe

你可以简单地从你的代码中删除shadowRoot

它将使您有机会访问所有元素并querySelect选择您想要的内容。

export default class PlaceMark extends HTMLElement {
constructor() {
super();
this.appendChild(template.content.cloneNode(true));}}
window.customElements.define("place-mark", PlaceMark);

全局querySelector代码无法访问shadowRoots中的 DOM 内容。

如果你有一个open的 shadowRoot,你可以这样做:
document.querySelector("my-component").shadowRoot("[data-cell]")

当您嵌套了 shadowRoots 时,这当然会变得棘手。

您可能希望将逻辑更改为:

  • 板子发出一个事件
  • 9 个瓦片监听事件,并采取相应的行动

下面的工作SO片段:

  • 单击图块以发出tileclicked事件
  • <my-board>监听这个事件
  • 并发出一个 Event colortile
  • 所有 9 个图块都监听colortile事件
  • 每块瓷砖都会改变颜色

 <my-board></my-board> <hr> <my-board></my-board> <script> class GameComponent extends HTMLElement { constructor(html){ super().attachShadow({mode: "open"}).innerHTML = html; } dispatch({ from = this,eventname,detail = {} }) { from.dispatchEvent(new CustomEvent(eventname, { composed: true, bubbles: true, detail })); } listen({at = this,eventname,func }) { at.addEventListener(eventname, func); } } customElements.define("my-board", class extends GameComponent { constructor() { super(`<style>:host{display:grid;grid:repeat(3,20px)/repeat(3,60px);gap:1px}</style>` + "green,red,blue,orange,olive,tan,teal,yellow,lime".split(",").map(color => `<my-tile>${color}</my-tile>`).join("")); } connectedCallback() { this.listen({ at:this, eventname:"tileclicked", func: (evt) => { //console.log(evt.target,evt.composedPath()); this.dispatch({ from: this, eventname: "colortile", detail: { color: evt.detail.color }})}}) } }); customElements.define("my-tile", class extends GameComponent { constructor() { super(`<style>:host{text-align:center;cursor:pointer}</style><slot></slot>`); } connectedCallback() { this.onclick = () => this.dispatch({ from: this, eventname: "tileclicked", detail: { color: this.innerText }}); this.listen({ at: this.getRootNode().host.closest("my-board"), eventname: "colortile", func: (evt) => this.style.background = evt.detail.color }); } }); </script>

游乐场: https://jsfiddle.net/WebComponents/Lk9r4gx2/

笔记:

  • 实际上,我不会在<my-tile>上设置 shadowDOM; 然后<my-board> STYLE 可以设置所有图块的样式

  • 您也不需要getRootNode()逃避shadowRoot,并找到closest("my-board")

  • 尝试禁用的console.log以了解事件如何重新定位,然后composedPath会保存您的...

  • 它的 JavaScript,您可以传递 Function参考detail:{}属性包...这样 Tile 可以访问板上的方法,反之亦然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM