JavaScript对象的图形表示(Tree-View)?

问题描述 投票:1回答:2

我有一个问题,我无法自己解决。我有一个所谓的GROUPS的JavaScript对象。每个组可以有一个或多个子组,也可以有所谓的系统。

我现在的任务是以图形方式显示此结构 - 一种树视图(彩色DIV元素)。但是我不知道如何阅读这个对象以便以图形方式构建它。

我的对象:

const test = {
      grp: [
        {
          groupID: 'group-1',
          grp : [
            {
              groupID: 'group-2',
              grp: [
                {
                  groupID: 'group-3',
                  sys: ['sys1','sys2','sys3']
                },
                {
                  groupID: 'group-4',
                  grp: [
                    {
                      groupID: 'group-5',
                      sys: ['sys4','sys5','sys6']
                    },
                    {
                      groupID: 'group-6',
                      grp: [
                        {
                          groupID: 'group-7',
                          sys: ['sys7','sys8','sys9']
                        }
                      ]
                    }
                  ]
                }
              ],
              sys: ['sys0']
            }
          ]
        }
      ]
    };

这是一个图形示例:https://pic-hoster.net/view/69453/grp-sys.jpg.htm

我非常希望有人可以帮助我。你将如何处理这项任务?

JavaScript对象的图形表示(Tree-View)

javascript object ecmascript-6 treeview recursive-datastructures
2个回答
0
投票

这里重要的是识别您的数据结构,以便您可以递归地攻击问题。

在您的情况下,您的组可以像这样定义:

{ groupID: string, sys?: string[], grp?: IGroup[] }

IGroup定义了上述结构)

所有组都有groupID,有些有sys,有些有grp儿童。

从这里我们可以定义一个逻辑如下的函数:

  1. 为当前组生成两行结构。
  2. 对于每个sys子元素(如果存在),使用sys值将单元格添加到顶行。
  3. 对于每个grp子元素(如果存在),调用此函数并将返回的结构附加到顶行的单​​元格中。
  4. 将单元格插入子元素colspan宽度的底行。将单元格内容设置为当前的grp groupID
  5. 返回两行结构元素,或者作为递归构建过程或作为最终结果。

以下是上述几点的粗略实现:

function groupToHTML(grp) {
    //Table to append to and return
    var container = document.createElement("table");
    container.border = "1";
    container.style.borderCollapse = "collapse";
    //Insert row to children of this node
    var childRow = container.appendChild(document.createElement("tr"));
    //Append all "sys" elements as cells
    if (grp.sys !== void 0) {
        for (var sysIndex = 0; sysIndex < grp.sys.length; sysIndex++) {
            var sys = grp.sys[sysIndex];
            var sysCell = childRow.appendChild(document.createElement("td"));
            sysCell.innerHTML = sys;
            sysCell.style.backgroundColor = "red";
            sysCell.style.verticalAlign = "bottom";
        }
    }
    //Append all "grp" children by calling "groupToHTML" on them and appending the returning table
    if (grp.grp !== void 0) {
        for (var grpIndex = 0; grpIndex < grp.grp.length; grpIndex++) {
            var child = grp.grp[grpIndex];
            var grpCell = childRow.appendChild(document.createElement("td"));
            grpCell.appendChild(groupToHTML(child));
            grpCell.style.verticalAlign = "bottom";
        }
    }
    //Add a row and cell for "this" grp
    var thisRow = container.appendChild(document.createElement("tr"));
    var thisCell = thisRow.appendChild(document.createElement("th"));
    thisCell.innerHTML = grp.groupID;
    thisCell.style.textAlign = "center";
    //Set cell colspan to number of child elements
    thisCell.colSpan = Math.max(1, (grp.grp !== void 0 ? grp.grp.length : 0) + (grp.sys !== void 0 ? grp.sys.length : 0));
    //Return table
    return container;
}
//TEST
//testdata
var data = {
    groupID: 'group-1',
    grp: [
        {
            groupID: 'group-2',
            grp: [
                {
                    groupID: 'group-3',
                    sys: ['sys1', 'sys2', 'sys3']
                }, {
                    groupID: 'group-4',
                    grp: [
                        {
                            groupID: 'group-5',
                            sys: ['sys4', 'sys5', 'sys6']
                        }, {
                            groupID: 'group-6',
                            grp: [
                                {
                                    groupID: 'group-7',
                                    sys: ['sys7', 'sys8', 'sys9']
                                }
                            ]
                        }
                    ]
                }
            ],
            sys: ['sys0']
        }
    ]
};
//Initiate
var node = groupToHTML(data);
//Append
document.body.appendChild(node);

0
投票

您可以使用递归函数为每个grp及其系统创建嵌套级别。因此每个级别都有名称和子元素。子元素将是嵌套组和系统。

纯粹的JavaScript解决方案

const test = {"grp":[{"groupID":"group-1","grp":[{"groupID":"group-2","grp":[{"groupID":"group-3","sys":["sys1","sys2","sys3"]},{"groupID":"group-4","grp":[{"groupID":"group-5","sys":["sys4","sys5","sys6"]},{"groupID":"group-6","grp":[{"groupID":"group-7","sys":["sys7","sys8","sys9"]}]}]}],"sys":["sys0"]}]}]}

function tree(data, parent) {
  if(data.grp) {
    data.grp.forEach(obj => {
      const child = document.createElement('div')
      child.className = 'child'

      const children = document.createElement('div')
      children.className = 'children'

      if(obj.groupID) {
        const name = document.createElement('div');
        name.className = 'name'
        name.textContent = obj.groupID
        child.appendChild(name)
      }

      if(obj.sys) {
        const system = document.createElement('div')
        system.className = 'system';

        obj.sys.forEach(s => {
          const sys = document.createElement('div')
          sys.className = 'item'
          sys.textContent = s
          system.appendChild(sys)
        })

        children.appendChild(system)
      }

      child.appendChild(children)
      parent.appendChild(child)
      tree(obj, children)
    })
  }
}

const root = document.body.querySelector('#root')
tree(test, root)
#root * {
  color: white;
}

.system {
  background: #E00022;
  display: flex;
  flex-direction: column-reverse;
  padding: 10px;
}

.name {
  background: #595959;
  padding: 10px;
}

.child {
  display: flex;
  flex-direction: column-reverse;
}

.children {
  display: flex;
  align-items: flex-end;
}

.children > div {
  flex: 1;
  border-bottom: 1px solid white;
}
<div id="root"></div>

反应解决方案

const {Component} = React;
const data = {"grp":[{"groupID":"group-1","grp":[{"groupID":"group-2","grp":[{"groupID":"group-3","sys":["sys1","sys2","sys3"]},{"groupID":"group-4","grp":[{"groupID":"group-5","sys":["sys4","sys5","sys6"]},{"groupID":"group-6","grp":[{"groupID":"group-7","sys":["sys7","sys8","sys9"]}]}]}],"sys":["sys0"]}]}]}

class Systems extends Component {
  render() {
    const { data } = this.props;
    return <div className="systems">
      {data.map((sys, i) => (
        <div key={i} className="system">{sys}</div>
      ))}
    </div>
  }
}

class Group extends Component {
  render() {
    const { data } = this.props;
    return data.map((group, i) => (
      <div key={i} className="group">
        {group.groupID && <div className="group-name">{group.groupID}</div>}
        <div className="children">
          {group.sys && <Systems data={group.sys} />}
          {group.grp && <Group data={group.grp} />}
        </div>
      </div>
    ))
  }
}

class App extends Component {
  state = {
    data: {}
  }

  componentWillMount = () => {
    this.setState({ data: this.props.data })
  }

  render() {
    console.log(this.state)
    return <div className="root">
      <Group data={this.state.data.grp} />
    </div>
  }
}

ReactDOM.render(
  <App data={data} />,
  document.getElementById('container')
);
#root * {
  color: white;
}

.group {
  display: flex;
  flex-direction: column-reverse;
}

.group-name {
  background: rgb(89, 89, 89);
  padding: 10px;
  color: white;
  border-top: 1px solid white;
}

.group-name {
  opacity: 0.85;
  transition: all 0.25s;
}

.children {
  display: flex;
}

.children > * {
  flex: 1;
}

.systems {
  display: flex;
  flex-direction: column-reverse;
}

.system {
  background: red;
  color: white;
  padding: 10px;
  opacity: 0.6;
  transition: all 0.25s;
  border-top: 1px solid white;
}

.system:hover,
.group-name:hover{
  opacity: 1;
}

.as-console-wrapper {
  display: none !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
© www.soinside.com 2019 - 2024. All rights reserved.