js 实现 dropdown
使用原生 JavaScript 实现 Dropdown
通过监听点击事件动态切换下拉菜单的显示状态。核心逻辑是检测点击事件是否发生在下拉区域外,从而关闭菜单。
document.addEventListener('DOMContentLoaded', function() {
const dropdowns = document.querySelectorAll('.dropdown');
dropdowns.forEach(dropdown => {
const button = dropdown.querySelector('.dropdown-button');
const menu = dropdown.querySelector('.dropdown-menu');
button.addEventListener('click', () => {
menu.classList.toggle('show');
});
});
document.addEventListener('click', function(event) {
dropdowns.forEach(dropdown => {
if (!dropdown.contains(event.target)) {
dropdown.querySelector('.dropdown-menu').classList.remove('show');
}
});
});
});
HTML 结构示例
需要配合以下HTML结构使用,注意添加data-dropdown属性用于标识组件。
<div class="dropdown">
<button class="dropdown-button">Menu</button>
<ul class="dropdown-menu">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
<li><a href="#">Item 3</a></li>
</ul>
</div>
CSS 基础样式
下拉菜单默认隐藏,通过show类控制显示。添加过渡效果增强用户体验。
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
display: none;
min-width: 160px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.dropdown-menu.show {
display: block;
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
键盘无障碍支持
通过监听键盘事件实现无障碍访问,符合WCAG标准。
dropdowns.forEach(dropdown => {
const button = dropdown.querySelector('.dropdown-button');
const menu = dropdown.querySelector('.dropdown-menu');
const items = menu.querySelectorAll('li a');
button.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
menu.classList.toggle('show');
}
});
items.forEach(item => {
item.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
menu.classList.remove('show');
button.focus();
}
});
});
});
动态内容加载
实现异步加载下拉菜单内容,适合数据量较大的场景。
function loadDropdownContent(url, dropdownId) {
fetch(url)
.then(response => response.json())
.then(data => {
const menu = document.querySelector(`#${dropdownId} .dropdown-menu`);
menu.innerHTML = data.map(item =>
`<li><a href="${item.url}">${item.text}</a></li>`
).join('');
});
}
多级嵌套实现
支持二级菜单的嵌套结构,通过CSS控制子菜单定位。
<div class="dropdown">
<button class="dropdown-button">Multi-level</button>
<ul class="dropdown-menu">
<li>
<a href="#">Parent Item</a>
<ul class="submenu">
<li><a href="#">Child Item 1</a></li>
<li><a href="#">Child Item 2</a></li>
</ul>
</li>
</ul>
</div>
.submenu {
display: none;
position: absolute;
left: 100%;
top: 0;
}
.dropdown-menu li:hover > .submenu {
display: block;
}
移动端优化
添加触摸事件支持,并防止滚动穿透问题。

button.addEventListener('touchstart', (e) => {
e.preventDefault();
menu.classList.toggle('show');
});
document.addEventListener('touchstart', (e) => {
if (!dropdown.contains(e.target)) {
menu.classList.remove('show');
}
});






