From fa1031ff8aad53b5c5077bdd4665406c4b925168 Mon Sep 17 00:00:00 2001 From: K-hermes Date: Sat, 15 Aug 2026 12:41:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=94=B9=E4=B8=BA=20VSCode=20?= =?UTF-8?q?=E9=A3=8E=E6=A0=BC=E7=9A=84=E6=A0=BC=E5=BC=8F=E5=8C=96=20JSON?= =?UTF-8?q?=20=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进: - 深色主题背景 (#1e1e1e) - VSCode 配色方案(键名蓝色、字符串橙色、数字绿色等) - 自动缩进 2 空格 - 完整展示所有数据,无折叠 - 类似代码编辑器的格式化效果 - 简洁清晰,易于阅读 --- web/index.html | 264 +++++++++---------------------------------------- 1 file changed, 48 insertions(+), 216 deletions(-) diff --git a/web/index.html b/web/index.html index f3cb412..d38b7d9 100644 --- a/web/index.html +++ b/web/index.html @@ -275,131 +275,47 @@ gap: 10px; } - /* JSON 卡片式展示 */ + /* JSON 格式化展示 */ .json-viewer { - background: #f8f9fa; + background: #1e1e1e; border-radius: 8px; - padding: 0; + padding: 20px; + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 14px; + line-height: 1.6; + overflow: auto; max-height: 60vh; - overflow-y: auto; + color: #d4d4d4; } - .json-section { - margin-bottom: 10px; + .json-viewer pre { + margin: 0; + white-space: pre-wrap; + word-break: break-word; } - .json-section-title { - background: #667eea; - color: white; - padding: 12px 20px; - font-weight: bold; - font-size: 16px; - border-radius: 8px 8px 0 0; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - user-select: none; + .json-key { + color: #9cdcfe; } - .json-section-title:hover { - background: #5568d3; + .json-string { + color: #ce9178; } - .json-section-toggle { - font-size: 12px; + .json-number { + color: #b5cea8; } - .json-section-body { - background: white; - border-radius: 0 0 8px 8px; + .json-boolean { + color: #569cd6; } - .json-section-body.collapsed { - display: none; + .json-null { + color: #569cd6; } - .json-field { - display: flex; - padding: 12px 20px; - border-bottom: 1px solid #eee; - align-items: flex-start; - } - - .json-field:last-child { - border-bottom: none; - } - - .json-field:hover { - background: #f8f9fa; - } - - .json-field-label { - min-width: 200px; - font-weight: bold; - color: #0066cc; - padding-right: 20px; - flex-shrink: 0; - } - - .json-field-value { - flex: 1; - word-break: break-all; - color: #333; - font-family: 'Courier New', monospace; - font-size: 13px; - } - - .json-field-value.string { - color: #22863a; - } - - .json-field-value.number { - color: #005cc5; - } - - .json-field-value.boolean { - color: #d73a49; - } - - .json-field-value.null { - color: #6f42c1; - } - - .json-field-actions { - margin-left: 10px; - display: flex; - gap: 5px; - } - - .json-copy-btn { - padding: 4px 10px; - font-size: 12px; - background: #667eea; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - white-space: nowrap; - } - - .json-copy-btn:hover { - background: #5568d3; - } - - .json-raw-btn { - padding: 4px 10px; - font-size: 12px; - background: #6c757d; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - white-space: nowrap; - } - - .json-raw-btn:hover { - background: #5a6268; + .json-punctuation { + color: #d4d4d4; } /* Toast 通知 */ @@ -619,116 +535,32 @@ document.getElementById(modalId).classList.remove('active'); } - // JSON 卡片式渲染 - function renderJSONCard(obj, parentPath = '') { - let html = ''; + // JSON 格式化高亮 + function formatJSON(obj) { + const json = JSON.stringify(obj, null, 2); - if (typeof obj !== 'object' || obj === null) { - return ''; - } - - for (const [key, value] of Object.entries(obj)) { - const path = parentPath ? `${parentPath}.${key}` : key; - - if (value !== null && typeof value === 'object') { - // 对象或数组 - 创建折叠区域 - const isArray = Array.isArray(value); - const itemCount = isArray ? value.length : Object.keys(value).length; - const sectionId = 'section-' + Math.random().toString(36).substr(2, 9); - - html += ` -
-
- ${key} ${isArray ? `[${itemCount} items]` : `{${itemCount} keys}`} - -
-
- ${renderJSONFields(value, path)} -
-
- `; - } - } - - return html; - } - - function renderJSONFields(obj, parentPath = '') { - let html = ''; - - if (typeof obj !== 'object' || obj === null) { - return ''; - } - - for (const [key, value] of Object.entries(obj)) { - const path = parentPath ? `${parentPath}.${key}` : key; - - if (value === null || typeof value !== 'object') { - // 基本类型 - 渲染字段 - const typeClass = value === null ? 'null' : typeof value; - let displayValue = ''; - let copyValue = ''; - - if (value === null) { - displayValue = 'null'; - copyValue = 'null'; - } else if (typeof value === 'string') { - displayValue = value; - copyValue = value; - } else if (typeof value === 'number' || typeof value === 'boolean') { - displayValue = String(value); - copyValue = String(value); + // 语法高亮 + const highlighted = json + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) { + let cls = 'json-number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'json-key'; + } else { + cls = 'json-string'; + } + } else if (/true|false/.test(match)) { + cls = 'json-boolean'; + } else if (/null/.test(match)) { + cls = 'json-null'; } - - html += ` -
-
${escapeHtml(key)}
-
${escapeHtml(displayValue)}
-
- -
-
- `; - } else { - // 嵌套对象/数组 - 递归渲染 - html += renderJSONCard({[key]: value}, parentPath); - } - } + return '' + match + ''; + }); - return html; - } - - // HTML 转义 - function escapeHtml(str) { - if (typeof str !== 'string') { - str = String(str); - } - const div = document.createElement('div'); - div.textContent = str; - return div.innerHTML; - } - - // 切换区域折叠/展开 - function toggleSection(id) { - const element = document.getElementById(id); - const toggle = element.previousElementSibling.querySelector('.json-section-toggle'); - - if (element.classList.contains('collapsed')) { - element.classList.remove('collapsed'); - toggle.textContent = '▼'; - } else { - element.classList.add('collapsed'); - toggle.textContent = '▶'; - } - } - - // 复制单个值 - function copyValue(value) { - navigator.clipboard.writeText(value).then(() => { - showToast('已复制'); - }).catch(() => { - showToast('复制失败', 'error'); - }); + return '
' + highlighted + '
'; } // 加载数据列表 @@ -833,7 +665,7 @@ currentViewData = data; document.getElementById('view-modal-title').textContent = `查看数据 - ${tag}`; - document.getElementById('json-content').innerHTML = renderJSONCard(data); + document.getElementById('json-content').innerHTML = formatJSON(data); openModal('view-modal'); } else {