What are Web Components

At present, our componentized development is mainly implemented with the help of frameworks, such as VUE/React. Now, a new set of technologies is well supported in all major browsers, and that’s Web Components. This is a standalone technology, not an API, but made up of three key technologies: Custom Elements, Shadow DOM, and HTML Templates. Through use, you can achieve effective isolation of CSS, JS, HTML between each component, which brings great convenience to development.

Our current development is becoming more and more componentized, and if we use this new technology, because it’s supported by native browsers, it’s going to run much faster than frameworks. So if we want TO carry out the technology selection, we need TO know our use scenario, such as TO B class background management system, so we can effectively specify the browser users use, then this situation is more suitable.

Take a look at the current level of support:

The support level of major browsers is quite good. (IE will soon be out of the picture, so it’s especially good for projects that don’t consider IE.)

Two, start learning

2.1 Creating a custom tag inherited from the P tag

Create a js file:

// custom-elements.js

class WordCount extends HTMLParagraphElement {
    constructor() {
        super(a); }// We just created a new custom element and did not use shadow DOM, so the styles are not isolated
    connectedCallback() {
        console.log('Triggered when first inserted into the DOM');
        this.render();
    }
    disconnectedCallback() {
        console.log('Triggered when deleted from the DOM');
    }
    attributeChangedCallback() {
        console.log('Called when a Custom Element adds, removes, or modifies its attributes');
    }
    render() {
        const count = this.getAttribute('count');
        const price = 20 * count;
        this.innerHTML = '<p> The number of choices is${count}The total price is${price}</p>`; }}// Create a custom element. The class object is WordCount, inherited from the 

element

customElements.define('word-count', WordCount, {extends: 'p'}); Copy the code

At creation time, there are three important life cycles:

  • The connectedCallback fires the first time it is inserted into the DOM, so it fires only once
  • DisconnectedCallback is fired when it is deleted from the DOM, so it only fires once
  • AttributeChangedCallback Is raised when custom Elements add, delete, or modify their attributes

HTML section:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>web components</title>
    <style>
        #title {
            font-size: 24px;
            color: # 333;
            height: 60px;
            line-height: 60px;
        }
        p {
            color:aquamarine;
            font-size: 30px;
        }

    </style>
    <script src="./custom-elements.js"></script>

</head>
<body>
    <div id="title">custom Component</div>
    
    <p is="word-count" count="10"></p>
</body>
</html>

Copy the code

So, the js file is introduced, and on the p tag, we have a custom attribute called is and count.

Take a look at the final browser render:

At present, there are the following basic conclusions:

  1. The custom component we created has been loaded into the browser
  2. The component is loaded under the P tag because our component inherits from the P tag
  3. The outer CSS properties can influence styles in custom components

2.2 Customize an HTML component and introduce shadow

Now create a fully custom component, like the vue or React custom components, and introduce style isolation

// shadow-dom.js

class PopupInfo extends HTMLElement {
    constructor() {
        super(a); }connectedCallback() {
        // Specify the code logic
        const shadow = this.attachShadow({mode: 'open'});
        const wrapper = document.createElement('span');
        wrapper.setAttribute('class'.'wrapper');
        const icon = document.createElement('span');
        icon.setAttribute('class'.'icon');
        icon.setAttribute('tabindex'.0);

        const info = document.createElement('span');
        info.setAttribute('class'.'info');

        // Get the content of the text property and add it to a SPAN tag
        const text = this.getAttribute('text');
        info.textContent = text;

        / / insert icon
        let imgUrl;
        if(this.hasAttribute('img')) {
            imgUrl = this.getAttribute('img');

        } else {
            imgUrl = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic%2F54%2F79%2F83%2F547983bb743d816230e483d A74bccbe1.jpg&refer=http%3A%2F%2Fup.enterdesk.com & app = 2002 & size = f9999, 10000 & q = a80 & n = 0 & g = 0 n & FMT = jpeg? = 1631007635 & t = faf the SEC afd459d7b1f23c5cfa51812c9e5fe';
        }
        const img = document.createElement('img');
        img.src= imgUrl;
        icon.appendChild(img);

        // Create CSS on shadow DOM
        const style = document.createElement('style');
        style.textContent = ` .wrapper { display: inline-block; width: 700px; height: 500px; background: #f5f5f5; font-size: 20px; } .icon { display: inline-block; height: 100px; } .icon img { height: 100%; } `;
        shadow.appendChild(style);
        shadow.appendChild(wrapper);
        wrapper.appendChild(icon);
        wrapper.appendChild(info);
    }

}

customElements.define('popup-info', PopupInfo);

Copy the code

This. AttachShadow ({mode: ‘open’}); AttachShadow MDN

There are two points that I think are important:

  • Some elements cannot use shadow DOM (e.g. )
  • Mode (mode)
    • openThe shadow root element can access the root node from outside of JS
    • closeDeny access to the closed Shadow root node from outside js

We created several tags, such as SPAN, IMG, and some attributes.

Look at the HTML operation:


<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Shadow DOM</title>
    <style>
        #title {
            font-size: 24px;
            color: # 333;
            height: 60px;
            line-height: 60px;
        }
        .span {
            font-size: 30px;
            color: green;
        }
        

    </style>
    <script src="./shadow-dom.js"></script>

</head>
<body>
    <div id="title">custom Component + shadow Dom</div>
    <popup-info text="Your card Validation code (CVC) is an extra security feature -- it is the last 3 or 4 numbers on the back of Your card."></popup-info>
    
</body>
</html>
Copy the code

If I do this, the result is:

As you can see, the component renders smoothly, and the styles on the outside do not affect the styles on the inside. Custom Element + shadow is used to isolate the custom component + styles.

2.3 Adding HTML Templates

The above two steps actually show the essence. However, there is still a step missing, that is, we are dealing with the template in JS processing, development is more troublesome, it is not easy to expand and maintain. So template can effectively solve this problem.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Web Components uses the template template</title>
    <style>
        #title {
            font-size: 24px;
            color: # 333;
            height: 60px;
            line-height: 60px;
        }
        p {
            color:aquamarine;
            font-size: 30px;
        }

    </style>
</head>
<body>
    <div id="title">custom Component</div>
    <template id="temp">

        <slot><p>Test test</p></slot>
    </template>
    
    <my-paragraph>
        <p>The new slot content replaces the default data</p>
    </my-paragraph>
</body>
<script src="./template.js"></script>
</html>

Copy the code

The template tag is not displayed on the page; it needs to be captured and then displayed



class MyParagraph extends HTMLElement {
    constructor() {
        super(a); }connectedCallback() {
        console.log('Triggered when first inserted into the DOM');
        const target = document.getElementById('temp');
        const content = target.content;
        const shadowRoot = this.attachShadow({mode: 'open'})
            .appendChild(content.cloneNode(true));
    }
}

customElements.define('my-paragraph', MyParagraph);



Copy the code

Another way to insert template is to use the link tag for HTML imports. Such as:

<link rel="import" href="./contents.html">

Copy the code

But this feature is no longer supported and will probably be removed later, see HTML_Imports

And:

So stop using HTML-imports.

That’s it for Web Components. It is important to note that this does not mean that frameworks such as VUE can be abandoned. The data-driven view of the MVVM framework cannot be implemented directly with Web Components. Combined, the two unlock new possibilities.