webpack querySelectorAll不选择shadowRoot中的元素

osh3o9ms  于 5个月前  发布在  Webpack
关注(0)|答案(2)|浏览(66)

我正在尝试使用WebpackWeb Component创建tic-tac-toe game
我需要在place-mark组件的shadowRoot中选择一个具有cell类的div标记,然后根据另一个函数计算的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

iqjalb3h

iqjalb3h1#

你可以简单地从代码中删除shadowRoot
它会给你给予机会去访问所有的元素和你想要的querySelect

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

字符串

brjng4g3

brjng4g32#

全局querySelector代码可以访问shadowRoots内的DOM内容
如果你有一个open shadowRoot,你可以做:
document.querySelector("my-component").shadowRoot("[data-cell]")
当你有nestedshadowRoots时,这当然会变得很麻烦。

您可能需要将逻辑更改为:

  • 板卡发出Event
  • 9个磁贴监听事件,并采取相应行动

下面是工作流程:

  • 单击平铺以发出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>

字符串

Playground:https://jsfiddle.net/WebComponents/Lk9r4gx2/
备注:

  • 在实践中,我不会在<my-tile>上设置shadowDOM;然后<my-board> STYLE可以设置所有tile的样式。
  • 你也不需要getRootNode()然后 escape shadowRoot,并找到closest("my-board")
  • 使用禁用的console.log进行实验,以了解事件如何重新定位,然后composedPath保存您的.
  • 它的JavaScript,你可以在detail:{}属性包中传递一个Functionreference...这样Tile就可以访问Board上的方法,反之亦然。

相关问题