Read and understand Web Component in one article

foreword

Since the author is learning about micro-frontends recently, web componentwhich is also one of the major features, some micro-frontend frameworks are used, and I have studied relevant knowledge in depth and shared it.

What are Web Components?

Web Component is actually a combination of a series of technologies, mainly including 3 parts:

  • Custom elements. Extend the custom label element outside the basic HTML label, which is the "component" of the framework we usually use;
  • Shadow DOM. It is mainly used to isolate the content of Shadow DOM from the outer document DOM, which can be understood as a sub-container in the document to place various components;
  • HTML templates. Use <template>to define component templates, <slot>use as slots (Vuer must be no stranger);

One in an html file web componentlooks like this:

<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
  <div slot="slot-ele">插槽内容</div>
</trace-ele>

Looks a lot like Vue, right? Next, let's learn demos one by one web component.

good

Due to Web Componentthe native affinity, there is no need to rely on other packages, index.htmland index.jsyou can experience learning one by one.

We directly write an html template, and the case components of the article are collectively called<trace-ele />

index.html:

<body>
 <template id="trace">
      <div class="container">
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        />
        <p class="title">学习Web Component</p>
        <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
        <p class="price">¥25.00</p>
      </div>
    </template>
    <trace-ele />
    <script src="./index.js" />
</body>

Here we write a "template" - templateand declare <trace-ele />the components below.

And the principle of realizing all this is in index.jsthe.

class Trace extends HTMLElement {
    
    
  constructor() {
    
    
    super();
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    this.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

Web ComponentThe essence of a component is that a class inherits from it HTMLElement. After customElements.definethe component is declared, the pointer in the class thispoints to the component itself. The printed results are as follows:

image.png

When initializing, you need to provide the component with an empty shell, and bind templatethe id of the element, so that the component effect appears.

image.png

Does it feel Vuesimilar to seeing here? Next, let's continue to upgrade the functions of the components~

let's style

On the basis of the previous section, it is very simple to add a style to the component, index.htmljust change it, and templateadd style:

<body>
 <template id="trace">
      <div class="container">
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        />
        <p class="title">学习Web Component</p>
        <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
        <p class="price">¥25.00</p>
      </div>
      
      <style>
        .container {
      
      
          display: inline-flex;
          flex-direction: column;
          border-radius: 6px;
          border: 1px solid silver;
          padding: 16px;
          margin-right: 16px;
        }
        .image {
      
      
          border-radius: 6px;
        }
        .title {
      
      
          font-weight: 500;
          font-size: 16px;
          line-height: 22px;
          color: #222;
          margin-top: 14px;
          margin-bottom: 9px;
        }
        .desc {
      
      
          margin-bottom: 12px;
          line-height: 1;
          font-size: 14px;
        }
        .price {
      
      
          font-size: 14px;
        }
      </style>
    </template>
    <trace-ele />
    <script src="./index.js" />
</body>

The styles take effect:

image.png

But here if you give a general label style, like this:

<body>
    <p>组件外的P标签</p>
        <template>
        <p>组件中的P标签</p>
        <style>
           p {
      
      
             color: red;
           }
            ...
            .container {
      
      }
        </style>
        </template>
</body>

The effect is as follows:

image.png

It can be seen that the outside of the component p标签is also affected, and the color changes to red, but in the component concept, this style is actually only expected to act on the component itself. This is also the concept of style isolation, and fortunately, Web Componentan out-of-the-box style isolation solution is provided.

In order to prevent  conflicts <template> between the internal  <style> CSS and the global CSS, we can hang the component on the Shadow Root, and then use the Shadow Root to hang it on the outer document DOM, so that CSS isolation can be achieved:

class Trace extends HTMLElement {
    
    
  constructor() {
    
    
    super();
    this.attachShadow({
    
     mode: "open" });
    
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

Observe from the console:

image.png

And if there are multiple components, the essence is that documentthere are multiple in Shadow Root.

The entire DOM architecture diagram is as follows:

image.png

One of the advantages of Shadow DOM is that it can isolate DOM structure, style, and behavior from Document DOM. It is very suitable for component encapsulation, so it can become one of the important components of Web Component.

Props

VueSame as and React, Web Componentit also provides the form of father-to-son.

index.html:

<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">

Here 3 props are passed to the component, and printed in the component thisas follows:

With keen eyes, I have found the entrance to accept parameter passing in components:

image.png

Do a simple dynamic assignment:

class Trace extends HTMLElement {
    
    
  constructor() {
    
    
    super();

    this.attachShadow({
    
     mode: "open" });

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle.querySelector('.container > .title').textContent = this.getAttribute('name');
    cloneEle.querySelector('.container > .price').textContent = this.getAttribute('version');
    cloneEle.querySelector('.container > .desc').textContent = this.getAttribute('desc');

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

done~

Slot

Another benefit of HTML templates is that they can  Vue be used like  <slot>. For example, now we can  <trace-ele> add a slot at the bottom of this:

<body>
    <template id="trace">
        <div class="container">
            <p>组件中的P标签</p>
            <img
              class="image"
              src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
              alt=""
            />
            <p class="title">学习Web Component</p>
            <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
            <p class="price">¥25.00</p>
            <slot name="slot-ele"></slot>
        </div>
        <style>
        ...
        </style>
    </template>
    <trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
        <div slot="slot-ele">插槽内容</div>
    </trace-ele>
</body>

This way we can implement custom slot content.

event binding

Web ComponentYou can also bind events to elements or slots in components.

class Trace extends HTMLElement {
    
    
  constructor() {
    
    
    super();

    this.attachShadow({
    
     mode: "open" });

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle
      .querySelector(".container > .title")
      .addEventListener("click", this.onClick);

    this.shadowRoot.appendChild(cloneEle);
  }

  onClick = () => {
    
    
    alert("Click Me!");
  };
}

customElements.define("trace-ele", Trace);

image.png

Summarize

The above mainly shared with you some usage methods of Web Component. In general, Web Component is a combination of a series of APIs:

  • Custom Element : Register and use components
  • Shadow DOM : Isolate CSS
  • HTML template and slot : flexible DOM structure

It seems to be the infrastructure implementation of the current mainstream framework, and the framework is also based on the native capabilities to implement a complete set of solutions, such as Vue's responsive tracking and template syntax data binding, all of which we want to see .

Guess you like

Origin blog.csdn.net/m0_46995864/article/details/130561772