简单树型列表(展示,编辑用)

千万年想起来发一篇博文,博大家一乐吧。

首先感谢大佬【龙恩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;
		}

最后

不要觉得简单,就直接复制粘贴!要不发现有的地方有点儿丑,那不是废话吗?好好看看我分析的内容!

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值