基于Lit封装UI组件库

3,175 阅读1分钟

Lit介绍

image.png

Lit is a simple library for building fast, lightweight web components.

  • Lit出自Google,是一个速度快且轻量的库,用来开发Web components非常方便。
  • Lit前身是Polymer,那个时候Web Component标准还未正式发布,记得当时还需要polyfill。
  • 而今天Web Component标准已经正式发布,可能将来的组件都全部会统一成Web Components。

更多关于Lit的介绍可以访问官网

封装一个Button


import { LitElement, html, css } from 'lit';

export class LuiButton extends LitElement {
    // 相当于props
    static properties = {
        label: {
            type: String
        }
    };
    
    static styles = css`
        .lui-button {
            color: green;
        }
    `;
    
    render() {
        //相当于template
        return html`
            <button class="lui-button">
                <slot>${this.label}</slot>
            </button>
        `;
    }

}

//定义一个custom element这样就可以在html里面直接使用这个组件了
customElements.define('lui-button', LuiButton);

使用直接插入html即可,非常方便,和使用原生html组件一样的

<body>
    <lui-button>Button Name</lui-button>
    <!-- 因为定义了一个label的属性,也可以这样用 -->
    <lui-button label="Button Name"></lui-button>
</body>

支持响应式

在properties里面默认就支持响应式,详情可以阅读:

同时Lit还可以通过Reactive Controllers的方式来支持Composition API

假设需要一个全局的Router的Controller,也就是把所有的路由都交由它管理,支持自动相应

//router-controller.js
export const Util = {
    getHash(key) {
        let hash = {};
        const h = location.hash.substr(1);
        if (h) {
            const usp = new URLSearchParams(h);
            hash = Object.fromEntries(usp);
        }
        if (key) {
            return hash[key];
        }
        return hash;
    },

    setHash(key, value) {
        if (!key) {
            return;
        }
        const hash = Util.getHash();
        if (hash[key] === value) {
            return;
        }
        hash[key] = value;
        const usp = new URLSearchParams(hash);
        location.hash = usp.toString();
    },

    delHash(key) {
        if (!key) {
            return;
        }
        const hash = Util.getHash();
        delete hash[key];
        const usp = new URLSearchParams(hash);
        location.hash = usp.toString();
    }
};

class RouterController {

    constructor() {
        this.host = [];
        this.hash = Util.getHash();
        window.addEventListener('popstate', (e) => {
            this.hash = Util.getHash();
            this.updateHost();
        });
    }

    set(key, value) {
        this.hash[key] = value;
        Util.setHash(key, value);
    }

    get(key) {
        return Util.getHash(key);
    }

    del(key) {
        Util.delHash(key);
    }

    addHost(host) {
        if (!host) {
            return;
        }
        if (typeof host.requestUpdate !== 'function') {
            return;
        }
        this.host.push(host);
    }

    removeHost(host) {
        if (!host) {
            return;
        }
        this.host = this.host.filter(item => {
            if (item === host) {
                return false;
            }
            return true;
        });
    }

    //当路由更新时,刷新对应的组件
    updateHost() {
        this.host.forEach(item => {
            item.requestUpdate();
        });
    }

}

export default new RouterController();

将Controller注册到组件里面


import routerController from './controllers/router-controller.js';
export default class extends LitElement {

    connectedCallback() {
        super.connectedCallback();
        //注册
        routerController.addHost(this);
    }

    disconnectedCallback() {
        super.disconnectedCallback();
        //解除注册
        routerController.removeHost(this);
    }
    
    render() {
        //使用Controller,读取url的hash值渲染
        //如果其他地方通过routerController.set(k, v)修改值且变动时,也会被requestUpdate触发渲染更新
        const tab = routerController.get('tab');
        return html`<div>${tab}</div>`;
    }
}

封装一套组件库 Lithops UI - 生石花UI

几点体会

  • 确实非常小,运行时0依赖
  • 原生的方式使用方便
  • 速度非常快,网上有benchmark对比,速度超过Vue3
  • 但功能和生态确实比不过Vue这些成熟框架,很多东西需要二开