手写一个JSON可视化工具

前言

JSON 平时大家都会用到,都不陌生,今天就一起来实现一个 JSON 的可视化工具。

大概长成下面的样子:

image.png

树展示

相比于现有的一些 JSON 格式化工具,我们今天制作的这个小工具会把 JSON 转为树去表示。其中:

  • 橙色标签表示 key
  • 蓝色标签表示 value
  • 绿色标签表示类型: Number String Object Array Null

左边是一个输入框,右边是一个实时反馈的 JSON 可视化区域。下面来看一下大致的实现思路:

  1. 当输入框的值变化时,使用 JSON.parse 解析值,如果是一个合法的 JSON ,则进行下一步处理;如果不是,则把异常显示出来
  2. 递归把 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>
    );
  };
  

image.png

这样就完成了基础的功能逻辑及渲染

搜索

这里我们拓展一个根据关键词搜索的功能,既可以搜索 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>
    );
  };

最后实现出来的效果就是这样的;

image.png

复制路径

我不知道大伙有过这样类似的需求:改动一个 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 属性复制到粘贴板。

image.png

image.png

这样就可以轻松获取到节点所对应的 key 了。

最后

以上就是本文的全部内容,如果你感兴趣的话,点点关注点点赞吧~

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的手写时间格式化函数: ```javascript function formatDate(date, format) { const o = { "M+": date.getMonth() + 1, // 月份 "d+": date.getDate(), // 日 "h+": date.getHours(), // 小时 "m+": date.getMinutes(), // 分钟 "s+": date.getSeconds(), // 秒 "q+": Math.floor((date.getMonth() + 3) / 3), // 季度 "S": date.getMilliseconds() // 毫秒 }; if (/(y+)/.test(format)) { format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); } for (let k in o) { if (new RegExp("(" + k + ")").test(format)) { format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); } } return format; } ``` 这个函数接受两个参数,一个是日期对象,另一个是格式字符串。它将日期对象格式化为指定格式的字符串。 例如: ```javascript const date = new Date(); const format = "yyyy-MM-dd hh:mm:ss"; const formattedDate = formatDate(date, format); console.log(formattedDate); // 2022-05-17 15:30:00 ``` 在上面的例子中,我们创建了一个日期对象,并指定了一个格式化字符串。然后,我们调用formatDate()函数将日期对象格式化为指定格式的字符串,并将结果打印到控制台上。 这个函数只是一个简单的例子,实际上还有很多情况需要考虑,比如日期的时区、月份和星期的名称等。如果需要进行更复杂的时间格式化,建议使用一些成熟的第三方库,例如moment.js或date-fns。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值