Custom Elements 的使用与实践教程

什么是 Custom Elements

Custom Elements 是 Web Components 的一种技术,它使得开发者能够创建自定义的 HTML 元素,这些元素可以添加自己的属性和方法,形成独立的组件,方便复用和维护。Custom Elements 是由 W3C 官方标准化的,因此它具有跨浏览器兼容性,并且可以不依赖于任何框架,单独使用。同时,使用 Custom Elements 还可以让代码更加规范化和可维护。

如何创建 Custom Elements

定义元素

定义元素的方式有两种:

通过类和继承

<template id="hello-world">
  <style>h1 { color: red; }</style>
  <h1>Hello World!</h1>
</template>
class HelloWorld extends HTMLElement {
  constructor() {
    super();

    const template = document.getElementById('hello-world').content;
    this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
  }
}

customElements.define('hello-world', HelloWorld);

这段代码中,我们通过 ES6 的类语法来创建一个名为 HelloWorld 的元素,并继承了 HTMLElement 类。在 constructor 函数中,我们首先调用父类 HTMLElementconstructor 方法,在方法内部,创建了 template 模板元素,并通过 attachShadow 方法创建了新的 shadow root,将模板元素添加到 shadow root 中。

最后,我们通过 customElements.define 方法定义了 hello-world,这个名称会在我们使用时派上用场。

通过原型对象

<template id="hello-world">
  <style>h1 { color: red; }</style>
  <h1>Hello World!</h1>
</template>
const HelloWorldProto = Object.create(HTMLElement.prototype, {
  constructor: {
    value: function () {
      const template = document.getElementById('hello-world').content;
      const shadowRoot = this.attachShadow({ mode: 'open' });
      shadowRoot.appendChild(template.cloneNode(true));
    },
    writable: true,
    configurable: true
  }
});

customElements.define('hello-world', HelloWorldProto);

这段代码中,我们通过 Object.create 方法创建了一个原型对象,并继承了 HTMLElement.prototype,之后给该原型对象添加了 constructor 方法,并将其传递了一个函数。在构造函数中,我们按照上述内容创建了元素,并将其添加到 shadow root 中。

使用元素

使用刚刚定义的元素非常简单,只需要在 HTML 中使用它的标签名即可:

<hello-world></hello-world>

此时,浏览器会自动创建我们定义的 HelloWorld 元素。

Custom Elements 的实践

组合元素

在实际开发中,我们有时需要将多个元素组合成一个新的元素,方便复用和维护。在 Custom Elements 中,我们可以通过组合使用 divslot 元素来实现元素的组合。

<!-- 定义一个可复用的 card 组件 -->
<template id="card-template">
  <style>
    .card {
      border: 1px solid #ddd;
      padding: 10px;
    }
  </style>
  <div class="card">
    <h2></h2>
    <p></p>
  </div>
</template>

<card-el>
  <h2>Custom Elements 实践</h2>
  <p>这是一个基于 Custom Elements 创建的 card 组件。</p>
</card-el>
class CardElement extends HTMLElement {
  constructor() {
    super();

    const template = document.getElementById('card-template').content;
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.appendChild(template.cloneNode(true));

    const titleElement = this.shadowRoot.querySelector('h2');
    const contentElement = this.shadowRoot.querySelector('p');

    titleElement.innerText = this.getAttribute('title');
    contentElement.innerText = this.innerHTML;
  }
}

customElements.define('card-el', CardElement);

在上面的代码中,我们定义了一个名为 CardElement 的元素,并组合使用了一个 div 标签和两个 slot 标签。在构造函数中,我们通过 getAttributeinnerHTML 方法来获取 title 和 content,分别赋值到 card 组件中的 h2p 元素上。这样,我们就创建了一个灵活且可复用的 card 组件!

监听属性变化

在 Web 组件中,我们经常需要监听属性的变化。在 Custom Elements 中,我们可以使用 attributeChangedCallback 方法来监听自定义属性的变化。

class HelloWorld extends HTMLElement {
  static get observedAttributes() { return ['name']; }

  constructor() {
    super();

    const template = document.createElement('template');
    template.innerHTML = `
      <div>Hello, <span></span>!</div>
    `;
    
    this.attachShadow({ mode: 'open' }).appendChild(template.content.cloneNode(true));
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'name') {
      this.shadowRoot.querySelector('span').innerText = newValue;
    }
  }
}

customElements.define('hello-world', HelloWorld);

在上面的代码中,我们首先通过 static get observedAttributes 方法定义监测的属性名数组,然后在 constructor 函数中创建了 template 模板元素,并将其添加到了 shadow root 中。

最后,我们定义了 attributeChangedCallback 方法来监听 name 属性的变化,如果属性变化,则修改页面上的文字信息。

生命周期方法

Custom Elements 提供了一些生命周期方法来监听元素在生命周期中的变化,它们分别是:

  • connectedCallback: 元素被插入到文档时调用。
  • disconnectedCallback: 元素从文档中删除时调用。
  • adoptedCallback: 元素被移动到新的文档时调用。
  • attributeChangedCallback: 自定义属性被添加、删除、更新时调用。

在实际开发中,我们可以使用这些生命周期方法来完成一些特殊的需求。

总结

Custom Elements 是一种非常适合组件化开发的技术,它提供了一种标准化的、可扩展的、独立于框架的定义和使用 Web 组件的方法。在使用 Custom Elements 进行组件开发时,我们需要重点关注元素的定义、使用、组合和监听属性等特殊需求。Custom Elements 的出现,有助于使 Web 组件的开发更加规范、高效,降低前端开发的复杂度,提高开发效率和代码质量。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6590e40feb4cecbf2d627eb9


纠错
反馈