/** * YwxApp 文档中心前台脚本 * * 提供:目录折叠、移动端抽屉、代码复制、右侧锚点滚动高亮、版本切换。 * 纯原生实现,不依赖任何库。 */ (function () { 'use strict'; document.addEventListener('DOMContentLoaded', function () { initTreeToggle(); initMobileDrawer(); initCodeCopy(); initTocScrollSpy(); initVersionSwitch(); scrollActiveIntoView(); }); /** * 侧边目录展开与折叠 */ function initTreeToggle() { var tree = document.querySelector('.dc-tree'); if (!tree) { return; } tree.addEventListener('click', function (e) { var toggle = e.target.closest('.dc-tree-toggle'); var dirLink = e.target.closest('.dc-tree-link.is-dir'); var trigger = toggle || dirLink; if (!trigger) { return; } var li = trigger.closest('li'); if (li) { li.classList.toggle('is-open'); } }); } /** * 移动端侧边栏抽屉 */ function initMobileDrawer() { var btn = document.getElementById('dcMenuToggle'); var sidebar = document.getElementById('dcSidebar'); var mask = document.getElementById('dcMask'); if (!btn || !sidebar) { return; } function close() { sidebar.classList.remove('is-open'); if (mask) { mask.classList.remove('is-show'); } } btn.addEventListener('click', function () { sidebar.classList.toggle('is-open'); if (mask) { mask.classList.toggle('is-show', sidebar.classList.contains('is-open')); } }); if (mask) { mask.addEventListener('click', close); } // 点击目录项后自动收起抽屉 sidebar.addEventListener('click', function (e) { if (e.target.closest('a.dc-tree-link') && window.innerWidth <= 860) { close(); } }); window.addEventListener('resize', function () { if (window.innerWidth > 860) { close(); } }); } /** * 代码块复制按钮 */ function initCodeCopy() { var blocks = document.querySelectorAll('.dc-content pre'); Array.prototype.forEach.call(blocks, function (pre) { var btn = document.createElement('button'); btn.className = 'dc-copy-btn'; btn.type = 'button'; btn.textContent = '复制'; btn.addEventListener('click', function () { var code = pre.querySelector('code'); var text = code ? code.innerText : pre.innerText; copyText(text, function (ok) { btn.textContent = ok ? '已复制' : '复制失败'; btn.classList.toggle('is-done', ok); setTimeout(function () { btn.textContent = '复制'; btn.classList.remove('is-done'); }, 1600); }); }); pre.appendChild(btn); }); } /** * 复制文本到剪贴板,兼容不支持 Clipboard API 的环境 * * @param {string} text 待复制文本 * @param {Function} cb 回调,参数为是否成功 */ function copyText(text, cb) { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(text).then(function () { cb(true); }).catch(function () { cb(fallbackCopy(text)); }); return; } cb(fallbackCopy(text)); } /** * 兜底复制方案 * * @param {string} text 待复制文本 * @returns {boolean} */ function fallbackCopy(text) { var ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (err) { ok = false; } document.body.removeChild(ta); return ok; } /** * 右侧锚点滚动高亮 */ function initTocScrollSpy() { var toc = document.getElementById('dcToc'); var content = document.getElementById('dcContent'); if (!toc || !content) { return; } var links = Array.prototype.slice.call(toc.querySelectorAll('a[data-anchor]')); if (!links.length) { return; } var headings = links.map(function (link) { return document.getElementById(link.getAttribute('data-anchor')); }).filter(Boolean); if (!headings.length) { return; } var offset = 90; var ticking = false; function update() { var current = 0; for (var i = 0; i < headings.length; i++) { if (headings[i].getBoundingClientRect().top <= offset) { current = i; } else { break; } } links.forEach(function (link, index) { link.classList.toggle('is-active', index === current); }); ticking = false; } window.addEventListener('scroll', function () { if (!ticking) { window.requestAnimationFrame(update); ticking = true; } }, { passive: true }); update(); } /** * 版本切换:保持当前文档路径,仅替换版本段 */ function initVersionSwitch() { var select = document.getElementById('dcVersionSelect'); if (!select) { return; } select.addEventListener('change', function () { var opt = select.options[select.selectedIndex]; var isDefault = opt.getAttribute('data-default') === '1'; // 地址形如 /docs/<项目>[/<版本>]/<文档> var parts = window.location.pathname.split('/').filter(Boolean); if (parts.length < 2) { return; } var project = parts[1]; var docName = parts[parts.length - 1]; // 只有项目段时说明还未进入具体文档 if (parts.length === 2) { window.location.href = '/docs/' + project; return; } window.location.href = isDefault ? '/docs/' + project + '/' + docName : '/docs/' + project + '/' + select.value + '/' + docName; }); } /** * 让当前选中的目录项进入可视区域 */ function scrollActiveIntoView() { var active = document.querySelector('.dc-tree-item.is-active'); var sidebar = document.getElementById('dcSidebar'); if (!active || !sidebar) { return; } var top = active.offsetTop - sidebar.clientHeight / 2; if (top > 0) { sidebar.scrollTop = top; } } })();