学习链接
效果图
使用步骤
1. 安装tocbot
npm install tocbot --save
2. vue组件中使用引入tocbot
只需要引入tocbot,然后调用tocbot.init(…),指定提取的文章内容所在的dom,以及要把生成的目录放到哪个dom里面,就可以生成目录了。
注意:tocbot要求原文章内容的h1-h6标签必须要有id才可以跳转的哦
。
<style lang="scss">
@import 'tocbot/src/scss/tocbot';
@import url('https://fonts.font.im/css?family=Roboto');
body {
margin: 0;
}
/* 整个滚动条 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* 滚动条上的滚动滑块,参考: 滚动条样式修改->https://blog.csdn.net/coder_jxd/article/details/124213962 */
::-webkit-scrollbar-thumb {
background-color: #49b1f5;
/* 关键代码 */
background-image: -webkit-linear-gradient(45deg,
rgba(255, 255, 255, 0.4) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.4) 50%,
rgba(255, 255, 255, 0.4) 75%,
transparent 75%,
transparent);
border-radius: 32px;
}
/* 添加行号插件后,它默认把滚动条给覆盖了,所以将padding-left改成margin-left */
[class*=v-md-prism-] {
margin-left: 72px !important;
padding-left: 0 !important;
}
/* 滚动条样式,参考: */
/* 滚动条轨道 */
::-webkit-scrollbar-track {
background-color: #dbeffd;
border-radius: 32px;
}
/* 行号相关样式 */
pre {
background-color: #282c34;
border-radius: 6px;
position: relative;
.line-numbers {
position: absolute;
color: #e0e0e0;
font-size: 16px;
margin: 16px 0;
padding-right: 10px;
width: 30px;
text-align: right;
font-family: 'Roboto', sans-serif;
border-right: 1px solid #c5c5c5;
}
}
code {
font-family: 'Roboto', sans-serif;
border-radius: 6px;
padding-left: 0 !important;
margin-left: 3em !important;
}
ul,
li {
margin: 0;
padding: 0;
list-style: none;
}
.article {
width: 600px;
display: flex;
width: 1200px;
margin: 0 auto;
margin-top: 50px;
.article-content {
width: 725px;
padding: 15px;
// border: 1px solid red;
border-radius: 5px;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.16);
flex-basis: 75%;
}
/* 目录相关样式 */
.right-container {
color: #666261;
padding-left: 15px;
.toc-wrapper {
position: sticky;
top: 10px;
flex-basis: 25%;
box-shadow: 0 4px 8px 6px rgba(7, 17, 27, .06);
padding: 20px;
border-radius: 10px;
.toc-header {
display: flex;
align-items: center;
padding: 10px;
}
#toc-content {
position: sticky;
top: 20px;
box-sizing: border-box;
width: 300px;
// border: 1px solid red;
background-color: #fff;
a {
transition: all 0.3s;
text-decoration: none;
display: block;
line-height: 1.6em;
padding-left: 10px;
border-left: 4px solid transparent;
&::before {
display: none;
}
&.is-active-link {
font-weight: normal;
color: #fff;
background-color: #00c4b6;
border-left-color: #009d92;
}
}
}
}
}
}
</style>
<template>
<div class="article">
<!-- <div style="height: 500px;"> </div> -->
<div class="article-content" id="article-content" v-html="htmlContent"></div>
<div class="right-container">
<div class="toc-wrapper">
<div class="toc-header">
<img src="@/assets/svg/menu.svg" style="margin-right: 8px;" width="16px" height="16px" alt="">
<span>目录</span>
</div>
<div id="toc-content"></div>
</div>
</div>
</div>
</template>
<script>
import { getArticle } from '@/api/articleApi'
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css'
console.log(hljs);
import tocbot from 'tocbot'
console.log('tocbot', tocbot);
export default {
name: 'Article',
data() {
return {
htmlContent: ''
}
},
created() {
getArticle(this.$route.params.articleId).then(data => {
this.htmlContent = data.htmlContent
this.$nextTick(() => {
// console.log('$nextTick...');
let articleContent = document.querySelector('#article-content')
let headingTag = ['h1', 'h2', 'h3']
let children = Array.from(articleContent.children)
for (let i = 0; i < children.length; i++) {
const e = children[i];
e.id = `h-${i}`
}
hljs.highlightAll()
let codes = document.querySelectorAll('code')
console.log(codes);
for (let i = 0; i < codes.length; i++) {
const codeBlock = codes[i];
// console.log(codeBlock.innerHTML);
let lineTotal = codeBlock.innerHTML.split('\n').length
let ul = document.createElement('ul')
ul.classList.add('line-numbers')
for (let i = 1; i <= lineTotal; i++) {
let li = document.createElement('li')
let lineNum = document.createTextNode(i)
li.appendChild(lineNum)
ul.appendChild(li)
}
codeBlock.parentNode.prepend(ul)
}
tocbot.init({
// Where to render the table of contents.
tocSelector: '#toc-content',
// Where to grab the headings to build the table of contents.
contentSelector: '#article-content',
// Which headings to grab inside of the contentSelector element.
headingSelector: 'h1, h2, h3, h4, h5, h6',
// For headings inside relative or absolute positioned containers within content.
hasInnerContainers: true,
});
})
})
},
mounted() {
// console.log('mounted');
},
components: {
}
}
</script>