WebCell
    Preparing search index...

    WebCell

    WebCell

    WebCell logo

    简体中文 | English

    基于 VDOM、JSXMobXTypeScriptWeb 组件 引擎

    NPM 依赖性 CI 和 CD

    反 996 许可证 UI 库推荐榜单

    幻灯片 Gitter

    编辑 WebCell 示例

    NPM

    特性 WebCell 3 WebCell 2 React Vue
    JS 语言 TypeScript 5 TypeScript 4 ECMAScript 或 TypeScript ECMAScript 或 TypeScript
    JS 语法 ES 装饰器 stage-3 ES 装饰器 stage-2
    XML 语法 JSX import JSX factory JSX factory/import HTML/Vue 模板或 JSX(可选)
    DOM API Web 组件 Web 组件 HTML 5+ HTML 5+
    视图渲染器 DOM Renderer 2 SnabbDOM (内置) SnabbDOM(分叉)
    state API MobX @observable this.state this.stateuseState() this.$dataref()
    props API MobX @observable @watch this.propsprops => {} this.$propsdefineProps()
    状态管理 MobX 6+ MobX 4/5 Redux VueX
    页面路由器 JSX 标签 JSX 标签 + JSON 数据 JSX 标签 JSON 数据
    资源打包工具 Parcel 2 Parcel 1 webpack Vite
    npm install dom-renderer mobx web-cell
    

    演示和 GitHub 模板

    npm install parcel @parcel/config-default @parcel/transformer-typescript-tsc -D
    
    {
    "scripts": {
    "start": "parcel source/index.html --open",
    "build": "parcel build source/index.html --public-url ."
    }
    }
    {
    "compilerOptions": {
    "target": "ES6",
    "module": "ES2020",
    "moduleResolution": "Node",
    "useDefineForClassFields": true,
    "jsx": "react-jsx",
    "jsxImportSource": "dom-renderer"
    }
    }
    {
    "extends": "@parcel/config-default",
    "transformers": {
    "*.{ts,tsx}": ["@parcel/transformer-typescript-tsc"]
    }
    }
    <script src="https://polyfill.web-cell.dev/feature/ECMAScript.js"></script>
    <script src="https://polyfill.web-cell.dev/feature/WebComponents.js"></script>
    <script src="https://polyfill.web-cell.dev/feature/ElementInternals.js"></script>

    <script src="source/MyTag.tsx"></script>

    <my-tag></my-tag>
    import { DOMRenderer } from 'dom-renderer';
    import { FC, PropsWithChildren } from 'web-cell';

    const Hello: FC<PropsWithChildren> = ({ children = '世界' }) => <h1>你好,{children}</h1>;

    new DOMRenderer().render(<Hello>WebCell</Hello>);
    import { DOMRenderer } from 'dom-renderer';
    import { component } from 'web-cell';

    @component({
    tagName: 'hello-world',
    mode: 'open'
    })
    class Hello extends HTMLElement {
    render() {
    return (
    <h1>
    你好, <slot />!
    </h1>
    );
    }
    }

    new DOMRenderer().render(
    <>
    <Hello>WebCell</Hello>
    {/* 或 */}
    <hello-world>WebCell</hello-world>
    </>
    );
    import { DOMRenderer } from 'dom-renderer';
    import { observable } from 'mobx';
    import { WebCell, component, attribute, observer } from 'web-cell';

    interface HelloProps {
    name?: string;
    }

    interface Hello extends WebCell<HelloProps> {}

    @component({ tagName: 'hello-world' })
    @observer
    class Hello extends HTMLElement implements WebCell<HelloProps> {
    @attribute
    @observable
    accessor name = '';

    render() {
    return <h1>你好,{this.name}!</h1>;
    }
    }

    new DOMRenderer().render(<Hello name="WebCell" />);

    // 或在 TypeScript 中提示 HTML 标签属性

    declare global {
    namespace JSX {
    interface IntrinsicElements {
    'hello-world': HelloProps;
    }
    }
    }
    new DOMRenderer().render(<hello-world name="WebCell" />);
    import { DOMRenderer } from 'dom-renderer';
    import { observable } from 'mobx';
    import { FC, observer } from 'web-cell';

    class CounterModel {
    @observable
    accessor times = 0;
    }

    const couterStore = new CounterModel();

    const Counter: FC = observer(() => (
    <button onClick={() => (couterStore.times += 1)}>计数:{couterStore.times}</button>
    ));

    new DOMRenderer().render(<Counter />);
    import { DOMRenderer } from 'dom-renderer';
    import { observable } from 'mobx';
    import { component, observer } from 'web-cell';

    @component({ tagName: 'my-counter' })
    @observer
    class Counter extends HTMLElement {
    @observable
    accessor times = 0;

    handleClick = () => (this.times += 1);

    render() {
    return <button onClick={this.handleClick}>计数:{this.times}</button>;
    }
    }

    new DOMRenderer().render(<Counter />);
    import { component } from 'web-cell';
    import { stringifyCSS } from 'web-utility';

    @component({
    tagName: 'my-button',
    mode: 'open'
    })
    export class MyButton extends HTMLElement {
    style = stringifyCSS({
    '.btn': {
    color: 'white',
    background: 'lightblue'
    }
    });

    render() {
    return (
    <>
    <style>{this.style}</style>

    <a className="btn">
    <slot />
    </a>
    </>
    );
    }
    }
    import { component } from 'web-cell';

    @component({
    tagName: 'my-button',
    mode: 'open'
    })
    export class MyButton extends HTMLElement {
    render() {
    return (
    <>
    <link
    rel="stylesheet"
    href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css"
    />
    <a className="btn">
    <slot />
    </a>
    </>
    );
    }
    }
    .btn {
    color: white;
    background: lightblue;
    }
    import { WebCell, component } from 'web-cell';

    import styles from './scoped.css' assert { type: 'css' };

    interface MyButton extends WebCell {}

    @component({
    tagName: 'my-button',
    mode: 'open'
    })
    export class MyButton extends HTMLElement implements WebCell {
    connectedCallback() {
    this.root.adoptedStyleSheets = [styles];
    }

    render() {
    return (
    <a className="btn">
    <slot />
    </a>
    );
    }
    }
    import { component, on } from 'web-cell';

    @component({ tagName: 'my-table' })
    export class MyTable extends HTMLElement {
    @on('click', ':host td > button')
    handleEdit(event: MouseEvent, { dataset: { id } }: HTMLButtonElement) {
    console.log(`编辑行:${id}`);
    }

    render() {
    return (
    <table>
    <tr>
    <td>1</td>
    <td>A</td>
    <td>
    <button data-id="1">编辑</button>
    </td>
    </tr>
    <tr>
    <td>2</td>
    <td>B</td>
    <td>
    <button data-id="2">编辑</button>
    </td>
    </tr>
    <tr>
    <td>3</td>
    <td>C</td>
    <td>
    <button data-id="3">编辑</button>
    </td>
    </tr>
    </table>
    );
    }
    }
    import { observable } from 'mobx';
    import { component, observer, reaction } from 'web-cell';

    @component({ tagName: 'my-counter' })
    @observer
    export class Counter extends HTMLElement {
    @observable
    accessor times = 0;

    handleClick = () => (this.times += 1);

    @reaction(({ times }) => times)
    echoTimes(newValue: number, oldValue: number) {
    console.log(`新值:${newValue},旧值:${oldValue}`);
    }

    render() {
    return <button onClick={this.handleClick}>计数:{this.times}</button>;
    }
    }
    import { DOMRenderer } from 'dom-renderer';
    import { WebField, component, formField, observer } from 'web-cell';

    interface MyField extends WebField {}

    @component({
    tagName: 'my-field',
    mode: 'open'
    })
    @formField
    @observer
    class MyField extends HTMLElement implements WebField {
    render() {
    const { name } = this;

    return (
    <input name={name} onChange={({ currentTarget: { value } }) => (this.value = value)} />
    );
    }
    }

    new DOMRenderer().render(
    <form method="POST" action="/api/data">
    <MyField name="test" />

    <button>提交</button>
    </form>
    );
    import { DOMRenderer } from 'dom-renderer';
    import { observer, PropsWithChildren } from 'web-cell';
    import { sleep } from 'web-utility';

    const AsyncComponent = observer(async ({ children }: PropsWithChildren) => {
    await sleep(1);

    return <p>{children} 中的异步组件</p>;
    });

    new DOMRenderer().render(<AsyncComponent>WebCell</AsyncComponent>);
    import { FC } from 'web-cell';

    const AsyncTag: FC = () => <div>异步</div>;

    export default AsyncTag;
    import { DOMRenderer } from 'dom-renderer';
    import { lazy } from 'web-cell';

    const AsyncTag = lazy(() => import('./AsyncTag'));

    new DOMRenderer().render(<AsyncTag />);
    import { DOMRenderer } from 'dom-renderer';

    new DOMRenderer().render(
    <a>
    <b>异步渲染</b>
    </a>,
    document.body,
    'async'
    );
    import { component } from 'web-cell';

    @component({
    tagName: 'async-renderer',
    renderMode: 'async'
    })
    export class AsyncRenderer extends HTMLElement {
    render() {
    return (
    <a>
    <b>异步渲染</b>
    </a>
    );
    }
    }
    import { DOMRenderer } from 'dom-renderer';
    import { AnimateCSS } from 'web-cell';

    new DOMRenderer().render(
    <AnimateCSS type="fadeIn" component={props => <h1 {...props}>淡入</h1>} />
    );
    npm install jsdom
    
    import 'web-cell/polyfill';
    

    https://github.com/EasyWebApp/DOM-Renderer?tab=readme-ov-file#nodejs--bun

    1. connectedCallback
    2. disconnectedCallback
    3. attributeChangedCallback
    4. adoptedCallback
    5. updatedCallback
    6. mountedCallback
    7. formAssociatedCallback
    8. formDisabledCallback
    9. formResetCallback
    10. formStateRestoreCallback
    1. 基础
    2. 仪表盘
    3. 移动端
    4. 静态网站

    我们建议将这些库与 WebCell 一起使用:

    1. 开发贡献