<div class="container">
  <div class="preview div"></div>
  <pre class="preview pre"></pre>
  <textarea class="textarea"></textarea>
</div>
body {
  display:flex;
  margin: 0;
    justify-content: center;
    align-items: center;
    padding: 0 10px;
    box-sizing: border-box;
    min-height: 100vh;
}
.container {
  
    display: flex;
    width: 100%;
}

.div {
  min-width: 220px;
}


.preview {
  flex: 1;
  margin-bottom: 20px;
  padding: 20px;
  background: #f5fcff;
  border: 1px solid #d3eeff;
  border-radius: 3px;
  margin: 0;
}

.textarea {
  flex: 1;
  min-width: 220px;
  margin-left: 20px;
  padding: 10px;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
}

.preview + .preview {
  margin-left: 10px;
}
const isPlainObject = (v) => Object.prototype.toString.call(v) === "[object Object]"
const isString = (v) => Object.prototype.toString.call(v) === "[object String]"

/**
 * 格式 JSON 字符串为对象
 *
 * @author anran758
 * @param { any }
 */
function formatJsonStrAsObj(sample) {
  let temp = sample;

  if (isString(temp)) {
    // 因为有解析失败的可能,使用 try catch 做相应处理
    try {
      temp = JSON.parse(temp);
    } catch (ex) {
      // parse error,return this sample
      return sample;
    }
  }

  if (isPlainObject(temp)) {
    temp = { ...temp };

    Object.keys(temp).forEach(key => {
      const item = temp[key];

      // 字符串或者对象进行递归确认
      if (isString(item) || isPlainObject(item)) {
        temp[key] = formatJsonStrAsObj(item);
      }
    });
  }

  return temp;
}

/**
 * 将 JSON 字符串转换为带缩进的字符串
 *
 * @param {*} sample JSON 字符串
 * @param {number} [indnt=2] 缩进数
 * @returns
 */
function formatJSONIndnt(sample, indnt = 2) {
  const newSample = formatJsonStrAsObj(sample);

  if (isString(newSample)) return newSample;

  try {
    return JSON.stringify(newSample, null, indnt);
  } catch (ex) {
    return newSample.toString();
  }
}

const info = JSON.stringify({
  name: 'anran758',
  avatar: 'https://xxx',
  detail: JSON.stringify({
    desc: 'some description',
    level: 2,
  })
})
const data = formatJSONIndnt(info);

const textarea = document.querySelector('.textarea');
const preview = document.querySelector('.pre');
const div = document.querySelector('.div');

textarea.addEventListener('paste', (e) => {
  const value = (e.clipboardData || window.clipboardData).getData('text');
  e.target.value =formatJSONIndnt(value, 2);
  e.preventDefault();
})
preview.innerHTML = data;
div.innerHTML = `
复制下面示例代码到输入框试试<br><br>
${data}`

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.