vue3解析markdown文件为html并且高亮显示代码块

前言:

很多时候我们程序员写的文档都是以markdown为主,但是我们每次找相关资料极为不便,如果能直接把markdown文档引进vue项目里,解析成html并且展示出来,然后部署在服务器上,查看是不是极为方便呢。(在做公司的私有组件库的时候,每一个组件都有一个README.md,我们在代码里查看并不方便,何不在展示组件的时候,把对应的README.md的也引进来解析出来,边看效果,边看文档多香啊)。

安装插件:

需要安装marked 和highlight.js两种插件

npm i marked highlight.js -D

编写mdToJs.js,用于将markdown文档转化为js

以下代码可直接复制应用

import path from "path";
import fs from "fs";
import { marked } from "marked";

const mdToJs = (str) => {
  const content = JSON.stringify(marked(str));
  return `export default ${content}`;
};

export function md() {
  return {
    name: "md",
    configureServer() {
      // 用于开发
      async ({ app }) => {
        app.use(async (ctx, next) => {
          // koa
          if (ctx.path.endsWith(".md")) {
            ctx.type = "js";
            const filePath = path.join(process.cwd(), ctx.path);
            ctx.body = mdToJs(fs.readFileSync(filePath).toString());
          } else {
            await next();
          }
        });
      };
    },
    transform(code, id) {
      // 用于 rollup // 插件
      // 获取文件后缀名
      const fileArr = id.split("."); //根据.分割数组
      const fileType = fileArr[fileArr.length - 1]; //取最后一个

      if (/\md$/.test(fileType)) {
        return mdToJs(code);
      }
      return;
    },
  };
}

配置vite.config.js

引入上面的md.js,在plugins里注入调用

import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { md } from "./mdToJs";

// https://vitejs.dev/config/
export default defineConfig({
  base: "/",
  server: {
    open: true,
    hmr: true,
  },
  plugins: [vue(), md()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});

到这里,项目里已经可以正常引入md文档,不报错了

我们来看看效果

因为解析成js,所以我们渲染的时候,需要用v-html来渲染

<template>
  <div>MD</div>
  <article v-html="MDFile" />
</template>

<script setup>
import MDFile from "./assets/README.md";
</script>

 我们可以看到,代码块是没有高亮显示的

接下来,我们将会借助highlight.js进行高亮显示代码块

高亮显示

写一个自定义hooks,然后在需要高亮的页面里调用这个hooks

src/hooks/md.js

下面的hooks可以直接复制到项目里用

import { onMounted } from "vue";
import hljs from "highlight.js"; // 引入 highlight.js

export function useHighLight() {
  const handleHighLight = () => {
    let blocks = document.querySelectorAll("pre code");
    blocks.forEach((block) => {
      hljs.highlightBlock(block);
    });
  };

  onMounted(() => {
    handleHighLight();
  });
}

 highlight.js事实上提供了很多种主题的高亮样式,我们看一下node_modules里

 我们选择其中一种引入到全局里就好

main.js

// import './assets/main.css'
import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import App from "./App.vue";
//引入highlight.js其中一种主题样式
import "highlight.js/styles/monokai-sublime.css"; 

const app = createApp(App);

app.use(ElementPlus);
app.mount("#app");

在需要高亮显示代码块的页面里调用上面的hooks

<template>
  <div>MD</div>
  <article v-html="MDFile" />
</template>

<script setup>
import MDFile from "./assets/README.md";
import { useHighLight } from '../src/hooks/md'

useHighLight()
</script>

再看一下效果

md解析完成,高亮显示代码块完成~


拓展:

下面是一些其他方面的心得,感兴趣的可以看下。

事实上,我们在plugins注入的md函数将markdown转化为js。还有其他方式,比如可以把markdown转化为vue。让我们来看下如何运用

编写mdToVue.js将markdown转化为vue

/*
 * @Description:
 * @Author: yangxiao
 * @Date: 2024-04-10 13:20:15
 * @LastEditTime: 2024-04-12 11:16:23
 * @LastEditors: yangxiao
 */
import { marked} from 'marked'

export default function (options) {
  return {
    name: 'vitePluginMd2Vue',
    transform(src, id) {
      /**
      * id是导入的文件路径
      * src是导入的文件内容
      */
      if (id.endsWith(".md")) { // 判断结尾字符串判断是否为markdown文件

        return {
          // code中使用sfc会导致没有走vite的解析流程,所以直接使用渲染函数编写
          code: `import {h, defineComponent} from "vue";
                const _sfc_md = defineComponent({
                    name: "Markdown",
                });

                const _sfc_render =() => {
                    return h("div", {
                      innerHTML: ${JSON.stringify(marked(src))},
                    })
                };

                _sfc_md.render = _sfc_render
                export default _sfc_md`, // code是转换后最终输出的代码
          map: null  // 是否提供source map,这里可以不用考虑
        }
      }
    }
  }
}

在vite.config.js的plugins里注入调用

import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import mdToVue from './examples/plugin/mdToVue.js'

// https://vitejs.dev/config/
export default defineConfig({
  base: "/",
  server: {
    open: true,
    hmr: true,
  },
  plugins: [vue(), mdToVue()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});

这个时候我们可以直接在页面里引入markdown文件,解析成html进行展示

<template>
  <div>MD</div>
  <MDFile/>
</template>

<script setup>
import MDFile from "./assets/README.md";
</script>

高亮的相关配置和上面的没有区别~

高亮随机主题色

我们从上面的node_modules的截图里可以看到,事实上,highlight.js提供了很多种高亮样式主题,我们只用一种未免过于单调,所以笔者呢,挑了10种,做了个随机代码高亮主题

编写一个mdCodeTheme.js用于存放随机高亮主题的代码

@/utils/mdCodeTheme.js

function getRandomInt() {
  return Math.floor(Math.random() * 10) + 1;
}

switch (getRandomInt()) {
  case 1:
    import("highlight.js/styles/devibeans.css");
    break;
  case 2:
    import("highlight.js/styles/a11y-dark.css");
    break;
  case 3:
    import("highlight.js/styles/agate.css");
    break;
  case 4:
    import("highlight.js/styles/an-old-hope.css");
    break;
  case 5:
    import("highlight.js/styles/androidstudio.css");
    break;
  case 6:
    import("highlight.js/styles/felipec.css");
    break;
  case 7:
    import("highlight.js/styles/arta.css");
    break;
  case 8:
    import("highlight.js/styles/github-dark-dimmed.css");
    break;
  case 9:
    import("highlight.js/styles/atom-one-dark-reasonable.css");
    break;
  case 10:
    import("highlight.js/styles/monokai-sublime.css");
    break;
}

然后把上面的mdCodeTheme.js引入到main.js里就好

// import './assets/main.css'
import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import App from "./App.vue";
import './src/utils/mdCodeTheme'

const app = createApp(App);

app.use(ElementPlus);
app.mount("#app");

这样就能每次进入项目的时候随机切换主题色啦~

手动切换高亮主题色

这里提供一个思路吧,就不再进行代码演示了。

在header区域加一个下拉框。然后写死一个数据源,给每一个主题色标上序号,切换主题色的时候,把对应的序号存到localStorage里,然后强制刷新页面(window.location.reload())。重新进入项目的时候。main.js里判断localStorage里存没存高亮主题色的序号,如果有,就懒加载对应的主题色css。如果没有,就显示默认的主题色。这样就实现手动切换主题色啦~

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零凌林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值