【问题标题】:Graphical representation (Tree-View) of a JavaScript object?JavaScript 对象的图形表示(树视图)?
【发布时间】:2019-09-06 06:51:36
【问题描述】:

我有一个自己无法解决的问题。 我有一个带有所谓 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 对象的图形表示(树视图)

【问题讨论】:

  • 首先确定一个对象是否是另一个对象的子对象 - 然后遍历树,边走边创建 DOM 节点。
  • 这正是我要问的,我如何确定我是否在第 5 组中,例如,这是第 4、2 和 1 组的子元素?

标签: javascript object ecmascript-6 treeview recursive-datastructures


【解决方案1】:

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

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

{ 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);

【讨论】:

    【解决方案2】:

    您可以使用递归函数为每个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;
    }
    &lt;div id="root"&gt;&lt;/div&gt;

    反应解决方案

    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>

    【讨论】:

    • 非常感谢,在您的帮助下,我可以毫无问题地继续我的项目。
    • 很高兴能帮上忙。
    • 嗨 Nenad (pozdrav :) 你对 React 有什么了解吗?我应该把它全部花在 React 上,但我无法处理循环。在 React 中会是什么样子?
    • @user11274144 使用 React 解决方案更新了答案。
    • 完美!非常感谢您的努力和帮助。
    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 2019-11-04
    相关资源
    最近更新 更多