说点没用的
年轻的时候一直想做个程序员,现在年龄越来越大,离志愿越来越远了,只能在空闲的时候拿来玩玩了。最近闲来无事,想给自己的小公司编一个BS结构的管理小应用。没想到要学习这么多东西,PYTHON、DJANGO、HTML、JS、JQ、CSS… …持续晕菜中。
为什么要写这段代码
我的小项目里,经常需要将很多数据从数据库中取出,转变为多层次的JSON数据,在前端展示。这里展示的是其中的一种,组织机构图。
写了一个比较通用的小代码段。以后可以反复应用。本人学习JS时间比较短,没有掌握到这种语言的精髓,代码还没有优化。一些地方写的还有点蹩脚,好在功能基本实现了,今后还要在些基础上不断优化,不断完善功能。
强烈希望这里的各位路过的大神留言批评,提出修改意见。我先在此谢过!
为了运行这段代码,你还需要自己找一些东西
- JQUERY.JS 。这个不用多说了。
- SVG.JS 。这个是画线用的,顺便吐槽一个,HTML画线可真费事。
- 把这两个(下载后改一下名,或在代码中改一下)都放在与本文.html文件同一目录下,就可以用了。
运行后是这样的
基本思路
- 将数据分层,每一层数据用一个容器包裹;
- 将同一层的数据按上一层父元素的位置顺序排列;
- 计算每个数据DOM的上下连线点;
- 用本层各数据DOM的上连接点与父级元素的下连接点连线。
- 以后还要完善 增、删、改功能
- 以后还要进行美化
一段真实可用的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="jquery-3.5.1.min.js"></script>
<script src="svg.min"></script>
<style>
*{
padding: 0;
margin: 0;
}
svg{
position: absolute;
overflow:visible;
align-self:baseline;
}
.treeBox{
background-color: aqua;
}
.treeBox .items div{
text-align: center;
margin-top: 50px;
margin-bottom: 50px;
}
.treeBox .line{
width: 0;
height: 1px;
background-color: khaki;
}
.treeBox div span{
text-align: center;
border-style: solid;
border-width: 1px;
border-radius: 4px;
padding: 2px 7px;
margin-left: 20px;
margin-right: 20px;
}
.treeBox .domTreeLevel1 .position_0_0{
background-color:brown;
}
</style>
<title>Document</title>
</head>
<body>
<div class='treeBox'></div>
</body>
</html>
<script>
// 这里是JSON数据,是组织图的数据基础
jsonData=[
{"pk":0,"description":'1,0','level':1,'parent':null,'operate':''},
{"pk":2,"description":'3,2','level':3,'parent':1,'operate':''},
{"pk":3,"description":'3,3','level':3,'parent':1,'operate':''},
{"pk":0,"description":'3,0','level':3,'parent':1,'operate':''},
{"pk":1,"description":'3,1','level':3,'parent':0,'operate':''},
{"pk":2,"description":'4,2','level':4,'parent':1,'operate':''},
{"pk":3,"description":'4,3','level':4,'parent':2,'operate':''},
{"pk":0,"description":'4,0','level':4,'parent':0,'operate':''},
{"pk":1,"description":'4,1','level':4,'parent':2,'operate':''},
{"pk":4,"description":'4,4','level':4,'parent':1,'operate':''},
{"pk":1,"description":'2,1','level':2,'parent':0,'operate':''},
{"pk":0,"description":'2,0','level':2,'parent':0,'operate':''},
]
//数据元素,用于记录一个数据点要表达的内容
function DataItem(dataObj){
this.dataItem=dataObj; //记录原始数据
this.domObj; //记录用于显示数据的DOM
this.uperLevelDom; //上一级数据的DOM
this.domTopPoint={}; //这是一个点坐标,记录着DOM元素上部连线点的位置
this.domBottomPoint={}; //这是一个点坐标,记录着DOM元素下部连线点的位置
this.toString=function(){
return this.dataItem["description"];
}
this.valueOf=function(){
return Number(this.dataItem["pk"]);
}
this.parent=function(strParent){ //返回点的PK(标识),数字类型
return strParent?this.dataItem["parent"]=strParent:this.dataItem["parent"];
}
this.resetLinkPoint=function(){ //重新计算连线点
var left = this.domObj.position().left;
var top = this.domObj.position().top;
var width = this.domObj.outerWidth(true);
var height = this.domObj.outerHeight(true);
this.domTopPoint = {x:left+width/2,y:top};
this.domBottomPoint = {x:left+width/2,y:top+height};
}
this.getTopPoint=function(){ //取得上部连线点
return [this.domTopPoint.x,this.domTopPoint.y];
}
this.getBottomPoint=function(){ //取得下部连线点
return [this.domBottomPoint.x,this.domBottomPoint.y];
}
return this;
}
//准备显示数据
function MakeTreeData(jsonData) {
//showList结构[{parent的pk:[{对象},{对象}]}, {},{},{}]
this.showList;
this.countLevel;
this.prepareShowList=function(jsonData){
//根据最大层数创建空列表
var maxLevel=0;
$.each(jsonData,function(i,data){
maxLevel=data['level']>maxLevel?data['level']:maxLevel;
})
this.showList=Array.apply(null, {length: maxLevel}).map(() => ([]));
var showList = this.showList;
this.countLevel = maxLevel;
//将数据加入到showList中
$.each(jsonData,function(i,data){
showList[data["level"]-1].push(new DataItem(data));
})
//各层数据根据父元素位置排序
var showList=this.showList;
function findIndex(level,itemPk){//查询数据在列表中的位置
var array=showList[level];
var ret;
$.each(array,function(i,item){
if(item.dataItem["pk"]===itemPk){
ret=i;
return false;
}
})
return ret;
}
$.each(this.showList,function(i,array){
array.sort(function(item1,item2){
if(i>0){
locat1=findIndex(i-1,item1.parent());
locat2=findIndex(i-1,item2.parent());
return locat1>locat2?1:locat1<locat2?-1:0;
}else{
return 0;
}
});
})
}
this.getItem=function(level,pk){
return this.showList[level-1][pk];
}
this.prepareShowList(jsonData);
return this;
}
//形成显示DOM
function makeDomTree(jsonData,jqDomBox){
//形成数据的DOM
jqDomBox.html("");
jqDomBox.append("<div class='line'></div>");
jqDomBox.append("<div class='items'></div>");
var jqDomBoxItems=jqDomBox.children(".items");
$.each(jsonData.showList,function(i,levelList){
var tmpStr = "domTreeLevel"+(i+1);
jqDomBoxItems.append("<div class='"+tmpStr+"'></div>");
$.each(levelList,function(j,item){
str="position_"+i+"_"+j;
strDom="<span class='"+str+"'>"+item.toString()+"</span>";
jqDomBoxItems.children("."+tmpStr).append(strDom);
item.domObj = jqDomBoxItems.children("."+tmpStr).children().last();
if(i != 0){
$.each(jsonData.showList[i-1],function(k,parentItem){
if(item.parent() == parentItem){
item.uperLevelDom = parentItem;
return false;
}
})
}
})
})
//形成各节点DOM的连线点
$.each(jsonData.showList,function(i,levelList){
$.each(levelList,function(i,item){
item.resetLinkPoint();
})
})
//连接
for(var i=jsonData.countLevel-1; i>=1; --i ){
$.each(jsonData.showList[i],function(i,item){
[x1,y1] = item.getTopPoint();
[x2,y2] = item.uperLevelDom.getBottomPoint();
jqDomBox.children(".line").append("<svg><line x1='"+x1+"'' y1='"+y1+"'' x2='"+x2+"'' \
y2='"+y2+"'' style='stroke:rgb(255,0,0);stroke-width:2'/></svg>");
})
}
}
var tmpData = new MakeTreeData(jsonData);
makeDomTree(tmpData,$(".treeBox"));
$(window).resize(function(){
makeDomTree(tmpData,$(".treeBox"))
});
</script>