querySelectorAll 不选择shadowRoot 中的元素

问题描述 投票:0回答:2

我正在尝试使用

tic-tac-toe game
Webpack
创建一个
Web Component

我需要在

div
组件的
cell
中选择具有
shadowRoot
类的
place-mark
标签,然后根据另一个函数计算的 Turn 将
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.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

javascript webpack web-component
2个回答
2
投票

您只需从代码中删除

shadowRoot
即可

它将让您有机会访问所有元素和

querySelect
您想要的东西。

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

0
投票

全局

querySelector
代码可以不能访问阴影根中内的DOM内容。

如果您有

open

 ShadowRoot,您可以执行以下操作:

document.querySelector("my-component").shadowRoot("[data-cell]")

当你有

nestedshadowRoots时,这当然会变得很麻烦。

您可能想将逻辑更改为:

    板发出一个
  • Event
  • 9 个图块监听
  • 事件,并采取相应行动
工作 SO 片段如下:

    单击图块即可发出
  • tileclicked
     事件
  • <my-board>
     监听此事件
  • 并发出一个事件
  • 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: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 可以设置所有图块的样式。你可以使用
    MY-BOARD.shadowRoot.querySelectorAll
    
    

  • 你也不需要

    getRootNode()

    然后去
    escapeshadowRoot,并找到closest("my-board")
    
    

  • 与残疾人进行实验

    console.log

    以了解事件如何重新定位,然后
    composedPath
    然后保存您的...

  • 它是 JavaScript,您可以在该

    detail:{} 属性包中传递函数 reference

    ...这样 Tile 就可以访问板上的 
    methods,反之亦然。

© www.soinside.com 2019 - 2024. All rights reserved.