学习链接
github上的tocbot
npmjs上的tocbot
效果图
使用步骤
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.htmlContentthis.$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').lengthlet 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>