在 Web 开发中,我们经常需要创建可复用的 UI 组件,以便在多个页面或项目中重复使用。然而,传统的 HTML、CSS 和 JavaScript 并没有提供一种良好的方式来创建自定义的组件和封装它们的样式和行为。这就导致了代码重复、维护困难和样式冲突等问题。
为了解决这些问题,HTML5 引入了两个新的特性:Shadow DOM 和 Custom Elements。它们提供了一种更加模块化和封装化的方式来创建可组合的 Web 应用程序。
Shadow DOM
Shadow DOM 是一种将 DOM 树封装在一个隔离的、私有的 DOM 子树中的技术。这个隔离的 DOM 子树称为 Shadow DOM 树。它可以让我们创建自定义的 UI 组件,并将它们的样式和行为封装在一个私有的作用域中,以避免样式冲突和污染全局命名空间。
创建 Shadow DOM
要创建 Shadow DOM,我们可以使用元素的 attachShadow()
方法。这个方法接受一个配置对象作为参数,其中 mode
属性可以指定 Shadow DOM 的模式,可以是 open
或 closed
。open
模式表示外部代码可以访问 Shadow DOM,closed
模式表示外部代码不能访问 Shadow DOM。
// javascriptcn.com 代码示例 <template id="my-component"> <style> /* Shadow DOM 样式 */ </style> <slot></slot> </template> <script> class MyComponent extends HTMLElement { constructor() { super(); const template = document.getElementById('my-component'); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.appendChild(template.content.cloneNode(true)); } } customElements.define('my-component', MyComponent); </script>
上面的代码定义了一个名为 my-component
的自定义元素,并将它的 Shadow DOM 树设置为 open
模式。<template>
标签中定义了 Shadow DOM 树的结构和样式,而 <slot>
标签则表示一个插槽,用于将外部内容插入 Shadow DOM 中。
使用 Shadow DOM
在外部使用 Shadow DOM 元素时,我们只需要像使用普通元素一样将它插入到 DOM 中即可。外部代码无法直接访问 Shadow DOM 中的内容和样式,但可以通过 CSS 的 ::slotted()
伪类选择器来选择插入到插槽中的内容。
// javascriptcn.com 代码示例 <my-component> <span slot="title">标题</span> <p>内容</p> </my-component> <style> my-component::slotted(span) { font-weight: bold; } </style>
上面的代码中,<my-component>
元素包含一个 <span>
元素,它被插入到了 my-component
的 Shadow DOM 中的 <slot>
中。外部样式可以通过 ::slotted()
伪类选择器来选择插入到插槽中的元素,并对它们应用样式。
Custom Elements
Custom Elements 是一种用于创建自定义 HTML 元素的技术。它可以让我们创建具有自定义行为和样式的元素,并将它们封装在一个独立的、可重用的组件中。
创建 Custom Elements
要创建 Custom Elements,我们需要定义一个继承自 HTMLElement
的类,并使用 customElements.define()
方法将它注册为一个自定义元素。在自定义元素的构造函数中,我们可以初始化元素的 Shadow DOM、属性和事件处理程序等。
// javascriptcn.com 代码示例 <template id="my-button"> <style> /* Shadow DOM 样式 */ </style> <button> <slot></slot> </button> </template> <script> class MyButton extends HTMLElement { constructor() { super(); const template = document.getElementById('my-button'); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.appendChild(template.content.cloneNode(true)); this.addEventListener('click', () => { // 处理点击事件 }); } } customElements.define('my-button', MyButton); </script>
上面的代码定义了一个名为 my-button
的自定义元素,并将它的 Shadow DOM 树设置为 open
模式。<template>
标签中定义了 Shadow DOM 树的结构和样式,而 <button>
标签则表示一个按钮元素。在构造函数中,我们初始化了 Shadow DOM、添加了点击事件处理程序等。
使用 Custom Elements
在外部使用 Custom Elements 时,我们只需要像使用普通元素一样将它插入到 DOM 中即可。Custom Elements 可以像普通元素一样设置属性和添加事件处理程序。
// javascriptcn.com 代码示例 <my-button> 点击我 </my-button> <script> const button = document.querySelector('my-button'); button.addEventListener('click', () => { alert('点击了按钮'); }); </script>
上面的代码中,<my-button>
元素被插入到了 DOM 中,并设置了一个文本内容。外部代码可以像普通元素一样添加事件处理程序,并在点击事件发生时弹出一个对话框。
组合 Shadow DOM 和 Custom Elements
Shadow DOM 和 Custom Elements 可以结合使用,以创建可组合的、封装的 UI 组件。我们可以将 Shadow DOM 和 Custom Elements 结合使用,以创建具有自定义行为和样式的元素,并将它们封装在一个独立的、可重用的组件中。
// javascriptcn.com 代码示例 <template id="my-card"> <style> /* Shadow DOM 样式 */ </style> <div class="card"> <img src="" alt="" class="card-image"> <div class="card-body"> <h2 class="card-title"><slot name="title"></slot></h2> <p class="card-text"><slot name="text"></slot></p> <slot></slot> </div> </div> </template> <script> class MyCard extends HTMLElement { constructor() { super(); const template = document.getElementById('my-card'); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.appendChild(template.content.cloneNode(true)); } } customElements.define('my-card', MyCard); </script>
上面的代码定义了一个名为 my-card
的自定义元素,并将它的 Shadow DOM 树设置为 open
模式。<template>
标签中定义了 Shadow DOM 树的结构和样式,而 <slot>
标签则表示插槽,用于将外部内容插入 Shadow DOM 中。
// javascriptcn.com 代码示例 <my-card> <img src="card.jpg" alt="" slot="image"> <span slot="title">卡片标题</span> <p slot="text">卡片内容</p> <button>查看详情</button> </my-card> <style> my-card { display: block; width: 300px; margin: 0 auto; border-radius: 4px; box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); } my-card .card { display: flex; flex-direction: column; align-items: center; padding: 16px; } my-card .card-image { width: 100%; height: 200px; object-fit: cover; margin-bottom: 16px; } my-card .card-title { font-size: 24px; margin-bottom: 8px; } my-card .card-text { font-size: 16px; margin-bottom: 16px; } my-card button { padding: 8px 16px; background-color: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; } </style>
上面的代码中,我们使用了自定义的 my-card
元素,并将它的 Shadow DOM 中的插槽填充了内容。外部样式可以选择自定义元素,并应用样式。
总结
Shadow DOM 和 Custom Elements 提供了一种更加模块化和封装化的方式来创建可组合的 Web 应用程序。使用 Shadow DOM,我们可以将 DOM 树封装在一个隔离的、私有的 DOM 子树中,并将样式和行为封装在一个私有的作用域中。使用 Custom Elements,我们可以创建自定义 HTML 元素,并为它们添加自定义行为和样式。结合使用 Shadow DOM 和 Custom Elements,我们可以创建具有自定义行为和样式的元素,并将它们封装在一个独立的、可重用的组件中。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6567a30dd2f5e1655d06da59