【前端markdown】markdown 提取目录 增加用户体验

【前端markdown】markdown 提取目录 增加用户体验

思路

首发 http://shudong.wang/article/103
根据markdown生成的html,二级标题,和三级标题的标志:h2 h3标签提取.
利用锚点加入a标签可以点击跳转到id,实现提取目录跳转。

参考 vue doc

实战

本篇教程只提取二级标签,后续会优化,请持续关注

结果


提取标签

vuejs dom

<div class="content" ref="content" v-html="article.content">

</div>

获取dom

let content = this.$refs.content;
// 提取h2标签
let headers = content.querySelectorAll('h2')
let each = [].forEach
let str = document.createElement('ul')
each.call(headers, function (h) {
  str.appendChild(self.makeLink(h))
})
makeLink 函数做的事情,添加a标签
返回 字符串dom
return str.innerHTML
function makeLink (h) {
  var link = document.createElement('li')
  window.arst = h
  var text = [].slice.call(h.childNodes).map(function (node) {
    if (node.nodeType === Node.TEXT_NODE) {
      return node.nodeValue
    } else if (['CODE', 'SPAN'].indexOf(node.tagName) !== -1) {
      return node.textContent
    } else {
      return ''
    }
  }).join('').replace(/\(.*\)$/, '')
  link.innerHTML =
    '<a class="section-link" data-scroll href="#' + h.id + '">' +
      htmlEscape(text) +
    '</a>'
  return link
}

vuejs 全部

  mounted(){
     this.sectionContainer = this.getContent()
   },
   methods: {
     getArticleList() {
       var params = {
         id: this.id
       };
       this.$http.get('/articles/desc', {
         params
       }).then((res) => {
         this.article = res.data;
       })
     },
     handleCurrentChange(val) {
       this.page = val;
       this.getArticleList();
       this.$router.replace({
         path: `/blog/${val}`
       })
     },
     makeLink (h) {
       var link = document.createElement('li')
       window.arst = h
       var text = [].slice.call(h.childNodes).map(function (node) {
         if (node.nodeType === Node.TEXT_NODE) {
           return node.nodeValue
         } else if (['CODE', 'SPAN'].indexOf(node.tagName) !== -1) {
           return node.textContent
         } else {
           return ''
         }
       }).join('').replace(/\(.*\)$/, '')
       link.innerHTML =
         '<a class="section-link" data-scroll href="#' + h.id + '">' +
           this.htmlEscape(text) +
         '</a>'
       return link
     },
      htmlEscape (text) {
     return text
       .replace(/&/g, '&amp;')
       .replace(/"/g, '&quot;')
       .replace(/'/g, '&#39;')
       .replace(/</g, '&lt;')
       .replace(/>/g, '&gt;')
   },
     collectH3s (h) {
     var h3s = []
     var next = h.nextSibling
     while (next && next.tagName !== 'H2') {
       if (next.tagName === 'H3') {
         h3s.push(next)
       }
       next = next.nextSibling
     }
     return h3s
   },
     getContent(){
       var self = this
       var sectionContainer
       var each = [].forEach
       // 获取dom
       var content = this.$refs.content;
       // 提取h2标签
       var headers = content.querySelectorAll('h2')
       sectionContainer = document.createElement('ul')
       each.call(headers, function (h) {
         sectionContainer.appendChild(self.makeLink(h))
       })
       return  sectionContainer.innerHTML
     }
   }

原生js

var sectionContainer
sectionContainer = document.createElement('ul')
var each = [].forEach
var content = document.querySelector('.content')
var headers = content.querySelectorAll('h2')
each.call(headers, function (h) {
   sectionContainer.appendChild(makeLink(h))
 })

 function makeLink (h) {
   var link = document.createElement('li')
   window.arst = h
   var text = [].slice.call(h.childNodes).map(function (node) {
     if (node.nodeType === Node.TEXT_NODE) {
       return node.nodeValue
     } else if (['CODE', 'SPAN'].indexOf(node.tagName) !== -1) {
       return node.textContent
     } else {
       return ''
     }
   }).join('').replace(/\(.*\)$/, '')
   link.innerHTML =
     '<a class="section-link" data-scroll href="#' + h.id + '">' +
       htmlEscape(text) +
     '</a>'
   return link
 }

 function htmlEscape (text) {
   return text
     .replace(/&/g, '&amp;')
     .replace(/"/g, '&quot;')
     .replace(/'/g, '&#39;')
     .replace(/</g, '&lt;')
     .replace(/>/g, '&gt;')
 }