vue实现文章目录
实现文章目录的基本思路
在Vue中实现文章目录,通常需要解析文章的标题(如h1、h2、h3等标签),动态生成目录结构,并支持点击跳转。以下是具体实现方法:
解析文章标题
通过DOM操作或正则表达式提取文章中的标题元素。假设文章内容包裹在<div id="article-content">中:
const headings = document.querySelectorAll('#article-content h1, #article-content h2, #article-content h3');
生成目录数据结构
遍历标题元素,提取文本和层级信息,生成树形结构或扁平数组:

const toc = Array.from(headings).map((heading) => ({
id: heading.id || `heading-${Math.random().toString(36).substr(2, 9)}`,
text: heading.innerText,
level: parseInt(heading.tagName.substring(1)),
}));
渲染目录组件
在Vue组件中,使用v-for动态渲染目录,并通过缩进或样式区分层级:
<template>
<div class="toc">
<div
v-for="item in toc"
:key="item.id"
:class="`toc-level-${item.level}`"
@click="scrollTo(item.id)"
>
{{ item.text }}
</div>
</div>
</template>
实现点击跳转
通过scrollIntoView或Vue Router的锚点跳转实现目录导航:

methods: {
scrollTo(id) {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
}
}
动态高亮当前章节
监听滚动事件,计算当前可见的标题并高亮对应目录项:
mounted() {
window.addEventListener('scroll', this.handleScroll);
},
methods: {
handleScroll() {
const scrollPosition = window.scrollY;
this.toc.forEach((item) => {
const element = document.getElementById(item.id);
if (element) {
const rect = element.getBoundingClientRect();
if (rect.top >= 0 && rect.top < 100) {
this.activeId = item.id;
}
}
});
}
}
样式优化
通过CSS控制目录的层级缩进和交互效果:
.toc-level-1 { font-weight: bold; margin-left: 0; }
.toc-level-2 { margin-left: 1rem; }
.toc-level-3 { margin-left: 2rem; }
.toc-item:hover { color: #42b983; cursor: pointer; }
.active { color: #42b983; font-weight: bold; }
完整组件示例
<template>
<div class="toc-container">
<div
v-for="item in toc"
:key="item.id"
:class="['toc-item', `toc-level-${item.level}`, { active: activeId === item.id }]"
@click="scrollTo(item.id)"
>
{{ item.text }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
toc: [],
activeId: '',
};
},
mounted() {
this.generateToc();
window.addEventListener('scroll', this.handleScroll);
},
methods: {
generateToc() {
const headings = document.querySelectorAll('#article-content h1, #article-content h2, #article-content h3');
this.toc = Array.from(headings).map((heading) => ({
id: heading.id || `heading-${Math.random().toString(36).substr(2, 9)}`,
text: heading.innerText,
level: parseInt(heading.tagName.substring(1)),
}));
},
scrollTo(id) {
const element = document.getElementById(id);
if (element) element.scrollIntoView({ behavior: 'smooth' });
},
handleScroll() {
const scrollPosition = window.scrollY;
this.toc.forEach((item) => {
const element = document.getElementById(item.id);
if (element) {
const rect = element.getBoundingClientRect();
if (rect.top >= 0 && rect.top < 100) {
this.activeId = item.id;
}
}
});
},
},
};
</script>
注意事项
- 标题ID唯一性:确保每个标题有唯一的
id,否则跳转可能失效。 - 性能优化:滚动事件监听建议使用防抖(debounce)避免频繁触发。
- 服务端渲染(SSR):需在客户端动态生成目录,避免服务端无法访问DOM。






