搜索面板:Ctrl+K 和输入框防抖
一个命令面板式的搜索:按 Ctrl+K 唤起,输入即时出结果,上下键选,回车跳转,Esc 关闭。
全局快捷键要处理三件事。
监听在 window 上的 keydown,判断 e.key === 'k' && (e.metaKey || e.ctrlKey)。mac 是 Cmd、Windows 是 Ctrl,两个都要。
第二件是别在输入框里抢键。用户在 textarea 里按 Ctrl+K 也许是想搜索,但按 Esc 一定是想退出输入。我加了一个判断:焦点在 input/textarea 时不劫持方向键。
第三件是卸载时解绑。组件卸载没清理监听,切两个页面之后按一次 Ctrl+K 弹两个面板。这类错误我在定时器那篇里写过,事件监听是完全一样的问题。
输入防抖用了 200ms。这里有一个比防抖更影响体验的东西:请求竞态。
let seq = 0
async function search(q: string) {
const my = ++seq
const res = await api.get('/search', { q })
if (my !== seq) return // 已经有更新的请求在跑,丢掉这个
results.value = res
}
输入 "vue" 时先后发了 v、vu、vue 三个请求,返回顺序不保证。慢的那个后回来会把新结果覆盖掉,界面显示的是 "v" 的匹配。用一个自增序号,只认最后一次。
键盘导航要维护一个 selectedIndex,输入变化时重置为 0,方向键加减并取模。滚动到可视区用 el.scrollIntoView({ block: 'nearest' }),不写 nearest 的话会把整个页面顶到中间。
最后是无障碍:面板要 role="dialog"、aria-modal,打开时焦点移进去、关闭时还给触发它的元素。这部分我第二版才补,第一版键盘能操作但读屏软件什么都念不出来。