js实现目录
使用 DOM 操作生成目录
通过遍历文档中的标题元素(如 h1、h2、h3 等),动态生成目录结构并插入到页面中。

function generateTOC() {
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
const tocContainer = document.createElement('div');
tocContainer.id = 'toc';
let currentLevel = 1;
let tocHTML = '<ul>';
headings.forEach((heading, index) => {
const level = parseInt(heading.tagName.substring(1));
const id = `heading-${index}`;
heading.id = id;
if (level > currentLevel) {
tocHTML += '<ul>';
} else if (level < currentLevel) {
tocHTML += '</ul></li>'.repeat(currentLevel - level);
} else if (index !== 0) {
tocHTML += '</li>';
}
tocHTML += `<li><a href="#${id}">${heading.textContent}</a>`;
currentLevel = level;
});
tocHTML += '</li></ul>'.repeat(currentLevel - 1) + '</ul>';
tocContainer.innerHTML = `<h2>目录</h2>${tocHTML}`;
document.body.prepend(tocContainer);
}
generateTOC();
使用 Intersection Observer 实现动态高亮
结合 Intersection Observer 监听当前滚动位置,高亮显示目录中对应的条目。

function setupTOCHighlight() {
const links = document.querySelectorAll('#toc a');
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const id = entry.target.id;
const link = document.querySelector(`#toc a[href="#${id}"]`);
if (entry.isIntersecting) {
links.forEach((l) => l.classList.remove('active'));
link?.classList.add('active');
}
});
},
{ rootMargin: '-50% 0px -50% 0px' }
);
headings.forEach((heading) => observer.observe(heading));
}
setupTOCHighlight();
添加 CSS 样式
为目录添加基础样式,使其更易读和交互友好。
#toc {
position: fixed;
top: 20px;
left: 20px;
max-width: 250px;
background: #f9f9f9;
padding: 10px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
#toc ul {
list-style: none;
padding-left: 20px;
}
#toc a {
text-decoration: none;
color: #333;
}
#toc a.active {
font-weight: bold;
color: #0066cc;
}
优化目录生成逻辑
如果文档结构较深,可优化生成逻辑,避免嵌套过多 ul 导致性能问题。
function generateOptimizedTOC() {
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
const tocContainer = document.getElementById('toc') || document.createElement('div');
tocContainer.id = 'toc';
const stack = [];
let html = '';
headings.forEach((heading, index) => {
const level = parseInt(heading.tagName.substring(1));
const id = `heading-${index}`;
heading.id = id;
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
stack.pop();
html += '</ul>';
}
if (stack.length === 0 || stack[stack.length - 1].level < level) {
html += '<ul>';
stack.push({ level, id });
}
html += `<li><a href="#${id}">${heading.textContent}</a>`;
});
html += '</ul>'.repeat(stack.length);
tocContainer.innerHTML = `<h2>目录</h2>${html}`;
document.body.prepend(tocContainer);
}
generateOptimizedTOC();






