From 8ba6a15a8a405a98b29fed73948c9d3921c3b428 Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Sun, 25 Jan 2026 01:03:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20Mermaid=20?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E8=87=AA=E5=8A=A8=E5=90=8C=E6=AD=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 setDarkmode() 中触发 argon:theme-switched 事件 - 优化 reRenderCharts() 函数,保持图表缩放级别和滚动位置 - 添加淡入淡出过渡动画,提升视觉体验 - 只替换 SVG 内容,保留容器结构和控制按钮 - 主题切换失败时保持原样,不影响用户体验 需求:17.1, 17.2, 17.3, 17.4, 17.5 --- .kiro/specs/pjax-lazyload-fix/tasks.md | 16 ++-- argontheme.js | 128 ++++++++++++++++++++++--- header.php | 5 + 3 files changed, 126 insertions(+), 23 deletions(-) diff --git a/.kiro/specs/pjax-lazyload-fix/tasks.md b/.kiro/specs/pjax-lazyload-fix/tasks.md index 08ec818..f512981 100644 --- a/.kiro/specs/pjax-lazyload-fix/tasks.md +++ b/.kiro/specs/pjax-lazyload-fix/tasks.md @@ -36,10 +36,10 @@ ### 阶段 2: Mermaid 显示效果优化 -- [~] 5. 优化 Mermaid 工具栏 - - [ ] 5.1 实现工具栏自动隐藏 _需求:11.1, 11.2_ - - [ ] 5.2 优化工具栏样式(半透明背景) _需求:11.3-11.5_ - - [ ] 5.3 添加按钮提示(tooltip) _需求:20.2_ +- [x] 5. 优化 Mermaid 工具栏 + - [x] 5.1 实现工具栏自动隐藏 _需求:11.1, 11.2_ + - [x] 5.2 优化工具栏样式(半透明背景) _需求:11.3-11.5_ + - [x] 5.3 添加按钮提示(tooltip) _需求:20.2_ - [~] 6. 增强 Mermaid 缩放功能 - [ ] 6.1 实现以鼠标为中心的缩放 _需求:12.1_ @@ -72,10 +72,10 @@ ### 阶段 4: Mermaid 主题和性能优化 -- [~] 11. 优化 Mermaid 主题同步 - - [ ] 11.1 实现主题自动切换 _需求:17.1, 17.2_ - - [ ] 11.2 保持图表状态 _需求:17.3_ - - [ ] 11.3 添加主题切换动画 _需求:17.4, 17.5_ +- [x] 11. 优化 Mermaid 主题同步 + - [x] 11.1 实现主题自动切换 _需求:17.1, 17.2_ + - [x] 11.2 保持图表状态 _需求:17.3_ + - [x] 11.3 添加主题切换动画 _需求:17.4, 17.5_ - [~] 12. 优化 Mermaid 渲染性能 - [ ] 12.1 实现批量渲染 _需求:18.1_ diff --git a/argontheme.js b/argontheme.js index a95a72c..99be8d0 100644 --- a/argontheme.js +++ b/argontheme.js @@ -5700,6 +5700,8 @@ void 0; /** * 重新渲染所有图表(主题切换时) + * 需求 17.3: 保持图表的缩放级别和位置 + * 需求 17.4, 17.5: 使用淡入淡出过渡效果 */ reRenderCharts() { // 只选择成功渲染的图表容器,排除错误容器 @@ -5748,25 +5750,121 @@ void 0; return; } + // 需求 17.3: 保存当前的缩放级别和滚动位置 + const inner = chart.querySelector('.mermaid-container-inner'); + let savedState = null; + + if (inner) { + const transform = window.getComputedStyle(inner).transform; + const scrollLeft = inner.scrollLeft; + const scrollTop = inner.scrollTop; + + // 提取缩放比例 + let scale = 1; + if (transform && transform !== 'none') { + const matrix = transform.match(/matrix\(([^)]+)\)/); + if (matrix) { + const values = matrix[1].split(',').map(v => parseFloat(v.trim())); + scale = values[0]; // scaleX + } + } + + savedState = { + scale: scale, + scrollLeft: scrollLeft, + scrollTop: scrollTop + }; + + this.logDebug('保存图表状态', savedState); + } + const chartId = `mermaid-chart-rerender-${Date.now()}-${index}`; - window.mermaid.render(`mermaid-svg-${chartId}`, code).then(result => { - chart.innerHTML = result.svg; - chart.dataset.currentTheme = newTheme; + // 需求 17.4: 添加淡出动画 + chart.style.transition = 'opacity 0.2s ease-out'; + chart.style.opacity = '0'; - // 确保 SVG 响应式 - const svg = chart.querySelector('svg'); - if (svg) { - svg.style.maxWidth = '100%'; - svg.style.height = 'auto'; - } + // 等待淡出完成后重新渲染 + setTimeout(() => { + window.mermaid.render(`mermaid-svg-${chartId}`, code).then(result => { + // 保存旧的内部容器引用 + const oldInner = chart.querySelector('.mermaid-container-inner'); + + // 更新 SVG 内容 + if (oldInner) { + // 只替换 SVG,保留容器结构 + const oldSvg = oldInner.querySelector('svg'); + if (oldSvg) { + // 创建临时容器解析新的 SVG + const temp = document.createElement('div'); + temp.innerHTML = result.svg; + const newSvg = temp.querySelector('svg'); + + if (newSvg) { + // 替换 SVG + oldSvg.replaceWith(newSvg); + + // 确保 SVG 响应式 + newSvg.style.width = '100%'; + newSvg.style.height = 'auto'; + } + } + } else { + // 如果没有内部容器,直接替换内容 + chart.innerHTML = result.svg; + + // 确保 SVG 响应式 + const svg = chart.querySelector('svg'); + if (svg) { + svg.style.width = '100%'; + svg.style.height = 'auto'; + } + } + + // 更新主题标记 + chart.dataset.currentTheme = newTheme; - this.logDebug(`图表重新渲染成功: ${chartId}`); - }).catch(error => { - this.logError('图表重新渲染失败', error); - // 重新渲染失败时,不替换为错误容器,保持原样 - // 因为之前已经成功渲染过,只是主题切换失败 - }); + // 需求 17.3: 恢复缩放级别和滚动位置 + if (savedState && oldInner) { + // 恢复缩放 + oldInner.style.transform = `scale(${savedState.scale})`; + + // 恢复滚动位置 + oldInner.scrollLeft = savedState.scrollLeft; + oldInner.scrollTop = savedState.scrollTop; + + // 更新缩放显示 + const zoomLevel = chart.querySelector('.mermaid-zoom-level'); + if (zoomLevel) { + zoomLevel.textContent = Math.round(savedState.scale * 100) + '%'; + } + + this.logDebug('恢复图表状态', savedState); + } + + // 需求 17.5: 添加淡入动画 + requestAnimationFrame(() => { + chart.style.transition = 'opacity 0.3s ease-in'; + chart.style.opacity = '1'; + + // 动画完成后清理过渡样式 + setTimeout(() => { + chart.style.transition = ''; + }, 300); + }); + + this.logDebug(`图表重新渲染成功: ${chartId}`); + }).catch(error => { + this.logError('图表重新渲染失败', error); + + // 重新渲染失败时,恢复显示 + chart.style.opacity = '1'; + chart.style.transition = ''; + + // 不替换为错误容器,保持原样 + // 因为之前已经成功渲染过,只是主题切换失败 + }); + }, 200); // 等待淡出动画完成 }); } catch (error) { diff --git a/header.php b/header.php index fc73caa..3c104ce 100644 --- a/header.php +++ b/header.php @@ -528,6 +528,11 @@ } + // 触发主题切换事件(用于 Mermaid 等组件响应主题变化) + document.dispatchEvent(new CustomEvent('argon:theme-switched', { + detail: { darkmode: enable } + })); + } function toggleDarkmode(){