Skip to content
返回设计中心

搜索建议与自动补全

防抖查询、键盘导航、最近搜索、结果分组。

UX 模式进阶

为什么

用户打字慢、拼错、不知有何。即输即建议将查询从 20 键击降到 3,浮现其不知存在的内容并纠正拼写。

Nielsen Norman Group 研究显示用户在离开前平均停留 10-15 秒。清晰的视觉层次和渐进式披露将任务完成率提高 40-60%。

何时使用

任何 >1000 项或用户不知确切词的搜索:产品、文章、人、命令。跳过小固定列表(10 项过滤器)— 下拉足够。

如何做

1. 防抖 — 末次键击后等 150–300ms 再查;勿每键查 2. 最小长度 — 查前要求 2+ 字符;1 字符查询是噪声 3. 缓存 — 每查询缓存结果;重复查询即时 4. 键盘 — ↑↓ 导航、Enter 选、Esc 关、Tab 接受高亮建议 5. 来源 — 混最近搜索、热门查询、实时结果;标每组 6. 高亮 — 粗每建议中匹配子串以让用户见为何匹配 7. a11y — combobox 角色、aria-activedescendant 高亮项、实时区域结果数 8. 加载 — 200ms 后显 spinner 或骨架;勿快查询闪

示例

function SearchBox() { const [q, setQ] = useState(""); const [highlight, setHighlight] = useState(-1); const { results, loading } = useSearch(debounce(q, 200)); // 200ms 防抖 return ( <Combobox value={q} onChange={setQ}> <ComboboxInput aria-label="搜索" /> <ComboboxList> {loading && <li>加载中…</li>} {!loading && results.map((r, i) => ( <ComboboxOption key={r.id} value={r.title} aria-selected={i === highlight} > <mark>{r.title.slice(0, q.length)}</mark>{r.title.slice(q.length)} </ComboboxOption> ))} </ComboboxList> </Combobox> ); } // useSearch — 防抖、缓存、最小长度 function useSearch(q: string) { const cache = useRef<Map<string, Result[]>>(new Map()); const [results, setResults] = useState<Result[]>([]); useEffect(() => { if (q.length < 2) return setResults([]); // 最小长度 if (cache.current.has(q)) return setResults(cache.current.get(q)!); api.search(q).then((r) => { cache.current.set(q, r); setResults(r); }); }, [q]); return { results, loading: q.length >= 2 && !cache.current.has(q) }; }

常见问题

  • ⚠每键查 — 'hello' 20 请求,后端被锤,UI 卡
  • ⚠无键盘导航 — 仅鼠标,高级用户无法 Tab 过建议
  • ⚠无匹配高亮 — 用户不见建议为何出现,信任低

最佳实践

  • ✓防抖 200ms + 最小 2 字符 — 请求降 10 倍,无单字符噪声
  • ✓全键盘支持 — ↑↓ 导航、Enter 选、Esc 关;高级用户友好
  • ✓高亮匹配子串 — 用户见为何匹配,建结果信任

常见问题解答