简单的JS滚动目录(动态高亮)的实现.
兼容性未测试!
本代码是作者初学时编写的,现已在 Next、Nuwari 等地使用了更新且略微规范的代码,不建议再使用本文章提及的代码。
JavaScript
参数
markdown_content: 文章容器(Node)
需要更改的地方
#toc: 挂载目录的容器
Code
function TOC(markdown_content) {
let toc = document.querySelector("#toc");
if(!toc) return;
let tocList = markdown_content.querySelectorAll("h1, h2, h3, h4, h5, h6");
let liList = [];
tocList.forEach((v) => {
let pid = '_' + Date.now().toString(36) + Math.random().toString(36).replace(/[\s\S]{3}/, '');
v.id = pid;
const H = v.nodeName[1];
let li = document.createElement('li');
li.classList.add(`li-${H}`);
li.setAttribute('pid', pid);
li.textContent = v.textContent;
li.addEventListener("click", () => {
window.scrollBy({ top: v.getBoundingClientRect().y, behavior: "smooth" });
});
toc.appendChild(li);
liList.push(li);
})
let tocArr = Array.from(tocList);
const removeClass = () => {
liList.forEach(v => v.classList.remove("active"));
}
const update = () => {
for (let i = 0; i < tocArr.length; i++) {
let v = tocArr[i];
let rect = v.getBoundingClientRect();
let top = rect.top + rect.height;
if (top > 0) {
removeClass();
let li = liList[i];
li.classList.add('active');
/*
这两句代码用来实现目录左侧的进度条,需要搭配CSS实现,删除没有影响。
CSS见下文
toc.style.setProperty('--g-start',li.offsetTop+li.getBoundingClientRect().height-5+'px');
toc.style.setProperty('--g-end',li.offsetTop+li.getBoundingClientRect().height+5+'px');
*/
break;
}
}
}
let ticking = false;
window.addEventListener("scroll", () => {
if (!ticking) {
window.requestAnimationFrame(() => {
update();
ticking = false;
})
}
ticking = true;
});
update();
}