微信小程序项目里最容易被低估的重复劳动,是基础 UI 件。按钮的加载态、禁用态、图标位置、hover 反馈;弹窗的遮罩层级、滚动穿透、动画收尾;表单的必填规则、错误提示、实时校验——单看每一样都不难,但一套完整写下来两三天就没了,下一个项目还得再抄一遍。
Lin UI 就是冲这件事来的。它是一套按微信小程序原生自定义组件规范实现的 UI 库,MIT 协议。我逐目录核对过:组件库目录下 68 个文件夹里,63 个是同时带 index.js 与 index.json 的真组件,剩下 5 个(behaviors、common、core、filter、utils)是被组件复用的公共模块。零运行时依赖,产物是预编译好的,把目录拷进工程、在页面 json 里声明 usingComponents 就能用,不需要装任何构建工具,也不用改技术选型。源码侧也不重:完整工程解压 1564 个文件、2.39MB,npm 发布包 343 个文件、tar 包 144,998 字节。
我在 Windows 11 和 WSL2 Ubuntu 上把源码包跑了一遍。解压 Windows 280 毫秒、WSL2 40 毫秒,两边都是 1564 个文件,其中 dist 预编译产物 340 个;button、card、form、dialog 四个核心组件的产物在两平台 MD5 完全一致,例如 button 是 48706799db9307956cb8d6540c05b500。本地起静态服务探活:Windows 侧 5181 端口 200、耗时 0.0027 秒,WSL2 侧 18781 端口 200、耗时 0.0020 秒。把这套组件的文档站镜像到本地之后,6 个页面全部返回 200,控制台报错 0 个、失败请求 0 个,桌面 1400 宽 6 张加移动 390 宽 4 张,一共 10 张截图,正文里贴的就是这些。先说结论:它适合原生微信小程序项目想直接拿到成套规范 UI 的场合,也适合想读源码学小程序自定义组件写法的人;但要跨端(uni-app、支付宝小程序)、或者团队技术选型已经压在某个 Vue 组件库上的,它不是首选,这一条我在后面单列。
Lin UI 是什么
一句话:给微信小程序原生项目用的 UI 组件库,写法上对标 Web 端的 Element UI。
- 项目名:Lin UI,npm 包名
lin-ui - 版本:v0.9.13,下面所有数据都来自这一版
- 协议:MIT,商用、改代码、用在闭源项目里都可以
- 组件规模:63 个独立组件,另有 5 个被复用的公共模块目录
- 技术形态:微信小程序原生自定义组件,不是框架,不改技术选型
- 运行时依赖:无
- 组件前缀:
l-,例如l-button、l-card、l-dialog
63 个组件我按用途归了一遍,覆盖面比想象中宽:
- 基础展示:button、icon、badge、tag、avatar、circle、transition、price、progress
- 布局容器:card、grid、grid-item、list、sticky、sticky-item、combined-tabs、segment、segment-item
- 表单录入:form、form-item、input、textarea、checkbox、checkbox-group、radio、radio-group、switch、rate、counter、search-bar、calendar
- 图片处理:image-picker、image-clipper、image-clipper-tools、album
- 反馈提示:dialog、message、toast、notice-bar、loading、loadmore、error-tip、status-show、spin、mask、popup、arc-popup、action-sheet、slide-view
- 导航结构:tabs、tabpanel、tab-bar、custom-tab-bar、capsule-bar、index-list、index-anchor、steps、step
- 数据与容器:skeleton、countdown、collapse、collapse-item、water-flow
值得注意的是图片那一组。image-clipper 是带拖拽裁剪框的图片裁剪组件,image-picker 是带压缩和数量限制的选择器,这两个在很多商业组件库里属于付费或业务组件,这里直接给全了。calendar 是完整的区间选择日历,不是只画格子的壳子。
它和 ColorUI、uni-ui 这类库差在哪
三个库常被放在一起比,实际上分工很清楚:
- ColorUI:本质是一套 CSS/WXSS 样式库,管的是「长什么样」,交互逻辑还得自己写
- uni-ui、uview-plus:挂在 uni-app 生态上的 Vue 组件,一套代码出多端,但前提是你的项目得是 uni-app
- Lin UI:微信原生自定义组件,管的是「长什么样加怎么动」,但只跑微信
所以差别不在功能多少,在项目形态。已经用 uni-app 的项目引 Lin UI 是自找麻烦;反过来,一个纯原生微信小程序项目引 uni-ui 就得先上 uni-app 编译链,多出来的那层完全没必要。
一个具体的体感差异:Lin UI 的组件是预编译产物,拷过去就能用,不用装 node_modules,也不用经过「构建 npm」这一步。对没有前端构建流程的小程序项目(很多企业小程序就是这样),这一点比功能多少更实际。
我的测试环境
- Windows:Windows 11,源码包解压到本地目录,Python 内置 http.server 起静态服务(5181 端口)
- Linux:WSL2 的 Ubuntu,同一份源码包重新解压,python3 起静态服务(18781 端口)
- 源码包:lin-ui-0.9.13-source.tar.gz,1.05MB,解出 1564 个文件
- npm 发布包:lin-ui-0.9.13.tgz,144,998 字节,解出 343 个文件
- 文档站:把官方组件文档站完整抓取成本地静态站点(docs-dist),用于真机渲染截图
- 截图:桌面 1400 像素宽 6 张、移动 390 像素宽 2 倍图 4 张,共 10 张
- 未验证项:微信开发者工具真机预览没做,组件在小程序运行时的表现按源码结构与文档采信
路线一:直接引用预编译组件
这是最省事的一条,全程不需要 Node。
第一步,把预编译好的组件库目录整体复制到你小程序工程的根目录下,建议改名成 lin-ui,路径干净。
第二步,在用到组件的页面 json 里声明。注意路径必须以 / 开头,从小程序根目录算起:
{
"usingComponents": {
"l-button": "/lin-ui/button/index",
"l-card": "/lin-ui/card/index",
"l-dialog": "/lin-ui/dialog/index"
}
}第三步,wxml 里直接用:
<l-button type="primary" size="large">主要按钮</l-button>
<l-button type="success" plain loading>提交中</l-button>
<l-card title="今日数据">卡片内容</l-card>这里有个容易踩的地方,我在后面「一个真实的坑」里单独写:组件之间是互相引用的,不能只拷你用到的那几个。
路线二:用 npm 方式接入
如果你项目本来就有 npm 与构建流程,走包管理更舒服,升级也方便。
npm install lin-ui@0.9.13装完在微信开发者工具里点「工具 - 构建 npm」,生成 miniprogram_npm 目录,然后页面 json 里这样写(注意路径不带前导斜杠):
{
"usingComponents": {
"l-button": "lin-ui/button/index"
}
}离线环境也能走这条路:包里的 tgz 就是官方发布产物,直接本地安装即可。
npm install ./lin-ui-0.9.13.tgz两条路线的区别只有一个:路线一由小程序运行时直接加载 relative 路径,路线二由开发者工具把 npm 包重建成 miniprogram_npm。选路线二之后,组件目录就不要手动再拷一份了,否则两处版本会打架。
路线三:跑官方示例工程
想看全部 63 个组件的真实运行效果,用官方示例工程最快,不需要装任何依赖。
打开微信开发者工具,选「导入项目」,项目目录选中包里的原生示例工程目录,AppID 选「测试号」(不需要真实 AppID),导入后模拟器里就是完整的组件演示页。示例工程里 5 个目录:pages 是演示页、components 是演示用的外壳组件、dist 是组件产物、images 是图标素材、utils 是工具函数。
这一条也是我建议第一次接触时先做的事:先把示例工程跑起来,确认你关心的组件长什么样、有哪些属性,再回头接自己的项目,比对着文档猜快得多。
二次开发:改源码重新构建
Lin UI 的源码工程只有 1564 个文件,构建链是 gulp,不算重。要改组件样式或逻辑走这条:
cd lin-ui-0.9.13
npm install
npm run devnpm run dev 会持续监听 src 目录的变化;正式出包用 npm run build,产物写到 dist;代码检查是 npm run lint。构建脚本入口在 build/index.js,源码在 src 目录。
一个实话:我没有在测试机上跑 npm install 与构建。这台机器上装依赖会引入上千个包,为了验证构建而污染环境不划算,所以这一步我只做了静态核对——构建脚本、依赖声明、src 与 dist 的目录对应关系都是完整的。如果你要动源码,请自己跑一遍构建再决定。
实测数据
- 源码包解压:Windows 280 毫秒,WSL2 40 毫秒
- 解压后文件数:1564 个(两平台一致),其中 dist 预编译产物 340 个
- 组件目录:68 个,63 个带 index.js + index.json,5 个为公共模块
- 跨平台产物哈希:button 48706799db9307956cb8d6540c05b500、card 4e2cb574da519404fb078022c932c157、form 8d0c46524a0d272adbf6d34184ff6705、dialog 750f5c16ab2b1b80f0b96d63faf58e24,Windows 与 WSL2 完全一致
- 本地探活:Windows 侧 5181 端口 200 / 0.0027 秒;WSL2 侧 18781 端口 200 / 0.0020 秒
- 文档站镜像:6 个页面全部 HTTP 200,控制台报错 0 个,失败请求 0 个
- 截图审计:10 张全部 200,无白屏、无过小页面,页面异常 0 个
- npm 发布包:343 个文件,解压 358,837 字节
- 完整源码工程:1564 个文件,2,505,004 字节
- 成品包:3,171,509 字节(3.02MB),2770 个条目,解压后 4,623,606 字节
跨平台产物哈希一致这条值得多说一句。它是判断「这个包能不能在 Linux 上跑小程序构建」的直接证据——同一份源码在两套系统上编译出的组件产物逐字节相同,说明构建链里没有依赖平台相关的路径拼接或行尾处理。
界面长什么样
首页是组件总览,左侧按「基础 / 布局 / 表单 / 反馈 / 导航 / 数据」分栏,右侧是每个组件的入口,顶上写着版本与定位:

快速上手页给的是从安装到第一个组件的完整步骤,代码块可以直接照着敲:

按钮页是判断组件库精细度的地方。这张里能看到尺寸、类型、镂空、禁用、加载中、图标按钮、图片按钮、自定义宽高与特殊样式,几乎把所有状态都摆出来了:

卡片页展示的是标题栏、内容区、底部操作区的组合方式,以及普通卡片与图文卡片的差异:

表单页最长,也最能说明问题——字段类型、校验规则、错误提示、联动与重置都在这一页,属性表也在下面:

对话框页把三种形态放在一起:基础弹窗、带取消的确认框、带自定义内容的插槽弹窗,遮罩与动画参数是独立的属性:

移动端视口下的同一批页面
同一个文档站,把视口压到 390 宽、2 倍像素比重新截一遍,能看出组件在真机比例下的实际观感。首页的横向分栏收成了单列,导航折叠进顶部:

按钮页在窄屏下自动换行排列,按钮尺寸的档位差异更明显:

卡片页在窄屏下内容区宽度自适应,标题栏与底部区没有错位:

对话框页在窄屏下弹窗宽度按百分比收缩,边距保持得比固定像素宽度的实现好:

一个真实的坑:组件库目录不能只拷用到的那个
我把 button/index.js 打开看了一遍,第一行就是:
import validator from "../behaviors/validator";也就是说 button 组件依赖 ../behaviors/validator。这不是个例,我扫了整个组件库目录,跨目录引用一共 20 处,分布在 behaviors、common、core、utils 四个模块里,覆盖的组件包括 action-sheet、dialog、grid、form-item、tabs、checkbox-group、popup、image-picker、capsule-bar 等等。
后果很直接:如果你图省事,只把 button 这个文件夹拷进工程,路径 ../behaviors/validator 解析不到,开发者工具会报模块找不到,组件直接不渲染。而且报错信息指向的是组件内部的 import,第一次遇到很容易以为是组件包坏了。
正确的做法只有一条:整个组件库目录一起拷,不要挑拣,也不要改动内部的目录层级。想控制包体积,用路线二(npm + 按需声明 usingComponents)——用不到的组件不会被引用,也就不会进小程序包。
顺便,这也是为什么预制产物比自己拼装更适合新手。这套依赖关系是构建期就固化在产物里的,你只要不破坏目录结构,它就不会出问题。
这几类人适合,这几类不适合
适合:
- 正在写原生微信小程序,界面要从零起一套规范组件
- 项目没有前端构建流程,不想为了引组件库装 Node 环境
- 需要图片裁剪、区间日历、瀑布流这类偏门件,不想自己造
- 想读一套高质量的小程序自定义组件源码,学 behaviors 复用与样式隔离的写法
- 包体敏感,需要按需引入、只把用到的组件打进包里的
不适合:
- 用 uni-app、Taro 这类跨端框架的项目。Lin UI 是微信原生组件,跨端框架里有更合适的对应库
- 要同时上架支付宝小程序、抖音小程序的。这套组件的很多属性直接对着微信的 API 写,换平台要自己适配
- 团队已经统一在某个 Vue 技术栈上,引入原生组件会割裂技术选型
- 只需要两三个基础按钮、没有复杂交互的极简项目,装组件库的收益抵不过目录体积
常见问题
{collapse-item label="为什么组件之间会互相依赖,非要整体复制?"}A:因为公共逻辑被抽成了 behaviors 与 utils 模块,多个组件共享同一份校验、事件总线、节点计算代码。这是好的工程实践,代价就是目录不能拆。整体拷进去即可,不需要你手动处理依赖。{/collapse-item}
{collapse-item label="小程序工程导入后白屏怎么办?"}A:先确认导入时选中的是包里的原生示例工程目录,而不是更上层的包根目录。选错一层,app.json 就找不到了。另外确认 AppID 选的是测试号。{/collapse-item}
{collapse-item label="能在支付宝小程序或者其他平台用吗?"}A:不能直接用。这套组件按微信小程序的自定义组件规范编写,属性命名与事件都对着微信的接口,其他平台需要自行改造。要跨端请选对应生态的组件库。{/collapse-item}
{collapse-item label="能改样式吗,会不会和全局样式打架?"}A:能改。组件对外暴露了 externalClasses,例如按钮上就能挂 l-class、l-label-class、hover 类等,页面样式里定义这些类名即可覆盖。如果需要全局统一换肤,建议走完整源码路线,改 src 里的样式变量后重新构建。{/collapse-item}
{collapse-item label="打开示例工程需要装依赖吗?"}A:不需要。示例工程是原生小程序工程,导入开发者工具就能跑。只有你要改源码、重新构建组件时才需要装 Node 与 gulp 依赖。{/collapse-item}
源码获取
建议先转存到自己网盘再下载。手机上打开链接点右下角「保存到网盘」,回头在夸克 App 的「我的网盘」里下。