用 React 写一个 JSON 格式化工具

我是 Java 后端出身,学 React 做的第一个实战项目就是一个 JSON 格式化工具。这篇文章记录我的实现思路和踩坑,新手可以参考。

最终效果:JSON 格式化工具


需求分析

JSON 格式化工具的核心功能很简单:

  1. 输入一段 JSON 字符串
  2. 解析并格式化输出(有缩进、语法高亮)
  3. 错误提示(如果有语法错误)
  4. 支持缩进设置(2 空格 / 4 空格)

扩展功能:

  • 压缩输出(去空格)
  • 复制到剪贴板
  • 清空输入
  • 快捷键(Ctrl+Enter 格式化)

实现方案

第 1 步:基础布局

用两个 textarea 左右并排,左边输入、右边输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function JsonFormatter() {
const [input, setInput] = useState('')
const [output, setOutput] = useState('')
const [error, setError] = useState('')
const [indent, setIndent] = useState(2)

return (
<div className="formatter-page">
<div className="editor-panel">
<textarea value={input} onChange={e => setInput(e.target.value)} />
</div>
<div className="result-panel">
<pre>{output}</pre>
{error && <div className="error">{error}</div>}
</div>
</div>
)
}

第 2 步:格式化逻辑

JSON.parse 解析,再用 JSON.stringify 重新序列化:

1
2
3
4
5
6
7
8
function formatJson(text: string, indentSize: number): string {
try {
const parsed = JSON.parse(text)
return JSON.stringify(parsed, null, indentSize)
} catch (e) {
throw new Error((e as Error).message)
}
}

这段代码看起来简单,实际开发中要注意几个坑:

坑 1:大 JSON 的解析性能
JSON.parse 对几 MB 的数据没问题,但超过 10MB 会有明显卡顿。我的做法是:

  • 检测输入大小,超过 5MB 就增量处理
  • 显示进度条
  • requestAnimationFrame 避免阻塞 UI

坑 2:错误定位
JSON.parse 报错信息还算清楚,但普通用户看不懂 "Unexpected token } in JSON at position 1234"。我解析了错误信息,把位置提取出来,在输入框里标红对应区域。

第 3 步:语法高亮

textarea 做语法高亮有几种方案:

  • textarea + 覆盖层(overlay) — 实现复杂,容易错位
  • CodeMirror / Monaco Editor — 功能强大但太重,一个工具站没必要
  • pre + 手工高亮 — 简单够用,我选了这种

最终用了 <pre><code> 然后给 JSON 的 key、string、number、boolean、null 分别上色:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function highlightJson(text: string): string {
return text.replace(
/("(?:\\.|[^"\\])*")\s*:/g, // key
'<span class="json-key">$1</span>:'
).replace(
/"((?:\\.|[^"\\])*)"/g, // string value
'<span class="json-string">"$1"</span>'
).replace(
/\b(-?\d+\.?\d*(?:[eE][+-]?\d+)?)\b/g, // number
'<span class="json-number">$1</span>'
).replace(
/\b(true|false)\b/g, // boolean
'<span class="json-boolean">$1</span>'
).replace(
/\bnull\b/g, // null
'<span class="json-null">$1</span>'
)
}

注意:dangerouslySetInnerHTML 渲染高亮结果时,一定要先做 XSS 过滤。我用了 DOMPurify

1
2
3
4
5
6
import DOMPurify from 'dompurify'

function sanitizedHighlight(text: string): string {
const html = highlightJson(text)
return DOMPurify.sanitize(html)
}

第 4 步:压缩功能

压缩就是把缩进去掉,变成一行:

1
2
3
4
function compressJson(text: string): string {
const parsed = JSON.parse(text)
return JSON.stringify(parsed)
}

实现就一行代码,但要注意:如果用户输入的是合法的 JSON,压缩和格式化公用同一个 JSON.parse,只是序列化参数不同。

第 5 步:复制和快捷键

复制到剪贴板:

1
2
3
4
async function copyToClipboard(text: string) {
await navigator.clipboard.writeText(text)
// 显示"已复制"提示
}

快捷键(Ctrl+Enter 格式化):

1
2
3
4
5
6
7
8
9
10
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.ctrlKey && e.key === 'Enter') {
e.preventDefault()
handleFormat()
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
}, [])

第 6 步:错误处理后膨胀

格式化工具的边界情况远比想象的多:

  • 输入为空 → 不做处理
  • 输入是合法 JSON → 正常格式化
  • 输入是非法 JSON → 提示错误,定位位置
  • 输入是一个超大文件 → 增量读取 + 进度提示
  • 输入是一个裸字符串(”hello”)→ 也是合法 JSON,正常格式化
  • 输入是一个数字 → 同上

每一个边界情况都要处理,不然用户遇到就会觉得”这个工具不好用”。


完整实现

这是最终的核心逻辑,去掉 UI 部分后大概只有 80 行核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface FormatResult {
success: boolean
data?: string
error?: string
errorPosition?: number
}

function processJson(input: string, action: 'format' | 'compress', indentSize = 2): FormatResult {
if (!input.trim()) return { success: true, data: '' }

try {
const parsed = JSON.parse(input)
const result = action === 'format'
? JSON.stringify(parsed, null, indentSize)
: JSON.stringify(parsed)
return { success: true, data: result }
} catch (e) {
const msg = (e as Error).message
const posMatch = msg.match(/position\s+(\d+)/)
return {
success: false,
error: msg,
errorPosition: posMatch ? parseInt(posMatch[1]) : undefined
}
}
}

总结

用 React 写一个 JSON 格式化工具,核心逻辑其实非常简单——就一个 JSON.parseJSON.stringify

一个好用的工具,功夫都在看似简单的地方

  • 错误信息的可读性
  • 大文件的处理
  • 快捷键支持
  • 语法高亮的准确性
  • XSS 安全

这些东西加起来,比核心逻辑多花了 3 倍的时间。但正是这些细节,让用户觉得”哎,这个工具用着挺顺手”。

我做的完整版 JSON 工具箱集成了格式化、压缩、校验、对比、代码生成等 20+ 个功能,全是纯前端实现,不上传服务器:

在线体验:https://jsonprocess.app/json-formatter