lowcode-engine hotkey 快捷键 API 完全指南:绑定、组合语法与内置快捷键实现原理
【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine
本文基于 hotkey - 快捷键 API 展开,结合 Hotkey 核心实现、类型定义 与 内置快捷键插件 的源码,系统讲解 lowcode-engine 中 hotkey API 的用法、组合键语法、底层事件机制,以及引擎内置快捷键的完整清单。
lowcode-engine 的hotkey是挂在插件上下文(IPublicModelPluginContext)上的快捷键 API,用于为低代码设计器自定义项目级快捷键。本文从bind方法的签名与返回类型讲起,覆盖基础绑定、多组合键绑定、在插件中注册保存 schema 快捷键等官方示例,并深入源码分析键名归一化、修饰键解析、keypress/keydown 事件选择与序列快捷键等底层原理,最后给出引擎内置快捷键的完整实现清单,帮助你快速上手并安全扩展自定义快捷键。
模块简介:hotkey API 是什么
在 lowcode-engine 中,hotkeyAPI 允许开发者为编辑器绑定自定义快捷键。官方文档(docs/docs/api/hotkey.md)给出的定位是:
绑定快捷键 API,可以自定义项目快捷键使用。
从源码角度,hotkey 由两个层次组成:
- 内部实现:
packages/editor-core/src/hotkey.ts中的Hotkey类,负责键盘事件的监听、键名解析与回调分发; - 对外类型:
packages/types/src/shell/api/hotkey.ts中的IPublicApiHotkey接口,定义了对外暴露的bind方法与callbacks属性。
在引擎装配过程中(packages/engine/src/engine-core.ts#L118-L119),引擎会创建内部热键实例并将其包装为对外可用的 shell 层Hotkey:
const innerHotkey = new InnerHotkey(); const hotkey = new Hotkey(innerHotkey);随后通过context.hotkey = hotkey(packages/engine/src/engine-core.ts#L143)注入每个插件的上下文,因此插件内可以直接解构使用const { hotkey } = ctx;。
bind 方法:绑定快捷键
方法签名与参数说明
bind是IPublicApiHotkey暴露的核心方法,签名如下(packages/types/src/shell/api/hotkey.ts#L20-L24):
/** * 绑定快捷键 * bind hotkey/hotkeys, * @param combos 快捷键,格式如:['command + s'] 、['ctrl + shift + s'] 等 * @param callback 回调函数 * @param action */ bind( combos: string[] | string, callback: IPublicTypeHotkeyCallback, action?: string, ): IPublicTypeDisposable;参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
combos | string \| string[] | 快捷键组合,可传入单个字符串(如'command+s')或字符串数组(如['command+s', 'command+c']),数组表示多个组合键共享同一回调 |
callback | IPublicTypeHotkeyCallback | 快捷键触发时的回调函数,接收键盘事件与组合键字符串 |
action | string \| undefined | 可选,指定监听的事件类型,取值通常为'keydown'、'keypress'或'keyup';不传时由引擎自动选择(详见下文"事件类型选择") |
回调与返回类型
回调类型定义于 packages/types/src/shell/type/hotkey-callback.ts:
export type IPublicTypeHotkeyCallback = (e: KeyboardEvent, combo?: string) => any | false;即回调接收两个参数:
e:原生KeyboardEvent,可用于调用e.preventDefault()阻止默认行为;combo:触发本次回调的组合键字符串,方便同一回调在绑定多个组合键时区分来源(内置快捷键插件中大量使用了这个参数,例如通过action.indexOf('x')判断是复制还是剪切)。
返回类型IPublicTypeDisposable(packages/types/src/shell/type/disposable.ts)是一个可执行函数类型:
export interface IPublicTypeDisposable { (): void; }实现层面,bind返回 Hotkey 实例本身(packages/editor-core/src/hotkey.ts#L384-L387),同时内部维护了callbacks注册表,配合unbind方法可以按组合键与回调引用精确解绑(packages/editor-core/src/hotkey.ts#L389-L402)。
使用示例
基础示例
单个组合键绑定,按下command+s时阻止浏览器默认的保存页面行为并执行自定义逻辑:
hotkey.bind('command+s', (e) => { e.preventDefault(); // command+s 快捷键按下时需要执行的逻辑 });同时绑定多个快捷键
传入字符串数组,command+s或command+c任一触发都会执行同一回调:
hotkey.bind(['command+s', 'command+c'], (e) => { e.preventDefault(); // command+s 或者 command+c 快捷键按下时需要执行的逻辑 });保存快捷键配置(插件内使用)
结合插件机制,可以在插件init阶段注册快捷键,将command+s绑定到 schema 保存逻辑上:
import { hotkey, } from '@alilc/lowcode-engine'; function saveSchema(schema) { // 保存 schema 相关操作 } const saveSampleHotKey = (ctx: IPublicModelPluginContext) => { return { name: 'saveSample', async init() { hotkey.bind('command+s', (e) => { e.preventDefault(); saveSchema(); }); }, }; } saveSampleHotKey.pluginName = 'saveSampleHotKey'; plugins.register(saveSampleHotKey);注意:这里
hotkey可以直接从@alilc/lowcode-engine导入,也可以在插件init(ctx)中通过ctx.hotkey获取——引擎装配时已将 hotkey 注入插件上下文(packages/engine/src/engine-core.ts#L143),两者指向同一实例。
快捷键组合语法深入
修饰键与别名
Hotkey 实现中定义了修饰键别名表(packages/editor-core/src/hotkey.ts#L97-L104):
const SPECIAL_ALIASES: CtrlKeyMap = { option: 'alt', command: 'meta', return: 'enter', escape: 'esc', plus: '+', mod: /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl', };这意味着:
command等价于meta(macOS 的 ⌘ 键);option等价于alt;return等价于enter,escape等价于esc;mod是一个跨平台快捷别名:在 macOS 上解析为meta,在 Windows/Linux 上解析为ctrl。需要同时兼容 Mac 与 Windows 用户的快捷键,建议直接写'mod+s',引擎会自动适配平台。
特殊功能键
源码中的键码映射表(packages/editor-core/src/hotkey.ts#L31-L54)支持以下特殊键名:
backspace、tab、enter、shift、ctrl、alt、capslock、esc、space、pageup、pagedown、end、home、left、up、right、down、ins、del、meta。
此外,代码通过循环自动补充了f1至f19功能键(packages/editor-core/src/hotkey.ts#L112-L114)以及数字小键盘的0-9(packages/editor-core/src/hotkey.ts#L119-L121)。因此你可以直接绑定类似'f2'、'alt+f4'这样的组合。
组合键写法
组合键使用+连接,例如文档中的'command + s'、'ctrl + shift + s',也可以省略空格写作'command+s'。解析逻辑位于 packages/editor-core/src/hotkey.ts#L254-L261 的keysFromString,它会按+拆分,并将连续两个+归一化为plus(用于单独绑定+键)。
序列快捷键(组合式连按)
除了单个组合键,Hotkey 还支持"序列快捷键":用空格分隔多个按键,按顺序依次按下才触发。例如'g i'表示先按g再按i。序列实现位于bindSequence(packages/editor-core/src/hotkey.ts#L571-L595),且序列状态会在 1 秒无操作后自动重置(packages/editor-core/src/hotkey.ts#L564-L569)。
底层实现原理
事件监听与激活开关
Hotkey构造时会通过mount(window)在document上同时监听keypress、keydown、keyup三类事件(packages/editor-core/src/hotkey.ts#L371-L382),并在handleKeyEvent入口处检查激活开关(packages/editor-core/src/hotkey.ts#L544-L562):
private handleKeyEvent(e: KeyboardEvent): void { if (!this.isActivate) { return; } // ... }isActivate通过activate(activate: boolean)方法控制(packages/editor-core/src/hotkey.ts#L367-L369),可整体启用/停用快捷键响应。
事件类型选择
pickBestAction(packages/editor-core/src/hotkey.ts#L234-L246)决定默认监听哪种事件:
- 若未显式传入
action,功能键(如esc、f1)默认走keydown,普通字符键默认走keypress; - 一旦组合中包含修饰键(
shift/ctrl/alt/meta),keypress会自动切换为keydown(因为修饰键在 keypress 下行为不一致)。
这也是bind的第三个参数action存在的意义:需要监听keyup(如某些拖拽结束手势)时可显式传入'keyup'。
回调触发与全局事件
fireCallback(packages/editor-core/src/hotkey.ts#L317-L340) 是回调执行的核心函数,它的行为值得注意:
- 通过
globalContext获取当前激活的 workspace 与 editor,进而取得 designer 与当前选中节点,拼出selected标识(格式为package-componentName或组件名); - 若回调返回
false,按 jQuery 惯例自动执行e.preventDefault()与e.stopPropagation(); - 无论回调结果如何,都会向编辑器事件总线发出
'hotkey.callback.call'事件,携带{ callback, e, combo, sequence, selected }参数——这意味着你可以监听该事件实现快捷键调用埋点或日志。
内置快捷键的实现范式
引擎内置的快捷键全部注册在 packages/engine/src/inner-plugins/builtin-hotkey.ts 的builtinHotkey插件中(插件名为___builtin_hotkey___),其统一范式是在init()中解构ctx后调用hotkey.bind。以下是完整的绑定清单:
| 组合键 | 功能 | 实现位置(builtin-hotkey.ts) |
|---|---|---|
backspace/del | 删除当前选中的顶层节点 | L230 |
escape | 清空当前选择 | L254 |
command+c/ctrl+c/command+x/ctrl+x | 复制 / 剪切选中节点到剪贴板 | L271 |
command+v/ctrl+v | 粘贴剪贴板中的节点 schema 到合适插入位置 | L314 |
command+z/ctrl+z | 撤销(history.back) | L351 |
command+y/ctrl+y/command+shift+z | 重做(history.forward) | L369 |
left/right | 选中上一个/下一个兄弟节点 | L386 |
up/down | 按文档树顺序选中上/下相邻节点 | L405 |
option+left/option+right | 将选中节点前移/后移一个兄弟位置 | L430 |
option+up | 将节点上移,遇到容器节点时尝试移入其内部 | L464 |
option+down | 将节点下移,遇到容器节点时尝试移入其内部 | L506 |
所有内置回调开头都有一段防御性检查:通过canvas.isInLiveEditing判断是否处于 live editing(在线编辑)态、通过isFormEvent(e)判断事件是否来自表单输入(避免在输入框中按backspace误删节点),并在确认安全后才执行e.preventDefault()与后续逻辑。
其他可用能力:callbacks 与 unbind
IPublicApiHotkey还暴露了以下能力(标注为@experimental,自 v1.1.0 起):
callbacks(getter):返回当前所有已绑定的快捷键配置(packages/types/src/shell/api/hotkey.ts#L11),结构为IPublicTypeHotkeyCallbacks,即以按键字符为 key、IPublicTypeHotkeyCallbackConfig[]为值的映射(packages/types/src/shell/type/hotkey-callbacks.ts)。每条配置包含callback、modifiers、action,以及序列快捷键的seq/level/combo字段(packages/types/src/shell/type/hotkey-callback-config.ts)。该 getter 目前仅在类型层面声明,属于实验性能力,使用时建议先确认所在版本已实现。unbind(combos, callback, action?):按组合键与回调引用移除绑定,实现会通过isEqual精确比对修饰键数组后从注册表中剔除(packages/editor-core/src/hotkey.ts#L389-L402)。
最佳实践与注意事项
- 优先使用
mod而非硬编码command/ctrl:mod会根据navigator.platform自动映射为 Mac 的meta或其它平台的ctrl(packages/editor-core/src/hotkey.ts#L103),一份绑定即可覆盖全平台。引擎内置的复制粘贴、撤销重做快捷键都同时绑定了command与ctrl两套,也是为了保证跨平台可用。 - 在回调中主动调用
e.preventDefault():低代码设计器页面内,command+s等组合键可能触发浏览器默认行为,绑定后请按官方示例显式阻止默认事件。 - 区分表单输入场景:参考内置快捷键插件的写法,绑定
backspace、方向键等高频键时,应先用isFormEvent(e)判断事件是否来自输入框/富文本编辑区,避免影响正常输入(packages/engine/src/inner-plugins/builtin-hotkey.ts#L238)。 - 利用回调第二参数区分组合来源:当多个组合键共享回调时,
combo参数可以帮你判断当前触发的是哪一个,如内置插件中通过action.indexOf('x') > 0区分复制与剪切(packages/engine/src/inner-plugins/builtin-hotkey.ts#L303)。 - 避免覆盖内置快捷键:引擎已占用删除、复制粘贴、撤销重做、方向键选择、
option+方向键移动等组合(完整清单见上文表格),自定义快捷键时应尽量避开这些组合,以免与设计器既有交互冲突。
相关文件索引
- API 文档:docs/docs/api/hotkey.md
- 对外类型定义:packages/types/src/shell/api/hotkey.ts、hotkey-callback.ts、disposable.ts
- 核心实现:packages/editor-core/src/hotkey.ts
- 引擎装配与上下文注入:packages/engine/src/engine-core.ts#L118-L143
- 内置快捷键插件:packages/engine/src/inner-plugins/builtin-hotkey.ts
【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考