name: ckui description: 关于使用CKUI界面库相关功能的技能
CKUI 界面库使用文档
CKUI 是一个现代化、无依赖的 UI 库,专为 Tampermonkey/Greasemonkey 用户脚本设计。
版本信息
- 当前版本: 2.5.0
- 许可证: GPL-3.0-only
- 作者: CKylinMC
引入方式
在用户脚本头部添加:
// @require https://update.greasyfork.org/scripts/564901/1753405/CKUI.js
(这个地址中的第二个数字部分会跟随版本更新而变化)
然后在脚本中通过 unsafeWindow.ckui 或 window.ckui 访问。
核心功能
1. 通知系统(Notification)
用于显示消息提示,支持成功、错误、警告、信息四种类型。
基础用法
// 成功提示
ckui.success('操作成功');
ckui.success('保存成功', '提示');
// 错误提示
ckui.error('操作失败');
ckui.error('保存失败,请重试', '错误');
// 警告提示
ckui.warning('请注意检查输入');
ckui.warning('数据不完整', '警告');
// 信息提示
ckui.info('这是一条提示信息');
ckui.info('请等待处理完成', '提示');
高级配置
ckui.notification.show({
title: '标题',
message: '消息内容',
type: 'success', // 'success' | 'error' | 'warning' | 'info'
duration: 3000, // 显示时长(毫秒),0表示不自动关闭
closable: true, // 是否显示关闭按钮
shadow: false // 是否使用 Shadow DOM 隔离
});
实际应用示例
// 来自 ckylin-script-bilibili-up-notes.user.js
ckui.success('备注已保存');
ckui.error('保存失败,请重试');
ckui.warning('标签数量已达上限');
2. 模态框(Modal)
支持多种对话框类型:确认框、提示框、输入框、选择框、排序列表等。
2.1 确认框(Confirm)
// 基础用法
const confirmed = await ckui.confirm('确定要删除吗?');
if (confirmed) {
// 用户点击确定
} else {
// 用户点击取消或关闭
}
// 自定义标题
const confirmed = await ckui.confirm('确定要删除这条记录吗?', '确认删除');
// 高级配置
const confirmed = await ckui.confirm({
content: '确定要删除吗?',
title: '确认删除',
width: '400px',
maskClosable: true, // 点击遮罩层是否关闭
shadow: false, // 是否使用 Shadow DOM
icon: '⚠️', // 标题图标
iconShape: 'circle', // 图标形状: 'circle' | 'square'
iconWidth: '24px' // 图标大小
});
2.2 提示框(Alert)
// 基础用法
await ckui.alert('操作已完成');
// 自定义标题
await ckui.alert('保存成功', '提示');
// 高级配置
await ckui.alert({
content: '操作已完成',
title: '提示',
width: '400px',
shadow: false
});
2.3 输入框(Prompt)
// 基础用法
const input = await ckui.prompt('请输入名称');
if (input !== null) {
console.log('用户输入:', input);
}
// 带默认值
const input = await ckui.prompt('请输入名称', '默认名称');
// 高级配置
const input = await ckui.prompt({
title: '请输入名称',
defaultValue: '默认名称',
placeholder: '请输入...',
width: '400px'
});
2.4 选择框(Select)
// 基础用法
const selected = await ckui.select({
title: '请选择',
options: ['选项1', '选项2', '选项3'],
defaultValue: '选项1'
});
// 对象数组形式
const selected = await ckui.select({
title: '选择分类',
options: [
{ label: '技术', value: 'tech' },
{ label: '生活', value: 'life' },
{ label: '娱乐', value: 'entertainment' }
],
defaultValue: 'tech',
width: '400px'
});
2.5 排序列表(Sortable List)
// 基础用法
const sortedItems = await ckui.sortableList({
title: '排序列表',
items: ['项目1', '项目2', '项目3'],
width: '500px'
});
// 对象数组形式
const sortedItems = await ckui.sortableList({
title: '调整顺序',
items: [
{ label: '首页', value: 'home' },
{ label: '分类', value: 'category' },
{ label: '关于', value: 'about' }
]
});
2.6 自定义模态框
// 创建自定义内容的模态框
const modal = new ckui.Modal({
title: '自定义模态框',
content: '这是自定义内容',
width: '600px',
showClose: true,
footer: null, // null=无底部, 'alert'=只有确定按钮, 默认=确定+取消
onOk: async () => {
// 点击确定时的回调
console.log('确定');
return true; // 返回 false 阻止关闭
},
onCancel: () => {
// 点击取消时的回调
console.log('取消');
}
});
// 显示模态框
const result = await modal.show();
// 使用 DOM 元素作为内容
const content = document.createElement('div');
content.innerHTML = '<p>自定义 HTML 内容</p>';
const modal = new ckui.Modal({
title: '自定义内容',
content: content,
width: '500px'
});
await modal.show();
// 使用 allowHtml 允许 HTML 字符串
const modal = new ckui.Modal({
title: '标题',
content: '<p style="color: red;">HTML 内容</p>',
allowHtml: true
});
实际应用示例
// 来自 ckylin-script-bilibili-up-notes.user.js
// 删除确认
const confirmed = await ckui.confirm(
`确定要删除 ${displayName} 的备注吗?`,
'确认删除'
);
if (confirmed) {
// 执行删除操作
}
// 编辑备注(使用表单构建器配合模态框)
const form = ckui.form()
.input({ label: '别名', name: 'alias', value: user.alias })
.textarea({ label: '备注', name: 'notes', value: user.notes });
const modal = new ckui.Modal({
title: '编辑备注',
content: form.render(),
width: '500px',
onOk: () => {
const values = form.getValues();
// 保存数据
return true;
}
});
await modal.show();
3. 浮动窗口(FloatWindow)
可拖拽、可最小化的浮动窗口。
基础用法
// 创建浮动窗口
const floatWindow = new ckui.FloatWindow({
title: '浮动窗口',
content: '窗口内容',
width: '400px',
height: 'auto',
x: 100, // 初始 X 坐标
y: 100, // 初始 Y 坐标
draggable: true, // 是否可拖拽
minimizable: true, // 是否可最小化
closable: true, // 是否可关闭
shadow: false // 是否使用 Shadow DOM
});
// 显示窗口
floatWindow.show();
// 关闭窗口
floatWindow.close();
// 最小化/恢复
floatWindow.toggleMinimize();
// 更新内容
floatWindow.setContent('新的内容');
高级功能
// 移动到鼠标位置
floatWindow.moveToMouse(0, 0); // 偏移量 (offsetX, offsetY)
// 关闭回调
floatWindow.onClose(() => {
console.log('窗口已关闭');
});
// 一次性关闭回调
floatWindow.onClose(() => {
console.log('只执行一次');
}, true);
// 移除关闭回调
floatWindow.offClose(callback);
// 刷新窗口配置
floatWindow.refresh({
title: '新标题',
content: '新内容'
});
// 使用 DOM 元素作为内容
const content = document.createElement('div');
content.innerHTML = '<button>点击我</button>';
const floatWindow = new ckui.FloatWindow({
title: '自定义内容',
content: content
});
floatWindow.show();
实际应用示例
// 来自 ckylin-script-video-barpic-maker.user.js
// 创建工具栏浮动窗口
createToolbar() {
const container = document.createElement('div');
container.style.cssText = 'display: flex; flex-direction: column; gap: 10px;';
// 添加按钮等控件
// ...
const floatWindow = new Utils.ui.FloatWindow({
title: 'Video Barpic Maker',
content: container,
width: '300px',
x: 100,
y: 100,
draggable: true,
minimizable: true
});
return floatWindow.show();
}
4. 标签页容器(Tabs)
现代化的标签页组件,支持多种样式风格、响应式变量控制和表单集成。
4.1 基础用法
// 创建基础标签页
const tabs = ckui.tabs({
tabs: [
{ label: '首页', content: '首页内容' },
{ label: '产品', content: '产品列表' },
{ label: '关于', content: '关于我们' }
],
style: 'default', // 'default' | 'pills' | 'bordered' | 'minimal'
width: '100%',
height: 'auto'
});
// 渲染到页面
document.body.appendChild(tabs.render());
4.2 样式风格
// 默认样式 - 底部下划线高亮
const tabs1 = ckui.tabs({
tabs: [...],
style: 'default'
});
// Pills样式 - 圆角药丸
const tabs2 = ckui.tabs({
tabs: [...],
style: 'pills'
});
// Bordered样式 - 带边框
const tabs3 = ckui.tabs({
tabs: [...],
style: 'bordered'
});
// Minimal样式 - 极简风格
const tabs4 = ckui.tabs({
tabs: [...],
style: 'minimal'
});
4.3 响应式变量控制
// 创建响应式变量
const activeTab = ckui.reactive(0);
const tabs = ckui.tabs({
tabs: [
{ label: 'Tab 1', content: '内容1' },
{ label: 'Tab 2', content: '内容2' },
{ label: 'Tab 3', content: '内容3' }
],
reactive: activeTab, // 绑定响应式变量
onChange: (index, tab) => {
console.log('切换到:', index, tab.label);
}
});
// 从外部控制切换
activeTab.value = 1; // 切换到第二个标签页
activeTab.value = 2; // 切换到第三个标签页
4.4 动态内容
// 使用DOM元素作为内容
const tabs = ckui.tabs({
tabs: [
{
label: '表单',
content: (() => {
const div = document.createElement('div');
const input = ckui.input({ placeholder: '输入内容...' });
const button = ckui.button({ label: '提交', primary: true });
div.appendChild(input);
div.appendChild(button);
return div;
})()
},
{
label: '列表',
content: document.createElement('ul') // 任意DOM元素
}
]
});
// 使用函数返回内容
const tabs2 = ckui.tabs({
tabs: [
{
label: '动态',
content: () => {
return `<p>生成的内容:${new Date().toLocaleString()}</p>`;
}
}
]
});
// 使用HTML字符串
const tabs3 = ckui.tabs({
tabs: [
{
label: 'HTML',
content: '<div><h3>标题</h3><p>段落内容</p></div>',
allowHtml: true
}
]
});
4.5 在表单中使用
// 作为表单字段使用
const result = await ckui.form({
title: '用户设置',
fields: [
{
type: 'input',
name: 'username',
label: '用户名',
value: 'Admin'
},
{
type: 'tabs',
name: 'settingType',
label: '设置类型',
tabs: [
{ label: '基础设置', content: '基础配置选项' },
{ label: '高级设置', content: '高级配置选项' },
{ label: '隐私设置', content: '隐私相关配置' }
],
style: 'pills',
activeIndex: 0
}
]
}).show();
if (result) {
console.log('用户名:', result.username);
console.log('选择的标签页索引:', result.settingType);
}
4.6 API方法
const tabs = ckui.tabs({ tabs: [...] });
// 切换标签页
tabs.switchTab(1); // 切换到索引为1的标签页
// 获取当前激活的标签页索引
const index = tabs.getActiveIndex();
// 获取当前激活的标签页对象
const tab = tabs.getActiveTab();
// 动态添加标签页
tabs.addTab({
label: '新标签',
content: '新内容'
});
// 删除标签页
tabs.removeTab(2); // 删除索引为2的标签页
// 更新标签页
tabs.updateTab(1, {
label: '更新后的标签',
content: '更新后的内容'
});
// 销毁组件
tabs.destroy();
4.7 配置选项
const tabs = ckui.tabs({
tabs: [], // 标签页数组
activeIndex: 0, // 初始激活的标签页索引
style: 'default', // 样式风格
width: '100%', // 容器宽度
height: 'auto', // 容器高度
noPadding: false, // 是否移除内容区域的padding
reactive: null, // 响应式变量
onChange: null // 切换回调 (index, tab) => {}
});
// 标签页对象结构
const tab = {
label: '标签标题', // 标签文本
content: '内容', // 内容(字符串、DOM元素或函数)
allowHtml: false // 是否允许HTML(仅字符串内容)
};
4.8 嵌套使用
// 创建嵌套的标签页
const nestedTabs = ckui.tabs({
tabs: [
{ label: '子标签 1', content: '嵌套内容 1' },
{ label: '子标签 2', content: '嵌套内容 2' }
],
style: 'pills'
});
const mainTabs = ckui.tabs({
tabs: [
{ label: '主标签 1', content: '普通内容' },
{
label: '主标签 2 (嵌套)',
content: nestedTabs.render() // 嵌套其他标签页
},
{ label: '主标签 3', content: '更多内容' }
],
style: 'bordered'
});
实际应用示例
// 多功能设置面板
function createSettingsPanel() {
const activeTab = ckui.reactive(0);
const tabs = ckui.tabs({
tabs: [
{
label: '常规',
content: (() => {
const form = ckui.form()
.input({ label: '用户名', name: 'username' })
.input({ label: '邮箱', name: 'email' });
return form.render();
})()
},
{
label: '外观',
content: (() => {
const form = ckui.form()
.select({
label: '主题',
name: 'theme',
options: [
{ label: '亮色', value: 'light' },
{ label: '暗色', value: 'dark' }
]
});
return form.render();
})()
},
{
label: '高级',
content: '<div style="padding: 20px;"><p>高级设置选项...</p></div>',
allowHtml: true
}
],
style: 'pills',
reactive: activeTab,
onChange: (index, tab) => {
console.log(`切换到: ${tab.label}`);
}
});
return tabs.render();
}
5. 表单构建器(FormBuilder)
用于快速构建表单,支持多种输入类型和数据验证。
4.1 基础表单元素
// 创建表单构建器
const form = ckui.form();
// 文本输入
form.input({
label: '用户名',
name: 'username',
value: '',
placeholder: '请输入用户名',
validator: (value) => {
if (!value) return '用户名不能为空';
if (value.length < 3) return '用户名至少3个字符';
return true;
},
onChange: (value, allValues) => {
console.log('输入值:', value);
}
});
// 多行文本
form.textarea({
label: '备注',
name: 'notes',
value: '',
placeholder: '请输入备注',
validator: (value) => {
if (value.length > 500) return '备注不能超过500字符';
return true;
}
});
// 下拉选择
form.select({
label: '分类',
name: 'category',
value: 'tech',
options: [
{ label: '技术', value: 'tech' },
{ label: '生活', value: 'life' },
{ label: '娱乐', value: 'entertainment' }
],
onChange: (value) => {
console.log('选择了:', value);
}
});
// 复选框
form.checkbox({
label: '我已阅读并同意条款',
name: 'agree',
value: false,
validator: (checked) => {
if (!checked) return '请先同意条款';
return true;
}
});
// 单选框
form.radio({
label: '性别',
name: 'gender',
value: 'male',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' }
]
});
// 按钮
form.button({
label: '提交',
primary: true,
onClick: (values) => {
console.log('表单值:', values);
}
});
4.2 标签输入(Tags)
// 基础标签输入
form.tags({
label: '标签',
name: 'tags',
value: ['标签1', '标签2'],
placeholder: '输入后按空格或回车添加',
maxTags: 10,
validator: (tag, currentTags) => {
if (tag.length < 2) return '标签至少2个字符';
if (tag.length > 20) return '标签不能超过20个字符';
return true;
},
onChange: (tags) => {
console.log('当前标签:', tags);
}
});
// 可选择的标签输入
form.selectTags({
label: '选择标签',
name: 'selectedTags',
value: [],
options: ['技术', '生活', '娱乐', '学习', '工作'],
allowCustom: true, // 是否允许自定义标签
maxTags: 5,
validator: (tag, currentTags) => {
if (currentTags.includes(tag)) return '标签已存在';
return true;
},
onChange: (tags) => {
console.log('选中的标签:', tags);
}
});
4.3 高级功能
// 隐藏区域(条件显示)
const visible = ckui.reactive(false);
form.hiddenarea({
visible: visible,
fields: [
{ type: 'input', label: '高级选项', name: 'advanced' }
]
});
// 折叠面板
const isOpen = ckui.reactive(false);
form.detail({
title: '高级设置',
open: false,
openState: isOpen,
fields: [
{ type: 'input', label: '选项1', name: 'opt1' },
{ type: 'input', label: '选项2', name: 'opt2' }
]
});
// 或者使用内容
form.detail({
title: '详细信息',
open: true,
content: '<p>这里是详细内容</p>'
});
// 间距
form.space(16); // 垂直间距 16px
form.space({ size: 20, direction: 'horizontal' }); // 水平间距
// 自定义 HTML
form.html('<p style="color: red;">提示信息</p>');
form.html({
content: '<div>HTML 内容</div>',
style: { padding: '10px', background: '#f0f0f0' },
class: 'custom-class'
});
// 自定义元素
const customElement = document.createElement('div');
customElement.textContent = '自定义元素';
form.element(customElement);
form.element(() => {
const el = document.createElement('button');
el.textContent = '动态生成的按钮';
return el;
});
// 多个元素
form.elements([element1, element2, element3]);
4.4 表单操作
// 渲染表单
const formElement = form.render();
document.body.appendChild(formElement);
// 获取表单值
const values = form.getValues();
console.log(values); // { username: 'xxx', notes: 'xxx', ... }
// 设置表单值
form.setValues({
username: '新用户名',
notes: '新备注'
});
// 数据绑定
const username = ckui.reactive('');
form.bindValue('username', username);
// 响应式订阅
form.values.subscribe((values) => {
console.log('表单值变化:', values);
});
4.5 配合模态框使用
// 方式1:直接使用 form API
const result = await ckui.form({
title: '用户信息',
width: '500px',
fields: [
{ type: 'input', label: '姓名', name: 'name' },
{ type: 'input', label: '邮箱', name: 'email' },
{ type: 'textarea', label: '简介', name: 'bio' }
]
});
if (result) {
console.log('提交的数据:', result);
}
// 方式2:手动构建
const form = ckui.form()
.input({ label: '姓名', name: 'name' })
.input({ label: '邮箱', name: 'email' })
.textarea({ label: '简介', name: 'bio' });
const modal = new ckui.Modal({
title: '用户信息',
content: form.render(),
width: '500px',
onOk: () => {
const values = form.getValues();
console.log('提交的数据:', values);
return true;
}
});
await modal.show();
实际应用示例
// 来自 ckylin-script-bilibili-up-notes.user.js
// 编辑UP主备注
static callUIForEditing(_uid, _displayName, _avatarUrl, closeCallback) {
const user = User.LoadOrCreate(_uid);
const form = Utils.ui.form()
.input({
label: 'UP主别名',
name: 'alias',
value: user.alias,
placeholder: '给这个UP主起个别名'
})
.textarea({
label: '备注',
name: 'notes',
value: user.notes,
placeholder: '记录一些信息'
})
.tags({
label: '标签',
name: 'tags',
value: user.getTags(),
maxTags: 10,
placeholder: '输入标签后按空格或回车添加'
});
const modal = new Utils.ui.Modal({
title: `编辑备注 - ${_displayName}`,
content: form.render(),
width: '500px',
icon: _avatarUrl,
iconShape: 'circle',
onOk: () => {
const values = form.getValues();
user.alias = values.alias;
user.notes = values.notes;
user.setTags(values.tags);
user.save();
Utils.ui.success('保存成功');
return true;
}
});
modal.show().then(() => {
if (closeCallback) closeCallback();
});
}
6. 响应式数据(Reactive)
用于创建响应式数据,自动更新 UI。
基础用法
// 创建响应式数据
const count = ckui.reactive(0);
// 读取值
console.log(count.value); // 0
// 修改值
count.value = 10;
// 订阅变化
const unsubscribe = count.subscribe((newValue) => {
console.log('值变化了:', newValue);
});
// 取消订阅
unsubscribe();
与表单绑定
const username = ckui.reactive('');
const password = ckui.reactive('');
const form = ckui.form()
.input({
label: '用户名',
name: 'username',
reactive: username
})
.input({
label: '密码',
name: 'password',
reactive: password,
inputType: 'password'
});
// 监听变化
username.subscribe((value) => {
console.log('用户名:', value);
});
// 手动设置值会自动更新表单
username.value = 'admin';
控制组件显示/隐藏
const showAdvanced = ckui.reactive(false);
const form = ckui.form()
.checkbox({
label: '显示高级选项',
name: 'showAdv',
value: false,
onChange: (checked) => {
showAdvanced.value = checked;
}
})
.hiddenarea({
visible: showAdvanced,
fields: [
{ type: 'input', label: '高级选项1', name: 'adv1' },
{ type: 'input', label: '高级选项2', name: 'adv2' }
]
});
7. 组件和工具
7.1 基础组件
// 按钮
const button = ckui.button({
label: '点击我',
primary: true, // 主要按钮样式
danger: false, // 危险按钮样式
success: false, // 成功按钮样式
disabled: false,
onClick: () => {
console.log('按钮被点击');
}
});
// 输入框
const input = ckui.input({
type: 'text',
placeholder: '请输入',
value: '',
reactive: someReactive, // 可选:绑定响应式数据
onChange: (value) => {
console.log('输入:', value);
}
});
// 多行文本
const textarea = ckui.textarea({
placeholder: '请输入',
value: '',
reactive: someReactive,
onChange: (value) => {
console.log('输入:', value);
}
});
// 标签
const label = ckui.label('标签文本');
// 加载动画
const loading = ckui.loading();
7.2 布局组件
// 行布局
const row = ckui.row(
ckui.col('内容1'),
ckui.col('内容2'),
ckui.col('内容3')
);
// 带配置的行
const row = ckui.row(
{ style: { padding: '10px' } },
ckui.col('内容1'),
ckui.col('内容2')
);
// 间距
const space = ckui.space(); // 默认垂直间距
const space = ckui.space(20, 'horizontal'); // 水平间距20px
const space = ckui.space(16, 'vertical'); // 垂直间距16px
// 分割线
const divider = ckui.divider();
// 卡片
const card = ckui.card({
title: '卡片标题',
content: '卡片内容',
style: { padding: '20px' }
});
// 折叠面板
const detail = ckui.detail({
title: '展开查看更多',
open: false,
content: '折叠的内容'
});
// 隐藏区域
const visible = ckui.reactive(false);
const hiddenArea = ckui.hiddenarea({
visible: visible,
content: '条件显示的内容'
});
7.3 工具函数
// 创建元素(类似 React.createElement)
const element = ckui.createElement('div', {
class: 'my-class',
style: { color: 'red', padding: '10px' },
onclick: () => console.log('clicked'),
dataset: { id: '123' }
}, ['子元素', otherElement]);
// 简写形式
const element = ckui.h('div', { class: 'my-class' }, ['内容']);
// 从 HTML 字符串创建
const element = ckui.html('<div class="container"><p>内容</p></div>');
// 注入样式
ckui.utils.injectStyles(`
.my-class {
color: red;
padding: 10px;
}
`, 'my-style-id');
// 转义 HTML
const safeHtml = ckui.utils.escapeHtml('<script>alert("xss")</script>');
// 生成唯一 ID
const id = ckui.utils.uuid(); // 'ckui-xxxxx-xxxxx'
8. 实例管理
CKUI 提供实例管理功能,可以通过 ID 获取和重用组件实例。
// 创建带 ID 的模态框
const modal = new ckui.Modal({
id: 'my-modal',
title: '模态框',
content: '内容'
});
modal.show();
// 获取已创建的实例
const existingModal = ckui.getModal('my-modal');
if (existingModal) {
existingModal.refresh({ title: '新标题' });
existingModal.show();
}
// 创建带 ID 的浮动窗口
const floatWindow = new ckui.FloatWindow({
id: 'my-window',
title: '窗口',
content: '内容'
});
floatWindow.show();
// 获取实例
const existingWindow = ckui.getFloatWindow('my-window');
// 创建带 ID 的表单
const form = ckui.form({ id: 'my-form' });
const existingForm = ckui.getForm('my-form');
// 通用获取方法
const instance = ckui.getInstance('modals', 'my-modal');
const instance = ckui.getInstance('floatWindows', 'my-window');
const instance = ckui.getInstance('forms', 'my-form');
9. 主题配置
切换主题
// 切换到暗色主题
ckui.setTheme('dark');
// 切换到亮色主题
ckui.setTheme('light');
自定义 CSS 变量
// 设置全局 CSS 变量
ckui.setCSSVars({
'primary': '#007bff',
'danger': '#dc3545',
'success': '#28a745',
'radius': '8px',
'spacing': '16px'
});
// 或者完整变量名
ckui.setCSSVars({
'--ckui-primary': '#007bff',
'--ckui-radius': '8px'
});
// 在特定元素上设置
const element = document.querySelector('.my-element');
ckui.setCSSVars({
'primary': '#ff0000'
}, element);
可配置的 CSS 变量
--ckui-primary: 主色
--ckui-primary-hover: 主色悬停
--ckui-secondary: 次要色
--ckui-secondary-hover: 次要色悬停
--ckui-border: 边框颜色
--ckui-border-dark: 深色边框
--ckui-text: 文本颜色
--ckui-text-secondary: 次要文本
--ckui-text-muted: 弱化文本
--ckui-bg: 背景色
--ckui-bg-secondary: 次要背景
--ckui-success: 成功色
--ckui-danger: 危险色
--ckui-warning: 警告色
--ckui-info: 信息色
--ckui-radius: 圆角半径
--ckui-shadow: 阴影
--ckui-spacing: 间距
10. Shadow DOM 支持
CKUI 支持使用 Shadow DOM 隔离组件样式,避免与页面样式冲突。
// 在通知中使用 Shadow DOM
ckui.notification.show({
title: '提示',
message: '消息',
shadow: true
});
// 在模态框中使用
const modal = new ckui.Modal({
title: '标题',
content: '内容',
shadow: true
});
// 在浮动窗口中使用
const floatWindow = new ckui.FloatWindow({
title: '窗口',
content: '内容',
shadow: true
});
11. Z-Index 管理
// 获取当前 z-index 基础值
const baseZIndex = ckui.getZIndexBase(); // 默认 999990
// 设置新的基础值
ckui.setZIndexBase(1000000);
12. 鼠标追踪
启用全局鼠标位置追踪,用于浮动窗口移动到鼠标位置。
// 启用鼠标追踪
ckui.trackMouseEvent();
// 之后可以使用
floatWindow.moveToMouse(0, -50); // 在鼠标上方50px显示
完整示例
示例1:用户信息管理
// 创建用户信息编辑表单
async function editUser(userData) {
const form = ckui.form()
.input({
label: '用户名',
name: 'username',
value: userData.username,
validator: (value) => {
if (!value) return '用户名不能为空';
if (value.length < 3) return '用户名至少3个字符';
return true;
}
})
.input({
label: '邮箱',
name: 'email',
value: userData.email,
validator: (value) => {
if (!value) return '邮箱不能为空';
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
return '邮箱格式不正确';
}
return true;
}
})
.select({
label: '角色',
name: 'role',
value: userData.role,
options: [
{ label: '管理员', value: 'admin' },
{ label: '用户', value: 'user' },
{ label: '访客', value: 'guest' }
]
})
.tags({
label: '标签',
name: 'tags',
value: userData.tags || [],
maxTags: 5
})
.textarea({
label: '个人简介',
name: 'bio',
value: userData.bio,
validator: (value) => {
if (value.length > 200) return '简介不能超过200字符';
return true;
}
});
const modal = new ckui.Modal({
title: '编辑用户信息',
content: form.render(),
width: '600px',
icon: userData.avatar,
iconShape: 'circle',
onOk: async () => {
const values = form.getValues();
// 保存数据
try {
await saveUserData(values);
ckui.success('保存成功');
return true;
} catch (error) {
ckui.error('保存失败: ' + error.message);
return false; // 阻止关闭
}
}
});
await modal.show();
}
示例2:设置面板
// 创建设置面板
function openSettings() {
const settings = loadSettings();
// 响应式状态
const showAdvanced = ckui.reactive(false);
const enableFeature = ckui.reactive(settings.enableFeature);
const form = ckui.form()
.select({
label: '主题',
name: 'theme',
value: settings.theme,
options: [
{ label: '浅色', value: 'light' },
{ label: '深色', value: 'dark' },
{ label: '自动', value: 'auto' }
],
onChange: (value) => {
if (value !== 'auto') {
ckui.setTheme(value);
}
}
})
.checkbox({
label: '启用高级功能',
name: 'enableFeature',
value: settings.enableFeature,
onChange: (checked) => {
enableFeature.value = checked;
showAdvanced.value = checked;
}
})
.hiddenarea({
visible: showAdvanced,
fields: [
{
type: 'input',
label: 'API 地址',
name: 'apiUrl',
value: settings.apiUrl
},
{
type: 'input',
label: '超时时间(秒)',
name: 'timeout',
value: settings.timeout,
inputType: 'number'
}
]
})
.space(20)
.detail({
title: '关于',
open: false,
content: `
<div style="padding: 10px;">
<p>版本: 1.0.0</p>
<p>作者: Your Name</p>
</div>
`
});
const modal = new ckui.Modal({
title: '设置',
content: form.render(),
width: '500px',
onOk: () => {
const values = form.getValues();
saveSettings(values);
ckui.success('设置已保存');
return true;
}
});
modal.show();
}
示例3:工具栏浮动窗口
// 创建工具栏
function createToolbar() {
const container = document.createElement('div');
container.style.cssText = `
display: flex;
flex-direction: column;
gap: 10px;
min-width: 200px;
`;
// 添加按钮
const btn1 = ckui.button({
label: '📸 截图',
onClick: () => {
ckui.info('开始截图');
// 执行截图逻辑
}
});
const btn2 = ckui.button({
label: '⚙️ 设置',
onClick: () => {
openSettings();
}
});
const btn3 = ckui.button({
label: '❌ 关闭',
danger: true,
onClick: () => {
floatWindow.close();
}
});
container.appendChild(btn1);
container.appendChild(ckui.divider());
container.appendChild(btn2);
container.appendChild(ckui.space(10));
container.appendChild(btn3);
const floatWindow = new ckui.FloatWindow({
id: 'toolbar',
title: '工具栏',
content: container,
width: '220px',
x: 100,
y: 100,
draggable: true,
minimizable: true
});
// 启用鼠标追踪并移动到鼠标位置
ckui.trackMouseEvent();
floatWindow.show().moveToMouse(0, -100);
return floatWindow;
}
// 使用
const toolbar = createToolbar();
示例4:数据导入导出
// 导出数据
async function exportData() {
const data = getAllData();
const json = JSON.stringify(data, null, 2);
const modal = new ckui.Modal({
title: '导出数据',
content: ckui.textarea({
value: json,
style: { width: '100%', height: '400px', fontFamily: 'monospace' }
}),
width: '600px',
footer: ckui.createElement('div', {
style: { display: 'flex', justifyContent: 'flex-end', gap: '10px' }
}, [
ckui.button({
label: '复制',
onClick: async () => {
await navigator.clipboard.writeText(json);
ckui.success('已复制到剪贴板');
}
}),
ckui.button({
label: '下载',
primary: true,
onClick: () => {
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `data-${Date.now()}.json`;
a.click();
URL.revokeObjectURL(url);
ckui.success('下载成功');
}
})
])
});
await modal.show();
}
// 导入数据
async function importData() {
const input = await ckui.prompt({
title: '导入数据',
placeholder: '粘贴 JSON 数据'
});
if (input) {
try {
const data = JSON.parse(input);
// 验证数据
if (!validateData(data)) {
ckui.error('数据格式不正确');
return;
}
// 确认导入
const confirmed = await ckui.confirm(
`将导入 ${data.length} 条记录,是否继续?`,
'确认导入'
);
if (confirmed) {
importAllData(data);
ckui.success('导入成功');
}
} catch (error) {
ckui.error('解析失败: ' + error.message);
}
}
}
注意事项
- 样式隔离: 所有 CKUI 组件都使用
.ckui-root类包裹,样式独立不会污染页面 - Shadow DOM: 对于样式冲突严重的页面,建议使用
shadow: true选项 - z-index: 默认基础 z-index 为 999990,可通过
setZIndexBase()修改 - 响应式数据: 使用
reactive()创建的数据会自动触发 UI 更新 - 实例复用: 通过设置
id选项可以复用组件实例,避免重复创建 - 异步操作: 所有对话框方法(
alert,confirm,prompt等)都返回 Promise - 表单验证: 表单验证在输入和失焦时自动触发,返回
true表示通过,返回字符串表示错误信息 - 主题切换: 主题切换会影响已存在的所有 CKUI 组件
调试技巧
// 查看 CKUI 版本
console.log('CKUI Version:', ckui.version);
// 查看所有实例
// (实例存储在内部,可通过 ID 获取)
// 检查是否正确加载
if (typeof ckui !== 'undefined' && ckui.__initialized) {
console.log('CKUI 已正确加载');
} else {
console.error('CKUI 未加载');
}
常见问题
Q: 模态框被页面元素遮挡?
A: 使用 ckui.setZIndexBase(更大的值) 或在模态框中使用 shadow: true
Q: 样式与页面冲突?
A: 所有组件都支持 shadow: true 选项,使用 Shadow DOM 完全隔离样式
Q: 如何获取表单的实时值?
A: 使用 form.values.subscribe() 订阅表单值的变化
Q: 浮动窗口如何记住位置?
A: 在关闭时保存窗口的 x, y 坐标,下次创建时传入
Q: 如何自定义样式?
A: 使用 ckui.setCSSVars() 修改 CSS 变量,或通过 style 属性传入自定义样式
更新日志
v2.5.0
- ✨ 新增 Tabs(标签页容器)组件
- 🎨 支持 4 种样式风格:default、pills、bordered、minimal
- 🔄 支持响应式变量控制标签页切换
- 📦 完整的表单集成支持
- 🔧 支持动态添加/删除/更新标签页
- 🎯 支持横向滚动和嵌套使用
- 🐛 修复所有按钮的 type 属性,防止意外触发表单提交
- 📝 完善文档和示例
v2.4.5
- 完善的主题支持(亮色/暗色)
- 新增 Shadow DOM 支持
- 优化表单构建器
- 新增标签输入组件
- 新增折叠面板和隐藏区域
- 优化响应式数据绑定
- 新增浮动窗口鼠标定位功能
- 完善实例管理系统
本文档基于 CKUI v2.5.0 版本编写,包含了所有核心功能和最佳实践。