作为俺网页设计课的某个实验作业,觉得老师提供的案例代码过于简陋,于是自己琢磨了个优雅又精美的下拉菜单功能。
效果
菜单点击触发,点击事件实现收起展开菜单,点击菜单项收起其他菜单项的一打开菜单,每项自带的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.