javascript 将页面上的JSON数据显示为可展开/可折叠列表

hmae6n7t  于 2022-11-27  发布在  Java
关注(0)|答案(4)|浏览(552)

我需要帮助与显示JSON数据在一个页面上,如可展开/可折叠的列表。
下面是我用Python从XML转换而来的一个有效JSON:
JSON Data
我用这个来展示它

<!DOCTYPE HTML>
<head>
    <title>JSON Tree View</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js" type="text/javascript"></script>

</head>
<script>
function json_tree(object){
        var json="<ul>";
        for(prop in object){
            var value = object[prop];
            switch (typeof(value)){
                case "object":
                    var token = Math.random().toString(36).substr(2,16);
                    json += "<li><a class='label' href='#"+token+"' data-toggle='collapse'>"+prop+"="+value+"</a><div id='"+token+"' class='collapse'>"+json_tree(value)+"</div></li>";
                break;
                default:
                json += "<li>"+prop+"="+value+"</li>";
            }
        }
        return json+"</ul>";
}
</script>
<body style="margin: 40px;">
<h3>Paste JSON Into The Textarea Below and Click 'Build Tree'</h3>

<textarea id="json" style="width: 100%;min-height:300px;">

</textarea>
<button onclick="$('#output').html(json_tree(JSON.parse($('#json').val())));">Build Tree</button>
<div id="output">

</div>
</body>
</html>

这是我得到的:
Image
我需要帮助“过滤”(或与上级节点合并)那些“0”和“1”,以及-如何只显示属性的值而不显示名称(或者如果你有一些更好的想法,我如何可以dusplay这个列表)?

btqmn9zl

btqmn9zl1#

a美观、紧凑、可折叠的树视图

pgrabovets' json-view是惊人的干净和良好的设计。
checkout the demo

uttx8gqw

uttx8gqw2#

如果可以考虑使用JS库,请考虑使用JSON FormatterRender JSON。这两个库都提供了主题、最大深度和排序等配置选项。要使用Render JSON以可折叠的形式显示简单的JSON字符串,可以使用

<script>
    document.getElementById("test").appendChild(
        renderjson({ hello: [1,2,3,4], there: { a:1, b:2, c:["hello", null] } })
    );
</script>
cld4siwp

cld4siwp3#

有些问题的链接已经无法访问了。我假设您正在寻找如何制作一个可折叠的JSON视图。

TL;DR

您可以跳至完整代码
代码很短(200行↓,包括JSDoc、注解、测试代码。)

启发您如何解决问题。

这道题在某些技巧上很像如何制作目录.(TOC)
1.首先,JSON数据就像一个对象,我们所要做的就是为每个项添加更多的属性(key、depth、children...)。
1.完成这些操作后,剩下的就是render,下面是用于呈现的伪代码。

render(node) {
  const divFlag = document.createRange().createContextualFragment(`<div style="margin-left:${node.depth * 18}px"></div>`)
  const divElem = divFlag.querySelector("div")
  const spanFlag = document.createRange().createContextualFragment(
    `<span class="ms-2">${node.key} : ${node.value}</span>`
  )
  node.children.forEach(subNode => {
    const subElem = render(subNode)
    spanFlag.append(subElem)
  })
  divElem.append(spanFlag)
  return divElem
}

完整代码

两个CSS都不是必需。

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossOrigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
      integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
      crossOrigin="anonymous" referrerpolicy="no-referrer"/>

<script type="module">
  // 👇 main script {Node, Tree, JsonView}
  class Node {
    /**
     * @description Add more attributes to the item.
     * @param {*} item
     * @param {*} key
     * @param {Node} parent
     * */
    constructor(item, key, parent) {
      this.key = key

      /** @param {string} */
      this.type = Array.isArray(item) ? "array" : typeof item

      /** @param {Number} */
      this.depth = parent ? parent.depth + 1 : 0
      this.value = item
      this.parent = parent

      /** @param {[Node]} */
      this.children = []
    }
  }

  class Tree {
    /**
     * @description Given the root node, it will complete the children of it.
     * @param {Node} rootNode
     */
    constructor(rootNode) {
      this.root = rootNode

      const obj = this.root.value
      if (!(obj instanceof Object)) { // Array is an Object too.
        return
      }
      Object.keys(obj).forEach(keyOrIdx => {
        const value = obj[keyOrIdx]
        const subNode = new Node(value, keyOrIdx, rootNode)
        const subTree = new Tree(subNode)
        rootNode.children.push(subTree.root)
      })
    }

    /**
     * @param {string | Object} jsonData
     * @return {Tree}
     */
    static CreateTree(jsonData) {
      jsonData = typeof jsonData === "string" ? JSON.parse(jsonData) : jsonData
      const rootNode = new Node(jsonData, "root", null)
      return new Tree(rootNode)
    }
  }

  class JsonView {
    static DefaultColorMap = {
      text: {
        string: "green",
        number: "#f9ae58",
        boolean: "#ca4ff8",
        array: "black",
        object: "black",
      },
      bg: {
        object: undefined,
        // ... You can add more by yourself. They are like the text as above.
      }
    }

    static NewConfig() {
      return JSON.parse(JSON.stringify(JsonView.DefaultColorMap))
    }

    static SEPARATOR = " : "

    /** @type {Tree} */
    #tree

    /**
     * @param {Tree} tree
     * */
    constructor(tree) {
      this.#tree = tree
    }

    /**
     * @param {Node} node
     * @param {Object} colorMap
     */
    #render(node, colorMap = JsonView.DefaultColorMap) {
      /**
       * @param {Node} node
       * */
      const getValue = (node) => {
        const typeName = node.type
        switch (typeName) {
          case "object":
            return `object {${Object.keys(node.value).length}}`
          case "array":
            return `array [${Object.keys(node.value).length}]`
          default:
            return node.value
        }
      }

      const arrowIcon = ["object", "array"].includes(node.type) ? `<i class="fas fa-caret-down"></i>` : ""
      const divFlag = document.createRange().createContextualFragment(`<div style="margin-left:${node.depth * 18}px">${arrowIcon}</div>`)
      const divElem = divFlag.querySelector("div")

      const textColor = colorMap.text[node.type] !== undefined ? `color:${colorMap.text[node.type]}` : ""
      const bgColor = colorMap.bg[node.type] !== undefined ? `background-color:${colorMap.bg[node.type]}` : ""
      const valueStyle = (textColor + bgColor).length > 0 ? `style=${[textColor, bgColor].join(";")}` : ""

      const keyName = node.depth !== 0 ? node.key + JsonView.SEPARATOR : "" // depth = 0 its key is "root" which is created by the system, so ignore it.
      const spanFlag = document.createRange().createContextualFragment(
        `<span class="ms-2">${keyName}<span ${valueStyle}>${getValue(node)}</span></span>`
      )

      const isCollapsible = ["object", "array"].includes(node.type)

      node.children.forEach(subNode => {
        const subElem = this.#render(subNode, colorMap)

        if (isCollapsible) {
          divFlag.querySelector(`i`).addEventListener("click", (e) => {
            e.stopPropagation()
            subElem.dataset.toggle = subElem.dataset.toggle === undefined ? "none" :
              subElem.dataset.toggle === "none" ? "" : "none"

            e.target.className = subElem.dataset.toggle === "none" ? "fas fa-caret-right" : "fas fa-caret-down" // Change the icon to ▶ or ▼

            subElem.querySelectorAll(`*`).forEach(e => e.style.display = subElem.dataset.toggle)
          })
        }

        spanFlag.append(subElem)
      })
      divElem.append(spanFlag)
      return divElem
    }

    /**
     * @param {Element} targetElem
     * @param {?Object} colorMap
     */
    render(targetElem, colorMap = JsonView.DefaultColorMap) {
      targetElem.append(this.#render(this.#tree.root, colorMap))
    }
  }

  // 👇 Below is Test
  function main(outputElem) {
    const testObj = {
      db: {
        port: 1234,
        name: "My db",
        tables: [
          {id: 1, name: "table 1"},
          {id: 2, name: "table 2"},
        ],
      },
      options: {
        debug: false,
        ui: true,
      },
      person: [
        "Foo", 
        "Bar"
      ]
    }
    const tree = Tree.CreateTree(testObj)
    const jsonView = new JsonView(tree)
    jsonView.render(outputElem)
    /* If you want to set the color by yourself, you can try as below
    const config = JsonView.NewConfig()
    config.bg.object = "red"
    jsonView.render(outputElem, config)
     */
  }

  (() => {
    window.onload = () => {
      main(document.body)
    }
  })()
</script>
  • 普通JavaScript*
j0pj023g

j0pj023g4#

我用卡森回复,它的工作就像魅力,但空对象的问题,因为woto说。改变脚本。

const getValue = (node) => {
        const typeName = node.type
        switch (typeName) {
          case "object":
            if (node.value !== null)
                return `object {${Object.keys(node.value).length}}`
            else
                return 'null'
          case "array":
            if (node.value !== null)
                return `array {${Object.keys(node.value).length}}`
            else
                return 'null'
          default:
            if (node.value !== null)
                return node.value
            else
                return 'null'
        }
      }

相关问题