如何用Vanilla JavaScript为简单下拉菜单添加键盘导航?有无HTML5原生方案?
下拉菜单的键盘导航实现方案
一、原生JavaScript实现方案
首先需要给菜单触发元素添加tabindex属性使其可被键盘聚焦,同时给下拉选项设置tabindex="-1"(让选项可被聚焦但不会被Tab键直接选中)。修改后的HTML结构如下:
<div class="dropdown"> <div tabindex="0" class="dropdown-trigger">Test Dropdown</div> <ul class="dropdown-menu" hidden> <li tabindex="-1">A</li> <li tabindex="-1">B</li> <li tabindex="-1">C</li> </ul> </div>
接下来编写JavaScript逻辑,实现以下核心交互:
- 回车/空格键:切换菜单的展开/收起状态
- 上下箭头键:在菜单选项间循环导航
- ESC键:关闭菜单并将焦点放回触发元素
- 点击菜单外部:自动关闭菜单
- 选中选项:执行对应操作并关闭菜单
const dropdown = document.querySelector('.dropdown'); const trigger = dropdown.querySelector('.dropdown-trigger'); const menu = dropdown.querySelector('.dropdown-menu'); const menuItems = menu.querySelectorAll('li'); let currentIndex = -1; // 切换菜单显示状态 function toggleMenu() { menu.hidden = !menu.hidden; if (!menu.hidden) { currentIndex = 0; menuItems[currentIndex].focus(); } } // 循环导航到指定索引的选项 function navigateToIndex(index) { if (index < 0) index = menuItems.length - 1; if (index >= menuItems.length) index = 0; currentIndex = index; menuItems[currentIndex].focus(); } // 点击触发元素切换菜单 trigger.addEventListener('click', toggleMenu); // 触发元素的键盘事件处理 trigger.addEventListener('keydown', (e) => { switch(e.key) { case 'Enter': case ' ': e.preventDefault(); toggleMenu(); break; case 'ArrowDown': e.preventDefault(); toggleMenu(); break; } }); // 菜单选项的键盘与点击事件处理 menuItems.forEach((item, index) => { item.addEventListener('keydown', (e) => { switch(e.key) { case 'Enter': case ' ': e.preventDefault(); console.log(`选中选项:${item.textContent}`); menu.hidden = true; trigger.focus(); break; case 'ArrowUp': e.preventDefault(); navigateToIndex(currentIndex - 1); break; case 'ArrowDown': e.preventDefault(); navigateToIndex(currentIndex + 1); break; case 'Escape': e.preventDefault(); menu.hidden = true; trigger.focus(); break; } }); item.addEventListener('click', () => { console.log(`选中选项:${item.textContent}`); menu.hidden = true; trigger.focus(); }); }); // 点击外部区域关闭菜单 document.addEventListener('click', (e) => { if (!dropdown.contains(e.target)) { menu.hidden = true; } });
可以配合基础CSS让交互更直观:
.dropdown { position: relative; display: inline-block; } .dropdown-trigger { padding: 8px 12px; border: 1px solid #ccc; cursor: pointer; } .dropdown-menu { position: absolute; top: 100%; left: 0; margin: 0; padding: 0; list-style: none; border: 1px solid #ccc; background: white; min-width: 100px; } .dropdown-menu li { padding: 8px 12px; cursor: pointer; } .dropdown-menu li:focus { background-color: #eee; outline: none; }
二、HTML5原生解决方案
如果不需要高度自定义的样式,HTML5的<select>和<option>元素本身就自带完整的键盘导航支持,浏览器会自动处理所有交互逻辑(上下箭头选择、回车确认、ESC关闭等),无需额外编写代码:
<select class="native-dropdown"> <option value="a">A</option> <option value="b">B</option> <option value="c">C</option> </select>
注意:原生<select>的样式在不同浏览器中差异较大,难以完全自定义。如果需要兼顾自定义样式和原生键盘支持,可以结合<select>的语义与JavaScript增强,但纯原生方案的优势是开箱即用,无需额外逻辑。
内容的提问来源于stack exchange,提问作者Arnold Zahrneinder
相关产品推荐
相关产品推荐

