- 2020-03-23
最近由于疫情的原因,在家里快闷坏了…
这么久没更新是因为在做一些设计上的工作,技术上遇到的问题比较少,今天又遇到一个很有意思的需求,我拿出来给大家展示一下~
页面的最终效果是这样:
得到的json格式
这个需求的主要难点在json格式上,如果想得到上图的样式,那么按照echarts中树状图的官方标准格式应该是这样展示的:
{
"name": "根元素",
"children": [{
"children": [{
"name": '属性1',
"value": '1'
},{
"name": '属性2',
"value": '1'
},{
"name": '属性3',
"value": '1'
},{
"name": '属性4',
"value": '1'
}],
"name": "子元素1"
},{
"children": [{
"children": [{
"name": '属性1',
"value": '1'
},{
"name": '属性2',
"value": '1'
},{
"name": '属性3',
"value": '1'
},{
"name": '属性4',
"value": '1'
}],
"name": "孙子元素"
}],
"name": "子元素2"
}]
}
但是我得到的接口数据是这样的:
{
"name": "根元素",
"children": [{
"children": "属性1:1; 属性2:null; 属性3: null; 属性4:null; ",
"name": "子元素1"
},{
"children": [{
"children": "属性1:1; 属性2:null; 属性3: null; 属性4:null; ",
"name": "孙子元素"
}],
"name": "子元素2"
},{
"children": [{
"children": "属性1:1; 属性2:null; 属性3: null; 属性4:null; ",
"name": "孙子元素1"
}],
"children": [{
"children": "属性1:1; 属性2:null; 属性3: null; 属性4:null; ",
"name": "孙子元素2"
}],
"name": "子元素3"
},{
"children": [{
"children": [{
"children": "属性1:1; 属性2:null; 属性3: null; 属性4:null; ",
"name": "重孙子元素"
}],
"name": "孙子元素"
}],
"name": "子元素4"
}]
}
由于后端同事使用的是map格式返回的数据,所以在格式上肯定是不对的,导致在echarts里面不能正确展示。总之,我们要先对这个json格式进行处理。
将map格式转换为对象数组
可以看到,接口中map返回的是字符串格式,那么先不考虑层级关系,我们先要把它转换成json格式。
//整理json格式 - 将map转换为对象数组
function collationFormat_mapToArr(data){
//因为我的是字符串格式,我就使用截取字符串了
//如果已经是json字符串格式,就可以用for(key in value)直接处理了
var arr = data.split(';');
var newArr = [];
$(arr).each(function(i,item){
if(item.indexOf(":") >= 0){
var tex = item.split(':');
var obj = {
"name": tex[0],
"value": tex[1]
}
newArr.push(obj);
}
})
return newArr;
}
这样,我们就可以用这个方法将字符串转换为json对象了。
注意,要把这个方法单独拿出来写,因为处理层级关系时会有很多地方调用这个方法。
处理层级关系
格式已经处理好了,那么就要开始处理层级关系了。
最简单的马上能想到的方法是遍历节点,在每个children中判断并更改格式。
但是在这个案例中,children所有的层级不确定,有几个children也不确定,我们不能把循环写死,而且那样代码的行数也太多了,显然是不合理的。
那么我们先整理一下思路,画一个逻辑上的流程图。
(不太会用这个流程图哈,大家凑合看看)
然后当根元素遍历结束,我们就可以拿着这个数据画图了。
下面是代码部分,为了便于理解,我把打印的数据留着了,不需要的话可以删掉。
//首先 - 根节点中,遍历子节点
function collationFormat(data){
for(var i = 0; i < data.children.length; i++){
data.children[i] = collationFormat_typeof(data.children[i], i);
console.log(" 第" + i + "个根节点的child处理完成,当前格式为: ", data);
}
console.log("根节点处理完成数据: ",data);
//当结束后调用echarts绘图方法。
draw_chart(data);
}
//其次 - 判断child是否为map格式
function collationFormat_typeof(data, i){
console.log(" ");
console.log(' --------child判断 ' + i + '--------');
if( typeof(data.children) == 'string'){
//已经是最终节点,需要把map转换为对象数组
data.children = collationFormat_mapToArr(data.children);
console.log(" str转换结束,返回数据: ", data.children);
return data;
}else if( typeof(data.children) == 'object'){
//里面还有子节点,需要再次遍历
console.log(" 子节点再次遍历", data);
var newChild = collationFormat_eachChild(data);
console.log("newChild: ",newChild);
return newChild;
}else{
//undefined 没有子元素了
}
}
//再次 - 如果子节点为object格式,则说明子节点内还包括孙子节点,则需要再次遍历child
//这个和根元素的遍历是一样的,但是在根元素遍历结束后需要调用画图方法,所以分开写了
//这里相当于一个循环嵌套,孙子元素和重孙子都会调用这个方法,直到没有map格式的为止
function collationFormat_eachChild(data){
for(var i = 0; i < data.children.length; i++){
data.children[i] = collationFormat_typeof(data.children[i], i);
}
console.log(" 子节点遍历完成,返回数据为: ", data);
return data;
}
以上就是代码部分了。
需要注意的是,这里我使用return返回值来修改源数据,所以return语句很重要,有用,不要删除。
- ps: 我一开始还想为什么会这样返回给我接口数据,我问了一下后端同事,他说不这样的话会有什么冲突(反正我也没记住),然后我想,那好吧…我前端处理一下数据格式好了
费了九牛二虎之力,终于改完之后我才觉得好像有哪里不对…然后我截图问后端同事,“你是想要这种效果吗?”
后端同事答:“不是啊,这些属性在悬浮窗里面显示就可以了”
我:“ !!!∑(゚Д゚ノ)ノ ”
我同事:“ Σ(っ°Д°;)っ ”
我:“… 那我改回来好了 (´¬`)… ”