Web Components 是可重用的颗粒化 UI 组件,可以大幅提升 Web 开发效率。Custom Elements 是 Web Components 的核心部分,它们允许开发者定义自己的 HTML 标签,让标准的浏览器在渲染时可以像普通的 HTML 标签一样处理它们。这篇文章将着重介绍如何用 Custom Elements 创建可重用的 Web Components。
Custom Elements 概述
Custom Elements 是 Web Components 的核心部分,它通过 ES6 的 class
和 extends
语法,可以让我们定义自己的 HTML 标签,使它们拥有自己的行为和样式。具体说来,Custom Elements 可以让我们:
- 定义新的 HTML 元素
- 定义 HTML 元素的行为和属性
- 监听 HTML 元素的生命周期事件
Custom Elements 由两个主要部分组成:
- 自定义元素注册 (custom element registration)
- 用户定义的自定义元素类 (user-defined custom element classes)
注册 Custom Elements
为了将 Custom Elements 注册到浏览器中,我们需要使用 customElements.define()
方法。这个方法的第一个参数是我们要定义的标签名,第二个参数是继承自 HTMLElement 的类。举个例子,我们可以创建一个自定义元素 MyElement,代码如下:
class MyElement extends HTMLElement { constructor() { super(); console.log('MyElement 构造函数执行了。'); } } customElements.define('my-element', MyElement);
在上面的代码中,我们定义了自定义元素 my-element
,它继承自 HTMLElement 类,它的构造函数在自定义元素被创建时执行。自定义元素注册完成后,我们就可以在页面中使用它了。
<my-element></my-element>
继承 HTMLElement 类
Custom Elements 通过继承 HTMLElement 类,让我们的自定义元素获得了标准的 HTML 元素特性。 HTMLElement 类有一些常用的属性和方法,如下:
shadowRoot
: 这是创建 Shadow DOM 的 API,可以在 Shadow DOM 中定义样式和 HTML 结构。attachShadow()
: 这是创建 Shadow DOM 的方法,可以将 Shadow DOM 附加到当前元素上。setAttribute()
: 设置元素的属性。getAttribute()
: 获取元素的属性。removeAttribute()
: 移除元素的属性。
除了以上方法,HTMLElement 类还拥有容许访问 DOM 树的所有其他方法和属性。Web 开发者熟悉的诸如 innerHTML
、style
、classList
等属性和方法,都是从 HTMLElement 类中继承而来的。
自定义元素类实现
自定义元素类需要实现两个方法:constructor()
和 connectedCallback()
。
constructor()
Custom Elements 会在我们定义的自定义元素被实例化时调用 constructor()
方法。在这个方法中,我们可以初始化元素的状态、属性和事件。
-- -------------------- ---- ------- ----- --------- ------- ----------- - ------------- - -------- -- ------- ---------- - - ------ - -- - -
connectedCallback()
当我们把自定义元素添加到 DOM 树中时,Custom Elements 会调用 connectedCallback()
方法。在这个方法中,我们可以初始化元素的样式、Shadow DOM 和事件。
-- -------------------- ---- ------- ----- --------- ------- ----------- - ------------- - -------- -- ------- ---------- - - ------ - -- - ------------------- - -- ------- ------------------ - -------- -- -- ------ --- ----- ---------- - ------------------- ----- ------ --- -- - ------ --- ----- ----- ---- - ------------------------------- ---------------- - ------- --------------------- ----------------------------- -- ------- ------------------------------ -- -- - --------------- ------ ---------------- - - --- --- - -
属性和方法
当我们创建自定义元素后,在使用时可以为它添加属性和方法,这样我们就可以在应用中将自定义元素当做常规 HTML 元素来使用。在自定义元素中,我们可以通过 setAttribute()
方法来设置属性,通过 getAttribute()
方法来获取属性。
-- -------------------- ---- ------- ----- --------- ------- ----------- - ------ --- -------------------- - ------ ---------- - ------------- - -------- -- ------- ---------- - - ------ - -- - ------------------- - -------------- - ------------------------------ --------- --------- - -- ----- --- -------- - -------------- - - -------- - ----- ---------- - ---------------- -- ------------ - -- -- ------ --- ------ ----- ---- - --------------------------------- ---------------- - --------------------------- - ---- - -- -- ------ --- ----- ---------- - ------------------- ----- ------ --- -- - ------ --- ----- ----- ---- - ------------------------------- ---------------- - ------- --------------------- ---------------- - --------------------------- ----------------------------- - - ----------- - --------------- ------ ---------------- - - --- - ------------------ - ---------- - - -------------- ----------- -- -------------- - - ----------------------------------- -----------
在上面的代码中,我们重载了 Custom Elements 提供的静态 observedAttributes
方法,指定我们希望监听的属性名称列表。当这些属性发生变化时,Custom Elements 就会调用 attributeChangedCallback()
方法。在 render()
方法中,我们在 Shadow DOM 中添加元素,并使用一些已知的属性来更新它们的样式。
使用自定义元素时,我们可以设置它的属性来改变样式。
<my-element color="blue"></my-element>
我们也可以通过访问自定义元素的方法来改变它的状态。
const el = document.querySelector('my-element'); el.increment();
组合和覆盖元素
Custom Elements 允许我们在元素和多个子元素之间建立关系。最常见的办法是通过组合(composition)把多个元素组合到一起。在 Shadow DOM 中,我们可以通过添加子元素来达到这个目的。
-- -------------------- ---- ------- ----- -------- ------- ----------- - ------------- - -------- - ------------------- - ------------------------- - - ------- ------ - ---------- ----- - -------- ------------------------------ -- - - ---------------------------------- ----------
在上面的代码中,我们定义了一个自定义元素 MyButton。在 connectedCallback()
方法中,我们使用了 innerHTML
属性来添加一个包含 <style>
和 <button>
子元素的 Shadow DOM。在 <button>
元素内,我们使用了 <slot>
元素来表示它包含的内容。在使用 MyButton 时,它会把按钮组件和传递给它的内容组合在一起。
<my-button>Click Me!</my-button>
另一方面,Custom Elements 还支持元素的覆盖(extending)。这种情况下,子元素可以把父元素的一些行为修改或扩展为更具体的形式。例如,我们可以创建一个 my-input
元素来扩展 HTML5 的 input
元素。
-- -------------------- ---- ------- ----- ------- ------- ---------------- - ------------- - -------- - ------------------- - ---------- - -------- - - --------------------------------- -------- - -------- ------- ---
在上面的代码中,我们继承了 HTMLInputElement
类,并将它的 constructor()
方法调用委托给它的父类。connectedCallback()
方法中,我们将 value
属性设置为 "hello"。由于我们设置了 extends: 'input'
,所以我们的自定义元素会扩展 HTML5 的 input
元素。在使用 my-input
元素时,HTML5 的其他属性和方法(如 type
、disabled
、focus()
等)都是可用的。
<input is="my-input" />
总结
Custom Elements 是 Web Components 技术的核心,它允许我们创建可重用的 UI 组件,并且在标准的浏览器中以普通 HTML 的方式使用。通过自定义元素注册和继承 HTMLElement 类,我们可以创建具有自定义功能和样式的 HTML 元素。在自定义元素类的定义中,我们可以重载生命周期方法来自定义元素的行为和属性。通过 Shadow DOM,我们可以把元素和子元素组合在一起,创建出更复杂的 UI 组件。Custom Elements 技术可以大幅提升 Web 开发效率,使前端工具更加规范化,更加易于维护。
示例代码
完整的自定义元素和继承 HTMLElement 类的示例代码如下:
-- -------------------- ---- ------- ----- --------- ------- ----------- - ------ --- -------------------- - ------ ---------- - ------------- - -------- -- ------- ---------- - - ------ - -- - ------------------- - -------------- - ------------------------------ --------- --------- - -- ----- --- -------- - -------------- - - -------- - ----- ---------- - ---------------- -- ------------ - -- -- ------ --- ------ ----- ---- - --------------------------------- ---------------- - --------------------------- - ---- - -- -- ------ --- ----- ---------- - ------------------- ----- ------ --- -- - ------ --- ----- ----- ---- - ------------------------------- ---------------- - ------- --------------------- ---------------- - --------------------------- ----------------------------- -- ------- ------------------------------ -- -- - --------------- ------ ---------------- - - --- --- - - ----------- - --------------- ------ ---------------- - - --- - ------------------ - ---------- - - -------------- ----------- -- -------------- - - ----------------------------------- ----------- ----- -------- ------- ----------- - ------------- - -------- - ------------------- - ------------------------- - - ------- ------ - ---------- ----- - -------- ------------------------------ -- - - ---------------------------------- ----------
完整的继承 HTMLInputElement 类的示例代码如下:
-- -------------------- ---- ------- ----- ------- ------- ---------------- - ------------- - -------- - ------------------- - ---------- - -------- - - --------------------------------- -------- - -------- ------- ---
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65b912c8add4f0e0ff199e2f