From 0616150dae9d88d78ff1c5d4ce296499e9f41999 Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Sun, 25 Jan 2026 00:47:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20PJAX=20=E5=86=85?= =?UTF-8?q?=E8=81=94=E8=84=9A=E6=9C=AC=E6=89=A7=E8=A1=8C=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 executeScript() 函数: - 创建新的 script 元素并复制内容 - 复制所有属性(包括 async、defer) - 添加错误捕获和日志记录 - 满足需求 4.4, 4.5 - 添加 executeInlineScripts() 函数: - 提取新页面中的所有 script 标签 - 区分内联脚本和外部脚本 - 按 DOM 顺序执行脚本 - 错误隔离机制(单个脚本失败不影响其他脚本) - 返回执行结果统计 - 满足需求 4.1-4.4 - 在 pjax:complete 事件中调用: - 在其他模块初始化之前执行 - 添加错误处理 - 满足需求 4.1-4.5 满足需求:4.1-4.5(内联脚本执行) --- .kiro/specs/pjax-lazyload-fix/tasks.md | 134 +++++++++++++++++++++++++ argontheme.js | 114 +++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 .kiro/specs/pjax-lazyload-fix/tasks.md diff --git a/.kiro/specs/pjax-lazyload-fix/tasks.md b/.kiro/specs/pjax-lazyload-fix/tasks.md new file mode 100644 index 0000000..08ec818 --- /dev/null +++ b/.kiro/specs/pjax-lazyload-fix/tasks.md @@ -0,0 +1,134 @@ +# 实施计划:PJAX、Lazyload 和 Mermaid 全面优化 + +## 概述 + +本实施计划整合了 PJAX 页面无刷新跳转、Lazyload 图片懒加载和 Mermaid 图表渲染的全面优化。 + +**实施策略:** +- 向后兼容:保持现有 API 和配置不变 +- 性能优先:优化渲染性能,减少卡顿 +- 用户体验:增强交互功能,提升视觉效果 + +## 任务 + +### 阶段 1: PJAX 和 Lazyload 核心修复 + +- [x] 1. 创建统一的资源清理管理器 + - 封装 `cleanupPjaxResources()` 函数 + - 清理 Lazyload Observer、Zoomify、Tippy、Mermaid 实例 + - 清理动态 style 和 script 标签 + - _需求:1.1-1.4, 2.3, 6.1_ + +- [x] 2. 优化 Lazyload 生命周期 + - [x] 2.1 添加 Observer 存在性检查 _需求:2.1, 2.2_ + - [x] 2.2 优化图片加载函数(使用 requestAnimationFrame) _需求:3.1-3.3_ + - [x] 2.3 实现滚动监听降级方案 _需求:2.4, 8.2_ + +- [x] 3. 重构 PJAX 事件处理器 + - [x] 3.1 优化 `pjax:beforeReplace` 事件 _需求:1.1-1.4_ + - [x] 3.2 优化 `pjax:complete` 事件(消除重复初始化) _需求:1.5, 1.6, 4.1-4.4_ + - [x] 3.3 优化 `pjax:end` 事件 _需求:1.7_ + +- [x] 4. 实现内联脚本执行器 + - 提取并执行新页面的 script 标签 + - 添加错误隔离机制 + - _需求:4.1-4.5_ + +### 阶段 2: Mermaid 显示效果优化 + +- [~] 5. 优化 Mermaid 工具栏 + - [ ] 5.1 实现工具栏自动隐藏 _需求:11.1, 11.2_ + - [ ] 5.2 优化工具栏样式(半透明背景) _需求:11.3-11.5_ + - [ ] 5.3 添加按钮提示(tooltip) _需求:20.2_ + +- [~] 6. 增强 Mermaid 缩放功能 + - [ ] 6.1 实现以鼠标为中心的缩放 _需求:12.1_ + - [ ] 6.2 优化缩放动画(CSS transform + transition) _需求:12.2, 12.3_ + - [ ] 6.3 实现智能缩放(双击) _需求:12.5_ + - [ ] 6.4 优化缩放按钮状态 _需求:12.4, 20.3_ + +- [~] 7. 优化 Mermaid 拖拽功能 + - [ ] 7.1 改进拖拽响应(requestAnimationFrame) _需求:13.3_ + - [ ] 7.2 优化拖拽视觉反馈 _需求:13.1, 13.2, 13.4_ + - [ ] 7.3 智能启用拖拽 _需求:13.5_ + +### 阶段 3: Mermaid 高级功能 + +- [ ] 8. 实现 Mermaid 全屏模式 + - [ ] 8.1 添加全屏按钮 _需求:14.1_ + - [ ] 8.2 全屏模式功能保持 _需求:14.2, 14.3_ + - [ ] 8.3 全屏模式退出(ESC 键) _需求:14.4, 14.5_ + +- [ ] 9. 实现 Mermaid 导出功能 + - [ ] 9.1 添加导出按钮和菜单 _需求:15.1_ + - [ ] 9.2 实现 PNG 导出 _需求:15.2, 15.4_ + - [ ] 9.3 实现 SVG 导出 _需求:15.3, 15.4_ + - [ ] 9.4 添加导出错误处理 _需求:15.5_ + +- [ ] 10. 优化 Mermaid 响应式设计 + - [ ] 10.1 移动端工具栏适配 _需求:16.1_ + - [ ] 10.2 实现触摸手势支持 _需求:16.2-16.4_ + - [ ] 10.3 横屏模式优化 _需求:16.5_ + +### 阶段 4: Mermaid 主题和性能优化 + +- [~] 11. 优化 Mermaid 主题同步 + - [ ] 11.1 实现主题自动切换 _需求:17.1, 17.2_ + - [ ] 11.2 保持图表状态 _需求:17.3_ + - [ ] 11.3 添加主题切换动画 _需求:17.4, 17.5_ + +- [~] 12. 优化 Mermaid 渲染性能 + - [ ] 12.1 实现批量渲染 _需求:18.1_ + - [ ] 12.2 添加加载动画 _需求:18.2, 18.3_ + - [ ] 12.3 实现延迟渲染 _需求:18.4_ + - [ ] 12.4 优化错误处理 _需求:18.5_ + +- [~] 13. 优化 Mermaid 错误提示 + - [ ] 13.1 设计友好的错误容器 _需求:19.1, 19.2, 19.4_ + - [ ] 13.2 添加原始代码查看 _需求:19.3_ + - [ ] 13.3 夜间模式适配 _需求:19.5_ + +### 阶段 5: 测试和优化 + +- [ ] 14. 单元测试 + - [ ] 14.1 PJAX 资源清理测试 + - [ ] 14.2 Lazyload 功能测试 + - [ ] 14.3 Mermaid 渲染测试 + +- [ ] 15. 集成测试 + - [ ] 15.1 PJAX 完整流程测试 + - [ ] 15.2 Mermaid 交互测试 + - [ ] 15.3 响应式测试 + +- [ ] 16. 性能测试 + - [ ] 16.1 内存泄漏检测 + - [ ] 16.2 渲染性能测试 + - [ ] 16.3 交互性能测试 + +- [ ] 17. 浏览器兼容性测试 + - 测试主流浏览器和移动端浏览器 + - 测试降级方案 + +- [ ] 18. 文档和代码审查 + - 更新代码注释和 JSDoc + - 代码风格检查 + +## 实施优先级 + +**P0 (必须完成):** +- 任务 1-4: PJAX 和 Lazyload 核心修复 +- 任务 5: Mermaid 工具栏优化 +- 任务 11: Mermaid 主题同步 +- 任务 12: Mermaid 性能优化 + +**P1 (重要):** +- 任务 6-7: Mermaid 缩放和拖拽优化 +- 任务 10: Mermaid 响应式设计 +- 任务 13: Mermaid 错误提示优化 + +**P2 (可选):** +- 任务 8: Mermaid 全屏模式 +- 任务 9: Mermaid 导出功能 + +**P3 (增强):** +- 任务 14-18: 测试和文档 diff --git a/argontheme.js b/argontheme.js index a252385..a95a72c 100644 --- a/argontheme.js +++ b/argontheme.js @@ -3029,6 +3029,113 @@ function resetGT4Captcha() { } } +// ========================================================================== +// 内联脚本执行器 (Inline Script Executor) +// ========================================================================== + +/** + * 执行单个脚本元素 + * 需求 4.4: 脚本执行失败时捕获错误并记录日志,不中断其他脚本执行 + * + * @param {HTMLScriptElement} oldScript - 原始脚本元素 + * @returns {boolean} 是否执行成功 + */ +function executeScript(oldScript) { + try { + // 创建新的 script 元素 + const newScript = document.createElement('script'); + + // 复制脚本内容 + if (oldScript.textContent) { + newScript.textContent = oldScript.textContent; + } + + // 复制所有属性(包括 type, async, defer 等) + // 需求 4.5: 尊重 async 和 defer 属性的执行时机 + Array.from(oldScript.attributes).forEach(attr => { + newScript.setAttribute(attr.name, attr.value); + }); + + // 将脚本添加到 head 并立即执行 + document.head.appendChild(newScript); + + // 执行后立即移除,避免污染 DOM + document.head.removeChild(newScript); + + ArgonDebug.log('Script executed successfully:', oldScript.textContent.substring(0, 50) + '...'); + return true; + } catch (error) { + // 需求 4.4: 捕获错误并记录日志 + ArgonDebug.error('Script execution failed:', error); + ArgonDebug.error('Failed script content:', oldScript.textContent); + return false; + } +} + +/** + * 执行新页面中的所有内联脚本 + * 需求 4.1: 提取新页面中的所有 script 标签 + * 需求 4.2: 区分内联脚本和外部脚本 + * 需求 4.3: 按照脚本在 DOM 中的顺序执行 + * 需求 4.4: 脚本执行失败不中断其他脚本执行 + * + * @param {HTMLElement|Document} container - 新页面的容器元素或文档对象 + * @returns {Object} 执行结果统计 {total, success, failed} + */ +function executeInlineScripts(container) { + // 如果没有传入容器,使用整个文档 + if (!container) { + container = document; + } + + // 需求 4.1: 提取所有 script 标签 + const scripts = container.querySelectorAll('script'); + + if (scripts.length === 0) { + ArgonDebug.log('No scripts found in new page'); + return {total: 0, success: 0, failed: 0}; + } + + let successCount = 0; + let failedCount = 0; + + ArgonDebug.log(`Found ${scripts.length} script tags in new page`); + + // 需求 4.3: 按照脚本在 DOM 中的顺序执行 + scripts.forEach((script, index) => { + // 需求 4.2: 只执行内联脚本(没有 src 属性的脚本) + if (!script.src) { + // 跳过空脚本 + if (!script.textContent || script.textContent.trim() === '') { + ArgonDebug.log(`Script ${index + 1}: Empty, skipped`); + return; + } + + ArgonDebug.log(`Executing inline script ${index + 1}/${scripts.length}`); + + // 需求 4.4: 错误隔离 - 单个脚本失败不影响其他脚本 + const success = executeScript(script); + if (success) { + successCount++; + } else { + failedCount++; + } + } else { + // 外部脚本由浏览器自动加载,不需要手动执行 + ArgonDebug.log(`Script ${index + 1}: External (${script.src}), skipped`); + } + }); + + const result = { + total: scripts.length, + success: successCount, + failed: failedCount + }; + + ArgonDebug.log('Script execution completed:', result); + return result; +} + $.pjax.defaults.timeout = 10000; $.pjax.defaults.container = ['#primary', '#leftbar_part1_menu', '#leftbar_part2_inner', '.page-information-card-container', '#rightbar', '#wpadminbar']; $.pjax.defaults.fragment = ['#primary', '#leftbar_part1_menu', '#leftbar_part2_inner', '.page-information-card-container', '#rightbar', '#wpadminbar']; @@ -3087,6 +3194,13 @@ $(document).pjax("a[href]:not([no-pjax]):not(.no-pjax):not([target='_blank']):no pjaxLoading = false; NProgress.inc(); + // ========== 需求 4.1-4.5: 执行新页面中的内联脚本 ========== + try { + executeInlineScripts(document); + } catch (err) { + ArgonDebug.error('executeInlineScripts failed:', err); + } + // MathJax 数学公式渲染 try{ if (MathJax != undefined){