Component development based on Custom Elements

Posted by T_Hayden on Tue, 22 Oct 2019 23:01:45 +0200

customElements It is a new API under the Web Components specification, which can be used to implement component-based development.

If your app is only compatible with the latest Chrome browser, it's a good alternative to React or Vue.

Basic Usage

The component is declared in an HTML file. Components include Style, DOM and 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();
      const shadow = this.attachShadow({ mode: 'closed' });
      const content = componentDocument.querySelector('template').content.cloneNode(true);
      shadow.appendChild(content);
    }
  }

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

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

Component files are imported into HTML files by < link rel = "import" href = ". / component. HTML" > The way to use components in HTML files is to write component tags directly. For example:

<!DOCTYPE HTML>
<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>

Component registration

The customElements.define API is used to catalog components. The API takes three parameters: component tag name, component class, and component inherited tag type. Such as:

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

A component labeled expanding list is declared above. The construction class of the component is that expanding list needs to be declared. The component inherits the characteristics of ul tag.

Component construction class

The construction class of the component needs to inherit the HTMLElement class, or it can inherit the subclass of HTMLElement such as HTMLParagraphElement. If it inherits the HTMLParagraphElement class, the component will have the property of p tag.

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

The constructor within the component is required. In the constructor, we first need to call the constructor of the parent class, and then create a Shadow DOM Node, and then add the component template content to the node.

Using Shadow DOM can make the styles inside and outside components not interfere with each other, and make component encapsulation more thorough.

We can use document.currentScript.ownerDocument; to get the heel node of the template itself.

Component properties

Components can use properties like HTML tags. Properties can be obtained in the component.

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

Component lifecycle

  • The connectedCallback component is mounted, which will be triggered after initialization and when moving.
  • disconnectedCallback component uninstall
  • The adoptedCallback component is moved to a new document tree
  • attributeChangedCallback component attribute change

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();
      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>

Example

Topics: Javascript React Vue Attribute