命令面板(Cmd+K)
对所有动作和页面的键盘优先搜索 — 高级用户到一切的快捷方式。
UX 模式高级
为什么
高级用户厌离键盘点击过菜单。命令面板(Cmd+K)让其打字跳任何页、运行任何动作、插任何模板 — Linear/Notion/Raycast 标志特性。
Nielsen Norman Group 研究显示用户在离开前平均停留 10-15 秒。清晰的视觉层次和渐进式披露将任务完成率提高 40-60%。
何时使用
任何 >20 动作或页的生产力应用:编辑器、仪表板、管理工具。跳过简单营销站或单用途应用,其导航已明显。
如何做
1. 触发 — Cmd/Ctrl+K 开;Esc 关;全局监听非每页
2. 输入 — 单文本字段,模糊搜所有命令
3. 命令 — { id, title, shortcut?, run(), group } — 页、动作、设置、最近
4. 模糊搜 — fuse.js 或 uFuzzy;按近度 + 相关排;显前 8
5. 键盘 — ↑↓ 导航、Enter 运行、Esc 关、Tab 接受参数化命令参数
6. 分组 — 页、动作、设置、最近 — 列表中标签区段
7. 提示 — 每命令旁显快捷键("跳到收件箱 ⌘1")以可发现
8. 近度 — 最近用命令提顶;用户重跑同 5 动作
示例
import { Command } from "cmdk"; // Vercel/Linear 用的库
function CommandPalette() {
const [open, setOpen] = useState(false);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); setOpen((o) => !o); }
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);
return (
<Command.Dialog open={open} onOpenChange={setOpen}>
<Command.Input placeholder="输入命令或搜索…" />
<Command.List>
<Command.Empty>无结果。</Command.Empty>
<Command.Group heading="页面">
<Command.Item onSelect={() => go("/inbox")}>去收件箱 <kbd>⌘1</kbd></Command.Item>
<Command.Item onSelect={() => go("/settings")}>去设置</Command.Item>
</Command.Group>
<Command.Group heading="动作">
<Command.Item onSelect={newDoc}>新文档 <kbd>⌘N</kbd></Command.Item>
<Command.Item onSelect={toggleTheme}>切换主题</Command.Item>
</Command.Group>
</Command.List>
</Command.Dialog>
);
}
常见问题
- ⚠无全局 Cmd+K — 面板仅从按钮开,高级用户无法随处触发
- ⚠静态排序 — 同 50 命令同序,近度会浮其真用的 5
- ⚠无快捷键提示 — 用户不发现 ⌘1 快捷键因藏设置中
最佳实践
- ✓全局 Cmd+K 监听 — 随处开,非仅按钮聚焦时
- ✓按近度 + 相关排 — 用户日跑的 5 命令应在顶
- ✓内联显快捷键提示 — '新文档 ⌘N' 用面板时教快捷键