在 Web 开发中,我们常常需要使用到复杂的 UI 元素,例如导航菜单、多级下拉框或自定义控件等。为了实现这些 UI 元素的重用和可维护性,我们需要将其封装为独立的组件。而本文将介绍如何使用 Custom Elements 和 Shadow DOM 来创建自定义的独立 UI 元素。
Custom Elements
Custom Elements 是一种浏览器原生支持的 JavaScript API,用于自定义 HTML 元素,使其具备自定义行为和属性。相较于传统的创建 DOM 元素的方式,使用 Custom Elements 可以创建更加优秀的封装组件。
创建 Custom Element
创建 Custom Element 可以使用 window.customElements.define()
方法,该方法需要两个参数:自定义元素的名称和其类定义。下面是一个简单的例子:
class HelloWorld extends HTMLElement { connectedCallback() { this.innerHTML = '<h1>Hello, World!</h1>'; } } customElements.define('hello-world', HelloWorld);
在上面的例子中,我们定义了一个名为 HelloWorld
的 Custom Element,并注册了它的标签名为 hello-world
。当页面加载时,HelloWorld
元素会自动渲染到页面中,并显示“Hello, World!” 消息。
自定义属性和方法
我们可以通过类属性和方法的方式为 Custom Element 添加自定义属性和行为。例如,我们可以为 HelloWorld
元素添加一个 name
属性,然后在 connectedCallback()
方法中使用该属性:
-- -------------------- ---- ------- ----- ---------- ------- ----------- - ------ --- -------------------- - ------ --------- - --- ----------- - ------------------------- ------- - --- ------ - ------ -------------------------- - ------------------- - ----- ---- - --------- -- -------- -------------- - ----------- --------------- - ------------------------------ --------- --------- - ------------------------- - - ------------------------------------ ------------
在上面的例子中,我们为 HelloWorld
元素添加了一个 name
属性,并在 connectedCallback()
方法中使用该属性绘制前缀。我们还将 name
属性定义为 observedAttributes
,以便我们可以跟踪任何属性的更改并在 attributeChangedCallback()
方法中反映这些更改。
生命周期回调
当我们使用 window.customElements.define()
方法定义一个 Custom Element 时,它将自动注册以下生命周期回调:
constructor()
- 元素创建时被调用。connectedCallback()
- 元素第一次被连接到文档 DOM 时被调用。disconnectedCallback()
- 元素从文档 DOM 中断开连接时被调用。attributeChangedCallback(name, oldValue, newValue)
- 元素的某个属性被添加、移除或更改时被调用。
通过覆盖这些回调,在特定生命周期阶段执行自定义逻辑。例如,我们可以在 connectedCallback()
方法中执行初始化逻辑,并在 disconnectedCallback()
方法中执行资源清理逻辑。
Shadow DOM
Shadow DOM 是在 Web 组件中用于封装样式和 DOM 的浏览器原生技术。它允许我们创建真正独立的组件,使其内部结构和样式对外部的 DOM 和样式不起作用。
创建 Shadow DOM
创建 Shadow DOM 可以使用 element.attachShadow()
方法。该方法将创建一个新的 Shadow DOM,并将其附加到指定的元素上。下面是一个创建 Shadow DOM 的例子:
-- -------------------- ---- ------- ----- ----------- ------- ----------- - ------------- - -------- -- -- ------ --- ----- ---------- - ------------------- ----- ------ --- -- ------- -------------------- - - ------- ----- - -------- ------ ----------------- ---- - -------- ---- ---------------- ------------- ------ -- - - ------------------------------------- -------------
在上面的例子中,我们使用 element.attachShadow()
方法创建一个带有 mode: 'open'
选项的 Shadow DOM。该选项允许外部文档访问内部 Shadow DOM 的内容。然后我们向 Shadow DOM 中添加了样式和内容。注意,我们使用了 :host
伪类选择器,以便为自定义元素本身添加样式。
样式隔离
Shadow DOM 的最大好处之一是样式隔离。这意味着我们可以将组件的样式封装在组件本身内部,并与外部文档的其他样式完全隔离。例如,我们可以在 Shadow DOM 中创建一个名为 content
的 div,然后为其添加背景颜色,而且它的样式不会影响外部文档:
.shadow-dom { width: 300px; height: 300px; background-color: blue; }
在上面的例子中,即使 shadow-dom
类被应用于外部文档中的其他元素,它也不会影响 content
div 的样式。
插槽
插槽是另一个 Shadow DOM 的有用功能。它可以在模板中定义一个或多个插槽,并将其填充为元素的内容。例如,我们可以在上面 MyComponent
的例子中使用插槽:
-- -------------------- ---- ------- ----- ----------- ------- ----------- - ------------- - -------- -- -- ------ --- ----- ---------- - ------------------- ----- ------ --- -- ------- -------------------- - - ------- ----- - -------- ------ ----------------- ---- - -------- ---- ---------------- ------------- ------ -- - - ------------------------------------- -------------
在上面的例子中,我们在 MyComponent
元素中定义了一个插槽,并在四周包围了 .content
div。这意味着任何放入 my-component
元素中的内容都将填充到插槽中。例如:
<my-component> <p>Hello, World!</p> </my-component>
上面的 HTML 将在 my-component
内部呈现为:
<div class="content"> <p>Hello, World!</p> </div>
总结
通过使用 Custom Elements 和 Shadow DOM,我们可以更好地封装和重用 UI 组件,并确保它们的样式和 DOM 不受外部文档的影响。我们还可以通过添加自定义属性和方法来扩展这些组件的行为。下面是一个示例 StarRating
组件,用于表示评级:
-- -------------------- ---- ------- ----- ---------- ------- ----------- - ------ --- -------------------- - ------ ---------- - ------------- - -------- ----- ---------- - ------------------- ----- ------ --- -------------------- - - ------- ----- - -------- ------------- - ----- - ------ -------- - ------ - ------ ----- - -------- ---- -------------- ----- ----------------------------- ------ -- ---------- - ------------------------------------- ------------------------- -- -- - ------------------------------ -- -- - ---------- - - - -- --- --- ---------- - -- - --- ------------ - -------------------------- ------- - --- ------- - ------ ------------------------------------ -- -- - ------------------------------ --------- --------- - ----- ----- - ------------------- ------------------------- -- -- - -- -- - ------ - ------------------------------- - ---- - ---------------------------- - --- - - ------------------------------------ ------------
该 StarRating
组件创建了一个包含五个星星的评级控件,可以通过点击星星进行打分,例如:
<star-rating value="3"></star-rating>
上面的 HTML 代码将呈现一个三星评级控件。
参考资料
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6478458f968c7c53b048596b