diff --git a/src/generator.js b/src/generator.js index 3d1714a..e8b85fb 100644 --- a/src/generator.js +++ b/src/generator.js @@ -440,6 +440,20 @@ function getSubmenuForNavItem(navItem, config) { return null; } +/** + * 将 JSON 字符串安全嵌入到 ` 结束标签导致脚本块被提前终止。 + * 说明:返回值仍是合法 JSON,JSON.parse 后数据不变。 + * @param {string} jsonString JSON 字符串 + * @returns {string} 安全的 JSON 字符串 + */ +function makeJsonSafeForHtmlScript(jsonString) { + if (typeof jsonString !== 'string') { + return ''; + } + + return jsonString.replace(/<\/script/gi, '<\\/script'); +} + /** * 准备渲染数据,添加模板所需的特殊属性 * @param {Object} config 配置对象 @@ -486,11 +500,13 @@ function prepareRenderData(config) { renderData.homePageId = renderData.navigation && renderData.navigation[0] ? renderData.navigation[0].id : null; // 添加序列化的配置数据,用于浏览器扩展(确保包含 homePageId 等处理结果) - renderData.configJSON = JSON.stringify({ - version: process.env.npm_package_version || '1.0.0', - timestamp: new Date().toISOString(), - data: renderData // 使用经过处理的renderData而不是原始config - }); + renderData.configJSON = makeJsonSafeForHtmlScript( + JSON.stringify({ + version: process.env.npm_package_version || '1.0.0', + timestamp: new Date().toISOString(), + data: renderData // 使用经过处理的renderData而不是原始config + }) + ); // 为Handlebars模板特别准备navigationData数组 renderData.navigationData = renderData.navigation; diff --git a/src/script.js b/src/script.js index 21c09b2..00694c6 100644 --- a/src/script.js +++ b/src/script.js @@ -29,14 +29,35 @@ if (window.visualViewport) { window.visualViewport.addEventListener('resize', menavUpdateAppHeight); } +// 配置数据缓存:避免浏览器扩展/站点脚本频繁 JSON.parse +let menavConfigCacheReady = false; +let menavConfigCacheRaw = null; +let menavConfigCacheValue = null; + // 全局MeNav对象 - 用于浏览器扩展 window.MeNav = { version: "1.0.0", // 获取配置数据 - getConfig: function() { + getConfig: function(options) { const configData = document.getElementById('menav-config-data'); - return configData ? JSON.parse(configData.textContent) : null; + if (!configData) return null; + + const raw = configData.textContent || ''; + if (!menavConfigCacheReady || menavConfigCacheRaw !== raw) { + menavConfigCacheValue = JSON.parse(raw); + menavConfigCacheRaw = raw; + menavConfigCacheReady = true; + } + + if (options && options.clone) { + if (typeof structuredClone === 'function') { + return structuredClone(menavConfigCacheValue); + } + return JSON.parse(JSON.stringify(menavConfigCacheValue)); + } + + return menavConfigCacheValue; }, // 获取元素的唯一标识符