Files

267 lines
7.2 KiB
JavaScript

/**
* 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;
}
}
})();