前言
在现代 Web 开发中,组件化已经成为了一种非常流行的开发模式。而 Custom Elements 和 Shadow DOM 则是其中非常重要的两个概念。本文将介绍 Custom Elements 和 Shadow DOM 的概念以及如何实战运用它们来开发 Web 组件。
Custom Elements
Custom Elements 是 Web Components 规范的一部分,它允许开发者创建自定义的 HTML 元素。开发者可以使用 JavaScript 来定义新的元素,包括其外观和行为,并将其注册为自定义元素。注册之后,这些自定义元素就可以像普通的 HTML 元素一样在页面中使用。
定义 Custom Elements
定义 Custom Elements 需要使用到 window.customElements
对象的 define()
方法。这个方法接收两个参数:元素名称和元素定义,其中元素名称必须包含短横线,以便与原生 HTML 元素区分开来。
下面是一个简单的例子:
<my-element></my-element>
class MyElement extends HTMLElement { constructor() { super(); this.innerHTML = 'Hello, World!'; } } window.customElements.define('my-element', MyElement);
在上面的例子中,我们定义了一个名为 MyElement
的自定义元素,并将其注册为 my-element
。当这个元素在页面中出现时,它的内部内容将被设置为 Hello, World!
。
生命周期方法
Custom Elements 有一些生命周期方法,可以让开发者在元素的生命周期中执行一些操作。常用的生命周期方法有:
connectedCallback()
: 当元素被插入到文档中时调用。disconnectedCallback()
: 当元素从文档中移除时调用。attributeChangedCallback(name, oldValue, newValue)
: 当元素的属性值发生变化时调用。
下面是一个例子:
// javascriptcn.com 代码示例 class MyElement extends HTMLElement { constructor() { super(); this._name = ''; } connectedCallback() { this._name = this.getAttribute('name'); this.render(); } attributeChangedCallback(name, oldValue, newValue) { if (name === 'name') { this._name = newValue; this.render(); } } render() { this.innerHTML = `Hello, ${this._name}!`; } } window.customElements.define('my-element', MyElement);
在上面的例子中,我们定义了一个名为 MyElement
的自定义元素,并在 connectedCallback()
和 attributeChangedCallback()
方法中更新了元素的内部内容。
继承原生元素
除了创建全新的元素之外,开发者还可以继承原生 HTML 元素,以扩展其功能。例如,我们可以创建一个名为 my-button
的按钮元素,它继承自原生的 button
元素,并添加了一些新的功能。
下面是一个例子:
<my-button>Click me!</my-button>
// javascriptcn.com 代码示例 class MyButton extends HTMLButtonElement { constructor() { super(); this.addEventListener('click', () => { console.log('Button clicked!'); }); } } window.customElements.define('my-button', MyButton, { extends: 'button' });
在上面的例子中,我们创建了一个名为 MyButton
的自定义元素,并将其继承自原生的 button
元素。我们还添加了一个点击事件监听器,以便在按钮被点击时打印一条消息。
指定样式
Custom Elements 的样式通常是由组件自身定义的。如果需要使用全局样式,则需要使用 :host
选择器。
下面是一个例子:
// javascriptcn.com 代码示例 <style> my-element { display: block; border: 1px solid black; padding: 10px; } my-element p { color: blue; } :host { font-family: Arial, sans-serif; } </style> <my-element> <p>Hello, World!</p> </my-element>
在上面的例子中,我们为 my-element
元素指定了一些样式,并使用 :host
选择器指定了全局样式。
Shadow DOM
Shadow DOM 是另一个 Web Components 规范的一部分,它允许开发者创建封装的 DOM 树。Shadow DOM 中的元素和样式都是私有的,不会被外部 CSS 或 JavaScript 影响。这使得开发者可以创建高度可定制化的组件,而不用担心组件内部的样式会与页面中的样式发生冲突。
创建 Shadow DOM
要创建 Shadow DOM,我们需要使用元素的 attachShadow()
方法。这个方法接收一个对象作为参数,其中 mode
属性指定了 Shadow DOM 的模式,可以是 open
或 closed
。open
模式允许外部 JavaScript 访问 Shadow DOM,而 closed
模式则不允许。
下面是一个例子:
<my-element></my-element>
// javascriptcn.com 代码示例 class MyElement extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); const style = document.createElement('style'); style.textContent = ` p { color: blue; } `; shadowRoot.appendChild(style); const p = document.createElement('p'); p.textContent = 'Hello, World!'; shadowRoot.appendChild(p); } } window.customElements.define('my-element', MyElement);
在上面的例子中,我们创建了一个名为 MyElement
的自定义元素,并使用 attachShadow()
方法创建了一个 Shadow DOM。我们还在 Shadow DOM 中添加了一个样式和一个段落元素。
事件传递
由于 Shadow DOM 中的元素是私有的,无法在外部 JavaScript 中直接访问。但是,我们可以使用 composed
选项来传递事件。
下面是一个例子:
<my-element></my-element>
// javascriptcn.com 代码示例 class MyElement extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); const button = document.createElement('button'); button.textContent = 'Click me!'; button.addEventListener('click', () => { const event = new CustomEvent('my-event', { bubbles: true, composed: true }); this.dispatchEvent(event); }); shadowRoot.appendChild(button); } } window.customElements.define('my-element', MyElement);
在上面的例子中,我们创建了一个名为 MyElement
的自定义元素,并在 Shadow DOM 中添加了一个按钮元素。当按钮被点击时,我们创建了一个自定义事件并将其分发到 MyElement
上,使用了 composed
选项。
插槽
插槽是 Shadow DOM 中的一个重要概念,它允许开发者在组件内部定义一些占位符,以便外部传递内容。插槽可以让组件更加灵活和可定制化。
下面是一个例子:
<my-element> <p slot="content">Hello, World!</p> </my-element>
// javascriptcn.com 代码示例 class MyElement extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); const template = document.createElement('template'); template.innerHTML = ` <style> .wrapper { display: flex; flex-direction: column; align-items: center; } </style> <div class="wrapper"> <slot name="content"></slot> <button>Click me!</button> </div> `; shadowRoot.appendChild(template.content.cloneNode(true)); } } window.customElements.define('my-element', MyElement);
在上面的例子中,我们创建了一个名为 MyElement
的自定义元素,并在 Shadow DOM 中定义了一个插槽 content
。我们还在 Shadow DOM 中添加了一个包含插槽和按钮的容器元素。
总结
Custom Elements 和 Shadow DOM 是 Web 组件的两个重要概念,它们可以让我们创建高度可定制化的组件,使得组件的样式和行为可以完全独立于页面中的其他元素。在实践中,我们可以使用 Custom Elements 和 Shadow DOM 来创建各种各样的组件,例如按钮、弹窗、菜单等等。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6555d9afd2f5e1655d04540c