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 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;

    render() {
        return (
            <main>
                <nav>
                    <a href="test">Test</a>
                    <a href="example">Example</a>
                </nav>
                {matchRoutes(
                    [
                        { paths: ['test'], component: Page },
                        { paths: ['example'], component: Page }
                    ],
                    history.path
                )}
            </main>
        );
    }
}

开箱即用

npm init -y

npm install \
    [email protected] \
    mobx \
    mobx-web-cell \
    [email protected] \
    boot-cell

npm install parcel-bundler -D

官方组件库 —— BootCell


竞争对手

Google Polymer

Ionic Stencil

Tencent Omi


https://web-cell.dev/


上一篇
PWA 即刻上手 PWA 即刻上手
应用元数据一个渐进式 Web 应用首先要声明一下自己的基本信息: index.html <head> <link rel="manifest" href="index.webmanifest" /> </head> i
2019-10-31
下一篇
结构化简历数据 结构化简历数据
参加工作久了,经历公司多了,每次换工作写简历都烦得要死 —— 常用招聘网站更新简历:简历编辑器改版了,操作习惯大变不说,数据格式很多也对不上号 注册新招聘网站填简历:所需内容和之前其它网站差不多,但填法大相径庭 所以,虽说每次只加一项前
2019-08-14