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

相关链接

相关推荐
灵感__idea1 小时前
JavaScript高级程序设计(第5版):好的编程就是掌控感
前端·javascript·程序员
烛阴2 小时前
Mix
前端·webgl
代码续发2 小时前
前端组件梳理
前端
试图让你心动3 小时前
原生input添加删除图标类似vue里面移入显示删除[jquery]
前端·vue.js·jquery
陈不知代码3 小时前
uniapp创建vue3+ts+pinia+sass项目
前端·uni-app·sass
小王码农记3 小时前
sass中@mixin与 @include
前端·sass
陈琦鹏3 小时前
轻松管理 WebSocket 连接!easy-websocket-client
前端·vue.js·websocket
hui函数4 小时前
掌握JavaScript函数封装与作用域
前端·javascript
行板Andante4 小时前
前端设计中如何在鼠标悬浮时同步修改块内样式
前端
Carlos_sam5 小时前
Opnelayers:ol-wind之Field 类属性和方法详解
前端·javascript