用 React 写一个 JSON 格式化工具
我是 Java 后端出身,学 React 做的第一个实战项目就是一个 JSON 格式化工具。这篇文章记录我的实现思路和踩坑,新手可以参考。
最终效果:JSON 格式化工具
需求分析
JSON 格式化工具的核心功能很简单:
- 输入一段 JSON 字符串
- 解析并格式化输出(有缩进、语法高亮)
- 错误提示(如果有语法错误)
- 支持缩进设置(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, '<span class="json-string">"$1"</span>' ).replace( /\b(-?\d+\.?\d*(?:[eE][+-]?\d+)?)\b/g, '<span class="json-number">$1</span>' ).replace( /\b(true|false)\b/g, '<span class="json-boolean">$1</span>' ).replace( /\bnull\b/g, '<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.parse 加 JSON.stringify。
但一个好用的工具,功夫都在看似简单的地方:
- 错误信息的可读性
- 大文件的处理
- 快捷键支持
- 语法高亮的准确性
- XSS 安全
这些东西加起来,比核心逻辑多花了 3 倍的时间。但正是这些细节,让用户觉得”哎,这个工具用着挺顺手”。
我做的完整版 JSON 工具箱集成了格式化、压缩、校验、对比、代码生成等 20+ 个功能,全是纯前端实现,不上传服务器:
在线体验:https://jsonprocess.app/json-formatter