使用 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
我目前正在使用 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