前言
JSON
平时大家都会用到,都不陌生,今天就一起来实现一个 JSON
的可视化工具。
大概长成下面的样子:
树展示
相比于现有的一些 JSON
格式化工具,我们今天制作的这个小工具会把 JSON
转为树去表示。其中:
- 橙色标签表示
key
- 蓝色标签表示
value
- 绿色标签表示类型:
Number String Object Array Null
左边是一个输入框,右边是一个实时反馈的 JSON
可视化区域。下面来看一下大致的实现思路:
- 当输入框的值变化时,使用
JSON.parse
解析值,如果是一个合法的JSON
,则进行下一步处理;如果不是,则把异常显示出来 - 递归把
JSON
对象解析成数组树的结构,主要会包含以下几个key
:key
唯一标识,后续用做复制路径title
JSON
属性节点key
value
JSON
属性节点值isArrayProps
是否是数组的节点children
子节点type
值类型
const handleParse = useCallback( debounce((value) => { if (!value) { return; } try { const res = JSON.parse(value); setJson(res); setError(null); setUpdateKey((key) => key + 1); setSearchValue(""); } catch (error) { setJson({}); setError(error); } }, 300), [] ); useEffect(() => { handleParse(value); }, [value]);
复制
value
是输入框的输入值,当输入值变化时,解析 JSON
。获取到新的 JSON
值后,开始递归处理,组装成树结构:
const treeData = useMemo(() => { const dfs = (json, parentKey) => { const res = []; const keys = Object.keys(json); for (const index in keys) { const key = keys[index]; const value = json[key]; res[index] = { key: parentKey ? `['${parentKey}']['${key}']` : `['${key}']`, title: key, value: value ? value.toString() : value, isArrayProps: Array.isArray(json), children: typeof value === "object" && value !== null ? dfs(value, key) : [], type: upperFirst( value === null ? "null" : Array.isArray(value) ? "array" : typeof value ), }; } return res; }; try { return dfs(json, ""); } catch (error) { console.log("err", error); return []; } }, [json]);
复制
然后用一个树组件把它渲染出来:
<Tree showIcon showLine titleRender={renderTitle} key={updateKey} treeData={treeData} defaultExpandAll />
复制
其中,我们希望自定义渲染树的每一个节点,所以可以实现一个 titleRender
方法:
const renderTitle = (node) => { return ( <div onClick={() => copy}> {!node.isArrayProps ? <Tag color="orange">{node.title}</Tag> : ""} {node.children.length === 0 && node.value ? ( <Tag color="blue">{node.value}</Tag> ) : ( "" )} <Tag color="green">{node.type}</Tag> </div> ); };
复制
这样就完成了基础的功能逻辑及渲染
搜索
这里我们拓展一个根据关键词搜索的功能,既可以搜索 key
,也可以搜索 value
。
用到一个 Search
组件来搜集 keyword
。
<Input.Search style={{ marginBottom: 8 }} placeholder="Search" onChange={(e) => setSearchValue(e.target.value)} />
复制
然后当 keyword
变化的时候,去匹配树节点中的属性值,如果匹配到了,就把对应的值标红。
const renderTitle = (node) => { const highlight = (strTitle) => { const index = strTitle.indexOf(searchValue); const beforeStr = strTitle.substring(0, index); const afterStr = strTitle.slice(index + searchValue.length); const title = index > -1 ? ( <span> {beforeStr} <span style={{ color: "red" }}>{searchValue}</span> {afterStr} </span> ) : ( <span>{strTitle}</span> ); return title; }; return ( <div onClick={() => copy}> {!node.isArrayProps ? ( <Tag color="orange">{highlight(node.title)}</Tag> ) : ( "" )} {node.children.length === 0 && node.value ? ( <Tag color="blue">{highlight(node.value)}</Tag> ) : ( "" )} <Tag color="green">{node.type}</Tag> </div> ); };
复制
最后实现出来的效果就是这样的;
复制路径
我不知道大伙有过这样类似的需求:改动一个 json
对象某个 key
对应的值。我之前是有过这样的场景,那是在使用 Lottie
做动画的时候。
我需要对描述 Lottie
动画的 json
文件进行一些修改,但往往这种文件层级非常深,如果不借助一些工具,是很难找到对应的值的路径是什么,找不到路径就很难修改了。
那么我们有了这个工具之后,就很轻松可以通过搜索+复制的方式来找到某个值对应的路径。
<Clipboard text={node.key} onCopy={() => message.success("路径已复制")}> <div> {!node.isArrayProps ? ( <Tag color="orange">{highlight(node.title)}</Tag> ) : ( "" )} {node.children.length === 0 && node.value ? ( <Tag color="blue">{highlight(node.value)}</Tag> ) : ( "" )} <Tag color="green">{node.type}</Tag> </div> </Clipboard>
复制
用一个复制组件包裹树节点,点击的时候把节点的 key
属性复制到粘贴板。
这样就可以轻松获取到节点所对应的 key
了。
最后
以上就是本文的全部内容,如果你感兴趣的话,点点关注点点赞吧~