vue2 vue-katex markdown-it 展示数学公式

1,977 阅读1分钟

需求

  1. markdown支持数学公式
  2. 流式期间也要支持

解决

1.前置条件

    npm install markdown-it markdown-it-highlightjs katex highlight.js vue-katex
    // markdown-it是markdown解析插件 markdown-it-highlightjs是高亮 但是需要引入highlight.js样式
    // vue-katex 数学公式展示 katex也是需要样式

2.代码实现

//记得把样式也一起引入进来
import VueKatex from "vue-katex";
import "katex/dist/katex.min.css";
Vue.use(VueKatex, {
  globalOptions: {
    //定义好界定符,好让它能够找到渲染的latex公式块
    delimiters: [
      { left: "$$", right: "$$", display: true },
      { left: "$", right: "$", display: false },
      { left: "\\(", right: "\\)", display: false },
      { left: "\\[", right: "\\]", display: true },
    ],
    throwOnError:false
    //... Define globally applied KaTeX options here
  },
});
<template>
  <div>
    <div v-katex:auto v-html="renderMdText(text)" class="mdTextBox"></div>
  </div>
</template>
<script>
import MarkdownIt from "markdown-it";
import MarkdownItHighlightjs from "markdown-it-highlightjs";
import "highlight.js/styles/a11y-dark.css";
export default {
  data() {
    return {
      text: "\\( a^2 - 2ab + b^2 = (a - b)^2 \\)",
      markdownRender: new MarkdownIt({
        html: true,
        linkify: true,
        typographer: true,
      }).use(MarkdownItHighlightjs),
    };
  },
  updated() {
    let that = this;
    this.$nextTick(() => {
      // 获取页面上的pre和code标签
      const codeBlocks = document.querySelectorAll("pre code");
      codeBlocks.forEach((block) => {
        let newDiv;
        // 获取code标签
        const preElement = block;
        // 获取code标签的父元素
        const parentElement = preElement.parentNode;
        // 获取parentElement下的第一个div元素
        const firstDiv = parentElement.querySelector("div");
        // 检查是否找到了div元素
        if (!firstDiv) {
          // 创建一个div
          newDiv = document.createElement("div");
          // 给div添加文字内容
          newDiv.innerText = "复制代码";
          // 给div设置class样式
          newDiv.setAttribute("class", "copyButton");
          // 把div插入到code标签前面
          parentElement.insertBefore(newDiv, preElement);
          // 给div添加点击事件
          newDiv.onclick = function () {
            const textArea = document.createElement("textarea");
            textArea.value = preElement.innerText;
            document.body.appendChild(textArea);
            textArea.select();
            document.execCommand("copy");
            document.body.removeChild(textArea);
            that.$message.success('复制成功');
          };
        }
      });
    });
  },
  methods: {
    renderMdText(text) {
      //生成html
      return this.markdownRender.render(text);
    },
  },
};
</script>
<style lang="less" scoped>
</style>

以上会有问题 \[或者(这种适配太低了 npm install katex 页面引入样式和katex markdown-it还是要有的

renderMdText(text) {
      // markdown转html
      text = this.markdownRender.render(text);
      text = this.renderMath(text);
      return text;
    },
    // markdown转latex
    renderMath(html) {
      // 匹配 $$...$$, \[...\], \(...\), and $...$
      const regex =
        /(\$\$([\s\S]+?)\$\$)|(\[([\s\S]+?)\])|(\(([\s\S]+?)\))|(\$([^\$]+?)\$)/g;
      return html.replace(regex, (match, p1, p2, p3, p4, p5, p6, p7, p8) => {
        let latex;
        if (p2) {
          // $$...$$
          latex = p2;
        } else if (p4) {
          // \[...\]
          latex = p4;
        } else if (p6) {
          // \(...\)
          latex = p6;
        } else if (p8) {
          // $...$
          latex = p8;
        }
        if (latex) {
          try {
            return `${katex.renderToString(latex, {
              throwOnError: false,
            })}`;
          } catch (e) {
            console.error("KaTeX rendering error:", e);
            return match;
          }
        }
        return match; // Return original match if no LaTeX was found
      });
    },

原来的vue-katex不用了 原来是自动渲染 匹配现在改为手动匹配 更精确