HTML原生autocomplete仅提示浏览器填充类型,不提供下拉列表或JS逻辑;可控补全需input事件+AbortController防竞态;datalist适合静态候选词;手写键盘导航易出错,应优先用成熟库。
HTML 原生
属性能做什么、不能做什么
原生
只负责告诉浏览器“这个输入框想填什么类型的数据”,比如
或
,它不提供下拉建议列表,也不触发任何 JS 逻辑。浏览器是否弹出提示、弹出哪些历史值,完全由用户本地设置和浏览器实现决定——你无法控制内容、样式、触发时机,也不能绑定搜索接口。
常见误用:
或
在现代浏览器中基本失效;
这类特殊值只对密码字段有意义,乱用反而干扰 autofill。
适合场景:表单字段语义明确(如地址、电话),且只需复用用户已存的本地数据
不适合场景:需要实时查后端、按关键词过滤、展示自定义描述或图标
兼容性无坑,但功能边界极窄——它不是“自动补全组件”,只是“自动填充提示”
用
+
+
实现最小可行补全
真正可控的自动补全,得自己监听输入、发请求、渲染列表。核心是避免卡顿和竞态:用户快速打字时,上一个请求返回的结果可能已经过期。
必须用
事件而非
,否则会漏掉粘贴、语音输入等场景
是防竞态最轻量的方案,不用引入防抖库也能保证只处理最新请求
后端接口要支持
参数,并返回数组(如
)
注意:别在每次
都发请求,加个长度阈值(如
)更合理
用
快速实现静态候选词补全
如果候选词固定、数量少(比如 10 个以内城市名),
是零 JS 的最优解。它原生支持键盘上下键选择、回车确认,且不依赖任何框架。
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
立即学习
“
前端免费学习笔记(深入)
”;
仅支持完全匹配前缀(输入 “Bei” 会显示 “Beijing”,但 “jing” 不会)
不能动态更新
,改完 DOM 后需重新聚焦才能生效
Chrome 和 Edge 支持最好;Firefox 会把
当作纯提示,不阻止用户输入任意值;Safari 对空格、中文支持偶有异常
适合配置项、枚举型字段,不适合搜索场景
为什么不要自己写键盘导航逻辑?
手动监听
、
并模拟焦点切换,看似简单,实际要处理的边界极多:列表滚动位置、无障碍支持(ARIA)、失焦时清空、Esc 关闭、鼠标点击与键盘行为同步……这些已有成熟方案覆盖。
推荐直接用
(React)或
(原生 JS),它们已解决 focus 管理、ARIA 标签、移动端适配等问题
若必须手写,至少给下拉容器加
,每个选项加
和
,否则屏幕阅读器无法识别
最常被忽略的一点:补全列表必须用
且
足够高,否则会被父级
截断
补全的核心从来不是“怎么显示列表”,而是“什么时候发请求、怎么防抖/防竞态、怎么让键盘和鼠标操作一致”。细节堆起来,比写个 API 还费神。
autocompleteautocompleteautocomplete="name"autocomplete="email"autocomplete="on"autocomplete="off"autocomplete="new-password"inputkeydownfetchconst input = document.querySelector('input[name="search"]');
let abortController;
input.addEventListener('input', async () => {
const query = input.value.trim();
if (!query) return;
// 中断上一次请求
abortController?.abort();
abortController = new AbortController();
try {
const res = await fetch(`/api/suggest?q=${encodeURIComponent(query)}`, {
signal: abortController.signal
});
const suggestions = await res.json();
renderSuggestions(suggestions); // 自己实现 DOM 渲染
} catch (err) {
if (err.name !== 'AbortError') console.error(err);
}
});
inputkeyupAbortControllerq[{"value":"react","label":"React.js"}]inputquery.length > 2datalistdatalist
optiondatalistArrowDownEnterdownshiftawesompleterole="listbox"role="option"aria-selectedposition: absolutez-indexoverflow: hidden