目前提供以下的库:
@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 中将属性和事件绑定到元素上,使之能够正常工作。
import { LInput } from '@lun/react';
export default function () {
return <LInput onUpdate={() => {}} />;
}
全量引入
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 被渲染出来而造成闪烁
:not(:defined) {
visibility: hidden;
}
/** or */
:not(:defined) {
opacity: 0;
}
动态引入
import { autoDefine } from '@lun/components';
import { autoImportTheme } from '@lun/theme';
autoImportTheme();
autoDefine();
动态引入会自动检测页面上的元素并自动加载引入,动态引入无法 Tree Shaking,但会动态加载需要的脚本
自定义引入
import { defineButton } from '@lun/components';
import { importButtonBasicTheme, importButtonSurfaceTheme } from '@lun/theme';
每个组件都导出了单独的 define 函数,用于单独引入该组件,没有使用的组件最终不会被打包,每个组件的主题也单独提供了 import 函数。 组件的 define 函数可以单独对该组件以及它依赖的组件进行命名,而不是使用默认命名,例如
importButtonBasicTheme();
importButtonSurfaceTheme();
defineButton('my-button', {
spin: 'my-spin',
});
// 此后你便可以直接使用<my-button></my-button>和<my-spin></my-spin>了
注
自定义引入需要注意组件的引入顺序,这在 SSR 场景下尤为重要,最先使用的组件需要最先定义,例如你可能需要在其他组件定义前先调用defineThemeProvider
和defineTeleportHolder()
,有明显父子关系的组件也需要注意,例如form
和form-item
需要这么做的原因是,大部分组件都有继承关系,部分状态由父组件提供。在 SSR 场景下,页面上的元素已经存在,如果子组件先被定义,此时它无法探测到父组件(组件未被定义时是无效组件),等父组件再被定义时子组件也不会被更新,便会出现问题
TS 支持
目前提供了Vue
和React
的组件类型定义,你需要在 TS 配置对应引入@lun/components/elements-types-vue
或@lun/components/elements-types-react
需要注意的是,提供的类型文件是针对默认namespace
,也就是l-button
, l-input
等以l
开头的组件,如果你自定义了命名空间,可以仿造以下示例编写
// 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 和两个类型,注意区分
import { Button, tButton, iButton } from '@lun/components';
Button; // 组件的class,这是值,不是类型,一般用不到
tButton; // 组件class的类型,相当于typeof Button
iButton; // 组件实例的类型,相当于InstanceType<typeof tButton>
当需要组件实例类型时,你可以像下面这样使用:
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
处理或自行编写样式
- customElement
- BigInt
- flatMap
- fromEntries
- Named capture group
- IntersectionObserver
- ResizeObserver
- CSS gap in flex
- CSS :where :is
- CSS Logical Properties
当前用户代理信息
某些特性需要的版本较高, 但它们在内部有做兼容处理或替代方案, 如下
注
当前浏览器支持该特性 当前浏览器不支持该特性- adoptedStyleSheets
- CustomStateSet
- Dialog
- HTMLSlotElement.assign
- Input cancel Event
- popover
- showOpenFilePicker
- Selection.getComposedRanges
- CSS Anchor Positioning
- CSS Layer
- CSS Subgrid
- CSS color()
某些特性无法或不好做兼容,但它们影响不大,不使用那些功能即可