# web component 自定义元素 and Shadow DOM

自定义元素的一个重要方面是封装,因为自定义元素从定义上来说是一种可重用功能:它可以被放置在任何网页中,并且期望它能够正常工作。因此,很重要的一点是,运行在页面中的代码不应该能够通过修改自定义元素的内部实现而意外地破坏它。影子 DOM(Shadow DOM)允许你将一个 DOM 树附加到一个元素上,并且使该树的内部对于在页面中运行的 JavaScript 和 CSS 是隐藏的。

影子 DOM 允许将隐藏的 DOM 树附加到常规 DOM 树中的元素上——这个影子 DOM 始于一个影子根,在其之下你可以用与普通 DOM 相同的方式附加任何元素。

  • 影子宿主(Shadow host): 影子 DOM 附加到的常规 DOM 节点。
  • 影子树(Shadow tree): 影子 DOM 内部的 DOM 树。
  • 影子边界(Shadow boundary): 影子 DOM 终止,常规 DOM 开始的地方。
  • 影子根(Shadow root): 影子树的根节点。

# Element.attachShadow()

创建一个自定义元素类,它继承了HTMLElement,并在构造函数中定义了元素的行为。然后,我们使用customElements.define()方法来注册这个自定义元素。

// 定义一个自定义元素类  
class GreetingElement extends HTMLElement {  
  constructor() {  
    // 调用 super() 是必须的,它确保了我们正确地继承了 HTMLElement  
    super();  
  
    // 创建一个 shadow root,它是一个独立的 DOM 树,用于封装自定义元素的内部结构  
    const shadow = this.attachShadow({mode: 'open'});  
  
    // 在 shadow root 中创建一个 p 元素,并设置其文本内容  
    const paragraph = document.createElement('p');  
    paragraph.textContent = '欢迎来到我的自定义元素!';  
  
    // 将 p 元素添加到 shadow root 中  
    shadow.appendChild(paragraph);  
  }  
}  
  
// 注册自定义元素,使其可以在 HTML 中使用  
customElements.define('greeting-element', GreetingElement);

在 HTML 中使用这个自定义元素了:

<!DOCTYPE html>  
<html>  
<head>  
  <title>自定义元素示例</title>  
</head>  
<body>  
  <!-- 使用自定义元素 -->  
  <greeting-element></greeting-element>  
  
  <script>  
    // 在这里定义和注册自定义元素  
    // ...(上面的 JavaScript 代码)  
  </script>  
</body>  
</html>

创建了一个名为greeting-element的自定义元素。当这个元素被插入到 DOM 中时,它会创建一个 shadow root,并在其中创建一个包含欢迎消息的 p 元素。这个 p 元素对于页面上的其他代码是不可见的,因为它被封装在 shadow root 中。这样,我们就可以确保自定义元素的内部结构和样式不会影响到页面的其他部分。

# Element.shadowRoot

Shadow Root 是 Shadow DOM(阴影DOM)的一个关键部分。Shadow DOM 是一种允许开发者在 DOM(文档对象模型)中封装一部分 HTML 结构及其相关样式和 JavaScript 的机制,这样被封装的部分就不会影响到页面的其他部分。Shadow Root 就是这个封装结构的根节点。

Shadow Root 类似于一个普通的 DOM 树,但它不是主文档 DOM 的一部分,而是通过 Shadow DOM 创建的。它包含了 Shadow DOM 中的所有元素和节点,但对外部来说是不可见的。这意味着,除非通过特定的 API(如 shadowRoot 属性),否则无法直接访问或修改 Shadow Root 中的内容。

Shadow Root 使得开发者可以创建可复用的组件,这些组件的样式和行为可以独立于主文档的其他部分。这对于创建封装良好的自定义元素(如 Web Components)特别有用,因为自定义元素的行为和样式可以被完全封装在其 Shadow Root 内。

在 JavaScript 中,你可以通过元素的 shadowRoot 属性来访问一个元素的 Shadow Root。如果元素没有 Shadow Root,该属性将返回 null。一旦你有了对 Shadow Root 的引用,你就可以像操作普通的 DOM 树一样来操作它,包括添加、删除和修改节点。

Shadow Root 有两种模式:'open' 和 'closed'。在 'open' 模式下,Shadow Root 是可访问的,可以通过 shadowRoot 属性来访问。而在 'closed' 模式下,Shadow Root 是不可访问的,尝试访问将返回 null。默认情况下,新创建的 Shadow Root 是 'open' 模式的,但可以通过 attachShadow 方法的第二个参数来指定为 'closed' 模式。

// 假设你有一个自定义元素 <my-element>  
const myElement = document.querySelector('my-element');  
  
// 获取 Shadow Root  
const shadowRoot = myElement.shadowRoot;  
  
if (shadowRoot) {  
  // 现在你可以操作 shadowRoot 中的 DOM 了  
} else {  
  console.error('该元素没有 Shadow Root');  
}

MDN链接 (opens new window)

最后更新: 11/26/2024, 1:31:53 PM