效果展示
实现思路及部分代码
1、定义整体页面结构
从上述的效果展示图可以看出,页面的整体结构应该需要一个总菜单容器来装载父级菜单项,并且对应的父级菜单项应该有对应的菜单子项。子菜单是分类的话,我们还需要额外在扩展对应的容器来装载分类子菜单。所以我们可以这样来定义页面的结构:
<div class="header">
<div class="dropdown">
<button class="link"></button>
<!-- 分组子菜单 -->
<div class="dropdown-menu">
<div>
<div class="dropdown-heading"></div>
<div class="dropdown-links">
<a href="#" class="link"></a>
</div>
</div>
</div>
<!-- 只有一组菜单 -->
<div class="dropdown">
<button class="link"></button>
<div class="dropdown-menu">
<div class="dropdown-links">
<a href="#" class="link"></a>
</div>
</div>
</div>
<!-- 带有表单的子菜单 -->
<div class="dropdown">
<button class="link">登录</button>
<div class="dropdown-menu">
<form class="login-form">
<label for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Password</label>
<input type="password" name="password" id="password" />
<button type="submit">Login</button>
</form>
</div>
</div>
</div>
</div>
2、编写对应的样式
在页面结构的基础上进行样式的编写,具体核心代码如下:
.header {
background-color: #f3f3f3;
display: flex;
align-items: baseline;
padding: 0.5rem;
gap: 1rem;
}
.link {
background: none;
border: none;
text-decoration: none;
color: #777;
font-family: inherit;
font-size: inherit;
cursor: pointer;
padding: 0;
}
.dropdown-menu {
position: absolute;
left: 0;
top: calc(100% + 0.25rem);
background-color: white;
padding: 0.75rem;
border-radius: 0.25rem;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
opacity: 0;
pointer-events: none;
transform: translateY(-10px);
transition: opacity 150ms ease-in-out, transform 150ms ease-in-out;
}
.dropdown.active > .link + .dropdown-menu {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
.information-grid {
display: grid;
grid-template-columns: repeat(2, max-content);
gap: 2rem;
}
.dropdown-links {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.login-form > input {
margin-bottom: 0.5rem;
}
3、决定下拉菜单的触发事件并编写对应事件代码
在这里我选择点击
事件来触发菜单的显示,并且为了方便事件额获取,所以我这里会为关键的事件元素添加对应的data
属性,具体实例如下:
<div class="dropdown" data-dropdown></div>
<button class="link" data-dropdown-button>新闻版块</button>
document.addEventListener("click", (e) => {
const isDropdownButton = e.target.matches("[data-dropdown-button]");
if (!isDropdownButton && e.target.closest("[data-dropdown]") != null) return;
let currentDropdown;
if (isDropdownButton) {
currentDropdown = e.target.closest("[data-dropdown]");
currentDropdown.classList.toggle("active");
}
document.querySelectorAll("[data-dropdown].active").forEach((dropdown) => {
if (dropdown === currentDropdown) return;
dropdown.classList.remove("active");
});
});
完整代码
完整代码示例下载