作为俺网页设计课的某个实验作业,觉得老师提供的案例代码过于简陋,于是自己琢磨了个优雅又精美的下拉菜单功能。
效果
菜单点击触发,点击事件实现收起展开菜单,点击菜单项收起其他菜单项的一打开菜单,每项自带的after伪元素实现的三角提示标,并随收起展开状态动态变换效果。。。做完直接对👴🏿的聪明才智佩服的五体投地。
代码实现也简洁,层次属实清晰,可谓惊天地泣鬼神集代码带成者😅
代码实现
下拉菜单功能的中心思想是通过一个类表示按下菜单后的样式,本例取active类。
设置active类的元素即样式表示为菜单选中状态。无active类下,子级菜单为隐藏状态,即透明度为0,且关闭鼠标事件,三角图形向下指示展开。设置active类下,子菜单显示,透明度为1,启用鼠标事件,三角图形向上指示收起。
为了实现鼠标事件,单击元素为其设置active类,动态切换分配active类,则需用javascript配置交互。
HTML
作为数量众多的菜单项与相应的子级菜单元素,需要将菜单划分为主级与子级两层,且需要将属于同菜单块的菜单项存放在无序列表中,故基础HTML架构应有如下排布:
<ul id="mainMenu">
<li>
<a href="#" role="button" id="mainBtn">Xbox Game Pass</a>
<ul id="subMenu">
<li><a href="#">概观</a></li>
<li><a href="#">浏览游戏</a></li>
<li><a href="#">Xbox Game Pass for PC</a></li>
<li><a href="#">Xbox Live Gold</a></li>
</ul>
</li>
<li>
<a href="#" role="button" id="mainBtn">游戏</a>
<ul id="subMenu">
<li><a href="#">选购所有主机游戏</a></li>
<li><a href="#">使用Xbox的电脑游戏</a></li>
<li><a href="#">所有游戏展示</a></li>
</ul>
</li>
<li>
<a href="#" role="button" id="mainBtn">设备</a>
<ul id="subMenu">
<li>
<p>所有Xbox主机</p>
</li>
<li><a href="#">全新 Xbox Series X</a></li>
<li><a href="#">全新 Xbox Series S</a></li>
<hr>
<li>
<p>所有Xbox配件</p>
</li>
<li><a href="#">控制器</a></li>
<li><a href="#">头戴式设备</a></li>
<li><a href="#">硬盘与存储空间</a></li>
</ul>
</li>
<li>
<a href="#" role="button" id="mainBtn">社群</a>
<ul id="subMenu">
<li><a href="#">Xbox Community</a></li>
<li><a href="#">多人游戏</a></li>
</ul>
</li>
<li>
<a href="#" role="button" id="mainBtn">支持</a>
<ul id="subMenu">
<li><a href="#">支持首页</a></li>
<li><a href="#">Xbox Live 状态</a></li>
<li><a href="#">无障碍游戏</a></li>
<li><a href="#">支持服务的新功能</a></li>
</ul>
</li>
</ul>
其中,mainMenu用于标识主菜单类,subMenu用于标识二级菜单列表,mainBtn标识主菜单项,即文字背后需要添加三角形指示图形的元素。
接下来开始对元素具体装饰
CSS
首先对主菜单类容器指定项目的行内弹性盒子排布,使其菜单项横向排列:
#mainMenu{
display:inline-flex;
}
子菜单与主菜单同样是以无序列表存放,对于子菜单,需要将子菜单块准确置于对应主菜单项的底下,故需先将子菜单项设置绝对定位,再给子菜单的父li类设置相对定位,以标识参考系。配置了必要及其他装饰属性代码应如下:
#mainMenu li{
position: relative;
}
#subMenu{
opacity: 0;
position: absolute;
top: 100%;
left: 0;
min-width: 100%;
background-color: white;
border: 1px solid lightgray;
pointer-events: none;
border-radius: .366em;
-webkit-border-radius: .366em;
-moz-border-radius: .366em;
-ms-border-radius: .366em;
-o-border-radius: .366em;
transition: all 0.2s;
-webkit-transition: all 0.2s;
-moz-transition: all 0.2s;
-ms-transition: all 0.2s;
-o-transition: all 0.2s;
}
其他对a标签的按钮样式及hover伪元素样式设置就不作过多赘述,接下来实现主菜单项的指示三角形,这里使用after伪元素样式。
- ::after对具有行内属性的标签的作用相当于加在文字尾部的样式,必须指定content属性,否则无法显示。
- 实现三角形形状,需要灵活使用border属性,对尖头方向的border设置为none
配置了基本样式及微调下的::after应如下:
#mainBtn::after{
display: inline-block;
margin-left: .255rem;
vertical-align: .255rem;
content: '';
border-top: .3em solid;
border-left:.3em solid transparent;
border-right: .3em solid transparent;
border-bottom: none;
transition: all 0.2s;
-webkit-transition: all 0.2s;
-moz-transition: all 0.2s;
-ms-transition: all 0.2s;
-o-transition: all 0.2s;
}
接下来应对active类进行样式设置;
对于active类下的子菜单块,设置显示等属性:
.active #subMenu{
opacity: 1;
top: 120%;
pointer-events: all;
}
对三角图形伪元素类,设置为向上指示,可重新配置border实现尖头向上,本例则为了方便且具有动态效果,利用了transform旋转:
.active #mainBtn::after{
transform-origin: center;
transform: rotateZ(180deg);
-webkit-transform: rotateZ(180deg);
-moz-transform: rotateZ(180deg);
-ms-transform: rotateZ(180deg);
-o-transform: rotateZ(180deg);
}
核心CSS设置完成,为实现active类的动态分配,需编写javascript。
Javascript
为实现active类的统一控制,将该类分配给主菜单块的li标签;
编写自定义函数实现类切换功能:
const mainBtn = document.querySelectorAll('#mainMenu #mainBtn');
//active类切换器
function activeToggler(index) {
for (let j = 0; j < mainBtn.length; j++) {
const activeList = mainBtn[j].parentElement;
if (j != index) {
activeList.classList.remove('active'); //移除索引外的active
}
}
mainBtn[index].parentElement.classList.toggle('active');
activeToggler函数带有1个index参数,表示mainBtn类数组的序号,以该序号作为索引,for循环遍历所有mainBtn类,按照传入的index,移除除index索引元素外的active类。由于active需加在li上,故需选择mainBtn的父元素,即父li。
toggle方法能实现灵活执行add与remove方法,具有指定类则remove,没有指定类则add这个类。
为每个mainBtn绑定点击事件,实现点击按钮即为其父li配置active类:
//绑定点击事件
for (let i = 0; i < mainBtn.length; i++) {
const btn = mainBtn[i];
btn.onclick = function () {
activeToggler(i);
}
}
为养成好的习惯,同学们需要将这些交互功能代码放置在页面加载对象window.onload中,故完整js代码应如图:
window.onload = function () {
const mainBtn = document.querySelectorAll('#mainMenu #mainBtn');
//绑定点击事件
for (let i = 0; i < mainBtn.length; i++) {
const btn = mainBtn[i];
btn.onclick = function () {
activeToggler(i);
}
}
//active类切换器
function activeToggler(index) {
for (let j = 0; j < mainBtn.length; j++) {
const activeList = mainBtn[j].parentElement;
if (j != index) {
activeList.classList.remove('active'); //移除索引外的active
}
}
mainBtn[index].parentElement.classList.toggle('active');
}
}
结语
下拉菜单实现其实用不了多少js代码,如果单纯使子菜单在hover时而不是鼠标单击时显示的话,甚至可以直接用纯CSS实现,无需半句javascript。
单击显示也无非是利用了css设置active类样式,js动态控制active这一基本思想,虽说在带佬们眼中,这种小技巧实属常识中的常识,但对初学者来说还是受益匪浅滴。
怎么样铁汁们,学废了🐴,另外现在评论区可以发emoji了嗷,蛆宝宝们走起来😅
内容的丰富性和深度让人仿佛置身于知识的海洋,受益匪浅。
By olxmjycmib at March 4th, 2025 at 07:57 pm.
建议多用口语化表达,拉近与读者距离。
By fzxnhkojub at March 3rd, 2025 at 07:10 am.
建议引入反面案例,增强辩证性。
By lgicdvcrmc at March 3rd, 2025 at 04:36 am.
哈哈哈,写的太好了https://www.lawjida.com/
By kusfrkqekj at January 6th, 2025 at 02:42 pm.
兄弟写的非常好 https://www.cscnn.com/
By sfcocyznuh at October 19th, 2024 at 05:33 pm.
看的我热血沸腾啊www.jiwenlaw.com
By lujacjmeex at October 6th, 2024 at 07:56 pm.
看的我热血沸腾啊https://www.ea55.com/
By egedwwglwl at October 4th, 2024 at 10:13 pm.
想想你的文章写的特别好https://www.237fa.com/
By vlbolygycj at October 1st, 2024 at 09:32 pm.
怎么收藏这篇文章?
By ctbtuuttup at September 27th, 2024 at 01:43 pm.
叼茂SEO.bfbikes.com
By emvwwyoqrr at September 23rd, 2024 at 08:02 am.
添加了一堆表情,不知道要不要加点qq和微信的表情
By cvlocke at January 16th, 2021 at 05:07 pm.