效果展示
实现思路及部分代码
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");});
});
完整代码
完整代码示例下载