vue实现目录
Vue 实现目录功能
在 Vue 中实现目录功能通常涉及动态渲染内容标题、监听滚动位置以及高亮当前章节。以下是常见的实现方法:
动态生成目录结构
使用 v-for 循环渲染标题元素,通过 querySelectorAll 获取页面中的标题标签(如 h2/h3):
<template>
<div class="toc">
<div v-for="(item, index) in headings" :key="index"
:class="{ active: activeIndex === index }"
@click="scrollTo(item)">
{{ item.text }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
headings: [],
activeIndex: 0
}
},
mounted() {
this.initHeadings()
window.addEventListener('scroll', this.onScroll)
},
methods: {
initHeadings() {
this.headings = Array.from(document.querySelectorAll('h2, h3'))
.map(el => ({
text: el.innerText,
offsetTop: el.offsetTop
}))
},
scrollTo(item) {
window.scrollTo({
top: item.offsetTop,
behavior: 'smooth'
})
},
onScroll() {
const scrollPosition = window.scrollY
this.headings.forEach((item, index) => {
if (item.offsetTop <= scrollPosition + 100) {
this.activeIndex = index
}
})
}
}
}
</script>
使用 IntersectionObserver 优化性能
替代滚动事件监听,减少性能消耗:
methods: {
setupObserver() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const index = this.headings.findIndex(
h => h.text === entry.target.innerText
)
this.activeIndex = index
}
})
}, { threshold: 0.5 })
document.querySelectorAll('h2, h3').forEach(el => {
observer.observe(el)
})
}
}
嵌套目录实现
对于多级目录(如 h2+h3 层级),需结构化数据:
computed: {
nestedHeadings() {
const result = []
let currentH2 = null
this.headings.forEach(item => {
if (item.tagName === 'H2') {
currentH2 = { ...item, children: [] }
result.push(currentH2)
} else if (currentH2) {
currentH2.children.push(item)
}
})
return result
}
}
样式优化
添加基础交互样式:
.toc {
position: fixed;
max-height: 100vh;
overflow-y: auto;
}
.toc div {
padding: 8px 12px;
cursor: pointer;
}
.toc div.active {
color: #42b983;
font-weight: bold;
}
.toc div.children {
padding-left: 20px;
font-size: 0.9em;
}
使用第三方库
如需快速实现,可考虑以下库:
vue-toc:自动生成目录组件vue-scrollactive:滚动高亮集成vue-affix:固定侧边栏定位
实现时需注意:

- 在
beforeDestroy中移除事件监听 - 对于 SSR 场景需做客户端判断
- 动态内容需使用
nextTick确保 DOM 更新






