vue中引入md文件,解析爲組件並實現代碼高亮

正在造一個的中後臺框架輪子 e-admin ,文檔與開發同步進行。
文檔部分涉及了markdown解析,剛開始是嘗試使用現成庫 vue-markdown-loader,可是代碼高亮部分很差定製處理,遂放棄。
第一次嘗試自已寫個loader,出乎意料的簡單。
markdown解析使用的是hyperdown
代碼高亮經過prismjs實現;
代碼高亮部分剛開始是嘗試用highlight.js可是不知爲什麼JavaScript第一行的格式化會出現異常,用prismjs則無此問題。
首先安裝依賴javascript

npm install hyperdown prismjs -D

建立loader

markdown-loader.jscss

const HyperDown = require('hyperdown');
const Prism = require('prismjs');

function markdownLoader(val) {
  let parser = new HyperDown();
  let html = parser.makeHtml(val);
  html = html.replace(/(?<=<pre><code[^>]*?>)[\s\S]*?(?=<\/code><\/pre>)/gi, v => {
    v = v.replace(/_&/g, ' ').replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
    return Prism.highlight(v, Prism.languages.javascript);
  });
  return (
    `<template><div class="markdown">${html}</div></template>`
  );
}

module.exports = markdownLoader;

使用

項目使用的是vue-cli 3.x,在vue.config.js添加如下配置html

module.exports = {
  configureWebpack: config => {
    config.module.rules.push({
        test: /\.md$/,
        use: [
          {
            loader: 'vue-loader',
          },
          {
            loader: require.resolve('./markdown-loader'),
          },
        ],
      },
    );
  },
};

在入口文件main.js導入prismjs樣式vue

import 'prismjs/themes/prism.css';

如今能夠把.md文件當成vue組件來使用了
test.mdjava

test.md

test.vuegit

<template>
  <test-md></test-md>
</template>
<script>
  import testMd from './test.md';

  export default {
    components: {testMd},

md組件效果
組件效果圖github

固然也能夠做爲路由組件來使用,最終實現以下預期效果vue-cli

路由組件效果

擴展 slot

自擼loader的另外一個好處就是自由度高,咱們能夠隨意擴展功能,好比既然md文件被解析成vue組件,由於文檔一般都伴隨着實例,若是能在裏面md裏面插入slot在使用中咱們隨意在插槽中插入實例,那可太方便了,實現起來也就是一個正則的事npm

function markdownLoader(val) {
  let parser = new HyperDown();
  let html = parser.makeHtml(val);
  html = html.replace(/(?<=<pre><code[^>]*?>)[\s\S]*?(?=<\/code><\/pre>)/gi, v => {
    v = v.replace(/_&/g, ' ').replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
    return Prism.highlight(v, Prism.languages.javascript);
  });
  // 解析slot轉換爲正常標籤
  html = html.replace(/&lt;slot[\s\S]*?&gt;&lt;\/slot&gt;/gi, v => {
    v = v.replace(/_&/g, ' ').replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
    return v;
  });
  return (
    `<template><div class="markdown">${html}</div></template>`
  );
}

如今咱們能夠在md文件裏面直接寫slot插槽了
test-slot.mdmarkdown

#擴展 slot 
###default
這裏插入一個默認插槽
<slot></slot>
####footer
這裏插入一個具名插槽
<slot name="footer"></slot>

在咱們實例中使用這個組件試試效果

<template>
  <test-slot>
    <el-button type="primary">default</el-button>
    <template v-slot:footer>
      <el-button type="success">footer</el-button>
    </template>
  </test-slot>
</template>
<script>
  import testSlot from './test-slot.md'

  export default {
    components: {
      testSlot
    },

運行 done
test-slot.md 效果


添加一個錨點id解析方案

/**
 * id解析方案
 * markdown  ###(#item-1)標題
 * html      <h3 id="item-1">標題</>
 * @type {string} 
 */
html = html.replace(/>\(#[\s\S]*?\)/gi, v => {
  const id = v.substr(3, v.length - 4);
  return ` id="${id}">`;
});

這段代碼插入到上面函數的return以前,就能夠把(#item-1)解析成當前標籤的id id = "item-1" ,效果是有的,可是由於這種寫法不是markdown規範,因此慎用吧

以這篇文章的內容爲基礎搭建的 e-admin中文文檔

相關文章
相關標籤/搜索