\s*\[\^([^\]]+)\]:\s*([\s\S]*?)<\/p>/g, function(_, id, content) { return '
' + content + ' ↩'; }); } catch (e) { /* 忽略 */ } next(html); }); hook.doneEach(function () { try { // 重新绑定点击事件,拦截脚注链接,平滑滚动到同页目标 var prev = window.__footnoteContainer; var prevHandler = window.__footnoteHandler; if (prev && prevHandler) { prev.removeEventListener('click', prevHandler, true); } var container = document.querySelector('.markdown-section'); if (!container) return; var handler = function (e) { var a = e.target && e.target.closest ? e.target.closest('a') : null; if (!a) return; var href = a.getAttribute('href') || ''; if (!/^#(fn-|fnref-)/.test(href)) return; var targetId = href.slice(1); var el = document.getElementById(targetId); if (!el) return; e.preventDefault(); e.stopPropagation(); try { el.scrollIntoView({ behavior: 'smooth', block: 'start' }); } catch (_) { el.scrollIntoView(true); } }; container.addEventListener('click', handler, true); window.__footnoteContainer = container; window.__footnoteHandler = handler; } catch (e) { // 忽略脚注绑定中的异常 } }); }, // 语言切换插件 function(hook, vm) { hook.mounted(function() { // 添加语言切换按钮到导航栏 var nav = document.querySelector('.app-nav'); if (!nav) { nav = document.createElement('nav'); nav.className = 'app-nav'; document.querySelector('main').appendChild(nav); } var langSwitcher = document.createElement('ul'); langSwitcher.innerHTML = ` 中文 `; nav.appendChild(langSwitcher); // 监听语言切换 var selector = document.getElementById('lang-selector'); selector.addEventListener('change', function(e) { var lang = e.target.value; var currentPath = location.hash.replace('#/', ''); if (lang === '') { // 切换到中文 if (currentPath.startsWith('en/')) { location.hash = '#/' + currentPath.replace('en/', ''); } else { location.hash = '#/'; } } else { // 切换到英文 if (currentPath === '' || currentPath === '/') { location.hash = '#/en/'; } else if (currentPath.startsWith('en/')) { // 已经在英文页面 return; } else { location.hash = '#/en/' + currentPath; } } }); // 根据当前路径设置选择器状态 function updateSelector() { var currentPath = location.hash.replace('#/', ''); if (currentPath.startsWith('en/')) { selector.value = 'en'; } else { selector.value = ''; } } updateSelector(); // 监听路由变化 window.addEventListener('hashchange', updateSelector); }); }, // 重写原始 HTML 的相对路径,使其与 docsify 的 Markdown 图片解析一致 function(hook, vm) { function getRouteDir() { var hash = decodeURIComponent(window.location.hash || ''); if (!hash || hash === '#/' || hash === '#') return ''; var path = hash.replace(/^#\//, '').replace(/(\?.*|#.*)/g, ''); if (path && !path.endsWith('/')) { path = path.replace(/[^\/]*$/, ''); } return path; } hook.doneEach(function() { try { var routeDir = getRouteDir(); // location.pathname 例如: /all-in-rag/ var base = window.location.origin + window.location.pathname + routeDir; var selector = '.markdown-section img:not([data-origin])'; var imgs = document.querySelectorAll(selector); imgs.forEach(function(img) { var src = img.getAttribute('src'); if (!src) return; // 跳过已是绝对路径或以 / 开头的路径 if (/^(https?:)?\/\//i.test(src) || src.startsWith('/')) return; try { // 利用 URL 自动规范化 ./ 和 ../ var abs = new URL(src, base).pathname; img.setAttribute('src', abs); } catch (e) { // 忽略单个元素的失败 } }); } catch (e) { // 忽略整体处理失败,避免影响页面其他功能 } }); } ] }