像这种可以折叠展开的json可视化功能是如何实现的?

作者站长头像
站长
· 阅读数 12

像这种可以折叠展开的json可视化功能是如何实现的?

回复
1个回答
avatar
test
2024-06-23

answer image

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    .json-view {font-family:Consolas, monospace;}
    .json-view .tpl {display:none;}

    .json-view .k {color:#369;}
    .json-view .k:empty ~ .colon {display:none;}

    .json-view .json-boolean .v {color:#993;}
    .json-view .json-number .v {color:#939;}
    .json-view .json-bigint .v {color:#939;}
    .json-view .json-string .v {color:#393;}
    .json-view .json-null .v {color:#CCC;}

    .json-view a {display:block;}
    .json-view a > .tag-open:before {content:'[+]';margin-right:0.5em;color:#399}
    .json-view a > .tag-ddd {}
    .json-view a > .content {display:none;margin-left:1em;}
    .json-view a.open > .tag-open:before {content:'[-]';color:#F33;}
    .json-view a.open > .tag-ddd {display:none;}
    .json-view a.open > .content {display:block;}

    .json-view a:last-child > .comma {display:none}
    .json-view a .content :last-child > .comma {display:none}
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function(){
        function json_view_create_value($domBase, $domTpl, $tplClass, $key, $v)
        {
            let domTpl, dom;
            domTpl = $domTpl.querySelector($tplClass);
            dom = domTpl.cloneNode(true);

            if(typeof($key) === 'string')
                dom.querySelector('.k').innerHTML = '"'+$key+'"';

            dom.querySelector('.v').innerHTML = $v;
            $domBase.appendChild(dom);
        }
        function json_view_boolean($domBase, $domTpl, $key, $v)
        {
            json_view_create_value($domBase, $domTpl, '.json-boolean', $key, $v ? 'true' : 'false');
        }
        function json_view_number($domBase, $domTpl, $key, $v)
        {
            json_view_create_value($domBase, $domTpl, '.json-number', $key, $v);
        }
        function json_view_bigint($domBase, $domTpl, $key, $v)
        {
            json_view_create_value($domBase, $domTpl, '.json-number', $key, $v);
        }
        function json_view_string($domBase, $domTpl, $key, $v)
        {
            json_view_create_value($domBase, $domTpl, '.json-string', $key, '"'+$v+'"');
        }
        function json_view_null($domBase, $domTpl, $key, $v)
        {
            json_view_create_value($domBase, $domTpl, '.json-null', $key, 'null');
        }
        function json_view_array($domBase, $domTpl, $key, $arr)
        {
            let domTpl, dom;
            domTpl = $domTpl.querySelector('.json-array');
            dom = domTpl.cloneNode(true);

            if(typeof($key) === 'string')
                dom.querySelector('.k').innerHTML = '"'+$key+'"';

            dom.addEventListener('click', function($evt){
                if($evt.target.classList.contains('tag-ac') === false)
                    return;
                
                let domContent = dom.querySelector(':scope > .content');
                if(this.classList.contains('open') === true)
                {
                    this.classList.remove('open');
                }
                else
                {
                    if(domContent.classList.contains('none') === true)
                    {
                        if(typeof($key) === 'string')
                            dom.querySelector('.k').innerHTML = '"'+$key+'"';

                        domContent.classList.remove('none');
                        for(let i=0; i<$arr.length; i++)
                        {
                            json_view(domContent, $domTpl, null, $arr[i]);
                        }
                    }
                    this.classList.add('open');
                }

                $evt.stopPropagation();
            });
            $domBase.appendChild(dom);
        }
        function json_view_object($domBase, $domTpl, $key, $ob)
        {
            let domTpl, dom;
            domTpl = $domTpl.querySelector('.json-object');
            dom = domTpl.cloneNode(true);

            if(typeof($key) === 'string')
                dom.querySelector('.k').innerHTML = '"'+$key+'"';

            dom.addEventListener('click', function($evt){
                if($evt.target.classList.contains('tag-ac') === false)
                    return;

                let domContent = dom.querySelector(':scope > .content');
                if(this.classList.contains('open') === true)
                {
                    this.classList.remove('open');
                }
                else
                {
                    if(domContent.classList.contains('none') === true)
                    {
                        if(typeof($key) === 'string')
                            dom.querySelector('.k').innerHTML = '"'+$key+'"';

                        domContent.classList.remove('none');
                        for(let key in $ob)
                        {
                            json_view(domContent, $domTpl, key, $ob[key]);
                        }
                    }
                    this.classList.add('open');
                }

                $evt.stopPropagation();
            });
            $domBase.appendChild(dom);
        }
        function json_view($domBase, $domTpl, $key, $json)
        {
            let mapView = {
                'boolean' : json_view_boolean,
                'number' : json_view_number,
                'bigint' : json_view_bigint,
                'string' : json_view_string,
                'null' : json_view_null,
                'array' : json_view_array,
                'object' : json_view_object,
            };

            let type = typeof($json);
            if(type === 'object')
            {
                if($json === null) type = 'null';
                else if(Array.isArray($json) === true) type = 'array';
            }

            if(type in mapView === false)
                throw 'invalid type ['+type+']';

            mapView[type]($domBase, $domTpl, $key, $json);
        }

        let json = {
            'null' : null,
            'number' : 123,
            'string' : 'abc',
            'array' : [null, 123, 'abc', false, {
                'null' : null,
                'number' : 123,
                'string' : 'abc',
            }],
            'object' : {
                'boolean' : true,
            },
        };
        let domRoot = document.querySelector('.json-view .json-root');
        let domTpl  = document.querySelector('.json-view .tpl');
        json_view(domRoot, domTpl, null, json);
    });
    </script>
</head>
<body>
<div class="json-view">
    <div class="json-root"></div>
    <div class="tpl">
        <div class="json-boolean">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="v"></span>
            <span class="comma">,</span>
        </div>
        <div class="json-number">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="v"></span>
            <span class="comma">,</span>
        </div>
        <div class="json-bigint">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="v"></span>
            <span class="comma">,</span>
        </div>
        <div class="json-string">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="v"></span>
            <span class="comma">,</span>
        </div>
        <div class="json-null">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="v"></span>
            <span class="comma">,</span>
        </div>
        <a class="json-array">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="tag-ac tag-open">[</span><span class="tag-ac tag-ddd">...</span><div class="content none"></div><span class="tag-ac tag-close">]</span>
            <span class="comma">,</span>
        </a>
        <a class="json-object">
            <span class="k"></span>
            <span class="colon">:</span>
            <span class="tag-ac tag-open">{</span><span class="tag-ac tag-ddd">...</span><div class="content none"></div><span class="tag-ac tag-close">}</span>
            <span class="comma">,</span>
        </a>
    </div>
</div>
</body>
</html>
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容