我为什么要为 Web Components 编写一个微型库
挑战自己
消除疼痛
完全控制
分配
装饰器
进入 Readymade
一个例子
Readymade 现已升级至 v1
我知道似乎每个人都在构建这个微型计算机,那个微型计算机。
微服务、微前端,现在还有微库?!
目前已经有了开发 Web 组件的优秀解决方案。
一些主流的 JavaScript 框架,例如 Svelte 和 Angular,甚至可以编译为自定义元素。不过,考虑到将现代 JavaScript 框架编译为 Web 组件所需的工具数量,这可能有点过头了。
那么我为什么要编写另一个库呢?
挑战自己
构建一个现代的、零依赖的框架。我想要一个只使用浏览器中 API 的解决方案。这意味着某些功能需要 polyfill,但这没问题。事实证明,浏览器中存在一些 API,可以让你构建一个支持数据绑定、高级事件处理、动画等功能的 UI 微型库!
- 自定义元素
- 创建TreeWalker
- 代理人
- 自定义事件
- 广播频道
- 网络动画
消除疼痛
开发 Web 组件是该项目的另一个目标。自定义元素的编码涉及大量可精简的样板代码。在允许ShadowDOM
和不允许的自定义元素之间切换可能很困难。自主自定义元素的处理方式与自定义内置元素不同。事件处理仅与典型的 DOM 一样好,需要调用addEventListener
和dispatchEvent
,即使这样,您也只能遵循事件通常冒泡的方式。此外,更新自定义元素的模板也存在问题,需要选择 DOM 并更新属性和内部内容。这为工程师提供了做出性能不佳的选择的机会。如果一个库可以处理所有这些,那会怎样?
完全控制
这正是我想要的。如果我想改变这个库的行为方式,我可以做到。Readymade 可以将其构建为开箱即用的 SVG 支持(它确实如此),但如果我想支持 GL 对象,它也可以渲染。只需更换状态引擎,WebGL 支持就来了。我一直在尝试不同的 UI,需要一个可塑性强的 UI。
分配
这是我长期以来一直在做的另一个项目的关键方面。我希望找到一种不依赖任何框架的方法来分发 UI 组件库。该项目的目标是提供一个小于 20KB 的 UI 库。Readymade 本身的大小约为 3KB,导入了所有必要的功能。使用 Readymade 构建的组件可以像任何其他 DOM 元素一样,在任何使用 JavaScript 框架构建的项目中使用,前提是该框架支持自定义元素。
装饰器
在 Angular 中,这些功能对我来说是理所当然的,我想了解这些高阶函数是如何工作的。我构建的微库高度依赖于这个未来的规范,但这也没问题。使用 TypeScript 从头构建这个库还提供了类型检查、IntelliSense 等额外优势,并且让我能够使用优秀的 TypeScript 编译器。
进入 Readymade
Readymade 是一个用于处理 Web 组件开发常见任务的微型库。其 API 与 Angular 或 Stencil 类似,但内部机制有所不同。Readymade 使用上面列出的浏览器 API,为您提供丰富的开发体验。
- 🎰 声明 CSS 和 HTML ShadowDOM 模板的元数据
- ☕️“自主定制”和“定制内置”元素的单一界面
- 🏋️ ‘Hello World’(gzip 压缩)大小约为 1Kb
- 1️⃣ 单向数据绑定
- 🎤 事件发射器模式
- 🌲 可摇树
一个例子
下面的按钮示例展示了 Readymade 的一些优势。
import { ButtonComponent, Component, Emitter, Listen } from '@readymade/core';
@Component({
template:`
<span>{{buttonCopy}}</span>
`,
style:`
:host {
background: rgba(24, 24, 24, 1);
cursor: pointer;
color: white;
font-weight: 400;
}
`,
})
class MyButtonComponent extends ButtonComponent {
constructor() {
super();
}
@State()
getState() {
return {
buttonCopy: 'Click'
}
}
@Emitter('bang')
@Listen('click')
public onClick(event) {
this.emitter.broadcast('bang');
}
@Listen('keyup')
public onKeyUp(event) {
if (event.key === 'Enter') {
this.emitter.broadcast('bang');
}
}
}
customElements.define('my-button', MyButtonComponent, { extends: 'button'});
ButtonComponent
是一个预定义的 ES2015 类,它扩展HTMLButtonElement
并链接了一些支持装饰器中定义的函数template
,style
并Component
调用其他装饰器添加到该类原型的任何方法。这里有趣的部分是它ButtonComponent
是可组合的。以下是其定义。
export class ButtonComponent extends HTMLButtonElement {
public emitter: EventDispatcher;
public elementMeta: ElementMeta;
constructor() {
super();
attachDOM(this);
attachStyle(this);
if (this.bindEmitters) { this.bindEmitters(); }
if (this.bindListeners) { this.bindListeners(); }
if (this.onInit) { this.onInit(); }
}
public onInit?(): void;
public bindEmitters?(): void;
public bindListeners?(): void; public bindState?(): void;
public setState?(property: string, model: any): void;
public onDestroy?(): void;
}
-
State
允许您为按钮实例定义本地状态,并且状态中定义的任何属性都可以绑定到模板。Readymade 在底层使用document.createTreeWalker
和Proxy
来监视更改并独立地更新attributes
和textContent
。 -
Emitter
定义一个 EventEmitter 模式,该模式可以使用BroadcastChannel API
,因此事件不再只是冒泡,它们甚至可以跨浏览器上下文发出。 -
Listen
是一个为您连接的装饰器addEventListener
,因为谁愿意一直输入这个?
Readymade 现已升级至 v1
所以去GitHub上看看吧。文档门户是用 Readymade 构建的,可以在Github Pages上找到。
文章来源:https://dev.to/steveblue/why-i-coded-a-micro-library-for-web-components-46ig