水歌 —— WebCell 引擎作者
水歌其人
- Web/JavaScript 全栈开发者
- WebCell 等多个开源项目的作者
- jQuery、Babel 等多个国际开源项目的贡献者
- freeCodeCamp 成都社区负责人
- 开源社官网开发组长、执委会成员
- 微软 MVP
Web 组件的概念
将网页中某块界面的 HTML 结构、CSS 样式、JS 逻辑,封装成一个可移植的模块
Web 组件技术简史
上古时代
W3C:
<frameset />
、<iframe />
IE: HTML Component (HTC)
中古时代
function MyComponent(options) {
this.options = options;
}
$.extend(MyComponent.prototype, {
method: function () {}
});
$.fn.myComponent = function (options) {
this.each(function () {
$.data(this, 'instance', new MyComponent(options));
});
};
近代
import React from 'react';
export default class MyComponent extends React.Component {
render() {
return <h1>Hello, World!</h1>;
}
}
历史问题
隔离性好的,运行时过重
易用性好的,工程化不佳
实用性强的,工具链过重
Web 组件标准
https://www.webcomponents.org/
标准集
- HTML 5.3
- DOM 4.1
- CSS Variables level 1
- ECMAScript 6+
主要目标
运行时 轻量级 隔离环境
框架无关的 DOM 接口
原生写法
样式定制
my-component {
--my-color: blue;
}
:host {
}
:host(.class) {
}
:host-context(.class) {
}
::slotted(*) {
color: var(--my-color);
}
生命周期
class MyComponent extends HTMLElement {
static get observedAttributes() {
return ['title'];
}
attributeChangedCallback(attrName, oldVal, newVal) {}
connectedCallback() {}
disconnectedCallback() {}
adoptedCallback() {}
}
扩展原生
customElements.define('my-button', class extends HTMLButtonElement {}, {
extends: 'button'
});
<button is="my-button">按钮</button>
规范模式
不要接管一切
<my-button>
<!-- shadow-root -->
<button><slot></slot></button>
<!-- shadow-root -->
按钮
</my-button>
渐进增强,优雅降级
<!-- 良 -->
<my-button>
<!-- shadow-root -->
<slot></slot>
<!-- shadow-root -->
<button>按钮</button>
</my-button>
<!-- 优 -->
<button is="my-button">
<!-- shadow-root -->
<slot></slot>
<!-- shadow-root -->
按钮
</button>
兼容性
原生
polyfill
IE 11 +
工程问题
数据绑定
资源打包
路由定义
状态管理
WebCell
优雅、轻量的 Web 组件引擎
声明式组件
官方适配 MobX
import { createCell } from 'web-cell';
import { observer } from 'mobx-web-cell';
import { app } from '../model';
export default observer(function PageIndex() {
return <div onClick={app.increase}>count: {app.count}</div>;
});
import { createCell, component, mixin } from 'web-cell';
import { observer } from 'mobx-web-cell';
import { app } from '../model';
@observer
@component({
tagName: 'page-index'
})
export default class PageIndex extends mixin() {
render() {
return <div onClick={app.increase}>count: {app.count}</div>;
}
}
极简路由 —— Cell Router
路径即状态,容器即组件
import { createCell, component } from 'web-cell';
import { observer } from 'mobx-web-cell';
import { HTMLRouter } from 'cell-router/source';
import { history } from '../model';
const Page = ({ path }) => <span>{path}</span>;
@observer
@component({
tagName: 'page-router',
renderTarget: 'children'
})
export default class PageRouter extends HTMLRouter {
protected history = history;
protected routes = [
{ paths: ['test'], component: Page },
{ paths: ['example'], component: Page }
];
render() {
return (
<main>
<nav>
<a href="test">Test</a>
<a href="example">Example</a>
</nav>
{super.render()}
</main>
);
}
}
开箱即用
npm init -y
npm install web-cell mobx mobx-web-cell cell-router web-utility boot-cell
npm install parcel-bundler -D
官方组件库 —— BootCell
竞争对手
Google Polymer
Ionic Stencil
Tencent Omi