千万年想起来发一篇博文,博大家一乐吧。
首先感谢大佬【龙恩0707】,本文数据结构转换部分参考借鉴大佬的博文 js将有父子关系的数据转换成树形结构数据 - 龙恩0707 - 博客园 ,有对这方面感兴趣的可跳转大佬正文。
自己设想的效果:树型展示,开开闭闭,能取自己、父级等的id(以便编辑删除等)。
别的废话少说,上代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>power</title>
<link href="./js/layui/css/layui.css" rel="stylesheet" />
<script src="./js/jquery.min.js"></script>
<script src="./js/layui/layui.all.js"></script>
</head>
<body>
<table class="layui-table">
<thead>
<tr class="titleTr" style="text-align: center;">
<th style="text-align: center;">名称</th>
<th style="text-align: center;">链接</th>
<th style="text-align: center;">操作</th>
</tr>
</thead>
<tbody id="dataList"></tbody>
</table>
<script type="text/javascript">
var nodes = [{
"id": "1",
"name": "1",
"url": "sgdsfhbf.htm",
"childNode": [{
"id": "11",
"name": "11",
"url": "dfsdkfdkl.htm",
"childNode": [{
"id": "111",
"name": "111",
"url": "toPowerList",
"childNode": []
}]
}]
}, {
"id": "2",
"name": "2",
"url": "",
"childNode": [{
"id": "21",
"name": "21",
"url": "",
"childNode": [{
"id": "211",
"name": "211",
"url": "toPowerList",
"childNode": []
}]
}, {
"id": "22",
"name": "22",
"url": "",
"childNode": [{
"id": "221",
"name": "221",
"url": "toPowerList",
"childNode": [{
"id": "2211",
"name": "2211",
"url": "",
"childNode": [{
"id": "22111",
"name": "22111",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2212",
"name": "2212",
"url": "",
"childNode": [{
"id": "22121",
"name": "22121",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2213",
"name": "2213",
"url": "",
"childNode": [{
"id": "22131",
"name": "22131",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2214",
"name": "2214",
"url": "",
"childNode": [{
"id": "22141",
"name": "22141",
"url": "toPowerList",
"childNode": []
}]
}]
}]
}, {
"id": "23",
"name": "23",
"url": "",
"childNode": [{
"id": "231",
"name": "231",
"url": "toPowerList",
"childNode": []
}]
}]
}];
function initData(pid,list,divAreaName) {
var trhtml = "";
if (list.length > 0) {
for (var i = 0; i < list.length; i++) {
trhtml = "";
trhtml += "<tr class=\'"+pid+"\' id=\'"+(pid+"_"+list[i].id)+"\'>";
trhtml += "<td"+((list[i].childNode.length > 0)?" onclick=\"chickTr(\'"+(pid+"_"+list[i].id)+"\')\"":"")+">";
if (list[i].childNode.length > 0) {
trhtml += "<img class='gb' id=\'img_"+(pid+"_"+list[i].id)+"\' src='./img/wenjianjia_gb_xi.png' height='16px' />";
}else {
trhtml += "<img src='./img/wenjian_xi.png' height='16px' />";
}
trhtml += list[i].name;
trhtml += "</td>";
trhtml += "<td>";
trhtml += list[i].url;
trhtml += "</td>";
trhtml += "<td style=\"text-align: center;\">";
trhtml += "<a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>修改</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>删除</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>添加下级权限</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>添加本级权限</font></a>";
trhtml += "</td>";
trhtml += "</tr>";
$("#"+divAreaName+"").append(trhtml);
//console.log(list[i].childNode)
if (list[i].childNode.length > 0) {
initData((pid+"_"+list[i].id),list[i].childNode,divAreaName);
}
}
}
}
function chickTr(showTrClassName){
var isDkThisTr = $("#img_"+showTrClassName).attr("class");
$(".dk").attr("class","gb").attr("src","./img/wenjianjia_gb_xi.png");
$("tr").hide();
$(".titleTr").show();
$(".root").show();
var showTrIdList = showTrClassName.split("_");
var showTrClassNames = "";
for (var j = 0; j < showTrIdList.length; j++) {
if(j==0){
showTrClassNames += showTrIdList[j];
}else {
showTrClassNames += ("_" + showTrIdList[j]);
}
if(showTrClassNames != showTrClassName){
$("."+showTrClassNames).show();
$("#img_"+showTrClassNames).attr("class","dk").attr("src","./img/wenjianjia_dk_xi.png");
}
}
if ("dk" == isDkThisTr) {
$("#img_"+showTrClassName).attr("class","gb").attr("src","./img/wenjianjia_gb_xi.png");
$("."+showTrClassName).hide();
}else {
$("."+showTrClassName).show();
$("#img_"+showTrClassName).attr("class","dk").attr("src","./img/wenjianjia_dk_xi.png");
}
}
$(function (){
initData("root",nodes,"dataList");
$("tr").hide();
$(".titleTr").show();
$(".root").show();
});
</script>
</body>
</html>
分析:(额,没什么分析的,就是觉得太长,拆分一下)
碰///瓷layui
虽然head标签一通瞎加载,但是这个例子里只有jQuery用的多,layui就用了下样式、layer弹出层 (这些不想用的话,自己写一个更香)
HTML
<table class="layui-table">
<thead>
<tr class="titleTr" style="text-align: center;">
<th style="text-align: center;">名称</th>
<th style="text-align: center;">链接</th>
<th style="text-align: center;">操作</th>
</tr>
</thead>
<tbody id="dataList"></tbody>
</table>
里边三个注意点:
1,table标签class不能写错,毕竟我用的layui的样式;
2,thead里的tr标签的class可以不用这个,但是需要和下边JavaScript里保持一致,至于样式,想怎么来怎么来;
3,#dataList,除了名称得和下边保持一致,其他的随意。
目前就只有一个列表,需要的什么搜索啦、按钮啦......根据你的需求自己加。
JavaScript
大部分我在编辑这一块时候又加了注释,注意看
1,数据格式
//主要的就id/name/childNode,其他的看心情加
var nodes = [{
"id": "1",
"name": "1",
"url": "sgdsfhbf.htm",
"childNode": [{
"id": "11",
"name": "11",
"url": "dfsdkfdkl.htm",
"childNode": [{
"id": "111",
"name": "111",
"url": "toPowerList",
"childNode": []//这玩意儿即使没下级,也要让后台给你搞个空集合
}]
}]
}, {
"id": "2",
"name": "2",
"url": "",
"childNode": [{
"id": "21",
"name": "21",
"url": "",
"childNode": [{
"id": "211",
"name": "211",
"url": "toPowerList",
"childNode": []
}]
}, {
"id": "22",
"name": "22",
"url": "",
"childNode": [{
"id": "221",
"name": "221",
"url": "toPowerList",
"childNode": [{
"id": "2211",
"name": "2211",
"url": "",
"childNode": [{
"id": "22111",
"name": "22111",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2212",
"name": "2212",
"url": "",
"childNode": [{
"id": "22121",
"name": "22121",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2213",
"name": "2213",
"url": "",
"childNode": [{
"id": "22131",
"name": "22131",
"url": "toPowerList",
"childNode": []
}]
},{
"id": "2214",
"name": "2214",
"url": "",
"childNode": [{
"id": "22141",
"name": "22141",
"url": "toPowerList",
"childNode": []
}]
}]
}]
}, {
"id": "23",
"name": "23",
"url": "",
"childNode": [{
"id": "231",
"name": "231",
"url": "toPowerList",
"childNode": []
}]
}]
}];
2,装入数据()
/*
pid:上级id(第一级pid传自己喜欢的值就行,注意避免和数据id搞混)
list:需要添加的数据
divAreaName:添加到哪里,就前边让你保持一致那个
*/
function initData(pid,list,divAreaName) {
var trhtml = "";
if (list.length > 0) {
for (var i = 0; i < list.length; i++) {//循环
trhtml = "";
trhtml += "<tr class=\'"+pid+"\' id=\'"+(pid+"_"+list[i].id)+"\'>";
/*把点击事件加在td上,避免点击【操作】时触发*/
trhtml += "<td"+((list[i].childNode.length > 0)?" onclick=\"chickTr(\'"+(pid+"_"+list[i].id)+"\')\"":"")+">";
if (list[i].childNode.length > 0) {//添加图片,一是好看,二是为之后的打开关闭做标志
trhtml += "<img class='gb' id=\'img_"+(pid+"_"+list[i].id)+"\' src='./img/wenjianjia_gb_xi.png' height='16px' />";
}else {
trhtml += "<img src='./img/wenjian_xi.png' height='16px' />";
}
trhtml += list[i].name;
trhtml += "</td>";
trhtml += "<td>";
trhtml += list[i].url;
trhtml += "</td>";
trhtml += "<td style=\"text-align: center;\">";
trhtml += "<a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>修改</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>删除</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>添加下级权限</font></a>";
trhtml += " | <a href='#' onclick='layer.alert("+list[i].id+")'><font color='blue'>添加本级权限</font></a>";
trhtml += "</td>";
trhtml += "</tr>";
$("#"+divAreaName+"").append(trhtml);
//console.log(list[i].childNode)
if (list[i].childNode.length > 0) {
initData((pid+"_"+list[i].id),list[i].childNode,divAreaName);//有下级就递归继续加
}
}
}
}
3,列表展开关闭点击事件
/*showTrClassName:当前点的ID值,即需要开闭的class值*/
function chickTr(showTrClassName){
var isDkThisTr = $("#img_"+showTrClassName).attr("class");//首先记录点击的那个开闭状态
$(".dk").attr("class","gb").attr("src","./img/wenjianjia_gb_xi.png");//所有全关闭
$("tr").hide();
$(".titleTr").show();
$(".root").show();//基本展示
var showTrIdList = showTrClassName.split("_");
var showTrClassNames = "";
for (var j = 0; j < showTrIdList.length; j++) {//将父级全部打开
if(j==0){
showTrClassNames += showTrIdList[j];
}else {
showTrClassNames += ("_" + showTrIdList[j]);
}
if(showTrClassNames != showTrClassName){
$("."+showTrClassNames).show();
$("#img_"+showTrClassNames).attr("class","dk").attr("src","./img/wenjianjia_dk_xi.png");
}
}
if ("dk" == isDkThisTr) {//判断自身开闭
$("#img_"+showTrClassName).attr("class","gb").attr("src","./img/wenjianjia_gb_xi.png");
$("."+showTrClassName).hide();
}else {
$("."+showTrClassName).show();
$("#img_"+showTrClassName).attr("class","dk").attr("src","./img/wenjianjia_dk_xi.png");
}
}
4,【操作】(略,目前写的是弹出层提示,所以取id就取当前id,取父级就取class然后自己截取)
5,初次加载(包括简易版的ajax请求)
$(function (){
initData("root",nodes,"dataList");
$("tr").hide();
$(".titleTr").show();
$(".root").show();
/*后台请求*/
/*$.ajax({
url:"queryPower",
success: function (res){
initData("root",res.nodes,"dataList");//当res={...,nodes=[],...}时
initData("root",res,"dataList");//当res=[]时
$("tr").hide();
$(".titleTr").show();
$(".root").show();
}
});*/
});
数据结构转换
很多时候我们后端会直接传一个列表回来(如下),那么这时候就需要转换数据形式。
数据结构转换这块懒省事,直接借鉴的大佬【龙恩0707】的博文 js将有父子关系的数据转换成树形结构数据 - 龙恩0707 - 博客园
var nodes = [{
"id":"1",
"name":"1",
"url":"1",
"pid":"root"
},{
"id":"11",
"name":"11",
"url":"11",
"pid":"1"
},{
"id":"12",
"name":"12",
"url":"12",
"pid":"1"
},{
"id":"121",
"name":"121",
"url":"121",
"pid":"12"
},{
"id":"122",
"name":"122",
"url":"122",
"pid":"12"
},{
"id":"2",
"name":"2",
"url":"2",
"pid":"root"
},{
"id":"21",
"name":"21",
"url":"21",
"pid":"2"
},{
"id":"211",
"name":"211",
"url":"211",
"pid":"21"
},{
"id":"22",
"name":"22",
"url":"22",
"pid":"2"
}];
// 属性配置设置
let attr = {
id: 'id',
pid: 'pid',
name: 'name',
url: 'url',
rootId: "root"
};
function toTreeData(data, attr) {
let tree = [];
let resData = data;
//装入一级目录
for (let i = 0; i < resData.length; i++) {
if (resData[i].pid === attr.rootId) {
let obj = {
id: resData[i][attr.id],
name: resData[i][attr.name],
url: resData[i][attr.url],
childNode: [],
};
tree.push(obj);
resData.splice(i, 1);
i--;
}
}
//逐层装入下级
var run = function(treeArrs) {
if (resData.length > 0) {
for (let i = 0; i < treeArrs.length; i++) {
for (let j = 0; j < resData.length; j++) {
if (treeArrs[i].id === resData[j][attr.pid]) {
let obj = {
id: resData[j][attr.id],
name: resData[j][attr.name],
url: resData[i][attr.url],
childNode: [],
};
treeArrs[i].childNode.push(obj);
resData.splice(j, 1);
j--;
}
}
run(treeArrs[i].childNode);
}
}
};
run(tree);
return tree;
}
let arr = toTreeData(nodes, attr);
好久好久以后,20220806再次更新,下面版本适合根节点数目不定的情况,比如不是全树展示,只展示关键字搜索后的结果
function listToTree(menuList) {
let menuTree = [];
if (menuList && menuList.length > 0) {
let pidall = [];
menuList.forEach(m => {
if (pidall.length == 0) {
pidall.push(m.pid);
} else{
let haspid = false;
pidall.forEach(p => {
if (p == m.pid) {
haspid = true;
}
})
if (!haspid) {
pidall.push(m.pid);
}
}
})
let pids = [];
pidall.forEach(p => {
let hasid = false;
menuList.forEach(m => {
if (p == m.id) {
hasid = true;
}
})
if (!hasid) {
pids.push(p);
}
})
var run = function (list,pid) {
let children = [];
for (var i = 0; i < list.length; ) {
if (list[i].pid == pid) {
children.push(list[i]);
list.splice(i,1);
} else {
i++;
}
}
if (children.length > 0) {
children.forEach(child => {
child.children = run(list,child.id);
})
}
return children;
}
pids.forEach(p => {
menuTree.push(run(menuList,p));
})
}
return menuTree;
}
最后
不要觉得简单,就直接复制粘贴!要不发现有的地方有点儿丑,那不是废话吗?好好看看我分析的内容!