JSON UI Schema 参考
Such 插件声明式 UI 定义完整指南
JSON UI Schema 参考
JSON UI Schema 是 Such 插件声明式 UI 的定义方式。通过 window.source.uiSchema 配置,宿主会自动渲染为 Naive UI 组件,无需手动编写 render 方法。
基本结构
interface PluginUISchema {
title?: string // 页面标题
sections: UISection[] // UI 区块列表
}
interface UISection {
title?: string // 区块标题
description?: string // 区块描述
fields?: UIField[] // 字段列表
actions?: UIAction[] // 操作按钮列表
}一个 Schema 由多个 sections 组成,每个 section 可包含多个字段(fields)和操作按钮(actions)。
UIField 字段类型
input — 文本输入框
{
type: 'input',
key: 'decryptorPath', // 对应插件 props 中的 key
label: '解密器路径', // 显示标签
placeholder: '输入路径...', // 占位符文本
readonly: false, // 是否只读(可选)
action: 'browse' // 关联的 emit 事件名(可选)
}属性:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | 'input' | 是 | 字段类型 |
key | string | 是 | 对应 props 中的 key,值通过 setProps({ key: value }) 更新 |
label | string | 否 | 输入框左侧标签 |
placeholder | string | 否 | 占位符文本 |
readonly | boolean | 否 | 设为 true 时输入框只读 |
action | string | 否 | 关联的 emit 事件名,用户交互时触发 emit(action, value) |
ℹ️ 设置
action: 'browse'时,输入框右侧会显示"浏览"按钮,点击触发emit('browse', currentValue)。
text — 只读文本
{
type: 'text',
key: 'musicDir',
label: '音乐输出目录'
}显示只读文本,值通过 setProps({ musicDir: '...' }) 更新。
log — 多行日志
{
type: 'log',
key: 'outputLog'
}多行日志输出区域,支持自动滚动。值通过 setProps({ outputLog: '日志内容' }) 更新,多次设置会替换整个内容。
tag — 状态标签
{
type: 'tag',
key: 'statusText'
}显示小型状态标签,值通过 setProps({ statusText: '运行中' }) 更新。
UIAction 操作按钮
{
type: 'button',
label: '开始解密', // 按钮文字
method: 'startDecrypt', // 点击时调用的插件方法名
variant: 'primary' // 按钮样式(可选)
}variant 可选值:
| variant | 说明 | 适用场景 |
|---|---|---|
primary | 主色调按钮(绿色) | 主要操作 |
default | 默认样式 | 次要操作 |
warning | 警告色(橙色) | 需谨慎的操作 |
error | 危险色(红色) | 破坏性操作 |
ℹ️ 点击按钮时,宿主会调用
window.source[method]()。如果方法返回 Promise,按钮会自动显示加载状态。
与 setProps 配合
UI Schema 中所有 field 的 key 都对应 props 中的一个属性。通过 this.setProps() 更新即可自动刷新界面:
initialization() {
this.setProps({
decryptorPath: '',
ncmDir: '',
musicDir: suchmusic.getSetting('musicFolder'),
statusText: '就绪',
outputLog: ''
})
}
async startDecrypt() {
this.setProps({ statusText: '解密中...' })
// 执行解密逻辑...
this.setProps({ statusText: '完成', outputLog: '解密成功' })
}完整示例
以下是一个 NCM 解析插件的完整 UI Schema:
window.source = {
id: 'SUCH_NETEASE_NCM_WIDGET',
name: '网易云音乐 NCM 解析器',
version: '1.0.0',
author: 'enzymeym',
isUIWidget: true,
permissions: ['local_program', 'file_system', 'app_info'],
uiSchema: {
sections: [
{
title: '解密器设置',
description: '配置外部解密工具',
fields: [
{
type: 'input',
key: 'decryptorPath',
label: '解密器路径',
placeholder: '例如: D:\\tools\\ncmdump-go.exe',
action: 'browse'
},
{
type: 'input',
key: 'ncmDir',
label: 'NCM 文件目录',
placeholder: '选择包含 .ncm 文件的目录',
readonly: true,
action: 'browseDir'
},
{
type: 'text',
key: 'musicDir',
label: '音乐输出目录'
}
]
},
{
title: '状态',
fields: [
{ type: 'tag', key: 'decryptorStatusText' },
{ type: 'tag', key: 'statusText' }
]
},
{
title: '操作',
actions: [
{
type: 'button',
label: '下载解密器',
method: 'downloadDecryptor',
variant: 'default'
},
{
type: 'button',
label: '检测解密器',
method: 'checkDecryptorStatus'
},
{
type: 'button',
label: '开始解密',
method: 'startDecrypt',
variant: 'primary'
}
]
},
{
title: '输出日志',
fields: [
{ type: 'log', key: 'outputLog' }
]
}
]
},
initialization() {
this.setProps({
decryptorPath: '',
ncmDir: '',
musicDir: suchmusic.getSetting('musicFolder'),
decryptorStatusText: '未检测',
statusText: '就绪',
outputLog: ''
})
},
async startDecrypt() {
this.setProps({ statusText: '解密中...' })
// ... 解密逻辑
this.setProps({ statusText: '完成', outputLog: '解密完成' })
}
}UI 布局说明
- 多个
sections从上到下排列 - 每个 section 内
fields在上、actions在下 actions按钮从左到右排列log字段占据整行宽度,高度自适应