新生代的原生 WebComponent 架构设计,邀请你一起参与共建

前言

经过一段儿时间对之前 web-core-plus 的架构进行了重新梳理、重构,并在此基础了实现了大部分 ElementUI 的样式组件以及 Api,统一封装成新的 WebComponent 组件库 web-plus-ui。

相关资料

相关介绍

什么是 web component?

在此再多啰嗦几句,为之前不是很了解此技术栈的读者简单灌输一下概念。

web component是web原生提供的封装组件的方式,让开发者定义一些可重复使用的自定义元素。主要包含custom elements、shadow dom、html templates部分,分别用于注册自定义元素、提供shadow-dom接口,为自定义元素的样式和脚本提供一个隔离的环境、通过template和slot编写自定义元素的结构模板。

关于

目前架构基于 WebComponent 提供了一套更加完善的 Api,用户可基于该框架快速创建出 WebComponent。

目前该框架主体分为两部分:

  • web-core-plus 是底层的依赖包,主要为提供虚拟 DOM、属性、事件、生命周期钩子函数定义等功能;

  • web-ui-plus 是基于 web-core-plus 实现的一套标准的 WebComponent 组件库,其中样式继承自 ElementUI,与 ElementUI、Ant Design 的区别在于该 UI 不依赖于任何的框架(vue、react、angular等),只需一个 <script src=""></script> 就能使用优雅的样式和丰富的 Api,同时也不影响在 vue、react 中使用。

特性

  • 便捷高效
    • 可直接使用脚手架创建模板组件,采用装饰器定义组件,采用 JSX 编写视图代码。
  • 数据响应
    • 组件内部实现了微型的响应式框架,开发者开发组件时无需关心视图渲染更新。
  • 沙箱隔离
    • 框架继承自 WebComponent,具有完善的 js、css 沙箱。

架构介绍

整体架构

wu-component-design.png

目前整个体系如上图所示,整体包括底层的 Core 架构包、基于 Core 机构包的 UI 组件库、脚手架 CLI,以及后续计划的 Route、Store 等一系列的扩展插件。

decorators.png

上图的类图中基本标注了些 Core 架构对外提供的一些 Api 装饰器。

渲染流程

Component-line.png

目前的架构,内部实现了一个微型的响应式前端框架,包括数据劫持、JSX 解析、Diff、批量异步更新等现代框架的功能,开发者也可以根据框架抛出的生命周期钩子函数手动干预渲染任务调度。

浏览器解析到自定义 HTML 标签后,组件内部会初始化一些配置项,包括标签的属性、事件等,初始化完成后会先根据默认(绑定的 Attr 属性)的值进行一次渲染流程,渲染流程内部和 react、vue 等现代框架类似,先将 JSX 通过 h 函数转换为虚拟 dom,后续进入 diff 流程进行最小化的 Dom 更新,其中有非常重要的一环,批量异步更新可以尽可能的减少更新操作(此特性正在开发中)。

快速上手

创建组件

安装 t-cli 脚手架、创建组件模板工程:

## 安装脚手架
npm install @canyuegongzi/t-cli -g
## 创建组件 <web-component-name> 为组件需要定义的组件名 此处按照 test-web-core-component 做示例
t init-web-component <web-component-name>
## 进入对应目录
cd test-web-core-component
## install
npm install

使用 yarn 也可以,如果你的网络环境不佳,推荐使用 cnpm

开发组件

install 之后,你就可以直接 npm run dev:package 实时预览,即可就可以如 vue、react 工程般热更新开发

example-web-component.png
web-component-see1.png

组件构建

组件开发完成后可采用 npm run build:package 构建产物,最终产物如下:

dist
    index.cjs.js
    index.esm.js   // ES6 模块代码
    index.umd.js   // umd 模式
    index.d.ts

生产预览

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <!-- 自定义标签 -->
    <wu-test-example></wu-test-example>
    <!---->
</div>
<!-- 引入构建后的产物 -->
<script src="./dist/index.umd.js"></script>
</body>
</html>

Decorators API 介绍

通过注解快速创建 WebComponent 组件。

Component

该注解用于快速定义组件,内部实现了一些较为底层的逻辑,包括各类生命周期钩子函数、虚拟dom、dom事件等。

Example

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
}

Api

interface CustomTagOptions {
    name: string;
    is?: ComponentEnums;
    css?: string;
    options?: ElementDefinitionOptions;
}

Emit

该装饰器用于自定义 dom 事件,底层基于 CustomEvent 实现。

Example

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
    
    @Emit('change')
    private change() {
        return {
            value: this.checked,
            name: this.name,
            label: this.label,
        };
    }
}

Api

Emit 必须传入事件名

Watch

该装饰器用于组件内部的监听。

Example

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
    
    @Watch('checked')
    public checkedChange(val: any, oldVal: any) {}
    
}

Api

Watch 目前仅支持一个参数,为需要监听的属性,函数包含俩参数新值和旧值。

Prop

该装饰器用于定义 Attribute。

Example

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
    @Prop({ default: false, type: Boolean })
    public disabled: boolean;
    
}

Api

export interface PropOptions {
    default?: any;
    type?: PropTyp;
}

Inject

Inject 需要和 Provide 配套使用,Inject 用于接收父级组件注入的数据。

Example

如案例中从父级组件中接受 wuFormRef 数据,最常见的需求如在定义 Form 表单时,单个表单列需要拿到 Form 组件实例(类似 ElForm 组件)。

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
    
    @Inject("wuFormRef")
    public wuForm;
}

Api

Inject 必须传入需要接收的变量名称。

Provide

Provide 需要和 Inject 配套使用,Inject 用于向子孙组件注入数据。

Example

如示例中向子孙组件注入一个名为 wuFormRef 的数据。

@Component({
    name: 'wu-test-example',
    css: css,
})
export class TestExample extends HTMLElement {
    constructor() {
        super();
    }
    
    @Provide("wuFormRef")
    public provideParentDescTitle() {
        return this;
    }
}

Api

Provide 的装饰对象必须是一个函数,该函数必须要有返回值,返回注入的数据。

State

...待实现

UI 库

在此列举了目前实现的一些组件,具体实现感兴趣的可移步到官网查阅(官网已做移动端适配奥)。

官方文档

  • wu-plus-button
  • wu-plus-icon
  • wu-plus-radio
  • wu-plus-input
  • wu-plus-row
  • wu-plus-col
  • wu-plus-checkbox
  • wu-plus-checkbox-group
  • wu-plus-switch
  • wu-plus-link
  • wu-plus-table
  • wu-plus-tag
  • wu-plus-progress
  • wu-plus-breadcrumb
  • wu-plus-breadcrumb-item
  • wu-plus-page-header
  • wu-plus-rate
  • wu-plus-time-line
  • wu-plus-time-line-item
  • wu-plus-select
  • wu-plus-select-option
  • wu-plus-avatar
  • wu-plus-empty
  • wu-plus-card
  • wu-plus-popover
  • wu-plus-message
progress-comnponent.png
select-component.png
table-component.png
time-line-component.png

总结

目前该项目只能算是第一阶段完成了收尾,后续还需要不断的优化,不断的新增新的自定义组件,尤其是当下前端开发中通用的组件,诸如流程图绘制,GiS 组件、树组件等,以减少因为 vue、react 不用框架造成的 UI 层面的壁垒。

对 WebComponent 技术栈感兴趣的开发可点击下方链接查阅详细的文档,有想参与一起共建该技术栈的开发者可联系笔者一起参与。

参与共建

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容