原生JavaScript实现带收放动画效果的导航菜单
掌握如何使用原生JavaScript为网站添加动态交互效果,本文详细解析两种导航菜单特效:第一种利用JS变量控制透明度与容器高度,实现丝滑的收放动画;第二种结合CSS定位与事件委托,构建简洁的下拉菜单结构,助你快速提升前端页面表现力。
实现目标
导航菜单是网页中常见的交互组件。为了提升用户体验,我们通常希望菜单在展开和收起时具有平滑的过渡动画(如高度变化、透明度渐变),而不是生硬的显示与隐藏。本文将分享两个用原生 JavaScript 编写的案例。
准备条件
- 了解基础的 HTML 结构与 CSS 属性(如
position,opacity,display)。 - 掌握 JavaScript 的事件监听(
addEventListener)、DOM 元素获取及基础动画循环逻辑。 - 无需引入任何第三方库(如 jQuery),纯原生实现以保持轻量。
第1步:实现带有伸缩动画效果的嵌套菜单
目的:实现当用户点击主菜单项上的特定按钮时,子菜单能够根据当前状态平滑展开或收起,同时伴随高度的变化和透明度的渐变。
入口:创建一个标准的 HTML 页面,定义一个无序列表(<ul>)作为主菜单。
动作与参数:
- 结构搭建:将菜单项放入
<li>标签内。每个可展开的子菜单包含一个触发按钮(<span class="show-hide">)和一个内容容器(<div class="a-div">)。 - 样式定义:使用 CSS 设置容器的默认隐藏状态(
display: none或opacity: 0)。关键在于给容器加上transition属性或使用 JS 手动更新样式来实现动画。 - 事件绑定:为父级列表绑定
click事件监听器。当检测到点击的是 .show-hide 元素时,执行动画函数。 - 动画逻辑:
- 判断当前容器是否可见(检查
opacity是否大于 0.5)。 - 如果是要“打开”,则初始化起始值为 0,结束值为预设高度(如 90px)。通过
setTimeout递归调用,每隔约 16.7ms 增加一点高度和透明度,直到达到目标值。 - 如果是要“关闭”,则反之,逐渐减少高度和透明度至 0,完成后将
display设为none。
以下是完整的核心实现代码。注意处理了不同浏览器的兼容性写法(虽然现代浏览器大多支持标准 API,但保留了 attachEvent 以备旧版 IE 需求):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script>
window.onload = function() {
var ul = document.getElementById('ul');
if(ul.addEventListener){
ul.addEventListener('mouseover',listener1,true);
ul.addEventListener('mouseout',listener2,true);
ul.addEventListener('click',listener3,false);
} else if (ul.attachEvent) { //兼容IE8及以前版本
ul.attachEvent('onmouseover', listener1, false);
ul.attachEvent('onmouseout', listener2, false);
ul.attachEvent('onclick', listener3, false);
}
// mouseover 悬停显示子菜单框
function listener1(event){
var target = event.target || event.srcElement;
if(target.tagName.toLowerCase() === 'li') {
var div1 = target.getElementsByTagName('div')[0];
div1.style.display = 'block';
div1.style.opacity = 1;
}
}
// mouseout 移除鼠标后隐藏子菜单框
function listener2(event){
var target = event.target || event.srcElement;
if(target.tagName.toLowerCase() === 'li'){
var div1 = target.getElementsByTagName('div')[0];
div1.style.display = 'none';
div1.style.opacity = 0;
}
}
var bool = true;
// click 点击特定按钮触发动画展开/收起
function listener3(event) {
var event = event || window.event;
var target = event.target || event.srcElement;
if (target.className === 'show-hide') {
var adiv = target.nextElementSibling;
// 判断当前状态来决定是展开还是收起
if (window.getComputedStyle(adiv, null).opacity > 0.5){bool=false}else{bool=true}
var height = 90,
changeH,
opacity,
id;
if (bool) {
// 展开动画
changeH = 0;
opacity = 0;
var text = target.innerHTML.slice(0,-1);
target.innerHTML = text+' -';
(function show() {
if (changeH > height) {clearTimeout(id);return}
changeH += 5;
opacity += 0.06;
adiv.style.height = changeH + 'px';
adiv.style.opacity = opacity;
adiv.style.display = 'block';
id = setTimeout(function () {
clearTimeout(id);
show();
}, 16.7);
})();
bool = false;
} else {
// 收起动画
changeH = height;
opacity = 1;
var text = target.innerHTML.slice(0,-1);
target.innerHTML = text+' +';
(function hidden() {
if (changeH < 0) {clearTimeout(id);adiv.style.display = 'none';return}
changeH -= 10;
opacity -= 0.11;
adiv.style.height = changeH + 'px';
adiv.style.opacity = opacity;
id = setTimeout(function () {
clearTimeout(id);
hidden();
}, 16.7);
})();
bool = true;
}
}
}
};
</script>
</head>
<body>
<!-- HTML 结构示例 -->
<ul id="ul">
<li>JavaScript实战
<div class="nav-div">
<span class="show-hide">导航特效 +</span>
<div class="a-div">
<a class="a" href="">可收放子菜单</a>
<a class="a" href="">切换页面</a>
</div>
</div>
</li>
</ul>
</body>
</html>
实现该特效后的视觉效果如下:点击带有加号/减号的标题栏,下方的链接区域会根据设定的速率平滑地变大变小。
第2步:实现基于CSS布局的下拉菜单
目的:实现一个更简单、性能更好的纯视觉反馈下拉菜单。主要依靠 CSS 的属性控制,配合少量的 JS 进行事件分发。
入口:同样使用无序列表结构,但层级关系变为扁平化。
动作与参数:
- CSS布局:使用绝对定位(
position: absolute)将子内容块(.contain)定位在对应的列表项正下方。通过display: none将其隐藏在初始状态下。 - JS事件:监听父容器的
mouseover和mouseout事件。当鼠标移入<li>或其内部元素时,找到对应的兄弟节点或子节点并设置style.display = 'block';移出时设为none。 - 简化逻辑:这种方案不需要复杂的帧动画计算,加载速度更快,适合移动端或对性能要求极高的场景。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
*{ margin: 0; padding: 0; }
#menu{ width: 400px; border: 1px solid gray; background-color: lemonchiffon; }
#menu li{ float: left; width: 99px; list-style: none; }
.contain{ position: absolute; display: none; width: 399px; background-color: lemonchiffon; color: #336699; border: 1px solid gray; top: 30px; left: 0; }
</style>
</head>
<script>
window.onload = function(){
var menu = document.getElementById('menu');
if(menu.addEventListener){
menu.addEventListener('mouseover',show,false);
menu.addEventListener('mouseout',hide,false);
} else if(menu.attachEvent){ //兼容旧版IE
menu.attachEvent('onmouseover',show,false);
menu.attachEvent('onmouseout',hide,false);
}
function show(event){
var target = event.target || event.srcElement;
// 找到关联的内容层并显示
if(target.tagName.toLowerCase() === 'li'){
target.firstElementChild.style.display = 'block';
} else if(target.parentNode.tagName.toLowerCase() === 'li'){
target.style.display = 'block';
}
}
function hide(event){
var target = event.target || event.srcElement;
// 找到关联的内容层并隐藏
if(target.tagName.toLowerCase() === 'li'){
target.firstElementChild.style.display = 'none';
} else if(target.parentNode.tagName.toLowerCase() === 'li'){
target.style.display = 'none';
}
}
}
</script>
<body>
<div id="menu">
<ul>
<li id="menu1">苏福的特效1
<div class="contain">内容区域 111...</div>
</li>
<li id="menu2">苏福的特效2
<div class="contain">内容区域 222...</div>
</li>
<li id="menu3">苏福的特效3
<div class="contain">内容区域 333...</div>
</li>
<li id="menu4">苏福的特效4
<div class="contain">内容区域 444...</div>
</li>
</ul>
</div>
</body>
</html>
该方案的运行效果如下所示:鼠标悬停在顶部栏目上,下方即弹出对应面板。
以上就是原生JavaScript制作带收放动画效果导航菜单的详细内容,更多关于JavaScript前端技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













