Electron TouchBarSpacer 指南:用 `size` 参数精准控制 macOS 触控栏间距布局
TouchBarSpacer 是 Electron 面向 macOS 原生 Touch Bar(触控栏)提供的布局辅助类,用于在 TouchBar 的各个条目(如按钮、标签、滑块)之间插入一段视觉间隔。本文围绕它在当前仓库中的完整 API 定义展开,结合 JS 层实现与原生 Objective-C++ 映射源码,说明 small、large、flexible 三种取值各自的含义与底层行为,并给出可直接运行的组合示例,帮助你构建间距整洁、分组清晰的触控栏界面。
TouchBarSpacer 是什么
TouchBarSpacer 用于在原生 macOS 应用(即 macOS 上运行的 Electron 应用)的 Touch Bar 中,在两个条目之间创建一个间隔区域。它对应官方文档的类描述:
Create a spacer between two items in the touch bar for native macOS applications
其本质是对 AppKit 中 NSTouchBar 固定/弹性间隔标识符的一层封装:Electron 通过它将你传入的 size 字符串翻译为原生的 NSTouchBarItemIdentifierFixedSpaceSmall、NSTouchBarItemIdentifierFixedSpaceLarge 或 NSTouchBarItemIdentifierFlexibleSpace。
使用限制如下:
- 仅在主进程(Main Process)可用:参考 术语表 Main Process 说明;
- 不能从
'electron'模块顶层直接导入:官方文档明确指出 This class is not exported from the'electron'module. It is only available as a return value of other methods in the Electron API。实践中通过TouchBar类的静态属性取用(见下文); - Touch Bar 相关 API 整体仍处于实验阶段(Electron 官方在 docs/api/touch-bar.md 中标注 "experimental and may change or be removed in future Electron releases");
- 仅适用于配备 Touch Bar 的 macOS 设备;无 Touch Bar 时该界面不显示。
构造语法与参数说明
new TouchBarSpacer(options)
optionsObjectsizestring (optional) — 间隔大小,取值范围如下:
size 取值 |
视觉效果 | 对应的原生标识符 | 说明 |
|---|---|---|---|
small |
固定小间隔 | NSTouchBarItemIdentifierFixedSpaceSmall |
默认值,不传 size 时采用此值 |
large |
固定大间隔 | NSTouchBarItemIdentifierFixedSpaceLarge |
视觉上明显大于 small |
flexible |
弹性间隔 | NSTouchBarItemIdentifierFlexibleSpace |
占据两个相邻条目之间的全部剩余可用空间 |
在 TypeScript 层实现 lib/browser/api/touch-bar.ts 中,TouchBarSpacer 的定义为:
class TouchBarSpacer
extends TouchBarItem<Electron.TouchBarSpacerConstructorOptions>
implements Electron.TouchBarSpacer
{
@ImmutableProperty(() => 'spacer')
type!: string;
@ImmutableProperty<TouchBarSpacer>((config) => config.size)
size!: Electron.TouchBarSpacer['size'];
onInteraction = null;
}
从这段源码可以确认两个关键实现事实:
size是只读不可变属性:它使用@ImmutableProperty装饰器在构造时从config.size一次性固化,对应的属性访问器没有set方法,运行期赋值会抛出Cannot override property错误。也就是说,你需要在构造时决定间距类型,无法像TouchBarLabel.label那样运行时动态修改。- 间隔没有交互行为:
onInteraction恒为null,与按钮、滑块等可交互条目的区分点就在这里。
实例属性 touchBarSpacer.size
每个 TouchBarSpacer 实例暴露一个只读字符串属性 size,取值为 small、large 或 flexible,即构造时传入并在实例上固化的值。
如何获取 TouchBarSpacer 类
由于 TouchBarSpacer 不从 'electron' 模块顶层导出,需要借助 TouchBar 类的静态属性获取。Electron 在主文档 docs/api/touch-bar.md 中为每种条目都声明了同名静态引用:
const { TouchBar } = require('electron')
// 从 TouchBar 的静态属性解构出各个条目类
const { TouchBarButton, TouchBarLabel, TouchBarSpacer } = TouchBar
const spacer = new TouchBarSpacer({ size: 'large' })
这正对应源码中 TouchBar 类末尾的静态挂载:static TouchBarSpacer = TouchBarSpacer;(见 lib/browser/api/touch-bar.ts)。使用 ES Module 语法时同理:const { TouchBarSpacer } = TouchBar; 或直接 new TouchBar.TouchBarSpacer(...)。
size 三种取值与原生层映射原理
了解每种取值的真实行为,最直接的方式是追踪 Electron 原生侧的映射逻辑。负责把 JS 配置转成 NSTouchBar 条目的代码位于 shell/browser/ui/cocoa/electron_touch_bar.mm:
if (type == "spacer") {
std::string size;
item.Get("size", &size);
if (size == "large") {
identifier = NSTouchBarItemIdentifierFixedSpaceLarge;
} else if (size == "flexible") {
identifier = NSTouchBarItemIdentifierFlexibleSpace;
} else {
identifier = NSTouchBarItemIdentifierFixedSpaceSmall;
}
}
small(默认值)
对应 NSTouchBarItemIdentifierFixedSpaceSmall。在原生的 defaultItemIdentifiers 数组中,它是一个宽度固定的「小空隙」标识符,适合给紧密相邻的同组控件留出轻微呼吸感。由于映射逻辑把「非 large、非 flexible」的一切情况都归入 small,因此构造时省略 size、传 undefined、甚至传入无法识别的字符串,最终都会安全退化为 small。
large
对应 NSTouchBarItemIdentifierFixedSpaceLarge,是固定宽度的大空隙。适合用于把语义不同的条目分组:例如把「操作类按钮」和「状态类标签」在视觉上拉开,避免误读为同一组。老虎机示例中即用它把 Spin 按钮与结果标签隔开。
flexible
对应 NSTouchBarItemIdentifierFlexibleSpace。AppKit 会把所有 flexible 标识符在栏内剩余的可用空间中按比例分配,实现经典的两端对齐或居中布局:
- 间隔前放一个
flexible间隔、间隔后紧接一组按钮,就能把按钮「推」到 Touch Bar 右侧; - 在左右各放一个
flexible、中间放一个标签,则标签在栏内水平居中。
需要特别留意:flexible 的真正生效依赖整条栏的剩余空间。若整条 Touch Bar 的条目总宽度恰好占满,弹性间隔的可视宽度会趋近于零,此时它与 small/large 的视觉差异并不明显。
完整可运行示例:在老虎机布局中插入间隔
官方在 docs/api/touch-bar.md 给出的「老虎机 Touch Bar 小游戏」示范了 spacer 的真实用途——把按钮、三个滚轮标签与结果标签组织成层次分明的布局。其布局核心部分如下:
const { app, BrowserWindow, TouchBar } = require('electron')
const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar
// 三个滚轮标签与结果标签
const reel1 = new TouchBarLabel({ label: '' })
const reel2 = new TouchBarLabel({ label: '' })
const reel3 = new TouchBarLabel({ label: '' })
const result = new TouchBarLabel({ label: '' })
// Spin 按钮(此处省略 click 回调中的抽奖逻辑)
const spin = new TouchBarButton({
label: '🎰 Spin',
backgroundColor: '#7851A9',
click: () => { /* ... */ }
})
// 用 large / small spacer 对条目分组
const touchBar = new TouchBar({
items: [
spin,
new TouchBarSpacer({ size: 'large' }), // 按钮组与滚轮组之间的大间隔
reel1,
new TouchBarSpacer({ size: 'small' }), // 滚轮之间的紧凑间隔
reel2,
new TouchBarSpacer({ size: 'small' }),
reel3,
new TouchBarSpacer({ size: 'large' }), // 滚轮组与结果标签之间的大间隔
result
]
})
let window
app.whenReady().then(() => {
window = new BrowserWindow({
frame: false,
titleBarStyle: 'hiddenInset',
width: 200,
height: 200,
backgroundColor: '#000'
})
window.loadURL('about:blank')
window.setTouchBar(touchBar) // 通过 BrowserWindow.setTouchBar 挂载到窗口
})
运行步骤:
- 将上述代码保存为
touchbar.js; - 安装 Electron:
npm install electron; - 运行:
./node_modules/.bin/electron touchbar.js; - 在支持 Touch Bar 的 macOS 设备(或 Touch Bar 模拟器)上即可看到效果。
布局心得与示例结构一一对应:spin 与第一组之间用 large 建立明显分区;三个滚轮标签之间用 small 保持「同组」的紧凑感;末尾再次用 large 把状态结果区隔开。这正是 spacer 最常见的三种用途:分组隔离、同组微距、区块留白。
代码级佐证:仓库测试中的组合用法
仓库测试 spec/api-touch-bar-spec.ts 也把 spacer 纳入真实布局做端到端验证——它构造了一个包含按钮、取色器、分组、标签、TouchBarOtherItemsProxy、弹出层、滑块、TouchBarSpacer({ size: 'large' })、分段控件、滚动选择器等多达十余个条目的 TouchBar,随后调用 window.setTouchBar(touchBar) 并验证换绑、escapeItem 动态更新等行为。这说明 TouchBarSpacer 可与任意其他 Touch Bar 条目类自由混排,并且会在 TouchBar 挂载时一并被消费:
const touchBar = new TouchBar({
items: [
/* 其他条目…… */
new TouchBarSpacer({ size: 'large' }),
new TouchBarSegmentedControl({ /* ... */ })
]
});
window.setTouchBar(touchBar);
在 lib/browser/api/touch-bar.ts 的 TouchBar 实现中,实例挂载最终通过 window._setTouchBarItems(this.orderedItems)(对应方法见 lib/browser/api/touch-bar.ts)把有序条目列表交给原生层,原生侧再按上文 electron_touch_bar.mm 的 identifiersFromSettings: 逐条翻译成 NSTouchBarItemIdentifier 序列。spacer 的「顺序敏感」因此被严格保留:间隔只作用于左右相邻条目之间,同样的 spacer 放在不同位置会呈现不同布局,这也解释了为什么 items 是一个强调顺序的数组。
注意事项与最佳实践小结
- 构造期决定大小:
size为不可变属性(源码使用@ImmutableProperty),需要动态调整间距时应重建TouchBarSpacer实例并重新setTouchBar; small是兜底默认值:从原生映射逻辑看,任何无法识别为large/flexible的值都会落到small,但请勿依赖这一容错特性,显式传值可读性更高;flexible依赖剩余空间:需要把控件推到 Touch Bar 边缘或居中时使用;若条目总宽几乎占满整栏,弹性间隔可能不可见;- Mac 限定与实验状态:本 API 面向原生 macOS 应用,且 Electron 官方将其标记为实验性,接口在未来版本中可能调整或移除;
- 更复杂的分组布局:除了扁平使用 spacer,还可以结合 TouchBarGroup(把多个条目打包成逻辑组)获得更强的结构化布局能力;间隔类与 TouchBarButton、TouchBarLabel、TouchBarSegmentedControl 等条目均可自由混排。
如需深入了解整体布局与其余条目,可继续阅读主文档 TouchBar(含完整老虎机示例),或查看相邻条目文档 TouchBarGroup、TouchBarOtherItemsProxy。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00