最近開了一個讀者回饋表單郵箱,無論是對文章的感想或是對部落格的感想,有什麼想回饋的都可以發郵箱跟我說:i_kkkp@163.com

基于Vue3和MathJax渲染的Latex富文本公式编辑器完美实践

前言

做项目需要用到富文本编辑器,但是看了很多的富文本编辑器都很少支持公式编辑,但项目有要用到,怎么办呢?先写一个显然并不现实。于是使用easy-formula-editorwangeditor写了一个功能小插件,是 基于Vue3和MathJax渲染的Latex富文本公式编辑器,支持零基础即可编辑公式,支持自定义编辑器配置和风格,支持二次编辑公式,支持作为插件和富文本编辑器一起使用。

  • 零基础即可编辑公式
  • 支持自定义编辑器配置和风格
  • 支持二次编辑公式
  • 支持作为插件和富文本编辑器一起使用

MathJax

安装和使用

NPM

npm i easy-formula-editor

import formulaEditor from "easy-formula-editor";
const editor = new formulaEditor();
editor.create('#test');

CDN

<script type="text/javascript" src="../dist/formula-editor.min.js"></script>
<script type="text/javascript">
  const editor = new formulaEditor();
  editor.create('#test');
</script>

导出

// latex 公式
editor.latex.text()

// html 公式
editor.$textSvgElem.html()

富文本编辑器菜单栏扩展

注册菜单

【注意】 推荐使用全局模式来注册菜单。 如果有多个编辑器,每个编辑器的自定义菜单不一样,则使用实例的方式来注册菜单

全局模式

// 菜单 key ,各个菜单不能重复
const menuKey = 'alertMenuKey' 

// 注册菜单
E.registerMenu(menuKey, AlertMenu)

const editor = new E('#div1')
editor.create()

const editor2 = new E('#div2')
editor2.create()

实例模式

// 菜单 key ,各个菜单不能重复
const menuKey = 'alertMenuKey' 
const menuKey2 = 'alertMenuKey2'

const editor = new E('#div1')
// 注册菜单
editor.menus.extend(menuKey, AlertMenu)

// 将菜单加入到 editor.config.menus 中    const menuKey = 'alertMenuKey' 
// 也可以通过配置 menus 调整菜单的顺序,参考【配置菜单】部分的文档    editor.config.menus.push(menuKey)
editor.config.menus = editor.config.menus.concat(menuKey)

// 注册完菜单,再创建编辑器,顺序很重要!!
editor.create()

const editor2 = new E('#div2')
editor2.menus.extend(menuKey2, AlertMenu)
editor2.config.menus.push(menuKey2)
editor2.create()

实际项目结合示例

import E from "wangeditor";
import formulaEditor from "easy-formula-editor";
import createPanelConf from "./create-panel-conf";

const { PanelMenu, Panel } = E;

class AlertMenu extends PanelMenu {
  constructor(editor) {
    // data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
    const $elem = E.$(
      `<div class="w-e-menu" data-title="数学公式">
        <span>公式</span>
      </div>`
    );
    super($elem, editor);
  }

  /**
   * 菜单点击事件
   */
  clickHandler() {
    const formula = new formulaEditor();
    const conf = createPanelConf(this.editor, formula);
    const panel = new Panel(this, conf);
    panel.create();

    formula.create("#edit-content");
  }

  tryChangeActive() {}
}

const menuKey = "alertMenuKey";

// 注册菜单
E.registerMenu(menuKey, AlertMenu);

export default E;
//create-panel-conf.ts
export default function (wangEditor, formulaEditor) {
    const btnOkId = 'btn-ok'
  
    /**
     * 插入公式
     */
    function insertFomule() {
      const formula = formulaEditor.latex.text()
      // 注意插入wangEditor时左右两边的空格不能去掉,不然会导致无法获取焦点
      wangEditor.txt.append('<p>'+formula+'</p>')
      return true
    }
  
    // tabs配置
    const tabsConf = [
      {
        // tab 的标题
        title: "插入数学公式",
        // 模板
        tpl: `<div>
                <div id="edit-content"></div>
                <div class="w-e-button-container">
                  <button type="button" id="${btnOkId}" class="right">插入</button>
                </div>
              </div>`,
        // 事件绑定
        events: [
          // 插入视频
          {
            selector: '#' + btnOkId,
            type: 'click',
            fn: insertFomule,
            bindEnter: true,
          },
        ],
      }, // tab end
    ]
  
    return {
        width: 660,
        height: 0,
        // panel 中可包含多个 tab
        tabs: tabsConf, // tabs end
      }
}

使用上面的代码,就可以在富文本编辑器中添加一个公式编辑器的菜单了:

<template>
  <div class="formula-container">
    <v-card elevation="0" class="formula-card" title="输出区域" subtitle="Output">
      <div id="formula" class="formula-content">
        {{ renderedFormula ? `$${renderedFormula}$` : '' }}
      </div>
    </v-card>
    <div class="editor-area">
      <div id="wang-editor" class="editor"></div>
    </div>
  </div>
</template>


<script setup>
import E from "../utils/formula-menu-conf";
import { ref, onMounted, nextTick, defineProps, watchEffect } from "vue";

// 定义props
const props = defineProps({
  initMessage: {
    type: String,
    default: "",
  }
});

watchEffect(() => {
  props.initMessage;
});

const editor = ref(null);
const renderedFormula = ref("");

function convert() {
  MathJax.texReset();
  MathJax.typesetClear();
  MathJax.typesetPromise();
}

function updateFormula() {
  renderedFormula.value = editor.value.txt.text();
  nextTick(convert);
}

onMounted(() => {
  editor.value = new E("#wang-editor");
  editor.value.config.height = 360;
  editor.value.config.menus = ['head', 'bold', 'underline', 'strikeThrough','emoticon', 'undo', 'redo'];
  editor.value.config.onchange = updateFormula;
  editor.value.config.onchangeTimeout = 500;
  editor.value.create();
  editor.value.txt.html(props.initMessage);
});

</script>

可以看到,我们的公式编辑器和富文本编辑器完美结合了,效果如下:

MathJax

贴一个wangeditor的官方文档:www.wangeditor.com/v4

记录一次向elementUI提PR的过程 React入门-第三篇

評論