脱离框架的组件化解决方案 - Web Component

7,582 阅读5分钟

前言

组件化已经成为目前主流的前端开发模式,其可复用性这一大特点是一众复制粘贴工程师的福音。目前我们实现组件化主要是依托于各大框架如 VueReactAngular 。这些框架基本都是在遵从浏览器的规则下制定出自己的一套开发规则和书写语法使开发者的项目获得组件化的能力。随着近年来组件化框架的盛行,官方也推行了一套组件化的解决方案和原生API上的支持 —— Web Component

今天我们就借着本文,和大家一起简单来聊一下 Web Component

本文目录结构如下:

Web Component 是什么

本节,我们先来简单了解一下什么是 Web Component

Web Components 是一系列加入 w3cHTMLDOM 的特性,使得开发者可以创建可复用的组件。由于 web components 是由 w3c 组织去推动的,因此它很有可能在不久的将来成为浏览器的一个标配。

抛开官方为了推进这套方案的宣传文案不说,单从 原生、定制化标签 这些字眼就已经足够让开发者忍不住去了解它。

使用 Web Component 编写的组件是脱离框架的,换言之,也就是说使用 Web Component 开发的组件库,是适配所有框架的,不会像 Antd 这样需要对 VueReact等框架出不同的版本。

编写 Web Component 组件后,你可以这样使用它:

//引入自定义的组件
<script src="/build/myCom.js"></script>

//组件的使用
<my-com></my-com>

这里的 my-com 标签是原生的哦,不需要经过框架复杂的逻辑和算法去编译成 dom 挂载,或者说是浏览器本身会帮你做一些编译,但肯定会比框架的实现更加具有性能优势。

使用 Web Component

了解了 Web Component 的概念以后,我们再来看看该如何使用 Web Component

Web Component 核心技术

我们先来了解一下 Web Component 涉及的核心技术:

  • Custom elements(自定义元素):一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。

  • Shadow DOM(影子DOM):一组 JavaScript API,用于将封装的 "影子" DOM 树 附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。

  • HTML templates(HTML模板)< template >< slot > 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

  • HTML Imports(HTML导入):一旦定义了自定义组件,最简单的重用它的方法就是使其定义细节保存在一个单独的文件中,然后使用导入机制将其导入到想要实际使用它的页面中。HTML 导入就是这样一种机制,尽管存在争议 — Mozilla 根本不同意这种方法,并打算在将来实现更合适的。

完成一个简单的组件

接下来,我们来具体看一下 Web Component 的具体用法:

  1. 定义自定组件:

    class MyButton extends HTMLElement {
        constructor () {
            super();
            const template = document.getElementById('mybutton');
            const content = template.content.cloneNode(true);
            this.appendChild(content);
        }
    }
    

    (是不是和 react 的类组件很像呢。)

  2. 定义组件模板:

    <template id="mybutton">
        <button>Add</button>
    </template>
    
  3. 注册组件:

    window.customElements.define('my-button', MyButton);
    
  4. 使用组件:

    <body>
        <my-button></my-button>
    </body>
    

这样, 一个简单的 Web Component 就完成了。

生命周期

和一般框架中的组件一样,Web Component 的组件为了支持更多场景的应用也是有生命周期的。

常用的生命周期方法如下:

  • connectedCallback

    web component 被添加到 DOM 时,会调用这个回调函数,这个函数只会被执行一次。可以在这个回调函数中完成一些初始化操作,比如更加参数设置组件的样式。

  • disconnectedCallback

    web component 从文档 DOM 中删除时执行。

  • adoptedCallback

    web component 被移动到新文档时执行。

  • attributeChangedCallback

    被监听的属性发生变化时执行。

Web Component 和 React 的结合

React 官方文档中专门对 Web Component 做了一些解释,以此说明即便以后 **Web Component **流行,React 也是可以和 Web Component 共存的,二者并不是替代关系。具体情况详见 - 详细说明

在 Web Component 中使用 React

用法如下:

class XSearch extends HTMLElement {
  connectedCallback() {
    const mountPoint = document.createElement('span');
    this.attachShadow({ mode: 'open' }).appendChild(mountPoint);

    const name = this.getAttribute('name');
    const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
    ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
  }
}
customElements.define('x-search', XSearch);

在 React 中使用 Web Component

用法如下:

class HelloMessage extends React.Component {
  render() {
    return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
  }
}

React 中使用 Web Component 时,有一个点需要我们特别注意。Web Components 通常暴露的是命令式 API。例如,Web Components 的组件 video 可能会公开 play()pause() 方法。要访问 Web Components 的命令式 API,你需要使用 ref 直接与 DOM 节点进行交互。如果你使用的是第三方 Web Components,那么最好的解决方案是编写 React 组件包装该 Web Components

Web Components 触发的事件可能无法通过 React 渲染树正确的传递。 你需要在 React 组件中手动添加事件处理器来处理这些事件。

写在最后

这是一个学不动也要学的技术!鉴定完毕!