本文介绍: ShadowRoot 是 Web Components 中的一个重要概念,它允许开发者创建封装的 DOM 树,用于隔离组件内部样式脚本,以防止与外部环境发生冲突。ShadowRoot通过使用 Shadow DOM 技术实现的。Shadow DOM 是一种将 DOM 树封装一个 ShadowRoot 内部机制,使得 ShadowRoot 内部的 DOM 结构样式不会被外部环境影响

目录

webComponents

概念和使用

生命周期

总结


Web Component一套不同技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 web 应用使用它们。

作为开发者我们知道可能多的重用代码一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的 HTML(以及相关样式脚本),有时你不得不写代码呈现自定义 UI 控件,并且如果你不小心的话,多次使用它们会使你的页面变得一团糟。

Web Components 旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用创建封装功能定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突

实现 web component基本方法通常如下所示

  1. 创建一个类或函数指定 web 组件功能,如果使用类,请使用 ECMAScript 2015 的类语法 (参阅获取更多信息)。
  2. 使用 CustomElementRegistry.define() 方法注册你的新自定义元素,并向其传递定义的元素名称指定元素功能的类、以及可选的其所继承自的元素。
  3. 如果需要的话,使用 Element.attachShadow() 方法将一个 shadow DOM 附加到自定义元素上。使用通常的 DOM 方法shadow DOM 中添加子元素、事件监听器等等。
  4. 如果需要的话,使用 <template> 和 <slot> 定义一个 HTML 模板。再次使用常规 DOM 方法克隆模板并将其附加到你的 shadow DOM 中。
  5. 页面任何你喜欢的位置使用自定义元素,就像使用常规 HTML 元素那样。

定义自定义元素的类定义中的特殊回调函数影响行为

ShadowRoot 是 Web Components 中的一个重要概念,它允许开发者创建封装的 DOM 树,用于隔离组件内部的样式和脚本,以防止与外部环境发生冲突。

ShadowRoot 是通过使用 Shadow DOM 技术实现的。Shadow DOM 是一种将 DOM 树封装在一个 ShadowRoot 内部的机制,使得 ShadowRoot 内部的 DOM 结构和样式不会被外部环境影响

ShadowRoot 具有以下特点:

  1. 封装性:ShadowRoot 内部的 DOM 结构和样式是私有的,不会影响外部环境。这意味着你可以在 ShadowRoot 内部定义自己的样式规则,而不用担心与外部环境的样式冲突。

  2. 作用域:ShadowRoot 内部的样式只会应用于 ShadowRoot 内部的 DOM 元素,不会泄漏外部环境。这样可以确保组件的样式只对组件内部生效,不会影响到其他组件或页面的样式。

  3. 继承性:ShadowRoot 内部的 DOM 结构可以继承外部环境的样式,这意味着你可以在组件内部使用外部环境定义的样式,同时又能保持样式的封装性。

ShadowRoot 可以通过使用 Element 的 attachShadow() 方法来创建,并将其附加到一个元素上。例如

const element = document.querySelector('#my-element');
const shadowRoot = element.attachShadow({ mode: 'open' });

在上面的例子中,我们将一个 ShadowRoot 附加到 #my-element 元素上,并指定了 mode: 'open'表示 ShadowRoot 是开放的,可以从外部访问

一旦创建了 ShadowRoot,你可以在其中添加自己的 DOM 结构和样式,以及处理事件和其他逻辑。这样,你就可以将组件的实现细节封装在 ShadowRoot 内部,与外部环境隔离开来,提高组件的可维护性和可重用性。

Web Components 是一种用于创建可重用组件的技术,它是由一组 W3C 规范组成的。Web Components 可以让开发者创建自定义的 HTML 标签,这些标签可以在不同项目重复使用,从而提高代码的可重用性和可维护性

Web Components 由三个主要技术组成:

  1. Custom Elements:允许开发者创建自定义的 HTML 元素,这些元素可以像原生 HTML 元素一样使用。

  2. Shadow DOM:允许开发者创建封装的 DOM 树,这样可以避免组件内部的样式和脚本对外部环境的影响

  3. HTML Templates:允许开发者创建可重用的 HTML 模板,这些模板可以在不同的组件中重复使用。

使用 Web Components 可以带来很多好处,比如

  1. 提高代码的可重用性和可维护性

  2. 提高代码的可读性和可理解性。

  3. 提高开发效率,减少重复代码编写

  4. 支持跨平台和跨框架的组件共享

要使用 Web Components,你需要了解 Custom Elements、Shadow DOM 和 HTML Templates 的使用方法,并且需要使用 JavaScript 编写组件的逻辑。在实际开发中,你可以使用一些现成的 Web Components 框架比如 Polymer、LitElement、Stencil 等,这些框架可以帮助你更快速地创建和使用 Web Components。

 CustomElementRegistry接口的 define() 方法定义了一个自定义元素。

你可以创建两种类型的自定义元素:

customElements.define(name, constructor, options);

name 自定义元素名。

constructor 自定义元素构造器。

options可选

控制元素如何定义。目前有一个选项支持

CustomElementRegistry.define() 方法用于定义一个自定义元素,并将其注册浏览器的自定义元素注册表中。该方法接受两个参数:元素名称和元素类。

元素名称是一个字符串,表示自定义元素的名称。元素名称必须包含一个短横线,以避免与现有的HTML元素名称冲突。

元素类是一个JavaScript类,用于定义自定义元素的行为和样式。该类必须继承自HTMLElement类,并实现自定义元素的生命周期方法(如connectedCallbackdisconnectedCallback等)。

以下是一个简单示例演示如何使用CustomElementRegistry.define()方法定义一个自定义元素:

class MyElement extends HTMLElement {
  connectedCallback() {
    console.log('MyElement connected');
  }
}

customElements.define('my-element', MyElement);

在上面的示例中,我们定义了一个名为MyElement的自定义元素,并将其注册浏览器的自定义元素注册表中。该元素的名称为my-element,它继承自HTMLElement类,并实现connectedCallback方法。

一旦定义了自定义元素,就可以在HTML文档中使用它了。例如:

<my-element&gt;</my-element&gt;

浏览器解析到上面的HTML代码时,它会创建一个MyElement实例,并调用其connectedCallback方法。

CustomElementRegistry.define()方法还可以接受第三参数,用于指定自定义元素的选项。例如,可以使用extends选项指定自定义元素的基类,或者使用observedAttributes选项指定自定义元素的属性列表

总的来说,CustomElementRegistry.define()方法是定义和注册自定义元素的关键方法,它使开发者能够创建可重用的自定义元素,并将其集成到现有的Web应用程序中。

Element.attachShadow() 方法给指定的元素挂载一个 Shadow DOM,并且返回对 ShadowRoot 的引用

要注意的是,不是每一种类型的元素都可以附加到 shadow root(影子根)下面。出于安全考虑,一些元素不能使用 shadow DOM(例如<a>),以及许多其他的元素。下面是一个可以挂载 shadow root 的元素列表

var shadowroot = element.attachShadow(shadowRootInit);

shadowRootInit 一个 ShadowRootInit 字典,包括下列字段

mode模式

指定 Shadow DOM 树封装模式字符串,可以是以下值:

element.shadowRoot; // 返回一个 ShadowRoot 对象
element.shadowRoot; // 返回 null

delegatesFocus 焦点委托

一个布尔值,当设置为 true 时,指定减轻自定义元素的聚焦性能问题行为。 当 shadow DOM 中不可聚焦的部分点击时,让第一个可聚焦的部分成为焦点,并且 shadow host(影子主机)将提供所有可用的 :focus 样式。

返回一个 ShadowRoot 对象或者 null

异常 说明
InvalidStateError 无效状态错误 添加的元素已经是一个 shadow host(影子主机).
NotSupportedError 不被支持错误 应该添加 HTML 元素的命名空间之外的 shadow root,或者这个元素不能有其他 shadow 挂载到它上面 (见上).

ment.attachShadow() 是一个用于将 Shadow DOM 附加到指定元素的方法。Shadow DOM 是一种用于封装组件内部结构和样式的技术,可以将组件的样式和 DOM 结构与外部文档的样式和结构隔离开来,以避免样式冲突和组件内部结构的意外修改

使用 Element.attachShadow() 方法,可以在一个元素上创建一个 Shadow Root,并将其附加到该元素上。Shadow Root 是一个独立的 DOM 子树,其中可以包含组件的内部结构和样式。

下面是 Element.attachShadow() 方法的基本语法
 

element.attachShadow(options);

其中,options 是一个可选的对象,用于指定 Shadow Root 的模式常见模式有两种:

使用 Element.attachShadow() 方法的一般步骤如下:

  1. 创建一个自定义元素或选择一个现有的元素。
  2. 调用 attachShadow() 方法,并传入适当的选项。
  3. 在 Shadow Root 中编写组件的内部结构和样式。
  4. 将 Shadow Root 附加到元素上。

以下是一个简单示例演示了如何使用 Element.attachShadow() 方法创建一个带有 Shadow DOM 的自定义按钮组件:

<!DOCTYPE html&gt;
<html>
  <head>
    <style>
      /* 外部文档的样式 */
      button {
        background-color: blue;
        color: white;
      }
    </style>
  </head>
  <body>
    <my-button></my-button>

    <script>
      // 创建自定义按钮组件
      class MyButton extends HTMLElement {
        constructor() {
          super();
          const shadowRoot = this.attachShadow({ mode: 'open' });
          shadowRoot.innerHTML = `
            <style>
              /* 组件内部的样式 */
              button {
                background-color: red;
                color white:;
              }
            </style>
            <button>Click me</button>
          `;
        }
      }

      // 注自册定义按钮组件
      customElements.define('my-button', MyButton);
    </script>
  </body>
</html>

在上面的示例中,我们创建了一个自定义按钮组件 MyButton,并在其构造函数中调用了 attachShadow() 方法来创建 Shadow Root。在 Shadow Root 中,我们定义了按钮的内部结构和样式。最后,我们通过 customElements.define() 方法将自定义按钮组件注册为 <my-button> 标签然后可以在页面中使用该组件。

总结来说,Element.attachShadow() 方法是用于将 Shadow DOM 附加到指定元素的方法。通过使用该方法,我们可以创建独立的 Shadow Root,将组件的内部结构和样式与外部文档隔离开来,实现更好的组件封装和样式隔离

总结

这段代码是一个HTML页面的代码,它包含了一个自定义的HTML元素<wu-jie>,这个元素有一个属性url。在页面中,我们使用了一个<div>元素来测试样式隔离。在这个<wu-jie>元素的内部,我们使用了一个<template>元素来定义它的样式和内容。在JavaScript部分,我们定义了一个名为WuJie的类,它继承自HTMLElement,用于创建<wu-jie>元素。在WuJie类的构造函数中,我们使用了attachShadow方法来创建一个影子DOM,以实现样式隔离。然后我们使用querySelector方法获取<template>元素的内容,并将其添加到影子DOM中。在WuJie类中,我们还定义了一些生命周期方法,如connectedCallbackdisconnectedCallbackattributeChangedCallback,它们分别在元素插入到文档、从文档中移除和元素属性发生变化时自动触发最后,我们使用customElements.define方法将WuJie类注册为<wu-jie>元素的构造函数以便在页面中使用<wu-jie>元素。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!--外层写一个div测试隔离-->
    <div>我是div</div>

    <wu-jie url="xxxxxx"></wu-jie>


    <template id="wu-jie">
        <!--div的样式是作用全局的-->
        <style>
            div {
                background: red;
            }
        </style>
        <div>
            (测试样式隔离)
        </div>
    </template>


</body>
<script>
    window.onload = () => {
        class WuJie extends HTMLElement {
            constructor() {
                super()
                this.init()
                this.getAttr()
            }
            init() {
                const shadow = this.attachShadow({ mode: "open" }) //开启影子dom就是样式隔离
                const template = document.querySelector('#wu-jie')
                console.log(template);

                shadow.appendChild(template.content.cloneNode(true))
            }
            getAttr() {
                console.log('获取参数', this.getAttribute('url'));

            }

            //生命周期自动触发有东西插入
            connectedCallback() {
                console.log('类似于vue 的mounted');
            }
            //生命周期卸载
            disconnectedCallback() {
                console.log('类似于vuedestory');
            }
            //跟watch类似
            attributeChangedCallback(name, oldVal, newVal) {
                console.log('跟vuewatch 类似 有属性发生变化自动触发');
            }

        }

        window.customElements.define('wu-jie', WuJie)
    }


</script>

</html>

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注