A modern, dependency-free UI library for Tampermonkey scripts
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/564901/1749919/CKUI.js
CKUI 是一个专为 Tampermonkey/Greasemonkey 用户脚本设计的现代化 UI 库,提供开箱即用的 UI 组件,无需任何外部依赖。
核心特性:
在你的用户脚本头部添加 @require 语句(页面顶部提供语句模板)
注意: CKUI 会在页面加载时自动初始化,你可以直接通过 ckui 或 unsafeWindow.ckui 访问所有功能。
显示各种类型的通知消息,自动定时关闭。
// 成功通知
ckui.success('操作成功!', '成功');
// 错误通知
ckui.error('发生错误!', '错误');
// 警告通知
ckui.warning('请注意!', '警告');
// 信息通知
ckui.info('提示信息', '提示');
ckui.notify({
title: '自定义标题',
message: '这是自定义消息内容',
type: 'success', // 'success' | 'error' | 'warning' | 'info'
duration: 5000, // 显示时长(毫秒)
shadow: false // 是否使用 Shadow DOM
});
创建各种类型的对话框,支持自定义内容和按钮。
// 简单提示
await ckui.alert('这是一个提示!');
// 带标题的提示
await ckui.alert('操作成功', '成功');
// 基本确认
try {
await ckui.confirm('确定要删除吗?', '确认');
console.log('用户点击了确定');
} catch (e) {
console.log('用户点击了取消');
}
// 自定义确认框
ckui.confirm({
title: '确认操作',
content: '你确定要执行此操作吗?此操作不可撤销。',
okText: '确定',
cancelText: '取消'
}).then(() => {
ckui.success('操作完成');
}).catch(() => {
ckui.info('操作已取消');
});
// 获取用户输入
const name = await ckui.prompt('请输入你的名字', '默认值');
console.log('用户输入:', name);
const modal = ckui.modal({
title: '自定义对话框',
content: '这里可以是任意内容,包括 HTML 元素',
width: '600px',
okText: '确定',
cancelText: '取消',
allowHtml: true, // 允许 HTML 内容
shadow: false, // 是否使用 Shadow DOM
onOk: () => {
console.log('点击了确定');
return true; // 返回 true 关闭模态框
},
onCancel: () => {
console.log('点击了取消');
}
});
modal.show(); // 显示
modal.close(); // 关闭
// 使用 Emoji 图标
ckui.alert('操作成功!', '成功', null, {
icon: '✅',
iconShape: 'circle', // 'circle' | 'square'
iconWidth: '28px'
});
// 使用图片 URL
ckui.modal({
title: '用户信息',
content: '个人资料已更新',
icon: 'https://example.com/avatar.png',
iconShape: 'circle',
iconWidth: '48px'
}).show();
创建可拖动、可调整大小的浮动窗口。
const win = ckui.floatWindow({
title: '浮动窗口',
content: '可拖动的窗口内容',
x: 100, // X 坐标
y: 100, // Y 坐标
width: '400px', // 宽度
draggable: true, // 可拖动
shadow: false // 是否使用 Shadow DOM
});
win.show(); // 显示窗口
win.close(); // 关闭窗口
win.toggle(); // 切换显示/隐藏
// 创建自定义内容
const content = ckui.createElement('div', {}, [
ckui.createElement('p', {}, ['这是一个复杂的窗口']),
ckui.button({
label: '点击我',
primary: true,
onClick: () => alert('按钮被点击了!')
})
]);
const win = ckui.floatWindow({
title: '工具面板',
content: content,
x: 200,
y: 200,
width: '500px'
});
win.show();
const win = ckui.floatWindow({
title: '我的窗口',
content: '内容'
});
// 添加关闭事件监听
win.onClose(() => {
console.log('窗口被关闭了');
ckui.info('窗口已关闭');
}, true); // true 表示一次性回调
win.show();
强大的表单系统,支持多种输入类型、验证和回调。
const form = ckui.form()
// 文本输入
.input({
label: '用户名',
name: 'username',
placeholder: '请输入用户名',
validator: (value, allValues) => {
if (!value) return '用户名不能为空';
if (value.length < 3) return '用户名至少3个字符';
return true; // 验证通过
},
onChange: (value, allValues) => {
console.log('用户名改变:', value);
}
})
// 密码输入
.input({
label: '密码',
name: 'password',
inputType: 'password',
placeholder: '请输入密码'
})
// 多行文本
.textarea({
label: '备注',
name: 'note',
placeholder: '请输入备注',
validator: (value, allValues) => {
if (value && value.length > 200) {
return `备注太长了(${value.length}/200)`;
}
return true;
}
})
// 下拉选择
.select({
label: '城市',
name: 'city',
options: [
{ label: '请选择', value: '' },
{ label: '北京', value: 'beijing' },
{ label: '上海', value: 'shanghai' }
],
validator: (value) => {
if (!value) return '请选择城市';
return true;
}
})
// 标签输入
.tags({
label: '技能标签',
name: 'skills',
placeholder: '输入后按空格添加',
value: ['JavaScript', 'Python'],
maxTags: 5,
validator: (tag, allTags) => {
if (tag.length > 20) return '标签太长了';
return true;
}
})
// 下拉选择标签
.selectTags({
label: '兴趣爱好',
name: 'hobbies',
placeholder: '输入或选择',
value: ['编程'],
options: ['编程', '阅读', '音乐', '运动'],
allowCustom: true, // 允许自定义标签
maxTags: 8
})
// 复选框
.checkbox({
label: '同意用户协议',
name: 'agree',
validator: (checked) => {
if (!checked) return '必须同意用户协议';
return true;
}
})
// 单选框
.radio({
label: '性别',
name: 'gender',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' }
]
})
// 提交按钮
.button({
label: '提交',
primary: true,
onClick: () => {
const values = form.getValues();
console.log('表单值:', values);
ckui.success('提交成功!');
}
});
// 在模态框中显示表单
ckui.modal({
title: '用户注册',
content: form.render(),
width: '500px',
footer: null // 不显示默认底部按钮
}).show();
验证器函数会在字段失去焦点时触发:
validator: (value, allValues) => {
// value: 当前字段的值
// allValues: 表单所有字段的值对象
// 返回 true 表示验证通过
if (isValid(value)) return true;
// 返回字符串表示验证失败,字符串为错误消息
return '验证失败的错误消息';
}
每当字段值改变时触发:
onChange: (value, allValues) => {
console.log('当前值:', value);
console.log('所有表单值:', allValues);
// 可以在这里实现联动逻辑
if (value === 'special') {
// 做一些特殊处理
}
}
创建响应式数据,自动更新绑定的 UI 组件。
// 创建响应式数据
const count = ckui.reactive(0);
// 创建绑定的输入框
const input = ckui.input({
placeholder: '输入文本...',
reactive: count
});
// 订阅数据变化
count.subscribe(value => {
console.log('值变化:', value);
});
// 修改值
count.value = 10; // 自动更新所有绑定的组件
const username = ckui.reactive('');
const email = ckui.reactive('');
const form = ckui.form()
.input({
label: '用户名',
name: 'username',
reactive: username
})
.input({
label: '邮箱',
name: 'email',
reactive: email
});
// 实时获取值
username.subscribe(value => {
console.log('用户名:', value);
});
email.subscribe(value => {
console.log('邮箱:', value);
});
提供灵活的布局方案。
const layout = ckui.row(
ckui.col(
ckui.card({ title: '卡片1', content: '内容1' })
),
ckui.col(
ckui.card({ title: '卡片2', content: '内容2' })
),
ckui.col(
ckui.card({ title: '卡片3', content: '内容3' })
)
);
document.body.appendChild(layout);
// 垂直间距(默认)
const layout = ckui.createElement('div', {}, [
ckui.card({ title: '卡片1', content: '内容1' }),
ckui.space(20), // 20px 间距
ckui.card({ title: '卡片2', content: '内容2' }),
ckui.space(30), // 30px 间距
ckui.card({ title: '卡片3', content: '内容3' })
]);
// 水平间距
const buttons = ckui.createElement('div', {
style: 'display: flex;'
}, [
ckui.button({ label: '按钮1' }),
ckui.space(10, 'horizontal'),
ckui.button({ label: '按钮2', primary: true }),
ckui.space(20, 'horizontal'),
ckui.button({ label: '按钮3', danger: true })
]);
const card = ckui.card({
title: '卡片标题',
content: '卡片内容',
footer: '卡片底部'
});
document.body.appendChild(card);
条件显示和折叠面板。
// 通过响应式变量控制显示/隐藏
const visible = ckui.reactive(true);
const hiddenArea = ckui.hiddenarea({
visible: visible,
content: '这里的内容可以通过 visible 控制显示/隐藏'
});
// 切换显示
visible.value = false; // 隐藏
visible.value = true; // 显示
const openState = ckui.reactive(true);
const detail = ckui.detail({
title: '点击展开/折叠',
openState: openState,
content: '这是可折叠的内容区域'
});
// 程序控制展开/折叠
openState.value = false; // 折叠
openState.value = true; // 展开
内置浅色和深色主题。
// 切换到暗色主题
ckui.setTheme('dark');
// 切换到亮色主题
ckui.setTheme('light');
// 获取当前主题
const currentTheme = ckui.getTheme(); // 'light' 或 'dark'
使用 Shadow DOM 完全隔离样式,避免与页面样式冲突。
ckui.modal({
title: 'Shadow Modal',
content: '这个 Modal 的样式完全隔离',
shadow: true // 启用 Shadow DOM
}).show();
ckui.floatWindow({
title: 'Shadow Window',
content: '样式隔离的窗口',
shadow: true
}).show();
ckui.success('成功消息', '成功', {
shadow: true
});
何时使用 Shadow DOM:
通过 ID 管理和复用组件实例。
// 创建浮动窗口并指定 ID
ckui.floatWindow({
id: 'my-window',
title: '命名窗口',
content: '这个窗口有 ID'
}).show();
// 通过 ID 获取实例
const window = ckui.getFloatWindow('my-window');
if (window) {
window.close(); // 关闭窗口
}
// 如果 ID 已存在,会更新现有实例而不是创建新的
ckui.floatWindow({
id: 'my-window',
title: '更新后的标题',
content: '更新后的内容'
}).show();
创建 DOM 元素的便捷方法。
const div = ckui.createElement('div', {
class: 'my-class',
style: 'color: red;',
id: 'my-id'
}, [
'这是文本内容',
ckui.createElement('span', {}, ['这是子元素'])
]);
// 基本按钮
ckui.button({
label: '点击我',
onClick: () => alert('被点击了!')
});
// 主要按钮
ckui.button({
label: '主要按钮',
primary: true,
onClick: () => {}
});
// 成功按钮
ckui.button({
label: '成功',
success: true
});
// 危险按钮
ckui.button({
label: '删除',
danger: true
});
(function() {
'use strict';
// 创建面板内容
const createPanel = () => {
const count = ckui.reactive(0);
return ckui.createElement('div', {
style: 'padding: 10px;'
}, [
ckui.createElement('h3', {}, ['工具面板']),
ckui.space(10),
ckui.createElement('div', {}, [
ckui.createElement('span', {}, ['计数器: ']),
ckui.createElement('strong', {}, [count.value.toString()])
]),
ckui.space(10),
ckui.createElement('div', {
style: 'display: flex; gap: 10px;'
}, [
ckui.button({
label: '增加',
primary: true,
onClick: () => {
count.value++;
ckui.success(`当前计数: ${count.value}`);
}
}),
ckui.button({
label: '减少',
danger: true,
onClick: () => {
count.value--;
ckui.warning(`当前计数: ${count.value}`);
}
}),
ckui.button({
label: '重置',
onClick: () => {
count.value = 0;
ckui.info('计数已重置');
}
})
])
]);
};
// 创建浮动窗口
const panel = ckui.floatWindow({
id: 'tool-panel',
title: '🛠️ 我的工具',
content: createPanel(),
x: 100,
y: 100,
width: '300px',
shadow: true
});
panel.show();
// 添加快捷键
document.addEventListener('keydown', (e) => {
// Ctrl + Shift + P 切换面板显示
if (e.ctrlKey && e.shiftKey && e.key === 'P') {
panel.toggle();
}
});
console.log('工具面板已加载!按 Ctrl+Shift+P 切换显示');
})();
CKUI 基于 GPL-3.0-only 协议开源。
这意味着:
unsafeWindow.ckui 访问shadow: true 参数ckui.reactive() 创建响应式变量,通过 .value 访问和修改id 参数可以避免重复创建相同窗口