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块的自定义内容,其他的,比如想要自定义标题、列表、图片等等的渲染逻辑,可以通过对应扩展进行处理。

相关链接

相关推荐
IT_陈寒11 分钟前
为什么你应该学习React?
前端·人工智能·后端
ZoeLandia12 分钟前
React04:事件处理与受控表单
开发语言·前端·react.js·typescript
亿元程序员16 分钟前
用AI做了一款微信小游戏,却发现上传不了
前端
Ai-_Man21 分钟前
我需要批量导出Poe左边栏所有对话,而不是一条具体的对话内容,你们AI导出鸭可以吗?
开发语言·前端·javascript·人工智能·小程序
java1234_小锋22 分钟前
【技术专题】HTML5 网页技术 - Web Storage 本地存储 & 文件 API & 拖放 API
前端·html·html5
恋猫de小郭23 分钟前
Flutter 官方表示:AI 时代代码越来越容易写,为什么还要一套代码库?
android·前端·flutter
软件派30 分钟前
Chrome 插件开发实战指南
前端·chrome
ly768930 分钟前
性能剖析与压测方法论:JMH、async-profiler 与分层瓶颈定位的可复现实验
服务器·前端·数据库·压测·jmh·性能剖析·async-profiler
ZoeLandia43 分钟前
React05:useEffect 与副作用
开发语言·前端·react.js·typescript
狮子座的男孩1 小时前
html+css基础:24、2D变换(位移/缩放/旋转/扭曲(了解)/多重变换/变换原点)
前端·css·经验分享·html·2d位移·原点变换·缩放/旋转/扭曲