JSON单行/多行渲染函数封装(带颜色区分)

前言

项目需求,需要将后端传过来的一段JSON字符串,解析成一行或多行的格式,并将key和value以不同颜色进行表示。同时为了以后可能的复用,要将他抽象出来。

效果

填写部分(这里没放代码)

在这里插入图片描述

展示部分(单行和多行)

在这里插入图片描述
在这里插入图片描述

实现

import React, { FC } from 'react';

interface JSONRenderProps {
  json: object;
  keyColor?: string;
  valueColor?: string;
  isOneline?: boolean;
}

const JSONRender: FC<JSONRenderProps> = (props: JSONRenderProps) => {
  const { json, keyColor = '#f9303c', valueColor = '#0070ff', isOneline = true } = props;

  const renderJsonOnline = (json: any): any => {
    if (typeof json !== 'object' || json === null) {
      return <span style={{ color: valueColor }}>{JSON.stringify(json)}</span>;
    }
    const children = [];
    Object.keys(json).forEach((key) => {
      const value = json[key];
      children.push(
        <span key={`${key}_key`} style={{ color: keyColor }}>
          &quot;{key}&quot;:{' '}
        </span>,
        <span key={`${key}_value`}>{renderJsonOnline(value)}</span>,
        ', ',
      );
    });
    children.pop();

    return (
      <span>
        {'{ '}
        {children}
        {' }'}
      </span>
    );
  };

  const renderJsonMultiLine = (json: any, indent = 1): any => {
    if (typeof json !== 'object' || json === null) {
      return <span style={{ color: valueColor }}>{JSON.stringify(json)}</span>;
    }

    const children = [];
    const { length } = Object.keys(json);
    Object.keys(json).forEach((key, index) => {
      const value = json[key];
      children.push(
        <div key={key} style={{ paddingLeft: `${indent * 20}px` }}>
          <span style={{ color: keyColor }}>&quot;{key}&quot;: </span>
          {typeof value === 'object' ? (
            renderJsonMultiLine(value, indent + 1)
          ) : (
            <span style={{ color: valueColor }}>{JSON.stringify(value)}</span>
          )}
          {index === length - 1 ? '' : ','}
        </div>,
      );
    });

    return (
      <span style={indent === 1 ? { fontSize: '12px' } : {}}>
        {'{ '}
        {children}
        {' }'}
      </span>
    );
  };

  return <>{isOneline ? renderJsonOnline(json) : renderJsonMultiLine(json)}</>;
};

export default JSONRender;

接下来分别介绍

单行渲染

  const { json, keyColor = '#f9303c', valueColor = '#0070ff', isOneline = true } = props;

  const renderJsonOnline = (json: any): any => {
    if (typeof json !== 'object' || json === null) {
      return <span style={{ color: valueColor }}>{JSON.stringify(json)}</span>;
    }
    const children = [];
    Object.keys(json).forEach((key) => {
      const value = json[key];
      children.push(
        <span key={`${key}_key`} style={{ color: keyColor }}>
          &quot;{key}&quot;:{' '}
        </span>,
        <span key={`${key}_value`}>{renderJsonOnline(value)}</span>,
        ', ',
      );
    });
    children.pop();

    return (
      <span>
        {'{ '}
        {children}
        {' }'}
      </span>
    );
  };

解释:
考虑到可能会对象里面value仍旧是对象的情况,因此需要用递归的方式来实现。
首先先写停止条件——判断传入的是否不为对象或者为null,如果为true,那么就返回stringify(json)后的span(PS:判断json === null的原因是 null也是对象,即 typeof null 为object);
当传入的是对象时,首先用Object.keys(json)获取一个存储所有key的数组,然后forEach遍历,在里面拼接类似于"key": value的格式,其中{’ '}代表一个空格

补充:

  1. 这里面用chidren.push()和children.pop()的原因:因为这样子递归的话,到最后会多出一个「逗号」,因此通过children.pop()方法删除最后一个元素即「逗号」。也有其他方法可以实现,比如用if判断
const children = [];
const keys = Object.keys(json);
keys.forEach((key, index) => {
  const value = json[key];
  children.push(
    <span key={`${key}_key`} style={{ color: keyColor }}>
      &quot;{key}&quot;:{' '}
    </span>,
    <span key={`${key}_value`}>{renderJsonOnline(value)}</span>,
  );
  if (index < keys.length - 1) {
    children.push(', ');
  }
});
  1. 为什么最后可以直接return children数组:React 允许在 JSX 中插入数组,因为它会自动将数组中的每个元素渲染为独立的子元素。这使得我们可以非常方便地处理动态生成的内容。
  2. 为什么是一行:因为用的是span标签,它为内联样式(inline-block)。
  3. 效果如下
    在这里插入图片描述

多行渲染

 const renderJsonMultiLine = (json: any, indent = 1): any => {
    if (typeof json !== 'object' || json === null) {
      return <span style={{ color: valueColor }}>{JSON.stringify(json)}</span>;
    }

    const children = [];
    const { length } = Object.keys(json);
    Object.keys(json).forEach((key, index) => {
      const value = json[key];
      children.push(
        <div key={key} style={{ paddingLeft: `${indent * 20}px` }}>
          <span style={{ color: keyColor }}>&quot;{key}&quot;: </span>
          {typeof value === 'object' ? (
            renderJsonMultiLine(value, indent + 1)
          ) : (
            <span style={{ color: valueColor }}>{JSON.stringify(value)}</span>
          )}
          {index === length - 1 ? '' : ','}
        </div>,
      );
    });

    return (
      <span style={indent === 1 ? { fontSize: '12px' } : {}}>
        {'{ '}
        {children}
        {' }'}
      </span>
    );
  };

解释:

  1. 多行渲染同样是用递归的方式进行渲染,与单行的区别在于,用了div使其为多行,另外多了个indent来控制缩进。当有嵌套的时候(typeof value === ‘object’),递归调用,并让缩进值+1
  2. {index === length - 1 ? ‘’ : ‘,’}的作用:和单行渲染里面提到的两个方法一样,就是用来增加逗号,并且当是最后一个元素的时候,就不添加逗号。
  3. 效果如下
    在这里插入图片描述

封装

  return <>{isOneline ? renderJsonOnline(json) : renderJsonMultiLine(json)}</>;
export default JSONRender;

封装并导出JSONRender,后面使用的时候只要传入json和isOneline即可,比如:我想做一个Bubble气泡交互,页面上展示的是一行的样子,当hover的时候,展示多行渲染的JSON

<Bubble
  content={
    <div style={{ maxHeight: 400, minHeight: 40, minWidth: 100, overflow: 'auto' }}>
      {JSONRender({ json, isOneline: false })}
    </div>
  }
  trigger="hover"
  placement="top-start"
>
  <span>{JSONRender({ json })}</span>
</Bubble>

总结

记录下这个主要是因为封装的还是比较好的,记录下来一是分享给大家,二是自己之后可以消化一下用于秋招。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值