html / vue 自动生成目录

本示例展示了如何在 Vue 中动态生成文章目录,根据 H1 到 H6 标题创建目录列表,并实现点击目录时内容区域滚动到对应标题。通过遍历 main 标签内的子元素,收集一级至六级标题信息,包括标题内容、HTML 代码、层级和偏移顶部距离。应用中还包含了一个固定定位的目录框和滚动同步功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现原理

获取全部内容节点,对节点进行遍历,将其中的标题节点存入目录列表中

完整范例代码 (以vue为例)

<template>
    <div style="padding: 20px">
        <div class="menuBox">
            <p>目录</p>
            <el-scrollbar ref="scrollMenuRef" class="scrollMenuBox">
                <aside v-for="i in menuList" :key="i" v-html="i.title"></aside>
            </el-scrollbar>
        </div>
        <div class="contentBox">
            <main v-for="i in Total" :key="i">
                <h1>一级标题{{i}}</h1>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
                <h2>二级标题{{i}}</h2>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
                <p>内容{{i}}</p>
            </main>
        </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                menuList: [],
                Total: 60
            }
        },
        mounted() {
            [...document.getElementsByTagName("main")]
                .forEach(item => {
                    [...item.children].forEach(
                        item2 => {
                            if (item2.tagName === "H1") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 1,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                            if (item2.tagName === "H2") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 2,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                            if (item2.tagName === "H3") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 3,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                            if (item2.tagName === "H4") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 4,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                            if (item2.tagName === "H5") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 5,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                            if (item2.tagName === "H6") {
                                this.menuList.push(
                                    {
                                        content: item2.innerText,
                                        title: item2.outerHTML,
                                        level: 6,
                                        offsetTop: item2.offsetTop
                                    }
                                )
                            }
                        }
                    )
                })
        },
    }
</script>
<style scoped>
    /*目录悬浮*/
    .menuBox {
        position: fixed;
    }

    /*内容居中*/
    .contentBox {
        width: 60%;
        margin: auto;
    }

    /*el-scrollbar 必须指定高度*/
    .scrollMenuBox {
        height: 600px;
        width: 200px;
    }

    /*隐藏水平滚动条*/
    /deep/ .el-scrollbar__wrap {
        overflow-x: hidden;
    }
</style>

最终效果

### 实现 Vue3 自动生成目录 为了实现在 Vue3 项目中根据页面内容自动生成目录的功能,可以采用多种方法和技术栈来达成目标。一种常见的方式是利用 `v-md-editor` 或者其他支持 Markdown 解析的库配合原生 JavaScript 来解析 HTML 结构并构建相应的导航条目[^1]。 #### 使用 v-md-editor 和 generate-asset-webpack-plugin 的组合方案 首先,在 Vue3 中集成 `v-md-editor` 可以方便地处理 Markdown 文本转换成 HTML 内容。接着,通过监听 DOM 更新事件获取渲染后的 HTML 节点,并从中提取所有的标题标签 (`<h1>` 到 `<h6>`) 创建目录列表项。当用户点击某个目录链接时,则平滑滚动至对应的内容部分。 对于更复杂的场景,比如希望在打包过程中动态创建配置文件或其他静态资源,可借助于 Webpack 提供的强大插件机制,如 `generate-asset-webpack-plugin` 插件能够帮助开发者轻松实现这一需求[^3]。 下面是一个简单的例子展示如何基于上述思路编写代码: ```javascript // main.js or setup file of your project import { createApp } from 'vue'; import App from './App.vue'; const app = createApp(App); app.use(VueMarkdownEditor); // 假设已经安装好 VMD Editor 组件 app.mount('#app'); // 在组件内部操作如下: export default { mounted() { this.$nextTick(() => { const headings = [...document.querySelectorAll('article h1, article h2')]; let tocHtml = '<ul>'; headings.forEach((heading) => { const id = heading.id; const text = heading.innerText || heading.textContent; tocHtml += `<li><a href="#${id}">${text}</a></li>`; }); tocHtml += '</ul>'; document.querySelector('.toc').innerHTML = tocHtml; // 将 TOC 渲染到指定容器内 }); } } ``` 此段脚本会在每次视图更新之后执行一次,确保即使有新的章节被加载进来也能及时反映在侧栏目录上。同时需要注意的是,这里假设存在一个名为 `.toc` 的 CSS 类用于放置最终生成出来的目录结构;而实际应用当中可能还需要考虑样式美化等问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝阳39

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值