markdown-it代碼塊渲染、自定義行號、複製代碼功能

之前寫過一篇關於代碼塊渲染添加自定義行號的文章:markdown-it和highlight.js的結合渲染代碼,並添加自定義行號

不過在之後的渲染使用過程中由於效果不是很好,所以重新改版,並藉此機會添加複製代碼功能。

本博客採用的後端是 node.js 框架 Express,在使用 markdown-it 渲染 md 文件的時候,選擇在添加文章或者更新文章的時候由 md 生成 html。

代碼塊生成

const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight: function (str, lang) {
    // 當前時間加隨機數生成唯一的id標識
    const codeIndex = parseInt(Date.now()) + Math.floor(Math.random() * 10000000)
    // 複製功能主要使用的是 clipboard.js
    let html = `<button class="copy-btn" type="button" data-clipboard-action="copy" data-clipboard-target="#copy${codeIndex}">複製</button>`
    const linesLength = str.split(/\n/).length - 1
    // 生成行號
    let linesNum = '<span aria-hidden="true" class="line-numbers-rows">'
    for (let index = 0; index < linesLength; index++) {
      linesNum = linesNum + '<span></span>'
    }
    linesNum += '</span>'
    if (lang && hljs.getLanguage(lang)) {
      try {
        // highlight.js 高亮代碼
        const preCode = hljs.highlight(lang, str, true).value
        html = html + preCode
        if (linesLength) {
          html += '<b class="name">' + lang + '</b>'
        }
        // 將代碼包裹在 textarea 中
        return `<pre class="hljs"><code>${html}</code>${linesNum}</pre><textarea style="position: absolute;top: -9999px;left: -9999px;z-index: -9999;" id="copy${codeIndex}">${str.replace(/<\/textarea>/g, '&lt;/textarea>')}</textarea>`
      } catch (error) {
        console.log(error)
      }
    }

    const preCode = md.utils.escapeHtml(str)
    html = html + preCode
    // 將代碼包裹在 textarea 中
    return `<pre class="hljs"><code>${html}</code>${linesNum}</pre><textarea style="position: absolute;top: -9999px;left: -9999px;z-index: -9999;" id="copy${codeIndex}">${str.replace(/<\/textarea>/g, '&lt;/textarea>')}</textarea>`
  }
})

前端

前端實現代碼選中的功能:

import Clipboard from 'clipboard'

export default {
  ...
  data () {
    return {
      ...
      clipboard: ''
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.clipboard = new Clipboard('.copy-btn')
      // 複製成功失敗的提示
      this.clipboard.on('success', (e) => {
        this.$message.success('複製成功')
      })
      this.clipboard.on('error', (e) => {
        this.$message.error('複製成功失敗')
      })
    })
  },
  ...
  destroyed () {
    this.clipboard.destroy()
  }
}

自定義行號

pre.hljs {
  padding: 12px 2px 12px 40px !important;
  border-radius: 5px !important;
  position: relative;
  font-size: 14px !important;
  line-height: 22px !important;
  overflow: hidden !important;
  code {
    display: block !important;
    margin: 0 10px !important;
    overflow-x: auto !important;
  }
  .line-numbers-rows {
    position: absolute;
    pointer-events: none;
    top: 12px;
    bottom: 12px;
    left: 0;
    font-size: 100%;
    width: 40px;
    text-align: center;
    letter-spacing: -1px;
    border-right: 1px solid rgba(0, 0, 0, .66);
    user-select: none;
    counter-reset: linenumber;
    span {
      pointer-events: none;
      display: block;
      counter-increment: linenumber;
      &:before {
        content: counter(linenumber);
        color: #999;
        display: block;
        text-align: center;
      }
    }
  }
  b.name {
    position: absolute;
    top: 2px;
    right: 50px;
    z-index: 10;
    color: #999;
    pointer-events: none;
  }
  .copy-btn {
    position: absolute;
    top: 2px;
    right: 4px;
    z-index: 10;
    color: #333;
    cursor: pointer;
    background-color: #fff;
    border: 0;
    border-radius: 2px;
  }
}

自定義行號主要使用的是CSS計數方面的知識,感興趣可以查看 css計數器

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章