高颜值跨框架组件库Lun:值得期待的全新的UI轮子

250 阅读7分钟

写在开头

相信很多人会有疑问,为什么市面上已经有那么多组件库,还要费功夫再造一个轮子呢?

很简单,跨框架的组件库可以让开发者在不同框架中拥有一致的体验。市面上的非 Web Components 组件库基本是靠单独适配来给不同的框架使用的,而现有的 Web Components 组件库功能和自定义性可以说堪称贫瘠。表单、表格、树、日历等复杂组件基本不支持,美观程度也一言难尽。

如果只是一些简单的组件,完全没有使用组件库的必要。我没有找到一个符合要求,美观好用又容易自定义的,那就再造一个喽,所以我直接取名为 Lun(轮子,哈哈)相信你能从这个轮子中发现很多新的东西

官网

仓库地址:Github

文档链接请根据网络情况自行选择,Github Page很可能遇到网络问题,可尝试上面两个

介绍

Lun是一款基于 Custom Elements(自定义元素) 和 Shadow DOM(影子DOM) 的全新 Web 组件库,可能很多人对这两个概念非常陌生。的确,这些 Web 特性本身就是面向框架作者的,应用开发者很少会使用到这些,而正是这些标准 Web 特性让我们有了 一次编写,随处可用 的可能。

功能

今天我们不需要了解实现原理,我们看看 Lun 提供了什么:

  • 基于 Vue3 及原生的 Web 自定义元素,兼容现代 web 环境和所有框架
  • 封装良好,功能丰富,提供了一套高质量的组件,仅 Vue3 和 floating-ui 为必须依赖,体积相对较小,目前近40个组件gzip也才100k(包含主题则为150k左右)
  • 提供了丰富的全局静态和动态配置,可灵活自定义内部各种行为
  • 支持无头模式,组件样式完全自主可控。也提供一套基于@radix/colors 定制的美观主题,如下所示丰富的主题配置,开箱即用的暗黑模式,支持响应式,丰富的色彩与变体,支持用户自选颜色,生成的颜色同样十分好看

image.png

  • 紧跟标准,致力于使用各种全新 Web API(如 Popover APICSS Anchor PositioningCustomStateSet...)提供优雅的回退,无需担心兼容性
  • 提供完整的 Typescript 支持,提供 Vue 和 React 组件类型和 JSX 元素定义

另外,Lun 还针对自定义元素的使用痛点提供了一些解决方案。熟悉自定义元素的人可能知道,这玩意流行不起来肯定是有它的问题的。就个人理解,我觉得主要有两个原因:

  1. 样式难以自定义:Shadow DOM带来了样式隔离,使得内部样式不会影响外部,但这也同样使得外部样式难以影响内部样式,特定的选择器写起来有点反人类
  2. 自定义渲染较为困难:复杂的组件一般都需要定制某些部分的自定义渲染,像Vue可以使用作用域插槽,React可以传一个函数用于自定义

首先针对样式,除了原生支持的样式修改方法,Lun 还支持通过全局配置设置组件的内置样式,甚至可以根据组件的属性动态生成样式。除此之外每个组件都有共同的属性 innerStyle 用于向内部直接插入样式表,亦或是提供一些属性设置直接设置某些内联样式。详细内容可查看文档自定义样式

至于自定义渲染,由于 Lun 使用了 Vue 运行时,因此可以直接通过函数返回 Vnode 来渲染任意内容。如果你不喜欢这种方式,亦或是要集成你现有框架的组件,Lun 也提供了自定义渲染器的能力。你可以通过注册自定义渲染器来渲染任意内容,例如 ReactElement,更多内容可查看文档自定义渲染

由于 Shadow DOM 的封装性,个人认为自定义元素做组件比较适合做“大而全”的组件,组件尽量通用并功能丰富,同时提供部分自定义渲染。

个人在功能的实现上参考了各大组件库,再加上自身经验做了不少实用且仅需少量代码就能实现的功能,限于篇幅限制这里不就展开了,你可查看一些特色组件比如 Input, Form, Table, Popover, Dialog等等,看看是否符合日常需求,欢迎提出各类意见。

使用

使用方式详细可见官网文档,文档列出了非常多的使用指南。

image.png

另外,文档中的所有组件示例都可以在线编辑,代码会实时编译生效,以便于你查看效果。在文档中的演练场写的demo会自动反射到URL,因此可通过URL分享复现。

你也可在 Stackblitz 中快速在线尝试:

也可以直接从CDN开始,如下:

兼容性

兼容信息可参考文档,详细列出了可能造成不兼容的特性,以下截取部分展示

image.png

FAQ & Roadmap

为什么引入 Vue 运行时?

为了良好的开发和使用体验,适当的运行时是必要的。Vue 本身有提供自定义元素的支持,且能够很好地支持外部自定义内容的渲染,再加上我也喜欢组合式开发,不喜欢 class 那种方式,所以选择了 Vue 而非 lit(一个知名自定义元素开发框架)。

如果你的项目本身没有使用 Vue,只要用的组件数量足够多,Vue 的运行时并不会是一个负担

Vue2 可以用吗?

可以,因为 Web Components 本身的特性是框架无关的,但是需要 Vue2 和 Vue3 在一个项目共存,需要些配置。如果是 Vite,可参考 Lun Vue2 Start - StackBlitz 的配置,需要在 package.json 重命名来一个安装 vue3,然后通过rollup的自定义解析,将组件库内的vue导入定向到 vue3,这样就不会影响项目里原来的 vue2;webpack等有空再研究怎么配置

小程序可以用吗?

不可以,小程序并非标准 Web 环境,海量 Web 特性小程序都不支持

支持SSR吗?

支持,Lun 本身可以在 node 环境使用,现代框架应该都支持自定义元素,可正常使用。但如果你需要更高级的支持,例如在 SSR 时将自定义元素的内部内容渲染成声明式 template,目前不支持

Roadmap

请注意,这是一款尚未完成的组件库,仍在开发中,不可在生产环境使用。很多功能只实现了一部分,且还有不少问题,目前发出来只希望收获反馈~

  • 稳定当前已有的组件,还有很多组件标了高度实验中,有待修复问题
  • 完善测试用例
  • 完善文档,提供组件的 Props、Events、Slots、Methods 等详细说明
  • 添加其他想实现但没时间做的组件或功能
    • slot 与 prop 优先级统一,目前各个组件有些不同
    • 确定输入组件的受控模式,目前不统一。确定某些更新事件是否可取消
    • 组件 Transition 方案确定,目前全在 common css 里,可能考虑迁移到全局配置,放 js 中
    • 为 Select、Tree 集成内部的虚拟渲染,同时支持外部虚拟渲染。完善 Table 的虚拟渲染
    • Input 掩码输入,Input hint 及 tab 补全,分组 Input 输入,简化 Input 渲染
    • 为 ScrollView 组件提供更完善的滚动驱动动画
    • 时间处理预设的完善,时间组件的完善
    • 添加颜色处理预设,完善 ColorPicker
    • 其他想实现的...
  • Accessibility 支持
  • 收集社区意见,确定组件的功能,属性方法命名是否需要修改
  • 英文翻译

由于当前只有我一个人干,离生产可用还有一段不小的距离。但本人吭哧吭哧干了一年能见到这样的成果,相信这个项目还是有不小的希望的。麻烦大家可以在 Github 给个 Star,关注一下项目的进展,有问题也随时欢迎提出,如果想要参与贡献也十分欢迎!大家的支持对我接下来的工作十分重要,谢谢!

最后,提前祝大家新年快乐啦~