iter(g17): select 键入字母快跳选项

This commit is contained in:
HIsheR
2026-10-26 11:00:17 +08:00
parent 2e48d9413f
commit 27d797ab63
7 changed files with 30 additions and 8 deletions
+15 -1
View File
@@ -51,6 +51,19 @@ export function select(props: SelectProps): HTMLElement {
const root = h('div', { class: () => `ua-select${open() ? ' ua-open' : ''}` }, trigger, pop); // 根带开合类,供箭头旋转
// —— 键入快跳缓冲 ——
let typed = ''; // 最近键入的字母串,用于前缀匹配
let typedAt = 0; // 最近键入时间戳,超 1 秒重置缓冲
const jumpByTyped = (ch: string): void => {
const now = Date.now();
typed = now - typedAt > 1000 ? ch : typed + ch; // 超时重新起词,否则追加
typedAt = now;
const at = options.indexOf(document.activeElement as HTMLElement); // 当前焦点序号,作为环形搜索起点
const order = options.map((_, i) => (at + 1 + i) % options.length); // 从下一项开始环形排列的序号
const hit = order.find((i) => props.options[i].label.toLowerCase().startsWith(typed.toLowerCase())); // 前缀匹配(忽略大小写)
if (hit != null) options[hit]?.focus(); // 命中即聚焦;无命中留在原地
};
root.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'Escape') { open(false); trigger.focus(); return; } // Esc 关闭并回焦触发器
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
@@ -63,7 +76,8 @@ export function select(props: SelectProps): HTMLElement {
return;
}
if (e.key === 'Home' && open()) { e.preventDefault(); options[0]?.focus(); return; } // Home 跳首项
if (e.key === 'End' && open()) { e.preventDefault(); options[options.length - 1]?.focus(); } // End 跳末项
if (e.key === 'End' && open()) { e.preventDefault(); options[options.length - 1]?.focus(); return; } // End 跳末项
if (open() && e.key.length === 1) jumpByTyped(e.key); // 可打印字符:键入快跳(Home/End/方向键已提前接管)
});
document.addEventListener('click', (e) => {
if (root.contains(e.target as Node)) return; // 卫语句:组件内点击不处理