Kupola

零框架依赖的声明式 UI 组件系统,适用于任何服务端渲染 Web 应用。

HTMX(数据获取)+ Alpine.js(声明式交互)+ Bootstrap(组件丰富度)— 合为一个零依赖包。

50+ UI 组件
按钮、输入框、卡片、模态框、表格、日期选择器、热力图等
响应式数据绑定
基于 Proxy 的双向绑定 data-bind,ref() / store()
双主题 + 11 品牌色
暗色优先,亮色切换,中国传统色品牌主题
后端无关
Flask / Django / FastAPI / Gin / Spring Boot / ASP.NET / Rails
TypeScript 就绪
完整 .d.ts 类型定义,编辑器智能提示
无障碍访问
符合 WCAG AA 标准,键盘导航支持

安装

npm

npm install @kupola/kupola

CDN

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kupola/kupola/dist/kupola.min.css"> <script src="https://cdn.jsdelivr.net/npm/@kupola/kupola/dist/kupola.min.js"></script>

ESM(现代浏览器)

<script src="https://cdn.jsdelivr.net/npm/@kupola/kupola/dist/kupola.esm.js" type="module"></script>

快速上手

一个完整页面,从零开始使用 Kupola 组件。

<!DOCTYPE html> <html lang="zh-CN"> <head> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kupola/kupola/dist/kupola.min.css"> </head> <body data-theme="dark"> <!-- 按钮 --> <button class="ds-btn ds-btn--primary">主要按钮</button> <!-- 卡片 --> <div class="ds-card"> <div class="ds-card__title">欢迎</div> <div class="ds-card__body">这是你的第一个 Kupola 页面</div> </div> <!-- 数据绑定 --> <input class="ds-input" data-bind="value:name" placeholder="输入姓名"> <span data-bind="text:name"></span> <script src="https://cdn.jsdelivr.net/npm/@kupola/kupola/dist/kupola.min.js"></script> </body> </html>
提示: Kupola 在 DOMContentLoaded 时自动初始化组件,无需手动调用 bootstrap。

组件初始化

通过 data-* 属性声明式初始化,MutationObserver 自动发现动态插入的元素。

<!-- 下拉框:声明 data-dropdown 自动初始化 --> <div data-dropdown data-value="a"> <div class="ds-dropdown__trigger">选择</div> <div class="ds-dropdown__menu"> <div data-value="a">选项 A</div> <div data-value="b">选项 B</div> </div> </div>

动态插入后刷新

// CDN / UMD 模式 Kupola.refresh(scopeElement); Kupola.cleanup(element);
// ESM 模式 import { refresh, cleanup } from 'kupola'; await refresh(scopeElement); cleanup(element);

数据绑定

基于 Proxy 的响应式双向绑定,DOM 随数据自动更新。

// HTML <input data-bind="value:username"> <span data-bind="text:username"></span>
// JS kupolaData.set('username', '张三'); // DOM 自动更新 kupolaData.get('username'); // 读取 kupolaData.load({ username: '...', phone: '...' }); // 批量加载 kupolaData.observe('key', (newVal) => {}); // 监听变化 kupolaData.computed('full', ['first','last'], (f,l) => f + l);

轻量响应式 ref()

import { ref } from 'kupola'; const count = ref(0); count.value++; // 自动触发所有订阅者

表单验证

内置验证引擎,支持自定义规则,声明式配置。

<form id="myForm"> <input name="email" data-validate="required,email"> <input name="pwd" data-validate="required,min:6"> <button type="submit">提交</button> </form>
import { KupolaForm } from 'kupola'; const form = new KupolaForm(formElement); form.getData(); // { email: '...', pwd: '...' } form.setData(data); // 填充 form.validate(); // 验证所有字段

主题系统

暗色优先,一行切换亮色;11 种中国传统色品牌主题。

<body data-theme="dark"> <!-- 或 "light" -->
import { setTheme, getTheme, setBrand, getBrand, BRAND_OPTIONS } from 'kupola'; setTheme('light'); setBrand('zengqing'); // 曾青 | cui_lv | xionghuang | ...
曾青翠绿雄黄 姜黄蓝绿孔雀蓝 玫瑰紫柿红山茶红 紫云柔蓝

图标系统

80+ SVG 图标,零配置可用。

import { svg, renderIcon, PATHS } from 'kupola'; svg('search'); // 返回 SVG 字符串 renderIcon('bell', el); // 渲染到 DOM 元素

组件速查 — 通用

组件导入初始化
Buttonds-btn ds-btn--primary纯 CSS
Cardds-card纯 CSS
Tagimport { Tag, initTags }initTags(root)
Badgeds-badge纯 CSS
Alertds-alert ds-alert--success纯 CSS
Avatards-avatar纯 CSS

组件速查 — 数据录入

组件导入清理
Selectimport { Select, initSelects }cleanupSelect(el)
Datepickerimport { Datepicker, initDatepickers }cleanupDatepicker(el)
Timepickerimport { Timepicker, initTimepickers }cleanupTimepicker(el)
FileUploadimport { FileUpload, initFileUploads }cleanupFileUpload(el)
ColorPickerimport { ColorPicker, initColorPickers }cleanupColorPicker(el)
Sliderimport { Slider, initSliders }cleanupSlider(el)
NumberInputimport { NumberInput, initNumberInputs }cleanupNumberInput(el)
DynamicTagsimport { DynamicTags, initDynamicTags }cleanupDynamicTags(el)
重要: 每个组件都有对应的 cleanup 函数,页面卸载时必须调用以防内存泄漏。

组件速查 — 数据展示

组件导入说明
Tableimport { KupolaTable, initAllTables }排序/分页/筛选/树形/虚拟滚动
Calendarimport { Calendar, initCalendars }月/周/日视图
Heatmapimport { Heatmap, initHeatmaps }活动热力图
StatCardimport { StatCard, initStatCards }统计卡片(数值+趋势)
Carouselimport { Carousel, initCarousels }图片/内容轮播
ImagePreviewimport { showImagePreview }图片预览灯箱
VirtualListimport { VirtualList, initVirtualList }大数据量虚拟列表

Table 示例

const table = new KupolaTable(el, { columns: [{ key: 'name', title: '名称', sortable: true }], pagination: true, pageSize: 20, }); table.setData(data); table.refresh();

组件速查 — 反馈

组件导入用法
Modalimport { Modal, createModal, confirmModal }createModal({ title, content, onConfirm })
Dialogimport { Dialog }声明式弹窗
Messageimport { message }message.success('操作成功')
Notificationimport { notification }notification({ title, content, type })
Tooltipimport { initTooltip }元素 data-title="提示"

组件速查 — 导航

组件导入清理
Dropdownimport { Dropdown, initDropdowns }cleanupDropdown(el)
Drawerimport { Drawer, initDrawers }cleanupDrawer(el)
Collapseimport { Collapse, initCollapses }cleanupCollapse(el)
Paginationimport { KupolaPagination, initPagination }

组件速查 — 其他

组件导入说明
Countdownimport { Countdown, initCountdowns }倒计时
SlideCaptchaimport { SlideCaptcha, initSlideCaptchas }滑块验证
Web Componentsimport { registerWebComponents }自定义元素桥接

声明式数据依赖

useDeps() — 声明式数据获取,自动缓存、重试、刷新。

import { useDeps } from 'kupola'; // 声明数据源 useDeps({ users: { url: '/api/users', staleTime: 60000, // 60秒缓存 retry: 3, // 失败重试3次 transform: (data) => data.list // 数据转换 } });
<!-- HTML 声明式绑定 --> <div data-deps="users:fetch:/api/users"> <template data-each="users"> <span data-bind="item.name:text"></span> </template> </div>

HTTP 客户端插件

可插拔架构,支持 Axios、@navios/http 或任意 HTTP 客户端。

import { configureHttpClient } from 'kupola'; import { createAxiosAdapter } from 'kupola/adapters/axios'; import axios from 'axios'; const api = axios.create({ baseURL: '/api' }); api.interceptors.request.use(config => { config.headers.Authorization = `Bearer ${getToken()}`; return config; }); configureHttpClient(createAxiosAdapter(api));

生命周期

页面级生命周期钩子:beforeMount → mount → afterMount → unmount → destroy

import { createLifecycle } from 'kupola'; const lc = createLifecycle('page:users'); lc.on('mount', () => { /* 初始化组件 */ }); lc.on('unmount', () => { /* 清理资源 */ }); await lc.bootstrap(); await lc.mount();

状态管理

KupolaStore — 轻量级状态管理,支持 state / getters / mutations / actions。

import { createStore } from 'kupola'; const store = createStore('counter', { state: { count: 0 }, mutations: { increment(state) { state.count++; } }, }); store.commit('increment');

国际化

import { t, setLocale, formatDate, formatCurrency } from 'kupola'; setLocale('zh-CN'); t('greeting'); // 翻译 key formatDate(new Date()); // 2026年7月12日 formatCurrency(99.9, 'CNY'); // ¥99.90

工具库(Tree-Shakable)

命名导出,未使用的工具函数会被 bundler 自动裁剪。

import { stringUtils, arrayUtils, dateUtils, debounce, throttle } from 'kupola'; stringUtils.capitalize('hello'); // 'Hello' stringUtils.camelize('my-class'); // 'myClass' arrayUtils.isEmpty([]); // true dateUtils.formatDate(new Date(), 'yyyy-MM-dd'); debounce(fn, 300); throttle(fn, 200);

可用命名空间

stringUtils arrayUtils objectUtils numberUtils dateUtils validatorUtils cryptoUtils preloadUtils debounce throttle

后端集成

Kupola 与任何输出 HTML 的后端兼容,三种集成模式:

模式说明适用场景
模板渲染 (SSR)后端直接输出 HTMLFlask / Django / Jinja2
RESTful API前端 data-deps 获取数据任何 REST API
混合模式SSR + 局部 API 刷新复杂交互场景
详见: INTEGRATION.md — Flask / Django / 静态站点完整集成示例。

TypeScript

完整的 .d.ts 类型定义,开箱即用。

// 自动类型推导 import { KupolaTable, KupolaForm, createStore } from '@kupola/kupola'; // tsconfig.json { "compilerOptions": { "types": ["@kupola/kupola"] } }

Tree-Shaking

所有模块均为 ES Module 命名导出,bundler 自动裁剪未使用代码。

// 只导入 Modal + 字符串工具 → 其他 40+ 组件被裁剪 import { Modal, createModal, stringUtils } from '@kupola/kupola';

package.json sideEffects

"sideEffects": ["./js/icons.js", "./js/theme-standalone.js", "*.css"]

构建与发布

构建命令

npm run build # Vite 构建(ESM + CJS + UMD) npm run build:rollup # Rollup 构建(替代方案) npm run build:css # 合并 + 压缩 CSS npm run build:all # CSS + SVG Sprite

产物

文件格式用途
dist/kupola.esm.jsESM现代 bundler
dist/kupola.cjs.jsCJSNode.js / 旧 bundler
dist/kupola.umd.jsUMDCDN / <script> 标签
dist/kupola.min.jsUMD min生产环境 CDN
dist/css/kupola.cssCSS完整样式

npm 发布

npm publish --access public

当前版本:v1.4.3 | minified ~75 KB gzipped | ESM ~550 KB (unminified) | 362 文件

贡献者: 查看 内部架构文档 — 核心引擎、模块依赖、构建管线、新增组件指南。