使用 Vue3 的 Web 组件中的 Shadow DOM

Shadow DOM in web components with Vue3

我目前正在使用 Vue3 测试 Web 组件,想知道这个 Shadow DOM 是如何工作的。某些第三方库正在访问具有 getElementById() 的元素并抛出错误,因为该元素是 null。 显然,这是因为无法从 Web 组件访问实际的 DOM。所以这意味着函数甚至无法找到组件本身使用的 HTML 元素。谁能解释为什么会这样?那么我将如何访问这些元素?也许 shadowRoot?

Test.vue:

<template>
<div id="test">Hello World!</div>
</template>

<script lang="js">
import {
    ref,
    onMounted
} from "vue";

export default {
    setup(props) {
        onMounted(() => {
            // NULL
            console.log(document.getElementById("test"));
        });
    }
}
</script>

main.js:

import { defineCustomElement } from 'vue'
import Test from './Test.vue'

const ExampleElement = defineCustomElement(Test)

// register
window.customElements.define('test-component', ExampleElement)

是的,shadowDOM是为了封装内容。

如果您不希望出现这种情况,请不要使用影子DOM
但是,如果您使用的是工具,它可能会对您施加阴影DOM,
在那种情况下,放弃该工具并使用 Vanilla JavaScript 创建一个组件,这不是火箭科学。

如果您正在学习 Web Components,最好先学习技术,而不是工具...因为拥有工具的傻瓜仍然是傻瓜。

如果自定义元素(带阴影DOM)存在于DOM中,并且已在mode:"open"中注册,您可以通过以下方式查询其内容:

document.querySelector("test-component").shadowRoot.querySelector("#test")

如果你想在页面中找到所有 Web组件,你可以像这样做一些事情

// findElements takes a function definition, the output must be Truthy or Falsy
function findElements( accept = x => customElements.get(x.localName) || 0) {
  function log() {
    console.log(`%c findElements `, `background:purple;color:yellow`, ...arguments);
  }
  let node, elements = [], shadowRootCount = 0;
  function diveNode( diveRoot ) {
    // IE9 was last to implement the TreeWalker/NodeIterator API ... in 2011
    let iterator = document.createNodeIterator(
      diveRoot,
      NodeFilter.SHOW_ELEMENT,
      node => accept(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
    );
    while ( node = iterator.nextNode() ) {
      if (node.shadowRoot) {
        log(`dive into shadowRoot #${++shadowRootCount} at`, node.outerHTML);
        [...node.shadowRoot.children].forEach( diveNode );
      }
      elements.push(node);
    }
  }
  diveNode( document.body ); // initial dive location
  log(elements.length, `elements found`,[elements]);
  //return elements;
}
findElements((x) => true); // find all DOM elements
findElements(); // find all Custom Elements