1.html部分
<body>
<ul class="menu-container">
<li class="menu">
<h2>菜单1</h2>
<ul class="subment">
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
<li>菜单4</li>
</ul>
</li>
<li class="menu">
<h2>菜单2</h2>
<ul class="subment">
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
<li>菜单4</li>
</ul>
</li>
<li class="menu">
<h2>菜单3</h2>
<ul class="subment">
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
<li>菜单4</li>
</ul>
</li>
<li class="menu">
<h2>菜单4</h2>
<ul class="subment">
<li>菜单1</li>
<li>菜单2</li>
<li>菜单3</li>
<li>菜单4</li>
</ul>
</li>
</ul>
<!-- <script src="./index.js"></script> -->
<script src="./index2.js"></script>
<script src="../animate.js"></script>
</body>
2.css部分
*{
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
font-weight: normal;
}
.menu-container{
width: 200px;
margin:0 auto;
line-height: 30px ;
}
.menu-container h2{
padding:0 25px;
background: teal;
cursor: pointer;
}
.subment{
background:thistle;
padding:0 30px;
height:0;
overflow:hidden;
}
.menu{
margin:20px 0;
}
.subment li{
height:30px;
}
3.js部分
var titles = document.querySelectorAll(".menu h2"); //获取所有的标题元素
var isHeight = 30; //定义每个li的高度
var totalMS = 300; //定义动画的总时间
var testSubment = document.querySelector(".subment"); //测试函数
for (let i = 0; i < titles.length; i++) {
//通过循环给每个h2元素注册点击事件
titles[i].onclick = function () {
var beforeSubment = document.querySelector(".subment[status=opened]"); //获取ul中 自定义属性[status=opened]
if (beforeSubment) {
//beforeSubment为true时, 有自定义属性,调用关闭子标签的函数
closeSubmenu(beforeSubment);
}
toggleSubmenu(this.nextElementSibling); //this.nextElementSibling 返回指定元素之后的下一个兄弟元素(相同节点树层中的下一个元素节点)
// console.log(this.nextElementSibling);
};
}
// console.log(titles.length * isHeight);
//打开子菜单
function openSubment(sub) {
//自定义属性status 三种状态: 关闭:colsed,打开:opened,动画打开中:playing
var status = sub.getAttribute("status"); //获取自定义属性
if (status !== "closed" && status) {
//如果当前状态 不等于关闭 和 为true 表示在打开中
return; //什么也不做 直接返回
}
sub.setAttribute("status", "playing"); //更改status的状态为: 打开中 playing
//因为涉及动画效果,调用之前封装的动画函数claerAnimate({})
claerAnimate({
from: 0, //开始的值
to: sub.children.length * isHeight, //结束的值,当前子元素的长度 * 每个li的高度
totalMS: totalMS, // 动画变化的总时间
onmove: function (n) {
sub.style.height = n + "px"; //要改变的回调函数,高度的变化就等对应传入参数的值 n
},
onend: function () {
sub.setAttribute("status", "opened"); //终止的回调函数,重新赋值status的状态为: 打开中 opened
},
});
}
//关闭子菜单
function closeSubmenu(sub) {
//自定义属性status 三种状态: 关闭:colsed,打开:opened,动画打开中:playing
var status = sub.getAttribute("status");
if (status !== "opened") {
return;
}
sub.setAttribute("status", "playing");
claerAnimate({
from: sub.children.length * isHeight, //开始的值
to: 0, //结束的值,当前子元素的长度 * 每个li的高度
totalMS: totalMS, // 动画变化的总时间
onmove: function (n) {
sub.style.height = n + "px"; //要改变的回调函数,高度的变化就等对应传入参数的值 n
},
onend: function () {
sub.setAttribute("status", "closed"); //终止的回调函数,重新赋值status的状态为: 打开中 opened
},
});
}
//切换子菜单
function toggleSubmenu(sub) {
var status = sub.getAttribute("status"); //获取自定义属性
//如果 status的状态为playing 运行中时 啥也不做
if (status === "playing") {
return;
//如果 status的状态为opened打开时 调用closeSubmenu(sub)关闭子菜单
} else if (status === "opened") {
closeSubmenu(sub);
} else {
openSubment(sub); //如果 status的状态为closed打开时 调用openSubment(sub)打开子菜单
}
}