js
// see https://ld246.com/article/1729605574188
(async ()=>{
whenElementExist('.sy__outline > .fn__flex-1').then(async el => {
//let clicking = false;
// 监听大纲标题被添加
observeChildAddition(el, node => {
return node.tagName.toLowerCase() === 'ul' &&
node.classList.contains('b3-list') &&
node.querySelector('.b3-list-item')
}, uls => {
// 获取大纲列表
const ul = uls[0];
// 遍历大纲第一级子元素
Array.from(ul.children).forEach(item => {
// 初始时,仅打开第一级
if(item.tagName === 'LI') {
const toggleBtn = item.querySelector('.b3-list-item__toggle');
const svg = toggleBtn?.querySelector('svg.b3-list-item__arrow');
if(!svg.classList.contains('b3-list-item__arrow--open')) {
svg.classList.add('b3-list-item__arrow--open');
}
}
if(item.tagName === 'UL') {
if(item.classList.contains('fn__none')) {
item.remove('fn__none');
}
// 初始时,隐藏第一级下面的后代元素
itemsShow(item, false);
}
// 监听大纲鼠标移入事件
const ul = item.tagName === 'LI' ? item.nextElementSibling : item;
item.addEventListener('mouseenter', (event) => {
if(!ul || ul?.tagName !== 'UL') return;
// 鼠标移入显示第一级后面的后代元素
itemsShow(ul, true);
})
// 监听大纲鼠标移出事件
item.addEventListener('mouseleave', (event) => {
//if(clicking) {
//clicking = false;
//return;
//}
if(!ul || ul?.tagName !== 'UL') return;
// 鼠标移出隐藏第一级后面的后代元素
itemsShow(ul, false);
// 始终定位光标处的标题
const heading = isInHeading();
if(heading){
headingNodeId = heading.dataset.nodeId;
const outlineNode = document.querySelector('.sy__outline [data-node-id="'+headingNodeId+'"]');
openCursorHeading(outlineNode);
}
});
// 监听大纲点击事件
// item.addEventListener('click', (event) => {
// clicking = true;
// });
});
});
// 添加光标被移动位置事件
document.addEventListener("selectionchange", () => {
//获取是否在heading中
const heading = isInHeading();
if(!heading) return;
// 关闭其他大纲展开
Array.from(el.firstElementChild.children).forEach(item => {
itemsShow(item, false);
});
// 展开光标处的标题
headingNodeId = heading.dataset.nodeId;
const outlineNode = document.querySelector('.sy__outline [data-node-id="'+headingNodeId+'"]');
openCursorHeading(outlineNode);
}, false);
});
function isInHeading() {
const el = getCursorElement();
let heading = el?.closest('[data-type="NodeHeading"]');
if(heading) {
return heading;
}
const Sibling = el?.closest('[data-node-index]');
heading = findPreviousNodeHeading(Sibling);
return heading;
}
function findPreviousNodeHeading(el) {
// 从当前元素开始向前查找兄弟节点
let sibling = el?.previousElementSibling;
while (sibling) {
// 检查是否具有 data-type="NodeHeading" 的属性
if (sibling.getAttribute('data-type') === 'NodeHeading') {
return sibling; // 找到了,返回这个节点
}
// 继续向前查找
sibling = sibling.previousElementSibling;
}
// 如果没有找到符合条件的兄弟节点,返回null
return null;
}
function openCursorHeading(node) {
// 遍历节点的祖先节点
while (node && !node.classList.contains('b3-list')) {
if (node.tagName === 'UL' && node.classList.contains('fn__none')) {
// 展开箭头
const li = node.previousElementSibling;
if(li){
const arrowSvg = li.querySelector('.b3-list-item__toggle svg.b3-list-item__arrow:not(.b3-list-item__arrow--open)');
if(arrowSvg) arrowSvg.classList.add('b3-list-item__arrow--open');
}
// 移除.fn__none类
node.classList.remove('fn__none');
}
// 向上查找父节点
node = node.parentElement;
}
}
function getCursorElement() {
const selection = window.getSelection();
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
// 获取选择范围的起始位置所在的节点
const startContainer = range.startContainer;
// 如果起始位置是文本节点,返回其父元素节点
const cursorElement = startContainer.nodeType === Node.TEXT_NODE
? startContainer.parentElement
: startContainer;
return cursorElement;
}
return null;
}
// 动态显示隐藏子标题
function itemsShow(ul, isOpen) {
if(isOpen){
const svgs = ul.querySelectorAll('span.b3-list-item__toggle svg:not(.b3-list-item__arrow--open)');
svgs.forEach(item => {
item.classList.add('b3-list-item__arrow--open');
});
const uls = ul.querySelectorAll('ul.fn__none');
uls.forEach(item => {
item.classList.remove('fn__none');
});
} else {
const svgs = ul.querySelectorAll('span.b3-list-item__toggle svg.b3-list-item__arrow--open');
svgs.forEach(item => {
item.classList.remove('b3-list-item__arrow--open');
});
const uls = ul.querySelectorAll('ul:not(.fn__none)');
uls.forEach(item => {
item.classList.add('fn__none');
});
}
}
function observeChildAddition(el, filter, handler) {
// 配置观察器选项
const config = { attributes: false, childList: true, subtree: false };
// 定义回调函数
const callback = function(mutationsList, observer) {
// 遍历 mutation 列表
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
// 查找新增加的具有类名 'b3-list' 的 ul 元素
const newULs = Array.from(mutation.addedNodes).filter(node => node.nodeType === Node.ELEMENT_NODE && filter(node));
// 如果有新的 ul 元素被添加,则调用处理函数
if(newULs.length > 0) {
handler(newULs);
}
}
}
};
// 创建一个新的 MutationObserver 实例
const observer = new MutationObserver(callback);
// 开始观察目标节点
observer.observe(el, config);
// 返回一个函数来停止观察
return () => {
observer.disconnect();
};
}
// 等待元素渲染完成后执行
function whenElementExist(selector, bySetTimeout = false, delay = 40) {
return new Promise(resolve => {
const checkForElement = () => {
let element = null;
if (typeof selector === 'function') {
element = selector();
} else {
element = document.querySelector(selector);
}
if (element) {
resolve(element);
} else {
if (bySetTimeout) {
setTimeout(checkForElement, delay);
} else {
requestAnimationFrame(checkForElement);
}
}
};
checkForElement();
});
}
})();