一、需求:
做一个部门的结构树,样子大概是如下图这样展示:
示例图
二、分析:
做成这样的一个效果图,虽然可以写但会比较麻烦,其实现在是有很多这样的前端控件帮我们实现,只需要我们按照要求传递数据即可,这就不需要重复造轮子。
例如:Esay UI的tree控件,Echarts的图表展示,这两个都是常用的。
本文就是用Echarts来展示结构树。
三、Echarts的基本使用
Echarts的使用很简单,只需要从官网下载引入js文件,或直接引入CDN<script src="https://cdn.bootcss.com/echarts/4.4.0-rc.1/echarts.min.js"></script>
然后只需要在js里调用,并传JSON数据即可,直接看我下方代码例子,应该都能看懂的,至于有关于Echarts的其他参数的配置说明,可以再自行查看官网。
//展示结构树的容器
<div id="item" style="width:1200px; height: 500px;">
<script>
//初始化echarts实例
var myChart = echarts.init(document.getElementById('item'));
//使用制定的配置项和数据显示图表
//myChart.showLoading(); //显示Loading标志;
//$.get('data/asset/data/flare.json', function (data) {
// myChart.hideLoading(); //得到数据后隐藏Loading标志
// echarts.util.each(data.children, function (datum, index) {
// index % 2 === 0 && (datum.collapsed = true);
// }); //间隔展开子数据,animate,display,physics,scale,vis是展开的
option = {
calculable: false,
tooltip: {
// show:'true',//默认:true;是否显示提示框组件,包括提示框浮层和 axisPointer。
trigger: 'item',//默认:item;触发类型。item:数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。'axis':座标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。'none':什么都不触发。
//formatter: '{b}:{c}',
hideDelay: 0 // chart.refresh();刷新时会维持当时图表的所有状态,所以设置隐藏延迟为0,否则在快速选择另一个节点时(尤其是数据比较多时)导致无法显示选择中的tooltip
//无法完全避免但是很大减轻了副作用
},
series: [
{
name: '树图',
type: 'tree',
orient: 'vertical', // vertical horizontal
rootLocation: { x: 'center', y: 30 }, // 根节点位置 {x: 100, y: 'center'}
nodePadding: 50,//节点间距
symbolSize: 50,//tree图上的原型的大小
//symbol: 'circle',
//roam: true,//设置次参数后,针对该图表可以放大和缩小,移动
initialTreeDepth: 3,//初始显示节点深度
itemStyle: {
normal: {
label: {
show: true,
formatter: "{b}",
position: 'inside',
textStyle: {
color: '#000',
fontSize: 12,
fontWeight: 'bolder'
}
},
lineStyle: {
color: '#48b',
shadowColor: '#000',
shadowBlur: 4,
shadowOffsetX: 3,
shadowOffsetY: 5,
type: 'curve' // 'curve'|'broken'|'solid'|'dotted'|'dashed'
}
},
emphasis: {
label: {
show: true
}
}
},
data: [
{
name: '根节点',
value: 6,
children: [
{
name: '节点1',
value: 4,
children: [
{
name: '叶子节点1',
value: 4
},
{
name: '叶子节点2',
value: 4
},
{
name: '叶子节点3',
value: 2
}
]
},
{
name: '节点2',
value: 4,
children: [{
name: '叶子节点7',
value: 4
},
{
name: '叶子节点8',
value: 4
}]
},
{
name: '节点3',
value: 1,
children: [
{
name: '叶子节点9',
value: 4
},
{
name: '叶子节点10',
value: 4
},
{
name: '叶子节点11',
value: 2
},
{
name: '叶子节点12',
value: 2
}
]
},
{
name: '节点8',
value: 1,
children: [
{
name: '叶子节点9',
value: 4
},
{
name: '节点2',
value: 4,
children: [{
name: '叶子节点7',
value: 4
},
{
name: '叶子节点8',
value: 4
}]
}
]
}
]
}
]
}
]
};
myChart.setOption(option);
</script>
Echarts官方示例
四、递归构建JSON
所以,从上面的Echarts使用可以知道,我们接下来需要做的就是生成一个对应结构的json传递到前端。
先说明一下,我的数据特点,ID
是主键,不存在会有相同列的数据,NAME_SHORT
就是一个展示名称,BELONG_ID
表示一个层级关系,相同根节点下的子节点,BELONG_ID
相同,数据取自ID
。
1. 建立用来保存树结构数据的目标对象
public class TreeObject
{
public string name { get; set; }
public string value { get; set; }
public IList<TreeObject> children = new List<TreeObject>();
public void Addchildren(TreeObject node)
{
this.children.Add(node);
}
}
2.查询表获得数据源
/// <summary>
///数据库的连接字符串
/// </summary>
private static readonly string connstr = @"server=.;database=userInfo;uid=sa;pwd=123456";;
public DataTable getTable(string cmdText)
{
using (SqlConnection cnn = new SqlConnection(connstr))
{
using (SqlCommand comm = new SqlCommand(cmdText, cnn))
{
comm.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = comm;
DataTable mytable = new DataTable();
da.Fill(mytable);
return mytable;
}
}
}
public DataTable GetDataTable()
{
string sql = @"select ID,NAME_SHORT,BELONGTO_ID
from UserInfo
order by BELONGTO_ID"
;
DataTable dt = getTable(sql);
return dt;
}
3.递归循环生成树
//全局变量用于保存数据
public List<TreeObject> treeNodes = new List<TreeObject>();
//建立树的递归方法
/// </summary>
/// <param name="dtSource">数据源</param>
/// <param name="parentNode">父节点</param>
/// <param name="parentID">节点的归属ID</param>
public void BindTree(DataTable dtSource, TreeObject parentNode, string parentID)
{
DataRow[] rows = dtSource.Select(string.Format("BELONGTO_ID={0}", parentID));
foreach (DataRow row in rows)
{
TreeObject tree = new TreeObject();
tree.name = row["NAME_SHORT"].ToString();
tree.value = row["ID"].ToString();
//递归性质,函数内调用自身函数
BindTree(dtSource, tree, row["ID"].ToString());
//递归结束的终点条件
if (parentNode == null)
{
treeNodes.Add(tree);
}
else
{
parentNode.children.Add(tree);
}
}
}
4.调用
//调用SQL,获取数据源
DataTable dt = GetDataTable();
//调用递归函数,传入数据源,根节点
BindTree(dt, null, "0");
//反序列化对象,生成json字符串
string jsonData = JsonConvert.SerializeObject(treeNodes);
return jsonData;
5.效果
[{
"name": 'A',
"value": '10000',
"children": [{
"name": 'B1',
"value": '10002',
"children": [{
"children": [],
"name": 'C',
"value": '10007'
},
{
"children": [],
"name": 'D',
"value": '10008'
},
{
"children": [],
"name": 'E',
"value": '10009'
}
]
},
{
"name": 'B2',
"value": '10003',
"children": [{
"children": [],
"name": 'F',
"value": '10010'
},
{
"children": [],
"name": 'G',
"value": '10011'
}
]
},
{
"name": 'B3',
"value": '10004',
"children": [{
"children": [],
"name": 'H',
"value": '10012'
},
{
"children": [],
"name": 'I',
"value": '10013'
},
{
"children": [],
"name": 'J',
"value": '10014'
}
]
},
{
"name": 'B4',
"value": '10005',
"children": [{
"children": [],
"name": 'K',
"value": '10015'
},
{
"name": 'L',
"value": '10016',
"children": [{
"children": [],
"name": 'L1',
"value": '10017'
},
{
"children": [],
"name": 'L2',
"value": '10018'
}
]
}
]
}
]
}]
效果图
五、总结
以上就是全部代码了,从代码来说,不难,整个过程就是引入Echarts,传递json数据。
因此最需要做的就是生成对应结构的json,而做这些循环嵌套,使用递归逐步深入还是比较简单,可能先尝试递归两三层来找到递归的规律,这个还是需要根据自己数据结构来做。