CustomElements is a new API under the Web Components specification that can be used for componentized development.

If your app only works with the latest Chrome browser, it’s a great alternative to React or Vue.

Basic usage

The component declaration is in an HTML file. Components include styles (Style), nodes (DOM), and interaction logic (Script). The basic structure of a component file is as follows:

<template>
  <style></style>
  <div>DOM node</div>
</template>
<script>
  const componentDocument = document.currentScript.ownerDocument;

  class Component extends HTMLElement {

    static get TAG_NAME() {
      return 'component-tag-name';
    };

    constructor() {
      super(a);const shadow = this.attachShadow({ mode: 'closed' });
      const content = componentDocument.querySelector('template').content.cloneNode(true);
      shadow.appendChild(content);
    }
  }

  customElements.define(Component.TAG_NAME, Component);
</script>
Copy the code

The template node contains the Style (Style) and node (DOM). The interaction logic is in the script tag.

Component files are imported into HTML files by . The way to use components in HTML files is to write component tags directly. Such as:


      
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
  <title>HTML</title>
  <link rel="import" href="./component.html">
</head>
<body>
<component-tag-name></component-tag-name>
</body>
</html>
Copy the code

The component registration

The customElements. Define API is used to catalog components. The API accepts three parameters: the component label name, the component’s class, and the label type that the component inherits. Such as:

customElements.define('expanding-list', ExpandingList, { extends: "ul" });
Copy the code

The component constructor class is ExpandingList. The component inherits ul label features.

Component constructor class

A component’s building class needs to inherit from the HTMLElement class, or it can inherit from a subclass of HTMLElement, such as HTMLParagraphElement. If you inherit the class HTMLParagraphElement, a component has the features of a P tag.

class Component extends HTMLElement {
  constructor() {
    super(a);const shadow = this.attachShadow({ mode: 'closed' });
    const content = componentDocument.querySelector('template').content.cloneNode(true); shadow.appendChild(content); }}Copy the code

The constructor inside the component is required. Inside the constructor, we call the parent class’s constructor, create a Shadow DOM node, and add the component template content to the node.

Using Shadow DOM, the styles inside the component and outside the component do not interfere with each other, which makes component encapsulation more complete.

We can through the document. CurrentScript. OwnerDocument; To get the nodes of the template itself.

Component attributes

Components can use attributes just like HTML tags. Properties can be obtained from components.

<component-tag-name attr-name="attr-value"></component-tag-name>
Copy the code
class Component extends HTMLElement {
  constructor() {
    super(a);const shadow = this.attachShadow({ mode: 'closed' });
    const content = componentDocument.querySelector('template').content.cloneNode(true);
    shadow.appendChild(content);
    const attrValue = this.getAttribute('attr-name'); }}Copy the code

Component life cycle

  • connectedCallbackComponent mount, triggered after component initialization and when moving
  • disconnectedCallbackComponent uninstall
  • adoptedCallbackThe component is moved to a new document tree
  • attributeChangedCallbackComponent property changes

Component events

Custom events can be triggered.

<template>
  <style></style>
  <button>Component events</button>
</template>
<script>
  const componentDocument = document.currentScript.ownerDocument;

  class Component extends HTMLElement {

    static get TAG_NAME() {
      return 'component-tag-name';
    };

    static get BUTTON_CLICK() {
      return 'button-click';
    }

    constructor() {
      super(a);const shadow = this.attachShadow({ mode: 'closed' });
      const content = componentDocument.querySelector('template').content.cloneNode(true);
      shadow.appendChild(content);
      const button = shadow.querySelector('button');
      button.addEventListener('click', () = > {this.dispatchEvent(new CustomEvent(Component.BUTTON_CLICK, { button }));
      });
    }
  }

  customElements.define(Component.TAG_NAME, Component);
</script>
Copy the code

example

  • A basic example of customElements
  • Sample indexedDB implemented with customElements