Web 组件标准实践

水歌 —— 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 { Component } from 'react';

export class MyComponent extends 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>
  <template shadowrootmode="open">
    <button><slot></slot></button>
  </template>
  按钮
</my-button>

渐进增强,优雅降级

<!-- 良 -->
<my-button>
  <template shadowrootmode="open">
    <slot></slot>
  </template>
  <button>按钮</button>
</my-button>

<!-- 优 -->
<button is="my-button">
  <template shadowrootmode="open">
    <slot></slot>
  </template>
  按钮
</button>

兼容性

原生

polyfill

IE 11 +


工程问题

  • 数据绑定

  • 资源打包

  • 路由定义

  • 状态管理


WebCell

优雅、轻量的 Web 组件引擎


声明式组件


官方适配 MobX

import { observer } from 'web-cell';

import { app } from '../model';

export const PageIndex = observer(() => (
  <div onClick={app.increase}>count: {app.count}</div>
));

import { component, observer } from 'web-cell';

import { app } from '../model';

@component({ tagName: 'page-index' })
@observer
export class PageIndex extends HTMLElement {
  render() {
    return <div onClick={app.increase}>count: {app.count}</div>;
  }
}

极简路由 —— Cell Router

路径即状态,容器即组件


import { DOMRenderer } from 'dom-renderer';
import { FC } from 'web-cell';
import { createRouter, PageProps } from 'cell-router';

const { Route, Link } = createRouter();

const TestPage: FC<PageProps> = ({
    className,
    style,
    path,
    history,
    ...data
}) => (
    <ul {...{ className, style }}>
        <li>Path: {path}</li>
        <li>Data: {JSON.stringify(data)}</li>
    </ul>
);

new DOMRenderer().render(
    <>
        <nav>
            <Link to="test?a=1">Test</Link>
            <Link to="example/2">Example</Link>
        </nav>
        <main className="router">
            <Route
                path=""
                component={props => <div {...props}>Home Page</div>}
            />
            <Route path="test" component={TestPage} />
            <Route path="example/:id" component={TestPage} />
        </main>
    </>
);

异步加载页面

tsconfig.json

{
  "compilerOptions": {
    "module": "ESNext"
  }
}

source/page/index.ts

import { lazy } from 'web-cell';

export default [
  {
    path: '',
    component: lazy(() => import('./Home'))
  },
  {
    path: 'list',
    component: lazy(() => import('./List'))
  }
];

开箱即用

npm init -y

npm i dom-renderer web-cell mobx cell-router web-utility boot-cell

npm i parcel -D

官方组件库 —— BootCell


推荐组件库 —— MDUI


竞争对手

  • Google Polymer/Lit

  • Ionic Stencil

  • Tencent Omi


https://web-cell.dev/


上一篇
PWA 即刻上手 PWA 即刻上手
近两年国内前端界很流行小程序,但大多数人都不知道小程序很多概念是鹅厂“借鉴”自 Google 主导的 Progressive Web App(渐进式网页应用)标准 —— “独立”运行:在“系统正在运行的应用”列表中独立显示 本地缓存:页面
2019-10-31
下一篇
结构化简历数据 结构化简历数据
参加工作久了,经历公司多了,每次换工作写简历都烦得要死 —— 常用招聘网站更新简历:简历编辑器改版了,操作习惯大变不说,数据格式很多也对不上号 注册新招聘网站填简历:所需内容和之前其它网站差不多,但填法大相径庭 所以,虽说每次只加一项前
2019-08-14
目录