当前位置: 代码迷 >> 综合 >> 无限极下拉菜单(两种方式实现:递归/递归+DOM)
  详细解决方案

无限极下拉菜单(两种方式实现:递归/递归+DOM)

热度:21   发布时间:2023-10-01 01:19:39.0

1.第一种思路:递归

无论哪种思路实现都需注意不能生成一级菜单后直接渲染到页面,而是需要生成所有的DOM节点及内容后,才一次性渲染到页面。

思路:

根据pid和id进行关联是否是父子级菜单

最终是将所以递归获得的数据渲染到页面,所以递归函数需要有返回值;

展开收缩思路:

找到当前元素,如果是展开的,直接收缩;

如果是收缩的,获取当前元素下的所有ul标签,将所有同级元素全部隐藏,再将当前元素进行显示

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><script src="data.js"></script><style>.view ul ul{display: none;}.show{display: block !important;}</style>
</head>
<body><div class="view"><!-- <ul><li><p>一级标题</p><ul><li><p>二级标题</p><ul><li>...</li></ul></li></ul></li></ul> --></div>
<script>
{/*思路:根据pid和id进行关联是否是父子级菜单最终是将所以递归获得的数据渲染到页面,所以递归函数需要有返回值;展开收缩思路:找到当前元素,如果是展开的,直接收缩;如果是收缩的,获取当前元素下的所有ul标签,将所有同级元素全部隐藏,再将当前元素进行显示*/let view = document.querySelector(".view");let getChild = (id) =>{//筛选pid等于id的情况就表示有子级return data.filter(item=>item.pid == id);}//最终是不断根据pid等于id的情况进行递归,所以需要将这个写成一个函数不断进行递归
//    let inner = '';
//    data.forEach(item=>{
//        inner +=`
//             <ul>
//                 <li>
//                     <p>${item.title}</p>
//                 </li>
//             </ul>
//        `;
//    });//最终要将所以递归到的inner渲染到页面,所以需要有返回值
let createUl = (data)=>{//不能在循环里面生成ul,否则会生成多个多个ullet inner = '<ul>';data.forEach(item=>{inner +=`<li><p>${item.title}</p>${// 如果当前id还能找到对应pid的子级就继续查找getChild(item.id)&&createUl(getChild(item.id))}</li>`;});inner += '</ul>';return inner;
}
view.innerHTML = createUl(getChild(-1));//获取到所有的p标签
let allP = document.querySelectorAll("p");
allP.forEach(item=>{item.onclick = () =>{let curUl = item.nextElementSibling;if(curUl){// 1. 当前是展开状态,点击之后就收缩起来if(curUl.classList.contains("show")){curUl.classList.remove("show");} else {// 当前是收缩状态,就把所有的同级收缩起来,然后展开当前的let allUl = curUl.parentNode.parentNode.querySelectorAll("ul");//所有的同级收起来allUl.forEach(item=>{item.classList.remove("show");});//展开当前curUl.classList.add("show");}}};
});
}
</script>
</body>
</html>

2.第二种思路实现:递归+DOM

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><script src="data.js"></script><style>.view ul ul{display: none;}.show{display: block !important;}</style>
</head>
<body><div class="view"><!-- <ul><li><p>一级标题</p><ul><li><p>二级标题</p><ul><li>...</li></ul></li></ul></li></ul> --></div>
<script>
{/*思路:根据pid和id进行关联是否是父子级菜单最终是将所以递归获得的数据渲染到页面,所以递归函数需要有返回值不能生成一级菜单就返回,要等所有的ul都生成后再返回*/let view = document.querySelector(".view");let getChild = (id) =>{//筛选pid等于id的情况就表示有子级return data.filter(item=>item.pid == id);}//最终是不断根据pid等于id的情况进行递归,所以需要将这个写成一个函数不断进行递归
//最终要将所以递归到的inner渲染到页面,所以需要有返回值
let createUl = (data)=>{let ul = document.createElement("ul");data.forEach(item=>{let li = document.createElement("li");let p = document.createElement("p");li.appendChild(p);p.innerHTML = item.title; //子级菜单每个都加在li上if(getChild(item.id)){li.appendChild(createUl(getChild(item.id)));}ul.appendChild(li);   });return ul;
}
view.appendChild(createUl(getChild(-1)));//获取到所有的p标签
let allP = document.querySelectorAll("p");
allP.forEach(item=>{item.onclick = () =>{let curUl = item.nextElementSibling;if(curUl){// 1. 当前是展开状态,点击之后就收缩起来if(curUl.classList.contains("show")){curUl.classList.remove("show");} else {// 2.当前是收缩状态,就把所有的同级收缩起来,然后展开当前的let allUl = curUl.parentNode.parentNode.querySelectorAll("ul");//所有的同级收起来allUl.forEach(item=>{item.classList.remove("show");});//展开当前curUl.classList.add("show");}}};
});}
</script>
</body>
</html>