6
头图

Write in front

Recently, I have devoted myself to researching Web components (hereinafter referred to as WC), and I have obtained certain results initially, but today I want to go back and re-examine WC.

What exactly is WC?

Quoting the explanation on MDN:

Web Components consists of several separate technologies. You can think of Web Components as reusable user interface widgets that are created using open Web technology. They are part of the browser and so they do not need external libraries like jQuery or Dojo. An existing Web Component can be used without writing code, simply by adding an import statement to an HTML page. Web Components use new or still-developing standard browser capabilities.

Simply put, Web Component is to encapsulate the component in the form of html tags, and there is no need to write additional js code when using it.

surrounding technology ecology, simply look at React and Vue as the component framework . Therefore, WC can be regarded as an extension/extension of the native label. After all, it is still a label!

Similar to the <video></video> tag, it has richer styles and operational attributes compared to the native tag.
image.png

Since Google has mastered the Chrome browser, it has been promoting the browser’s native components, the Web Components API. Compared with third-party frameworks, native components are simple, straightforward and intuitive, without loading any external modules, and the amount of code is small. It seems that everything is perfect, and there seems to be a trend that can be used to replace React, Vue and the like.

Many people have also proposed to compare it with the three front-end frameworks, such as "Who will become the future of Web Component and component-like technologies such as React, Angular, and Vue?" " , in fact, they are things in the two fields, and they are not comparable. The biggest advantage of WC lies in CSS anti-pollution and componentized implementation natively supported by browsers; while Vue and other MVVM frameworks focus on the realization of data separation and automatic binding. And the four major web apis contained in WC are standard specifications, and they are lagging in use (for example, newly implemented specifications often wait a few years before they are used), but frameworks such as vue, react, and ng will not.

Current defects

There are some minor problems when used with other web frameworks, which will cause some troubles in the development experience.

1. Callback of internal events of the component

For example, for the OK button in a pop-up component ( <my-dialog></my-dialog> ), how are its events triggered?

class myDialog extends HTMLElement {
  // ...
  connectedCallback() {
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.innerHTML = `
      <div class="dialog">
        <div class="dialog-content">
          <div class="dialog-body">
            弹窗内容
          </div>

          <button id="okBtn">确定</button>
        </div>
      </div>
    `;

    shadowRoot.querySelector('#okBtn').addEventListener('click', () => {
      // 组件内部定义事件
      this.dispatchEvent(new CustomEvent('okBtnFn'));
    });
  }
}

customElements.define('my-dialog', myDialog);

The current plan is to customize the event new CustomEvent() inside the custom element, and monitor it addEventListener This way of writing is very ugly, as if it has returned to the era of writing applications with native JS.

<my-dialog></my-dialog>

<script>
  export default {
    created() {
      document.addEventListener('okBtnFn', function(){
        // 点击弹窗按钮,触发回调事件
      });
    }
  }
</script>

2. Component style coverage

For developers, it is inevitable that they will encounter the need to adjust the internal style of the component. Whether you are using antd , vant or other component libraries, the CSS anti-pollution mechanism of WC makes it difficult for you to modify internal styles. This requires you to pay some price to modify the internal style in disguise. The specific method I wrote in the previous article is "8 Ways to Introduce External CSS in Web Components" , which is actually very cumbersome and does not conform to the developer's intuition. of.

3. The relative path of the internal resources of the component

For now, any component directly based on Custom Element v1, Template and HTML Import cannot be completely resource independent-use any internally encapsulated resources without knowing the user's environment and without adding additional restrictions to the user document. For example, if you have a custom icon component:

class MyIcon extends HTMLElement {
    static get observedAttributes() { return ['name','size','color'] }
    constructor() {
        super();
        const shadowRoot = this.attachShadow({ mode: 'open' });
        shadowRoot.innerHTML = `
            <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 1024 1024">
                <use id="use"></use>
            </svg>
        `
    }

    attributeChangedCallback (name, oldValue, newValue) {
        if( name == 'name' && this.shadowRoot){
            // 如果使用的项目中,根目录没有 icon.svg 文件,那就 gg
            this.use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `./icon.svg#icon-${newValue}`);
        }
    }
}

customElements.define('my-icon', MyIcon);

If there is no icon.svg file in the root directory of the project used, then gg. If you use the cdn path here, cross-domain problems will occur.

4. The problem of obtaining the value of form component

The values that contain tags such as <input>, <textarea>, or <select> in the Shadow DOM will not be automatically associated in the form.

Sample code:

// web component
class InputAge extends HTMLElement {
  constructor() {
    super();
  }
  
  // connect component
  connectedCallback() {
    const shadow = this.attachShadow({ mode: 'closed' });
    shadow.innerHTML = `<input type="number" placeholder="age" min="18" max="120" />`;
  }
}

// register component
customElements.define( 'input-age', InputAge );

After the WC component is used

<form id="myform">
  <input type="text" name="your-name" placeholder="name" />
  <input-age name="your-age"></input-age>

  <button>submit</button>
</form>

<script>
 const form = document.getElementById('myform');

  form.addEventListener('submit', e => {
    
    e.preventDefault();
    console.log('Submitted data:');

    const data = new FormData(form);
    for (let nv of data.entries()) {
      console.log(`  ${ nv[0] }: ${ nv[1] }`);
    }

  });
</script>

At the time of submission, the input-age of value could not be obtained. Of course there will be a solution, but it will be complicated.

Click to view

Other form tags to obtain value solution reference:

image.png

Click to view

5. Other

In addition, the lack of data binding and state management is also a defect of WC, which will not be repeated here.

Write at the back

  • WC refers to enriching the DOM features of HTML, allowing HTML to have more powerful reuse capabilities
  • WC can be directly used as a native label, running in any front-end framework and no framework
  • Combined with the current mainstream technology stack, the current main problem of WC is that there is a certain use cost for data communication and event delivery in complex components.
  • Compatibility issues, such as the :part method that can cover the internal style

above.


Allan91
2.3k 声望2.6k 粉丝