当前位置: 首页 > article >正文

100个小工具挑战 #002 | 做了个能直接编辑树形视图的 JSON 格式化工具

起因今年给自己定了个目标做 100 个小工具页面。不是为了流量就是想把平时开发中遇到的痛点一个个解决掉。这是第 2 个。第 1 个是发票批量识别工具这次做的是 JSON 格式化。为什么要自己做不用现成的用过很多在线 JSON 格式化工具大部分都是这个模式左边粘贴 JSON → 右边展示树形结构右边的树形视图只能看不能改。想改某个嵌套字段的值回左边找到那一行手动改再看右边有没有更新。嵌套层级深一点找个字段要翻半天。所以这次做的核心差异点就一个右侧树形视图可以直接编辑点击键名可以重命名点击值可以直接修改还能添加和删除节点修改后左侧文本编辑器实时同步。整体架构┌─────────────────────────────────────────┐ │ JSON 编辑器 │ ├──────────────────┬──────────────────────┤ │ 左侧文本编辑器 │ 右侧树形视图 │ │ - 原始文本输入 │ - 可折叠节点 │ │ - 实时语法验证 │ - 点击编辑键名/值 │ │ - 格式化/压缩 │ - 添加/删除节点 │ └──────────────────┴──────────────────────┘ ↕ 双向同步分屏布局左右两侧实时联动任意一侧修改都会同步到另一侧。一、实时语法验证最基础的功能监听 input 事件用 JSON.parse 捕获异常jsonInput.addEventListener(input, function() { updateStatus(); validateJSON(); // 防抖更新树形视图避免频繁重绘 clearTimeout(updateTreeTimer); updateTreeTimer setTimeout(() updateTreeView(), 800); }); function validateJSON() { const text jsonInput.value.trim(); if (!text) { setStatus(info, 等待输入...); return; } try { JSON.parse(text); setStatus(valid, JSON 格式正确); } catch (e) { setStatus(invalid, JSON 格式错误: e.message); } }防抖延迟 800ms 再更新树形视图避免用户每输入一个字符就触发一次完整的 DOM 重建。二、格式化与压缩本质上就是 JSON.stringify 的两种用法// 格式化美化 function formatJSON() { const obj JSON.parse(jsonInput.value); const indentSize document.getElementById(indentSize).value; const indent indentSize tab ? \t : parseInt(indentSize); jsonInput.value JSON.stringify(obj, null, indent); } // 压缩去除所有空白 function compressJSON() { const obj JSON.parse(jsonInput.value); jsonInput.value JSON.stringify(obj); }支持 2 空格、4 空格、制表符三种缩进方式通过 select 元素切换。三、转义与反转义在某些场景下比如把 JSON 作为字符串存入数据库或者嵌入 HTML 属性需要对 JSON 进行转义// 转义将 JSON 字符串本身作为字符串值处理 function escapeJSON() { const text jsonInput.value.trim(); jsonInput.value JSON.stringify(text); // 会自动转义特殊字符 } // 反转义解析被转义的 JSON 字符串 function unescapeJSON() { const text jsonInput.value.trim(); const unescaped JSON.parse(text); if (typeof unescaped string) { jsonInput.value unescaped; } }四、树形视图的核心实现这是整个编辑器最复杂的部分。核心思路是递归渲染根据数据类型分别处理function renderJSON(data, container, level 0, key null, path []) { const line document.createElement(div); line.className json-viewer-line; line.style.marginLeft (level * 20) px; if (data null || typeof data ! object) { // 基础类型直接渲染值绑定点击编辑事件 renderPrimitive(data, line, key, path); } else if (Array.isArray(data)) { // 数组渲染折叠按钮 [ 递归子项 ] renderArray(data, line, container, level, key, path); } else { // 对象渲染折叠按钮 { 递归属性 } renderObject(data, line, container, level, key, path); } }折叠/展开实现每个可折叠节点生成一个唯一 ID通过切换 hidden class 控制显示function toggleCollapse(id, toggle) { const element document.getElementById(id); const closeElement document.getElementById(close- id); const ellipsis document.getElementById(ellipsis- id); if (element.classList.contains(hidden)) { element.classList.remove(hidden); closeElement.style.display block; ellipsis.style.display none; toggle.innerHTML ▼; } else { element.classList.add(hidden); closeElement.style.display none; ellipsis.style.display inline; // 折叠时显示 3 items... toggle.innerHTML ▶; } }折叠时显示 3 items... 或 5 properties... 的摘要让用户知道折叠了多少内容。五、可视化编辑——双向同步的关键树形视图不只是展示还支持直接编辑。关键是维护一个 currentJsonObject 引用所有编辑操作都直接修改这个对象然后重新序列化到文本编辑器let currentJsonObject null; // 当前 JSON 对象的引用 function updateJsonValue(path, newValue) { if (path.length 0) { currentJsonObject newValue; return; } // 通过 path 数组定位到目标节点的父级 let current currentJsonObject; for (let i 0; i path.length - 1; i) { current current[path[i]]; } current[path[path.length - 1]] newValue; }path 是一个数组记录从根节点到当前节点的路径例如 [address, city] 表示 obj.address.city。编辑值的交互点击值时将 span 替换为 input失焦或按 Enter 保存function editValue(path, currentValue, valueType, element) { const input document.createElement(input); input.value currentValue; element.textContent ; element.appendChild(input); input.focus(); const saveEdit () { const newValue input.value.trim(); // 字符串类型允许清空为 if (newValue valueType string) { updateJsonValue(path, ); syncToTextEditor(); return; } // 数值类型清空时提示将变为 null if (newValue valueType number) { if (confirm(值已清空将把该字段设为 null确认吗)) { updateJsonValue(path, null); syncToTextEditor(); updateTreeView(); // 类型变了需要重新渲染 } return; } // 按原类型解析新值 const parsed parseByType(newValue, valueType); updateJsonValue(path, parsed); syncToTextEditor(); }; input.addEventListener(blur, saveEdit); input.addEventListener(keydown, e { if (e.key Enter) saveEdit(); if (e.key Escape) cancelEdit(); }); }重命名键名对象的键名重命名需要特殊处理——JavaScript 对象没有直接重命名 key 的 API需要删除旧 key 并添加新 key但这会改变属性顺序// 重命名键删除旧键添加新键会移到末尾 const value parent[oldKey]; delete parent[oldKey]; parent[newKey] value;如果需要保持顺序可以重建整个对象// 保持顺序的重命名 const newObj {}; for (const k of Object.keys(parent)) { newObj[k oldKey ? newKey : k] parent[k]; } Object.assign(parent, newObj); // 删除多余的旧键如果 newKey ! oldKey六、节点的添加与删除function addNode(path, nodeType) { let target getByPath(currentJsonObject, path); if (nodeType array) { target.push(新值); } else { // 自动生成不重复的键名 let newKey newKey; let counter 1; while (target.hasOwnProperty(newKey)) { newKey newKey counter; } target[newKey] 新值; } syncToTextEditor(); updateTreeView(); } function deleteNode(path) { const parent getByPath(currentJsonObject, path.slice(0, -1)); const lastKey path[path.length - 1]; if (Array.isArray(parent)) { parent.splice(lastKey, 1); // 数组用 splice } else { delete parent[lastKey]; // 对象用 delete } syncToTextEditor(); updateTreeView(); }七、性能优化对于大型 JSON几千个节点频繁的 DOM 操作会很慢。几个优化点1. 防抖更新clearTimeout(updateTreeTimer); updateTreeTimer setTimeout(() updateTreeView(), 800);2. 默认折叠深层节点超过一定深度的节点默认折叠减少初始渲染的 DOM 数量function renderJSON(data, container, level 0, ...) { // 超过 3 层默认折叠 if (level 3 isObject(data)) { renderCollapsed(data, container, level, key, path); return; } // ... }3. 虚拟滚动进阶对于超大 JSON可以引入虚拟滚动只渲染可视区域内的节点。不过对于日常开发场景10MB 以内的 JSON 用防抖 默认折叠基本够用。八、全屏模式全屏模式通过 CSS position: fixed 实现不依赖 Fullscreen API兼容性更好function toggleFullscreen() { isFullscreen !isFullscreen; if (isFullscreen) { editorContainer.classList.add(fullscreen-mode); document.body.style.overflow hidden; } else { editorContainer.classList.remove(fullscreen-mode); document.body.style.overflow ; } } // ESC 退出全屏 document.addEventListener(keydown, e { if (e.key Escape isFullscreen) toggleFullscreen(); });.fullscreen-mode { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 9998; border-radius: 0; }总结成品图片实现一个完整的 JSON 编辑器核心难点在于树形视图的递归渲染需要处理对象、数组、基础类型三种情况双向同步维护一个共享的 JSON 对象引用任意一侧修改后重新序列化path 路径定位用数组记录节点路径实现精准的深层节点更新类型感知编辑不同类型的值有不同的编辑规则字符串可以为空数值不能输入字母等大家可以来体验一下Json在线格式化工具代码量大约 2000 行纯原生 JS 实现无框架依赖可以直接作为独立页面部署。

相关文章:

100个小工具挑战 #002 | 做了个能直接编辑树形视图的 JSON 格式化工具

起因 今年给自己定了个目标:做 100 个小工具页面。 不是为了流量,就是想把平时开发中遇到的痛点一个个解决掉。这是第 2 个。 第 1 个是发票批量识别工具,这次做的是 JSON 格式化。 为什么要自己做,不用现成的? 用…...

手把手教你用YOLOv11和PyAutoGUI实现屏幕目标自动追踪(附完整Python代码)

基于YOLOv11与PyAutoGUI的屏幕目标自动化追踪技术实战 在数字化办公与自动化测试领域,屏幕目标识别与自动化操作正成为提升效率的关键技术。本文将深入探讨如何利用YOLOv11这一前沿目标检测算法,结合PyAutoGUI这一轻量级自动化工具,构建一个高…...

MiniCPM-V-2_6电商应用实战:商品图多角度比对+卖点文案自动生成

MiniCPM-V-2_6电商应用实战:商品图多角度比对卖点文案自动生成 1. 引言:电商内容创作的痛点与解决方案 电商卖家每天都要面对一个头疼的问题:商品上架需要大量图片和文案。同一个商品要从不同角度拍摄,还要写出吸引人的卖点描述…...

生成式AI对接知识库总卡壳?揭秘92%企业失败的4个底层架构缺陷及实时修复方案

第一章:生成式AI应用知识库集成 2026奇点智能技术大会(https://ml-summit.org) 生成式AI应用与企业知识库的深度集成,正从“文档检索增强”迈向“语义化决策协同”。这一演进依赖于结构化知识注入、实时上下文对齐与可审计推理链构建三大支柱。现代知识…...

你的企业还在靠人工做合规检查?同行已经用 AI 自动预警了 | 实在Agent企业级风险防控方案

进入2026年,企业面临的合规环境已发生质变。随着《数据安全法》深度落地以及AIGC相关强制标准(如GB45438-2025)的严格执行,合规检查不再是每季度的“例行公事”,而是关系到企业生存的“实时防线”。 然而,这…...

为什么说企业的效率差距,核心在自动化能力的差距?2026企业数字化转型:实在Agent重塑人机协同新范式

进入2026年,全球商业竞争的底层逻辑发生了深刻位移。 根据普华永道与麦肯锡的联合调研显示,领先企业与跟随者之间的财务表现差距已拉大至7.2倍。 这种鸿沟的本质,不再是简单的技术有无,而是自动化能力的系统性代差。 当多数企业仍…...

同样的招聘工作,别人 AI 一周筛选千份简历,你的 HR 要加班一个月:2026企业级实在Agent深度实践

在2026年的春招赛道上,企业间的竞争早已从“人才争夺”演变为“筛选效率”的降维打击。 根据最新的行业观察,头部企业通过部署智能体(Agent)技术,已实现从简历抓取、逻辑初筛到面试预约的全链路自动化。 相比之下&…...

3分钟!玩转游戏下载站系统!蜘蛛池seo功能完善部署!

从复杂的建站流程到全自动部署游戏站下载站养站系统,整个流程只要3分钟!养站系统中的每个网站URL路径有2000 0000 0000条!(不需要发文章,自动更新文章,解决seo站长文章问题)游戏站养站功能简述&…...

从SD卡到EMMC:手把手教你用U-Boot的tftp和update_mmc命令完成系统引导迁移

从SD卡到EMMC:U-Boot引导迁移全流程实战指南 当开发板通过SD卡成功启动U-Boot后,如何将引导程序永久写入板载EMMC?这不仅关乎设备能否独立启动,更直接影响产品化部署的可靠性。本文将手把手带你完成从临时启动到永久固件部署的关键…...

Vue3数字动画实战:用vue3-count-to打造数据大屏动态效果(附完整代码)

Vue3数字动画实战:用vue3-count-to打造数据大屏动态效果 数据可视化大屏已经成为企业展示核心指标的重要窗口,而动态数字效果则是其中最抓眼球的元素之一。想象一下,当领导带着客户参观时,大屏上的关键数据从0开始流畅增长到百万级…...

告别环境配置焦虑:在Ubuntu 22.04上为ESP32-S3搭建esp-idf v5.4.2的保姆级避坑指南

告别环境配置焦虑:在Ubuntu 22.04上为ESP32-S3搭建esp-idf v5.4.2的保姆级避坑指南 第一次在Ubuntu上配置ESP-IDF开发环境时,我盯着终端里密密麻麻的报错信息发了半小时呆——明明是按照官方文档一步步操作,为什么总是卡在奇怪的环节&#xf…...

儿童护眼大路灯哪个牌子好用?全网高赞的护眼大路灯十大品牌排行

护眼大路灯通过上下发光能够呈现出舒适且接近太阳光的光线,这样也伴随着护眼落地灯迅速得到众多人的认可火爆市场,护眼灯品牌越来越多,质量参差不齐,存在着一些可能会造成刺眼、眩光以及频闪的劣质护眼灯,所以我们不能…...

别再纠结了!MySQL和PostgreSQL到底怎么选?从CPU核数到索引类型,一次给你讲透

MySQL与PostgreSQL技术选型指南:从架构差异到业务场景适配 当项目面临数据库选型时,技术决策者常常陷入两难境地。作为开源关系型数据库的双雄,MySQL和PostgreSQL各有拥趸,但真正的专业选择应当基于客观的技术特性和实际业务需求。…...

战略仪表盘:搜极星如何成为AI时代品牌竞争的新坐标

战略仪表盘:搜极星如何成为AI时代品牌竞争的新坐标 当前,品牌营销正经历一场静默但剧烈的“底层代码”更换。过往以搜索引擎为核心、以关键词和链接为枢纽的传统范式,在生成式AI的冲击下加速瓦解。当用户不再输入关键词列表,而是…...

从‘删库跑路’到安全操作:详解SQL中DROP SCHEMA/TABLE的CASCADE和RESTRICT到底怎么选

从‘删库跑路’到安全操作:详解SQL中DROP SCHEMA/TABLE的CASCADE和RESTRICT到底怎么选 在数据库管理的日常工作中,DROP命令就像一把双刃剑——它既能快速清理无用数据,也可能因误操作导致灾难性后果。想象一下这样的场景:你在生产…...

深度解析SukiUI Avalonia主题库架构设计与技术实现

深度解析SukiUI Avalonia主题库架构设计与技术实现 【免费下载链接】SukiUI UI Theme for AvaloniaUI 项目地址: https://gitcode.com/gh_mirrors/su/SukiUI SukiUI是基于AvaloniaUI框架构建的现代化UI主题库,专为桌面和移动应用程序提供完整的组件系统与主题…...

深度解析高性能Windows AirPlay 2接收器:架构设计与实现原理

深度解析高性能Windows AirPlay 2接收器:架构设计与实现原理 【免费下载链接】airplay2-win Airplay2 for windows 项目地址: https://gitcode.com/gh_mirrors/ai/airplay2-win AirPlay 2 for Windows 是一个完整的跨平台投屏解决方案,通过逆向工…...

如何快速打造精简Windows 11系统:tiny11builder终极完整指南

如何快速打造精简Windows 11系统:tiny11builder终极完整指南 【免费下载链接】tiny11builder Scripts to build a trimmed-down Windows 11 image. 项目地址: https://gitcode.com/GitHub_Trending/ti/tiny11builder 你是否厌倦了Windows 11系统日益臃肿&…...

解密MAA:如何用计算机视觉技术解放明日方舟玩家的双手?

解密MAA:如何用计算机视觉技术解放明日方舟玩家的双手? 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址:…...

MiniMax M2.7 上手体验:国产大模型的“推理派“选手

前两天用阿里的接口感觉慢了很多,国外的模型也被封了,实在受不了一个任务卡半天,瞧着MiniMax上市的股票涨的那么猛,是不是可以试试?于是我把我的龙虾的模型换成了MiniMax-M2.7,和之前的GLM-5执行同样的任务对比了一下效…...

BaiduPCS-Go深度调优指南:10个高级配置技巧提升下载速度与稳定性

BaiduPCS-Go深度调优指南:10个高级配置技巧提升下载速度与稳定性 【免费下载链接】BaiduPCS-Go iikira/BaiduPCS-Go原版基础上集成了分享链接/秒传链接转存功能 项目地址: https://gitcode.com/GitHub_Trending/ba/BaiduPCS-Go BaiduPCS-Go作为一款强大的百度…...

基本数据结构的定义要自己会手写1(二叉树)

(C版本)struct TreeNode {int val;TreeNode *left;TreeNode *right;// 写三个构造函数,提供多种创建节点的方式// 1、无参构造TreeNode() : val(0),left(nullptr),right(nullptr){}// 2、单参构造TreeNode(int x) : val(x),left(nullptr),rig…...

2026届最火的六大AI辅助写作方案推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当今的学术环境当中,论文 AI 工具已然成了那些研究者的重要辅助办法,…...

测试工程师时间管理:从疲于奔命到游刃有余的高效工作法

对于广大软件测试从业者而言,时间似乎总是不够用。凌晨的办公室里,闪烁的报错红光映照着疲惫的脸庞,这并非个别现象,而是许多同行共同的日常写照。在敏捷开发、快速迭代的现代软件工程中,测试团队常常被重复的用例维护…...

PCB设计小技巧:如何在立创EDA专业版中完美添加二维码(附避坑指南)

PCB设计实战:立创EDA专业版二维码嵌入全流程与避坑指南 在PCB设计领域,二维码的应用已经从简单的产品标识演变为包含生产批次、设计版本、测试参数等关键信息的智能载体。立创EDA专业版作为国产PCB设计工具的代表,其二维码嵌入功能却存在不少…...

从零解析AlexNet:逐层维度推导与PyTorch实战复现

1. AlexNet的前世今生:为什么它改变了计算机视觉 第一次看到AlexNet的论文时,我正坐在实验室的旧电脑前啃着三明治。那是2012年的一个普通下午,谁也没想到这篇论文会成为深度学习革命的导火索。当时主流的图像识别方法还在用SIFT特征SVM分类器…...

2026届最火的六大AI论文工具推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当下学术情形里,AI相关的论文平台主要被分作三种类型,其一为文献检索…...

Feko里算RCS,MLFMM、ACA、PO这些算法到底该怎么选?一张图给你讲明白

Feko电磁仿真中RCS计算算法的实战选择指南 在电磁仿真领域,Feko作为一款专业工具,其算法选择直接决定了计算效率和精度。面对MLFMM、ACA、PO等多种算法,工程师们常常陷入选择困境——是追求速度牺牲精度,还是为了准确度忍受漫长的…...

WinUtil:5步掌握Windows系统优化与软件管理的终极指南

WinUtil:5步掌握Windows系统优化与软件管理的终极指南 【免费下载链接】winutil Chris Titus Techs Windows Utility - Install Programs, Tweaks, Fixes, and Updates 项目地址: https://gitcode.com/GitHub_Trending/wi/winutil WinUtil是Windows系统优化与…...

fre:ac音频转换器:如何在3分钟内完成无损格式转换

fre:ac音频转换器:如何在3分钟内完成无损格式转换 【免费下载链接】freac The fre:ac audio converter project 项目地址: https://gitcode.com/gh_mirrors/fr/freac 还在为不同设备间的音频格式不兼容而烦恼吗?fre:ac音频转换器为你提供了一站式…...