What is Web Component

Web Component is a W3C standards-supported componentization solution that allows us to write reusable components while giving us more detailed control over our own components. Like PWA, it is not a single technology, but consists of three:

  1. Shadow DOM
  2. Custom elements
  3. HTML templates

Let’s start with a simple example.

Let’s start with an example

We are going to write a TextReverse component that has a very simple function of displaying the incoming string upside down.

For example:
will display 321.

As a first step, we need to define the custom component.

class TextReverse extends HTMLElement {
    constructor() {
        super(a);const shadowRoot = this.attachShadow({ mode: 'open' });
        const text = this.getAttribute('text') | |' ';
        const wrapper = document.createElement('span');
        wrapper.textContent = text.split(' ').reverse().join(' '); shadowRoot.appendChild(wrapper); }}Copy the code

The way to define a component is quite simple. Just inherit HTMLElement and write your own initialization logic in the constructor.

During initialization, we first create a shadowRoot, which acts as a root for our entire component.

Next, we get our text property and invert it into the newly created SPAN element.

Finally, we insert the span with text into shadowRoot.

Once the definition is complete, we need to inform the system about the component registration.

customElements.define(
    'text-reverse',
    TextReverse
)
Copy the code

One small detail here is that the names we register must be underlined.

After the registration is completed, it can be used officially.

<text-reverse text='12345'></text-reverse>
Copy the code

Shadow Dom

In the example above, we used shadow root, which hosts all the content of our component. It is also the core technology of Web Component.

We all know that the Dom is really a tree, and our component is a node in the tree. We can call the component node shadow host.

Shadow Host contains an isolated DOM tree, which we call a Shadow Tree. The contents of the Shadow Tree do not affect the outside world. Shadow Root is the Root node of this lesson’s Shadow tree.

The structure is shown in the figure:

Style isolation

One of the highlights of Shadow DOM is style isolation. We can style the previous example.

class TextReverse extends HTMLElement {
    constructor() {
        super(a);// ...
        const style = document.createElement('style');
        style.textContent = `* { background: red; } `
        shadowRoot.appendChild(style);
        // ...}}Copy the code

We add a red background color to all the elements. However, it turns out that only the element background color within the component is affected. This style isolation feature is a good way to avoid style interference between different components.

Template

In the above example, we created the change node in code. This approach is less efficient than the React Jsx and Vue templates. So, we can use Template to solve this problem.

<template id='text-reverse'>
    <style>* {background: red;
        }
    </style>
    <span id='text'></span>
</template>
Copy the code
class TextReverse extends HTMLElement {
    constructor() {
        super(a);const shadowRoot = this.attachShadow({ mode: 'open' });
        const text = this.getAttribute('text') | |' ';
        const template = document.getElementById('text-reverse').content.cloneNode(true);
        template.getElementById('text').textContent = text.split(' ').reverse().join(' '); shadowRoot.appendChild(template); }}Copy the code

We define a template in HTML, then grab the template node just as we would a normal element, and then make a deep copy of the node’s contents. Finally, operate directly on the node.

Slot

Like Vue’s Slot, Slot gives components greater extensibility. With Slot, we can pass more custom content to the component.

In the example above, we add a custom title to the component.

<text-reverse text='12345'>
    <span slot='title'>text reverse</span>
</text-reverse>
<template id='text-reverse'>
        <h1><slot name='title'>default title</slot></h1>
        <span id='text'></span>
</template>
Copy the code

In the template, we define a slot element, name it title, and set a default value of default title if there is no content. When used, we add a slot attribute to the element to match the slot in the template.

Inheriting existing elements

So far, we have completely customized component content, and if we want to extend existing system elements, we need to define a built-in custom element. Let’s use a p element that shields numbers.

class PFilter extends HTMLParagraphElement {
    constructor() {
        super(a);const textContent = this.textContent;
        this.textContent = textContent.replace(/\d/g.The '*');
    }
}
customElements.define(
    'p-filter',
    PFilter,
    {
        extends: 'p'})Copy the code

Instead of inheriting HTMLElement, we inherit the P node HTMLParagraphElement that needs to be extended.

<p is='p-filter'>My mobile phone number is 10086</p>
Copy the code

Unlike a standalone custom component, we still need to declare it with the original element name, and in theisProperty for our component name.

The life cycle

Like most frameworks, Web Component has a number of ways to control the Component’s life cycle.

  1. ConnectedCallback: Called when custom elemen t is first inserted into the DOM.
  2. DisconnectedCallback: Called when a Custom Element is removed from the DOM.
  3. AdoptedCallback: Called when a Custom Element is moved to a new document.
  4. AttributeChangedCallback: when a custom element increase, delete and modify their own property, is invoked.

We simply declare the corresponding method in the class that defines the component. AttributeChangedCallback is special to other attributes in that it is used with observedAttributes.

class TextReverse extends HTMLElement {
    / /...
    static get observedAttributes () {
        return ['text'];
    }
    attributeChangedCallback () {
        const text = this.getAttribute('text') | |' ';
        this.shadowRoot.getElementById('text').textContent = text.split(' ').reverse().join(' '); }}Copy the code

We are inobservedAttributesAdd the value of the property to listen to in the static method. Then, in thetextChange when triggeredattributeChangedCallbackMethod to updatetextThe value of the.

The last

Web Component is very powerful. Compared to React, Vue and other frameworks, it has inherent style isolation and, most importantly, native browser support. But he still has a long, long way to go before he meets engineering standards.