@cldemo/ui-kit
VueDemo
Vue 3 + TypeScript 组件库,提供 PC 端和移动端的通用 UI 组件及工具函数。
快速开始
npm install # 安装依赖
npm run lib:build # 构建组件库产物
按需使用与全局注入
组件库支持 按需引入(推荐)与 全量 install 两种方式,需注意以下几点:
- 按需引入组件(三种路径任选,均自带组件样式与 TS 类型):
unplugin-vue-components+clResolver(见buildLibs/resolver),组件列表自动从clComponentMap解析;推荐业务侧首选,也是唯一零维护的接入方式;- 小驼峰入口:
import ClButton from '@cldemo/ui-kit/button'(./*通配,类型完备); - 精确组件路径:
import ClButton from '@cldemo/ui-kit/utils/Element/ClButton'(按端区分utils/Element|Web|Mobile)。 - 每个组件入口均已自带其样式(如
import '.../styles/Element/ClButton.css'),无需手动引全量 CSS。
- 具名导入:根入口
import { ClXxx } from '@cldemo/ui-kit'与按端入口@cldemo/ui-kit/web/@cldemo/ui-kit/mobile导出组件清单中的全部组件(清单见COMPONENT_CATALOG.md)。- 导出名 = 组件自身的
defineOptions({ name }),可用node scripts/check-manifest.cjs校验一致性; - 根入口会静态引入全部组件(含
ClEcharts/ClCropper/ClSelect/ClPreview),因此全量场景必须装齐全部 peer;按需场景请用clResolver或单组件入口。
- 导出名 = 组件自身的
- 全量 CSS:如需一次性引入所有样式,用
import '@cldemo/ui-kit/ui-kit.css'(唯一官方样式入口,勿用buildLibs/...深层路径——不在 exports 暴露,会被打包器拦截)。按端全量样式也可用@cldemo/ui-kit/styles下的组件样式。 - use* 工厂与
$ClGlobals是两套入口:- 独立 use 工厂:
useNotify/useAlert/usePreview/useClipboard/languagePack,随组件按需可用,自身 mount,不依赖app.use(install),推荐业务侧统一使用; $ClGlobals.*:依赖全量app.use(install)的provide,只在全量安装场景可用,按需模式下拿不到(成员明细见下方 use 工厂与$ClGlobals);- 请二选一使用,勿在同一项目混用,否则同一功能行为可能不一致。
- 独立 use 工厂:
- 组件名与标签的对应关系:组件
name同时决定「模板 kebab 标签」「clComponentMap键」「全局注册名」,三者由node scripts/generate-components.cjs+node scripts/generate-resolver.cjs从组件源码统一派生(事实源 =src/libs/*/componentsInstalls.ts)。- 标签一律是「组件名按大写边界加连字符并小写」:
ClDropdownMenuM→<cl-dropdown-menu-m>、ClColorPicker→<cl-color-picker>; clResolver额外容忍 PascalCase 直写标签(<ClDropdownMenu>)与全小写(<clbutton>);- 新增组件只需在对应
componentsInstalls.ts加 import,npm run dev/npm run lib:build会自动重生成清单,npm run gate会拦住漏导。
- 标签一律是「组件名按大写边界加连字符并小写」:
setGlobalConfig全局组件配置:单个入口配置所有组件的全局默认,按需加载与全量安装共用同一份配置注册表:- 按需加载(推荐直达子路径,只加载配置模块本身):
import CommonGlobalConfig from '@cldemo/ui-kit/common/globalConfig',如CommonGlobalConfig.setGlobalConfig({ calendar: { restDays: [...] } }); - 亦可从 common 具名引入:
import { setGlobalConfig } from '@cldemo/ui-kit/common'; - 全量安装:等价写法
app.use(ClLibs, { globalsOption: { calendar: { restDays: [...] } } })(install内部写入同一注册表); - 合并优先级:页面 props 显式值 > 全局配置 > 组件默认值;注册表为 reactive,运行中再次调用会自动刷新。
- 按需加载(推荐直达子路径,只加载配置模块本身):
- 类型提示:
install签名与$ClGlobals结构可从import { ClGlobals, ClGlobalOptions } from '@cldemo/ui-kit'获取。 - peer 依赖:
vue / vue-router / echarts / cropper-next-vue / vue-virtual-scroller为 peer,由使用方提供、组件库不内置(避免双实例),且已 external、不强制打包。- 按需引入(推荐):只装用到的,如
<cl-echarts>用时装echarts、<cl-cropper>用时装cropper-next-vue、<cl-select>/<cl-pull-to-refresh>用时装vue-virtual-scroller;用不到的无需安装。 - 全量安装:根入口静态引入含
ClEcharts/ClCropper/ClSelect在内的 Web 端全部组件,因此必须同时安装全部 peer,否则构建/运行时 resolve 失败。
- 按需引入(推荐):只装用到的,如
- Common 工具:
@cldemo/ui-kit/common(含CommDay等)不依赖 echarts;echarts 由<cl-echarts>内部按需import('echarts')懒加载,不因使用工具而触发。 - 运行环境:本库面向浏览器端渲染(CSR),目标场景为后台管理系统类 SPA,不提供 SSR / Nuxt 支持。组件按 CSR 假设编写(直接使用
window/document,不做服务端环境守卫)——这是有意的范围取舍,不是待补项。如需在服务端渲染环境中使用,请自行把组件包进客户端渲染分支。
主题定制(Design Token)
组件库的视觉值(颜色 / 间距 / 字号 / 圆角 / 层级等)统一由 Design Token 管理,单一事实源为 src/libs/Common/token.css。
- 自动注入,无需手动引入:Token 随库入口(全量)与各组件 entry(按需)自动加载,模块级去重保证全站只加载一次。
- 换主题 = 覆盖语义层变量:
:root {
--cl-primary: #7c3aed;
--cl-primary-hover: #8b5cf6;
--cl-primary-active: #6d28d9;
}
- 全部 token 清单与定制方式:见 docs/tokens/design-token.md。
- 新增组件/样式时:禁止硬编码色值,一律引用
var(--cl-*, fallback);新增类名须带cl-前缀且用 kebab-case。规则见 docs/通用组件规范.md 第 9 节。 - 门禁:
node scripts/check-tokens.cjs检查新增硬编码色值(存量已列基线,不阻塞)。 - 响应式:本库不提供响应式能力,尺寸与布局由使用方控制。
暗色模式
Token 只覆盖语义层与遮罩层,基础层与品牌色定制不受影响。
<!-- 1. 跟随系统:无需任何配置,系统深色时自动生效 -->
<!-- 2. 手动切换:html 上加属性 -->
<html data-cl-theme="dark">
<!-- 3. 局部暗色:任意容器加 class -->
<div class="cl-theme-dark">…</div>
被覆盖的语义变量:--cl-primary*、--cl-{success,warning,danger}-{text,bg,border}、
--cl-text-*、--cl-border*、--cl-bg*、--cl-mask*、--cl-overlay、--cl-shadow-*。
语言切换(i18n)
字典与取词能力由 languagePack 提供,语言本身放在全局配置注册表里(响应式),切换后已渲染的文案会立即刷新:
import { setLocale } from '@cldemo/ui-kit/common'
setLocale('en') // 支持 'zh_cn'(默认)| 'en'
setLocale('zh_cn')
- 组件内取词:
const { optPageLanguage, getPageLanguage } = useLanguage(); getPageLanguage('paginate'),模板用optPageLanguage.jumpTo; - 无障碍名称取词:
const { optA11yText } = useA11yLanguage(),模板用:aria-label="optA11yText.loading"; - 词条只增不改,新增文案请加进
src/libs/Common/i18n/{zh_CN,en}.ts(跨组件复用的通用词放Common/i18n/a11y.ts)。
v-model 契约
组件同时支持标准写法与历史写法,二者等效:
<cl-input v-model="value" /> <!-- Vue 3 标准(推荐)-->
<cl-input v-model:value="value" /> <!-- 1.x 历史写法,继续可用 -->
- 实现方式:组件同时声明并触发
update:value与update:modelValue,父组件只响应自己监听的那个; v-model:show等命名模型(弹层显隐)沿用各自的名字,不受影响;- 新增组件请两个事件都声明(
src/libsTest/componentManifest.test.ts会校验二者成对出现)。
日志开关
库内告警统一走 clLog,默认开发构建输出、生产构建静默(error 始终输出):
import CommonGlobalConfig from '@cldemo/ui-kit/common/globalConfig'
CommonGlobalConfig.setGlobalConfig({ debug: true }) // 全开
CommonGlobalConfig.setGlobalConfig({ debug: { warn: true, error: false } }) // 只开告警
CommonGlobalConfig.setGlobalConfig({ debug: null }) // 清除,回到默认策略
输出统一带 [ui-kit][组件名] 前缀,便于在控制台区分来源。
可访问性
- 组件普遍已补
role/aria-*/:focus-visible焦点样式; ClModal提供isEscapeClose(Esc 关闭)与isFocusTrap(焦点陷阱 + 焦点还原),默认开启;- 焦点陷阱可复用:
src/libs/Use/focusTrap.ts(useFocusTrap(refEl, isActive, { onEscape }),需在库内引用,未单独对外暴露); - 滚动锁全库统一(
src/libs/Use/scrollLock.ts):同容器多组件叠加计数,最后一个解锁才还原,不会互相打断; Load与过渡类动画遵循prefers-reduced-motion。
目录结构
src/
└── libs/
├── Element/ # 通用组件(PC / Mobile 共用)
├── Web/ # Web 端专用组件
├── Mobile/ # Mobile 端专用组件
└── Common/ # 公共工具(base、day、echart、axios 等)
组件列表
Element(通用组件)
| 组件 | 标签 | 说明 |
|---|---|---|
| Badge | <cl-badge> |
徽章 |
| Breadcrumb | <cl-breadcrumb> |
面包屑导航 |
| Button | <cl-button> |
按钮 |
| Callout | <cl-callout> |
提示条 |
| Card | <cl-card> |
卡片 |
| CardColor | <cl-card-color> |
彩色卡片 |
| Checkbox | <cl-checkbox> |
复选框 |
| Clipboard | <cl-clipboard> |
复制 |
| Collapse | <cl-collapse> |
折叠面板 |
| CountDown | <cl-count-down> |
倒计时 |
| Cropper | <cl-cropper> |
图片裁剪 |
| Darg | <cl-darg> |
拖拽排序 |
| Divider | <cl-divider> |
分割线 |
| Ellipsis | <cl-ellipsis> |
文本省略 |
| Empty | <cl-empty> |
空状态 |
| Form | <cl-form> |
表单 |
| FormGroup | <cl-form-group> |
表单组布局 |
| IconFont | <cl-icon-font> |
图标 |
| Image | <cl-image> |
图片 |
| Input | <cl-input> |
输入框 |
| InputCaptcha | <cl-input-captcha> |
验证码输入框 |
| InputNumber | <cl-input-number> |
数字输入框 |
| InputNumberStepper | <cl-input-number-stepper> |
数字输入框(加减步进) |
| InputPassword | <cl-input-password> |
密码输入框 |
| InputSearch | <cl-input-search> |
搜索框 |
| InputTextarea | <cl-input-textarea> |
文本域 |
| Link | <cl-link> |
链接 |
| Load | <cl-load> |
加载动画 |
| LoadScreen | <cl-load-screen> |
全屏加载遮罩 |
| Modal | <cl-modal> |
弹窗 |
| NumberRoll | <cl-number-roll> |
数字动画 |
| Overlay | <cl-overlay> |
遮罩层 |
| Progress | <cl-progress> |
进度条 |
| Radio | <cl-radio> |
单选框 |
| Slider | <cl-slider> |
滑动条 |
| Switchery | <cl-switchery> |
开关 |
| Tags | <cl-tags> |
标签 |
| Transition | <cl-slide-up-down> |
过渡动画 |
| Waterfall | <cl-waterfall> |
瀑布流 |
Web(Web 端组件)
| 组件 | 标签 | 说明 |
|---|---|---|
| Alert | useAlert() |
警告框(use 工厂,无标签) |
| AnchorNav | <cl-anchor-nav> |
锚点导航 |
| Calendar | <cl-calendar> |
日历 |
| CodeLegend | <cl-code-legend> |
图例卡片 |
| ColorPicker | <cl-color-picker> |
颜色选择器 |
| CropperPreview | <cl-cropper-preview> |
裁剪预览 |
| DateTime | <cl-date-time> |
日期时间 |
| DropdownMenu | <cl-dropdown-menu> |
下拉菜单 |
| DropdownPopup | <cl-dropdown-popup> |
下拉弹出层 |
| ECharts | <cl-echarts> |
图表 |
| EchartsLineAxisTag | <cl-echarts-line-axis-tag> |
折线标签图表 |
| FileUpload | <cl-file-upload> |
文件上传 |
| FramePhone | <cl-frame-phone> |
手机外壳 |
| InputTag | <cl-input-tag> |
输入标签 |
| Notify | useNotify() |
通知(use 工厂,无标签) |
| Paginate | <cl-paginate> |
分页 |
| Portlet | <cl-portlet> |
面板 |
| Preview | usePreview() |
大图预览(use 工厂,无标签) |
| PreviewExample | <cl-preview-example> |
预览示例 |
| ScrollxFence | <cl-scroll-xfence> |
横向滚动围栏 |
| Select | <cl-select> |
选择框 |
| SelectCascade | <cl-select-cascade> |
级联选择 |
| SelectMove | <cl-select-move> |
穿梭选择 |
| SelectTag | <cl-select-tag> |
标签选择器 |
| SelectTree | <cl-select-tree> |
树形选择 |
| SideMenu | <cl-side-menu> |
侧边菜单 |
| Table | <cl-table> |
表格 |
| TableEdit | <cl-table-edit> |
表格编辑 |
| TableSimple | <cl-table-simple> |
简易表格 |
| Tabs | <cl-tabs> |
标签页 |
| Tree | <cl-tree> |
树形 |
| WeekHour | <cl-week-hour> |
周时间选择器 |
| XEditable | <cl-x-editable> |
内联编辑 |
Mobile(移动端组件)
| 组件 | 标签 | 说明 |
|---|---|---|
| ActionSheet | <cl-action-sheet> |
动作面板 |
| AreaM | <cl-area-m> |
省市区三级联动选择器,内置全国数据(含港澳台),areaList 为空时自动按需加载 |
| BackTop | <cl-back-top> |
回到顶部 |
| Banner | <cl-banner> |
横幅 |
| CalendarM | <cl-calendar-m> |
日历 |
| Cell | <cl-cell> |
单元格 |
| CellSwipe | <cl-cell-swipe> |
滑动单元格 |
| CodeLegendM | <cl-code-legend-m> |
图例卡片 |
| DropdownMenuM | <cl-dropdown-menu-m> |
下拉菜单 |
| FloatingBubble | <cl-floating-bubble> |
浮动气泡 |
| FloatingPanel | <cl-floating-panel> |
浮动面板 |
| Grid | <cl-grid> |
宫格 |
| TextHighlight | <cl-text-highlight> |
文本高亮 |
| IndexBar | <cl-index-bar> |
索引栏 |
| InputOtp | <cl-input-otp> |
验证码输入框 |
| NavBar | <cl-nav-bar> |
导航栏 |
| NoticeBar | <cl-notice-bar> |
通知栏 |
| NotifyM | <cl-notify-m> |
消息通知 |
| NumberKeyboard | <cl-number-keyboard> |
数字键盘 |
| Picker | <cl-picker> |
选择器 |
| PickerCascader | <cl-picker-cascader> |
级联选择 |
| PickerDate | <cl-picker-date> |
日期选择 |
| PickerTime | <cl-picker-time> |
时间选择 |
| Popup | <cl-popup> |
弹出层 |
| PullToRefresh | <cl-pull-to-refresh> |
下拉刷新 |
| Rate | <cl-rate> |
评分 |
| ScrollCard | <cl-scroll-card> |
滚动卡片列表 |
| ShareSheet | <cl-share-sheet> |
分享面板 |
| Sidebar | <cl-sidebar> |
侧边导航 |
| SidebarSelect | <cl-sidebar-select> |
侧栏选择 |
| Signature | <cl-signature> |
签名 |
| Steps | <cl-steps> |
步骤条 |
| Swipe | <cl-swipe> |
轮播 |
| TabM | <cl-tab-m> |
标签页 |
| Tabbar | <cl-tabbar> |
标签栏 |
| Toast | <cl-toast> |
轻提示 |
| Watermark | <cl-watermark> |
水印 |
本地联调(符号链接接入)
消费方把 node_modules/@cldemo/ui-kit 指向本仓库根目录(符号链接 / npm link)后,可以边改组件边联调,但编辑器需要额外配置,否则 lib:build 之后会持续报 TS7016(找不到声明文件),或类型提示停留在旧版本。
原因:TypeScript 按 realpath 解析符号链接,最终读到的是本仓库的真实路径(位于消费方工作区之外),而 VS Code 的文件监视器对工作区外路径覆盖不可靠 —— 重建产物的事件传不到 TS 服务,失败状态会一直保留到手动重启。
注意:这与 .gitignore 无关。编辑器的文件监视不读取 .gitignore(只有搜索与源代码管理读),因此调整 buildLibs 的忽略规则解决不了该问题。
消费方两种修法(任选其一):
- 把组件库目录纳入监视范围 ——
files.watcherInclude只接受绝对路径,写相对路径会被当作工作区相对路径而落空,改完需重载窗口:
// 消费方 .vscode/settings.json
"files.watcherInclude": ["<组件库根目录的绝对路径>"]
- 把组件库根目录加入多根工作区(
.code-workspace的folders)—— 路径成为工作区内路径后监视天然覆盖,最稳。
未做上述配置时,每次 lib:build 后消费方都要手动执行一次命令面板的 TypeScript: Restart TS Server(本仓库 npm run lib:build 收尾会打印该提示)。
校验与门禁
| 命令 | 作用 |
|---|---|
npm run manifest:generate |
从 src/libs/*/componentsInstalls.ts 重生成 components.ts 与 resolver.ts |
npm run manifest:check |
校验:组件名唯一 · 标签与 name 自洽 · 导出无遗漏 · resolver 覆盖且产物存在 |
npm run token:check |
校验是否新增硬编码色值(基线只减不增) |
npm run gate |
一次跑完上面两项门禁(CI 建议挂这个) |
npm test |
运行单元测试(vitest) |
npm run lint |
代码检查 |
指令
指令随组件库一起发布,全量 app.use(install) 自动注册;按需模式下 clResolver 只解析组件、不解析指令(Components({ directives: true }) 对此无效),需显式注册后再在模板使用 —— 例如 import * as Tooltip from '@cldemo/ui-kit/core/tooltip' 后 app.use(createInstallCore({ tooltip: Tooltip }, {}))(完整入口清单见 COMPONENT_CATALOG.md 的「按需引入:细粒度入口」)。
| 指令 | 说明 |
|---|---|
v-cl-code-highlight |
代码高亮 |
v-cl-waves |
波纹效果 |
v-cl-tooltip |
工具提示 |
v-cl-lazy-image |
图片懒加载 |
use 工厂与 $ClGlobals
| 名称 | 说明 |
|---|---|
useNotify() |
通知 |
useAlert() |
警告框 |
usePreview() |
大图预览 |
useClipboard() |
剪贴板复制 |
languagePack() |
语言包 |
$ClGlobals |
全局注入容器(全量安装时可用,inject('$ClGlobals') 获取),成员明细见下方 |
setGlobalConfig() |
组件全局默认配置(推荐 @cldemo/ui-kit/common/globalConfig,亦可从 @cldemo/ui-kit/common 具名引入) |
$ClGlobals 共 8 个成员,其中 5 个与上方 use 工厂对应,另有 loadScreen / validate / toast 三个成员无对应 use 工厂:
| 成员 | 说明 | 对应 use 工厂 |
|---|---|---|
clipboard |
剪贴板复制 | useClipboard() |
loadScreen |
全屏加载遮罩 | — |
languagePack |
语言包 | languagePack() |
validate |
表单校验规则表 | — |
notify |
通知 | useNotify() |
alert |
警告框 | useAlert() |
preview |
大图/视频预览(懒加载) | usePreview() |
toast |
轻提示 | — |
具体使用方法见
COMPONENT_CATALOG.md的「use 工厂(开放 API)」与「$ClGlobals全局注入」章节。
组件命名规范
- 文件夹名:PascalCase(如
InputNumberStepper) - 组件名:
Cl+ PascalCase(如ClInputNumberStepper) - 使用标签:
cl-+ kebab-case(如<cl-input-number-stepper>)
License
MIT
Related Packages
A very fast and versatile markdown toolchain. AST, React, React Native, SolidJS,...
Lower level utilities for compiling Vue single file components
Storybook Vue 3 renderer: Develop, document, and test UI components in isolation
Vue 3 plugin and composables for TraceTail browser fingerprinting, with 99.6% ac...
Version History
| Version | Released | License |
|---|---|---|
| 1.1.12 | MIT | |
| 1.1.11 | MIT | |
| 1.1.10 | MIT | |
| 1.1.9 | MIT | |
| 1.1.8 | MIT | |
| 1.1.7 | MIT | |
| 1.1.6 | MIT | |
| 1.1.5 | MIT | |
| 1.1.4 | MIT | |
| 1.1.3 | MIT | |
| 1.1.2 | MIT | |
| 1.1.1 | MIT | |
| 1.1.0 | MIT | |
| 1.0.17 | MIT | |
| 1.0.16 | MIT | |
| 1.0.15 | MIT | |
| 1.0.14 | MIT | |
| 1.0.13 | MIT | |
| 1.0.12 | MIT | |
| 1.0.11 | MIT | |
| 1.0.10 | MIT | |
| 1.0.9 | MIT | |
| 1.0.8 | MIT | |
| 1.0.7 | MIT | |
| 1.0.6 | MIT | |
| 1.0.5 | MIT | |
| 1.0.4 | MIT | |
| 1.0.3 | MIT | |
| 1.0.2 | MIT | |
| 1.0.1 | MIT |
Showing the latest 30 of 31. See every release on npm