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

相关链接

相关推荐
LeeAt几秒前
真的!真的就一句话就能明白this指向问题
前端·javascript
阳火锅1 分钟前
都2025年了,来看看前端如何给刘亦菲加个水印吧!
前端·vue.js·面试
hahala233318 分钟前
ESLint 提交前校验技术方案
前端
夕水40 分钟前
ew-vue-component:Vue 3 动态组件渲染解决方案的使用介绍
前端·vue.js
Winwin42 分钟前
js基础-数据类型
javascript
Winwin43 分钟前
哈?Boolean能作为回调函数?
javascript
我麻烦大了43 分钟前
实现一个简单的Vue响应式
前端·vue.js
Shartin1 小时前
CPT208-Human-Centric Computing: Prototype Design Optimization原型设计优化
开发语言·javascript·原型模式
独立开阀者_FwtCoder1 小时前
你用 Cursor 写公司的代码安全吗?
前端·javascript·github
dme.1 小时前
Javascript之DOM操作
开发语言·javascript·爬虫·python·ecmascript