vue-markdown 之 markdown-it, 以及 table of content 的实现:markdown-it-toc-and-anchor

1. npm install --save uslug markdown-it markdown-it-toc-and-anchor

2. 主要代码

  • <template>
      <div id="lab_exp_book">
    
            ... ...
    
              <div class="directory_box">
                <div class="directory_title">目录</div>
                <ul class="directory_ul">
                  <li v-for="(item, index) in tocShow" :key="index">
                    <div v-if="item.children.length===0">
                      <a :class="{active: curContentScrollTop===item.anchorY}" class="lab_section_class hover_change_color"
                         @click="handleDirClick(item)" href="javascript:">{{item.nodeName}}</a>
                    </div>
    
                    <div v-else>
                      <div :class="{active: curContentScrollTop===item.anchorY || (!item.anchorY && index === 0)}" class="lab_section_title hover_change_color"
                           @click="handleDirClick(item)">{{item.nodeName}}</div>
                      <ul class="lab_section_children">
                        <li v-for="(each, index) in item.children" :key="index">
                          <div v-if="each.children.length===0">
                            <a  :class="{active: curContentScrollTop===each.anchorY}" class="lab_section_class hover_change_color"
                                @click="handleDirClick(each)" href="javascript:">{{each.nodeName}}</a>
                          </div>
    
                          <div v-else>
                            <div :class="{active: curContentScrollTop===each.anchorY}" class="lab_section_title hover_change_color"
                                 @click="handleDirClick(each)">{{each.nodeName}}</div>
                            <ul class="lab_section_children">
                              <li v-for="(third, index) in each.children" :key="index">
                                <div>
                                  <a  :class="{active: curContentScrollTop===third.anchorY}" class="lab_section_class hover_change_color"
                                      @click="handleDirClick(third)" href="javascript:">{{third.nodeName}}</a>
                                </div>
                              </li>
                            </ul>
                          </div>
                        </li>
                      </ul>
                    </div>
                  </li>
                </ul>
    
                <div class="directory_tips">开始学习后可阅读实验手册内容</div>
              </div>
            </div>
    
            <div class="right_book_content" ref="rightBookContent">
              <div class="book_box" v-if="1">
                <div class="lab_simple_content clearfix" v-html="htmlStr">
                </div>
              </div>
    
            ... ...
    
      </div>
    </template>
    
    <script>
      import uslug from 'uslug'
      import MarkdownIt from 'markdown-it'
      import markdownItTocAndAnchor from 'markdown-it-toc-and-anchor'
      data () {
          return {
             mdStr: '相关md字符串',
             htmlStr: '',    // 渲染到页面
             tocArray: [],
             tocShow: [],    // 渲染到页面
             isFirstClickDir: true,
             curContentScrollTop: 2
          }
      },
        computed: {
          ...mapState({
            labDirectory: state => state.lab.labDirectory
          })
        },
        watch: {
          tocArray: {
            deep: true,
            handler (newValue) {
              const oldArr = JSON.parse(JSON.stringify(newValue))
    
              let tocArr = []
              let cur1Arr = null
              let cur2Arr = null
              let cur3Arr = null
              let cur4Arr = null
              let cur5Arr = null
              oldArr.reduce((newArr, next) => {
                if (next.level === 2) {
                  cur1Arr = JSON.parse(JSON.stringify(next))
                  cur1Arr.children = []
                  cur1Arr.nodeName = cur1Arr.content
                  cur2Arr = cur1Arr.children
                  tocArr.push(cur1Arr)
                } else if (next.level === 3) {
                  cur3Arr = JSON.parse(JSON.stringify(next))
                  cur3Arr.children = []
                  cur3Arr.nodeName = cur3Arr.content
                  cur4Arr = cur3Arr.children
                  cur2Arr.push(cur3Arr)
                } else if (next.level === 4) {
                  cur5Arr = JSON.parse(JSON.stringify(next))
                  cur5Arr.children = []
                  cur5Arr.nodeName = cur5Arr.content
                  // cur6Arr = cur5Arr.children
                  cur4Arr.push(cur5Arr)
                }
                return newArr
              }, [])
    
              this.tocShow = tocArr
            }
          }
        },
        async mounted () {
          this.myConsole('_labExpBookInit')
          this._initLabExpBook()
          await this.$store.dispatch('getLabDirectory')
        },
        methods: {
          _uslugify(x) {
            return uslug(x)
          },
          _initLabExpBook () {
            let md = new MarkdownIt({
              html: false,
              xhtmlOut: true,
              typographer: true
            })
    
            md.use(markdownItTocAndAnchor, {slugify: this._uslugify})
    
            this.htmlStr = md.set({
              tocCallback: (tocMarkdown, tocArray, tocHtml) => {
                this.tocArray = tocArray
              }
            }).render(this.mdStr)
          },
          handleDirClick(dirNode) {
            window.scrollTo(0, 502)
            if (this.isFirstClickDir) {
              this.isFirstClickDir = false
              this._initDirScrollPos()
              bindEventFunc(this.$refs.rightBookContent, 'scroll', () => {
                this.curContentScrollTop = this.$refs.rightBookContent.scrollTop
              })
            }
            this.$refs.rightBookContent.scrollTo({ top: dirNode.anchorY, left: 0, behavior: 'smooth' })
          },
          _initDirScrollPos () {
            this.tocShow = this.tocShow.map((ele) => {
              myConsole(ele.anchor)
              this._addAnchorY(ele)
              if (ele.children.length > 0) {
                ele.children.forEach((each, i) => {
                  myConsole(ele.children[i].anchor)
                  this._addAnchorY(ele.children[i])
                  if (each.children.length > 0) {
                    each.children.forEach((one, j) => {
                      myConsole(ele.children[i].children[j].anchor)
                      this._addAnchorY(ele.children[i].children[j])
                    })
                  }
                })
              }
              return ele
            })
          },
          _addAnchorY (ele) {
            ele.anchorY = document.getElementById(ele.anchor).getBoundingClientRect().top - 120
          }
        ... ...
    </script>

3. 效果截图

--------小尾巴 ________一个人欣赏-最后一朵颜色的消逝-忠诚于我的是·一颗叫做野的心.决不受人奴役.怒火中生的那一刻·终将结束...
原文地址:https://www.cnblogs.com/tianxiaxuange/p/10908230.html