Skip to content
主题色
灰色
夜间模式组件大小小(1)中(2)大(3)组件圆角
none
small
medium
large
full
组件缩放90%95%100%105%110%

目前提供以下的库:

  • @lun/utils:js 工具函数库
  • @lun/core:提供组件功能的钩子函数库
  • @lun/components:组件库
  • @lun/theme:主题库
  • @lun/react:为 react19 之前的版本封装的组件库,详细见下文React 中使用
  • @lun/plugins: 为 JSX 或 Vue template 提供自定义指令

在使用本组件库之前,你需要了解自定义元素的相关知识,只需知道如何使用即可,无需了解如何创建

安装

暂未发布到 npm

  • 如果只需要组件,样式完全自定义的话,直接安装@lun/components即可
  • 如果需要主题,只需安装@lun/theme(其依赖于@lun/components
  • React 中需额外安装@lun/react,使用其导出的组件

React 中使用

React 是目前流行 web 框架中唯一不支持customElement的,详情见Custom Elements Everywhere。在 React 18 及之前版本中使用自定义元素,只会将属性设置为 attribute,不会自动设置为元素的 property,也无法使用onXXX监听自定义元素的事件

React 19 即将支持customElement,但目前还处于实验阶段。本文档使用的是 React 19 RC,在文档的 React 代码中可正常使用自定义元素。

对于 React 19 之前的版本,我们需要手动封装一层。@lun/react@lun/components中的每个组件都封装成了 React 组件,在 useLayoutEffect 中将属性和事件绑定到元素上,使之能够正常工作。

tsx
import { LInput } from '@lun/react';

export default function () {
  return <LInput onUpdate={() => {}} />;
}

全量引入

js
import { GlobalStaticConfig, defineAllComponents } from '@lun/components';
import {
  importCommonTheme,
  importAllColors,
  importAllP3Colors,
  importBasicTheme,
  importSurfaceTheme,
  importOutlineTheme,
  importSoftTheme,
  importSolidTheme,
} from '@lun/theme';

// 定义组件前设置想要更改的全局静态配置
GlobalStaticConfig.xx = xx;

// 引入所有的预设主题色
importAllColors(); // 如果需要自定义请参考导航栏中的“调色”一栏
// 如果需要P3广色域支持
// importAllP3Colors();

// 引入组件内部公共样式
importCommonTheme();
// 引入所有组件的基础主题
importBasicTheme();
// 引入所有其他主题
importSurfaceTheme();
importOutlineTheme();
importSoftTheme();
importSolidTheme();
// 定义全部组件
defineAllComponents();
  • 全局静态配置需要在组件被使用前修改,但最好在定义前就统一修改,因为namespace在定义时就会使用
  • 全量引入的组件会使用GlobalStaticConfig.namespace加上组件本身的名字作为命名,例如namespace默认为l,那么button组件的默认名字便是l-button。引入组件后你便可以在任何地方使用它们
  • 为保证视觉效果,你需要自行向页面添加类似于下面的样式,在组件未定义时隐藏它们,以避免它们的 children 被渲染出来而造成闪烁
css
:not(:defined) {
  visibility: hidden;
}
/** or */
:not(:defined) {
  opacity: 0;
}

动态引入

js
import { autoDefine } from '@lun/components';
import { autoImportTheme } from '@lun/theme';

autoImportTheme();
autoDefine();

动态引入会自动检测页面上的元素并自动加载引入,动态引入无法 Tree Shaking,但会动态加载需要的脚本

自定义引入

js
import { defineButton } from '@lun/components';
import { importButtonBasicTheme, importButtonSurfaceTheme } from '@lun/theme';

每个组件都导出了单独的 define 函数,用于单独引入该组件,没有使用的组件最终不会被打包,每个组件的主题也单独提供了 import 函数。 组件的 define 函数可以单独对该组件以及它依赖的组件进行命名,而不是使用默认命名,例如

js
importButtonBasicTheme();
importButtonSurfaceTheme();
defineButton('my-button', {
  spin: 'my-spin',
});

// 此后你便可以直接使用<my-button></my-button>和<my-spin></my-spin>了

自定义引入需要注意组件的引入顺序,这在 SSR 场景下尤为重要,最先使用的组件需要最先定义,例如你可能需要在其他组件定义前先调用defineThemeProviderdefineTeleportHolder(),有明显父子关系的组件也需要注意,例如formform-item

需要这么做的原因是,大部分组件都有继承关系,部分状态由父组件提供。在 SSR 场景下,页面上的元素已经存在,如果子组件先被定义,此时它无法探测到父组件(组件未被定义时是无效组件),等父组件再被定义时子组件也不会被更新,便会出现问题

TS 支持

目前提供了VueReact的组件类型定义,你需要在 TS 配置对应引入@lun/components/elements-types-vue@lun/components/elements-types-react

需要注意的是,提供的类型文件是针对默认namespace,也就是l-button, l-input等以l开头的组件,如果你自定义了命名空间,可以仿造以下示例编写

ts
// Vue
import * as Vue from 'vue';
// Vue template
declare module 'vue' {
  interface GlobalComponents {
    LButton: Vue.DefineComponent<import('@lun/components').ButtonProps>;
  }
}
// Vue JSX
declare module 'vue/jsx-runtime' {
  namespace JSX {
    interface IntrinsicElements {
      'l-button': Vue.HTMLAttributes & Vue.ReservedProps & import('@lun/components').ButtonProps;
    }
  }
}

// React
import * as React from 'react';
declare module 'react/jsx-runtime' {
  namespace JSX {
    interface IntrinsicElements {
      'l-button': React.HTMLAttributes<HTMLElement> &
        React.RefAttributes<import('./index').iButton> &
        import('@lun/components').ButtonProps;
    }
  }
}

每个组件都有一个 class 和两个类型,注意区分

ts
import { Button, tButton, iButton } from '@lun/components';
Button; // 组件的class,这是值,不是类型,一般用不到
tButton; // 组件class的类型,相当于typeof Button
iButton; // 组件实例的类型,相当于InstanceType<typeof tButton>

当需要组件实例类型时,你可以像下面这样使用:

ts
import { iButton } from '@lun/components';
const button = document.querySelector('l-button') as iButton;
button.asyncHandler = () => console.log('');

const buttonRef = ref<iButton>();
const render = () => <l-button ref={buttonRef}></l-button>;

兼容性

至少需要兼容customElement, 考虑到以下特性版本要求不高, 若不支持你需要自行 polyfill 或不使用某些特性,CSS 可考虑使用全局配置stylePreprocessor处理或自行编写样式

当前用户代理信息

某些特性需要的版本较高, 但它们在内部有做兼容处理或替代方案, 如下

当前浏览器支持该特性 当前浏览器不支持该特性 无法检测

某些特性无法或不好做兼容,但它们影响不大,不使用那些功能即可