markdown预览自定义扩展实现

概述

在CSDN文章和AI问答的产生的回答,都是markdown格式的文本,如果浏览器需要渲染对应的markdown文件,需要能够正确将markdown文件转化HTML字符串,这样才能被浏览器识别,比较常见的转化markdown文件的库有诸如:markedjs、markdown-it等,这些库能够将markdown转化为浏览器能够识别的标签内容,但是里面的代码块样式需要我们自定义处理,可以结合highlight.js进行高亮和主题定制。如果需要在markdown文件转化过程中,自定义部分响应内容,需要使用到对应的扩展。

效果

实现类似CSDN的代码块复制功能,如下在原markdown的文本基础上,扩展自定义的一部分内容,比如点击下面复制,可以复制对应代码块的内容

实现

需要使用到的库

  • marked:转化markdown文本
  • marked-highlight:marked的扩展,用于定制高亮样式
  • highlight.js:高亮代码块

具体实现

这里结合vue代码来实现,代码块上面的头部,我们定义成组件,通过组件挂载的形式注入到最后生成的markdown渲染的html片段中去。 App.vue

js 复制代码
<script setup lang="ts">
import { Marked, marked } from "marked";
import { markedHighlight } from "marked-highlight";
import { ref, createApp, nextTick, h } from "vue";
import HeaderCode from "./components/HeaderCode.vue";
import { str, codeStr } from "./test.js";
import { v1 } from "uuid";
import hljs from "highlight.js";
import "highlight.js/styles/github-dark.min.css";

window.myNamespace.age = 12;

const markdownContent = ref(null);


function handleTest() {
    //高亮主题配置
  const marked = new Marked(
    markedHighlight({
      emptyLangClass: "hljs",
      langPrefix: "hljs language-",
      highlight(code, lang, info) {
        console.log("lang", lang, info);
        const language = hljs.getLanguage(lang) ? lang : "plaintext";
        return hljs.highlight(code, { language }).value;
      },
    })
  );
  //自定义代码块的markdown渲染逻辑
  const renderer = {
    code(data) {
      const app = createApp({
        render() {
          return h(HeaderCode,{data});
        },
      });
      //拦截code返回的内容,然后自定义注入头部组件
      const parentNodeId = "code-header-" + v1();
      nextTick(() => {
        const container = document.querySelector(`#${parentNodeId}`);
        console.log("container", container);
        app.mount(container);
      });
    //返回渲染的内容
      return `
        <div id="${parentNodeId}" class="code-header">
        </div>
      <pre><code class="hljs language-js">${data.text}</code></pre>
      `;
    },
  };

  marked.use({ renderer });

  const parseStr = marked.parse(str);
  markdownContent.value.innerHTML = parseStr;
}
</script>

<template>
  <el-button @click="handleTest">模拟</el-button>

  <div class="markdown-content" ref="markdownContent"></div>
</template>

<style>
.code-header {
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 6px 14px 6px 6px;
  display: flex;
  background-color: #f5f5f5;
}
.copy-code {
  cursor: pointer;
}

#app {
  height: 100%;
  padding: 10px;
}

body {
  width: 100%;
  height: 100%;
  display: block;
}
</style>

HeaderCode.vue

js 复制代码
<script setup lang="ts">
import { ElMessage } from "element-plus";

const props = defineProps<{ data: any }>();
const downLoad = () => {
  console.log("downLoad", props.data);

  const content = props.data.raw.replace(/```/g, "");

  console.log("content", content);

  const reg = new RegExp(props.data.lang);

  console.log("res--code", content.replace(reg, ""));
  ElMessage.success("复制成功");
};
</script>
<template>
  <div class="code-title">{{ props.data.lang }}</div>
  <div class="copy-code" @click="downLoad">复制</div>
</template>

总结

上面只拦截了code块的自定义内容,其他的,比如想要自定义标题、列表、图片等等的渲染逻辑,可以通过对应扩展进行处理。

相关链接

相关推荐
treasure1401 小时前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神2 小时前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录2 小时前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
code_Bo3 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen3 小时前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能
OpsEye3 小时前
同一套用例跑两个大模型接口,差异到底出在哪
javascript·ai编程
X1A0RAN4 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
涛涛ing4 小时前
2026年最值得关注的前端变化,藏在“默认值”里
前端
量化分析码农5 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端
亿元程序员6 小时前
太牛了!这AI做出来的游戏,居然还能变现!
前端