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

思路

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

参考 vue doc

实战

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

结果


提取标签

<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

makeLink 转换成a标签函数

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;')
 }
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现 markdown 目录自动生成可以使用 markdown-it 插件,并结合 vue.js 实现。可以按以下步骤进行操作: 1. 安装依赖:`npm install markdown-it --save` 2. 在 vue 组件中引入 markdown-it:`import MarkdownIt from 'markdown-it'` 3. 创建 markdown-it 实例:`const md = new MarkdownIt()` 4. 解析 markdown 内容并生成 html:`const html = md.render(markdownContent)` 5. 使用正则表达式从生成的 html 中提取出所有标题(如 h1、h2、h3 等),并生成目录列表。 6. 将目录列表渲染到页面上。 以下是一个简单的实现示例: ```vue <template> <div> <div class="markdown-body" v-html="html"></div> <div class="toc" v-html="toc"></div> </div> </template> <script> import MarkdownIt from 'markdown-it' export default { data() { return { html: '', toc: '', } }, mounted() { const md = new MarkdownIt() const markdownContent = '# Title1\nContent1\n## Title2\nContent2\n### Title3\nContent3' const html = md.render(markdownContent) const toc = this.generateToc(html) this.html = html this.toc = toc }, methods: { generateToc(html) { const toc = [] const headers = html.match(/<h\d.*?>(.*?)<\/h\d>/gi) if (headers) { headers.forEach((header) => { const level = header.match(/<h(\d).*?>/i)[1] const title = header.replace(/<\/?h\d>/gi, '') toc.push(`<li class="toc-level-${level}"><a href="#">${title}</a></li>`) }) } return toc.length ? `<ul>${toc.join('')}</ul>` : '' }, }, } </script> ``` 在上面的示例中,我们首先创建了一个 markdown-it 实例,然后使用 render 方法将 markdown 内容转换成 html。接着,我们通过正则表达式从 html 中提取出所有标题,并生成目录列表。最后,将目录列表渲染到页面上。 需要注意的是,上面的示例只实现了基本的目录生成功能。如果需要更复杂的功能,可以考虑使用已有的 markdown-it 插件或者编写自己的插件来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值