Web Component

Web Component 最早的概念可以追溯到 2011 年,到了 2018 年 V1 版本开始被主流浏览器所支持(除了 IE)。到了现在,几乎所有的浏览器都支持了 Web Component。

什么是 Web Component

MDN 上面的解释是 Web Component 是一套不同的技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 web 应用中使用它们。

其实挺语义化的,就是组件的意思。相对于 react 和 vue 可以很容易的创建一些组件,原生的最早之前对组件的概念非常弱。Web Component 的一个愿景就是可以使用原生的创建组件,跨越不同团队不同项目不同框架共用组件。

现阶段,有蛮多在使用原生的 Web Component,比如 YouToBe、网页 Photoshop、Microsoft 等。一直在开发业务,没机会使用 Web Component 在实践中开发,只能是了解一下这个概念。

Web Component 三个最核心的概念:

  • Custom Elements:自定义元素,一组 JavaScript API,允许你定义 custom elements 及其行为,然后可以在你的用户界面中按照需要使用它们。
  • Shadow DOM:影子 DOM,一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,你可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
  • HTML Templates:HTML 模板,template 和 slot 元素使你可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

创建组件,最重要的一些因素:样式隔离、组件传值、回调、生命周期,Web Component 都支持,下面实现一个简单的 button 组件。

load.js
export default (url) => {
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        resolve(xhr.responseText);
      }
    };
    xhr.send();
  });
};
button.js
import loadTemplate from'./load.js'

const templateContent = `
  
  
`

class Button extends HTMLElement {
  constructor() {
    super();
    loadTemplate('./button.html').then(res => {
      this.attachShadow({ mode: 'open' });
      const template = document.createElement('template');
      //res换成templateContent也可以
      template.innerHTML = res;
      const content = template.content.cloneNode(true);
      this.shadowRoot.appendChild(content);
      this.$button = this.shadowRoot.querySelector('button');

      this.$button.addEventListener('click', () => {
        this.dispatchEvent(new CustomEvent('onCustomClick', {
          detail: '这是子组件的数据'
        }))
      });
    })
  }
  connectedCallback(){
    console.log('生命周期connectedCallback');
  }
  disconnectedCallback(){
    console.log('生命周期disconnectedCallback');
  }
  adoptedCallback(){
    console.log('生命周期adoptedCallback');
  }
  attributeChangedCallback(name, oldVal, newVal){
    console.log('生命周期attributeChangedCallback', name, oldVal, newVal);
  }
  static get observedAttributes() {
    return ['text', 'class'];
  }
}
customElements.define('w-button', Button);
button.html


index.html 使用



  
  
  Document
  


  
    这是组件button按钮
    
  
  
  
  
  



tips
  • 把样式和标签跟 js 分开,参考的是 jQuery 的 load 方法,其实就是用 xhr 加载。如果不分开,可以在 js 里面用字符串模板实现,外部加载可以更好的编写标签和样式,如果使用 webpack、vite 等,可能更容易实现
  • 样式和标签隔离,Shadow DOM 天然支持,实现的非常的好
  • 组件传值,可以用属性,static get observedAttributes()一定要定义,父组件可以改变组件的值,子组件可以监听值的变化,实现子组件根据数据处理。传递的数据,如果是对象,需要序列化一下,因为只能传递字符串
  • 如果单纯的组件样式,触发点击事件可以直接 onclick 绑定,如果是子组件回调,最好使用 new CustomEvent 创建,父组件通过监听获取回调的数据
  • new CustomEvent 一定要把数据放在 detail 里面,可以是任意数据类型
  • slot 也有具名和不具名,具名插槽在父组件使用正常的标签
  • 生命周期直接声明就监听了,adoptedCallback 不知道怎么实现

Web Component 也有一些限制,比如 css 隔离的太彻底,和外部交互比较困难,要做双向数据绑定也比较不容易。不过都不算问题,现在已经有很多实现了 Web Component 的库,可以轻松的使用和构建 Web Component,那些问题都容易解决。个人觉得,Web Component 最大的意义是,可以在不同的框架之间共享组件,比如 Vue、React、Angular,这些框架都有各自的组件,但是 Web Component 的组件可以跨框架使用。

需要意识到,组件化,一般是在一些复用、数据结构稍微复杂的项目使用,组件的目的就是把整体的复杂性解构,从而提高开发效率和可维护性。如果是一些静态为主,加上一些少量交互,就没必要了,反而更不适用。

都 2023 年了,为什么没有哪一家大公司牵头创建 Web Component 生态和推广 Web Component 呢?

欢迎关注订阅号 coding 个人笔记

你可能感兴趣的:(前端)