web component

web component

web component 的目的是实现可复用的定制元素。web component与vue这类MVVM框架的组件非常相似,但是不同的地方在于,web component是原生支持的,浏览器可以识别它,不需要经过编译才能被浏览器识别。

web component有以下特点

  • 原生支持,性能更好,迭代前景更好

  • 无关框架,理论上任何基于js的框架都能使用

  • 基于shadow DOM(影子DOM),保证组件功能和样式的私有性,实现真正的组件化

web component由三大部分组成

  1. 自定义元素。 可以在html使用自定义的标签,来实现UI。

  2. 影子DOM。创建影子DOM树,并附加到主文档DOM上,并保证内部功能和样式的私有话,防止内部与外部功能和样式冲突。

  3. HTML模板,使用templateslot ,使得元素结构能够被复用和定制。

stenciljs

stencil是ionic团队开发的一款用于开发基于web component的系统或组件的编译器。

优点

  • 大量使用装饰器,学习成本低,尤其是如果有Vue这类MVVM框架的经验时,很容易上手

  • 自动生成使用文档

  • 原生支持typescript和tsx

  • 提供多种框架集成的案例

  • 基于rollup打包,比webpack速度快

  • 集成e2e测试

最佳实践

尽量减少DOM结构

减少DOM结构不仅能够提升性能,更能使用户更方便地穿透样式。

穿透样式

  1. 当DOM结构比较简单使,使用inherit来继承Host上的样式

  2. 提供css变量来定制关键样式

  3. 尽可能地提供part,利用::part伪类元素选择器来定制样式(注意:part选择器无法选中子孙)

快速开发 vs 控制反转

对于不复杂且通用的组件逻辑,提供Prop来控制,对于复杂的组件功能,提供slot来实现。换句话说就是通过Prop来实现快速开发,通过slot(控制反转思想的实现)来提供定制组件的能力。

保留一个_this指向节点

component有时候会自行调用某些方法,例如message组件会在1.5s后调用destroy方法自动销毁,而这个时候就需要访问到对应到元素节点,这里有两种解决方法,一种是为元素节点设置一个id,并且每创建一个节点就让id++,并将id保存到this中,这样就可以通过document.querySelector('特定前缀' + this.id)来访问真实节点;另一种方法是通过jsx ref,直接获取host到节点对象,并存储为this的一个属性上(_this)。

第二种方法比第一种好,因为第二种不需要为host设置id,避免覆盖了用户设置的id。

更新:stencil提供@Element装饰器,可以直接获取Host元素。

踩坑记录

this的指向

stencil采用class来创建组件,而在class中this的指向有多种情况。

通常情况下this是指向实例,但是当类方法是作为事件处理程序被调用时,this则指向当前节点。

解决方法是使用箭头函数或者bind绑定this为类实例。

@font-face

在影子DOM使用@font-face无法正常的加载字体,无论是本地还是网络加载。目前的解决方式是通过js在主文档中创建style标签进行加载,或者直接将css引入。

storybook集成

storybook如果接入web component会导致无法正常工作,因此在init的时候应当选择html模板。

package.json添加script命令build:watch,设置成stencil build --watch,这样就可以在编写代码的时候自动重新编译。

然后在.storybook/preview.js中添加

import { defineCustomElements } from '../dist/esm/loader'; 
defineCustomElements();

最后更新于