Vue使用MathJax动态识别数学公式
本人菜鸟一名,如有错误,还请见谅。
1、前言
最近公司的一个项目需求是在前端显示Latex转化的数学公式,经过不断的百度和测试已基本实现。现在此做一个记录。
2、MathJax介绍
MathJax是一款运行在浏览器中的开源的数学符号渲染引擎,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。目前,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言。(Wiki)
3、步骤
3.1、引入MathJax
我们通过在index.html中加入下面语句即可引入MathJax,该语句导入的是国内的CDN。
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
3.2、创建方法配置MathJax
引入MathJax之后就需要我们配置MathJax了,这是为了让MathJax可以通过配置的标识来识别要被转化的数学公式。这一步我是参考了这位大佬的写法《MathJax: 让前端支持数学公式》的写法,具体如下。
(1)创建globalVariable.js文件,并在里面写下配置方法方法。
let isMathjaxConfig = false;//用于标识是否配置 const initMathjaxConfig = () => { if (!window.MathJax) { return; } window.MathJax.Hub.Config({ showProcessingMessages: false, //关闭js加载过程信息 messageStyle: "none", //不显示信息 jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [["$", "$"], ["\\(", "\\)"]], //行内公式选择符 displayMath: [["$$", "$$"], ["\\[", "\\]"]], //段内公式选择符 skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"] //避开某些标签 }, "HTML-CSS": { availableFonts: ["STIX", "TeX"], //可选字体 showMathMenu: false //关闭右击菜单显示 } }); isMathjaxConfig = true; //配置完成,改为true }; export default { isMathjaxConfig, initMathjaxConfig, }
这一步其实也可以使用直接配置的方法,这里就不记录了,具体可以看《前端整合MathjaxJS的配置笔记》这块。
(2)在main.js中将globalVariable.js引入,这样就可以在项目内任何地方都可以使用了。
import globalVariable from './components/globalVariable/globalVariable'
Vue.prototype.commonsVariable = globalVariable;
3.3、创建方法渲染公式
到了关键的一步了,这里的原理就是通过传入组件对象或者标签id再用MathJax的window.MathJax.Hub.Queue来渲染组件来转换公式。具体步骤如下。
(1)创建在globalVariable.js中创建渲染方法。
const MathQueue = function (elementId) { if (!window.MathJax) { return; } window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, document.getElementById(elementId)]); }; export default { Header, isMathjaxConfig, initMathjaxConfig, MathQueue, }
这一步不一定用传入id的方式,也可以传入标签name用getElementByName来获取组件对象。
(2)再需要渲染的页面中调用方法即可。当vue数据改变的时候,我们使用$nextTick等待组件数据渲染完成后,再将组件id传入方法中,让mathjax来渲染公式。
<template> <div> <div id="question-id"> <div class="swappy-radios" > <div name="titleDiv"> <h3> 题目:{{this.questionToOptions.Question.body}}</h3> //这里的questionToOptions.Question.body传入的就是Latex公式 </div> </div> </div> </div> </template> <script> export default { props: { value: {} }, data() { return { rawHtml:'', heightString: 'height: 500px;', questionToOptions: this.value, answer: '', imgIndex: 0, }; }, methods: { }, watch: { //监听prop传的value,如果父级有变化了,将子组件的myValue也跟着变,达到父变子变的效果 //这里看需求,若不使用监听,直接放在axios请求方法中也是可以的 value(value) { // titleDiv this.questionToOptions = value; this.answer = ''; this.$nextTick(function () { //这里要注意,使用$nextTick等组件数据渲染完之后再调用MathJax渲染方法,要不然会获取不到数据 if(this.commonsVariable.isMathjaxConfig){//判断是否初始配置,若无则配置。 this.commonsVariable.initMathjaxConfig(); } this.commonsVariable.MathQueue("question-id");//传入组件id,让组件被MathJax渲染 }) }, answer(newVal) { this.$emit('trouble', newVal) } }, mounted() { } } </script>
效果图:
3.4、出现错误和解决方法
本来到这里就应该结束了,但是在value数据连续改变的情况情况下MathJax渲染过得数据会不断堆积,造成错误。情况如下:
第一次改变:
第二次改变:
对于这个错误我没有找到一个好的解释,若有知道的大佬还请指出,多谢了。
我自己最后猜测是MathJax对于同一个组件渲染不是以刷新的方式,而是在上一次渲染的基础上添加数据进行渲染。所以我想到了,在下次渲染之前先将上一个组件内部带有数学公式清空,然后再进行渲染。具体方式如下:
<template> <div> <div id="question-id"> <div class="swappy-radios" > <div name="titleDiv"> <div v-html="rawHtml"></div>//这里改为用v-html,通过html字符串来每次生成html代码,从而达到刷新组件的效果。 </div> </div> </div> </div> </template> <script> export default { props: { value: {} }, data() { return { rawHtml:'', heightString: 'height: 500px;', questionToOptions: this.value, answer: '', imgIndex: 0, }; }, methods: { }, watch: { value(value) { // titleDiv this.questionToOptions = value; this.rawHtml = '<h3>题目:'+this.questionToOptions.Question.body +'</h3>';//将公式转化为html字符串存入。 this.answer = ''; this.$nextTick(function () { if(this.commonsVariable.isMathjaxConfig){ this.commonsVariable.initMathjaxConfig(); } this.commonsVariable.MathQueue("question-id"); }) }, answer(newVal) { this.$emit('trouble', newVal) } }, mounted() { } } </script>
这样就可以避免数据堆积的错误了。
效果图如下
第一次改变:
第二次改变:
ok,这样就修改完成了。
参考文章:https://www.jianshu.com/p/03a7bb984a1d
https://www.linpx.com/p/front-end-integration-mathjaxjs-configuration.html
原文地址:https://www.cnblogs.com/SilverSquab/p/11459218.html
- 反射的另类实现。(不知道这么用还算不算反射了?)
- 如何让普通变量也支持事务回滚?
- What is "Type" in managed heap?
- 一个特殊场景的 LR 预测优化 Trick
- 你知道Unity IoC Container是如何创建对象的吗?
- 发布一个锁定行列的一种方法。(实现Excel里的冻结窗格的功能)
- IoC+AOP的简单实现
- 使用了继承、多态还有工厂模式和反射,但是还是没有OO的感觉。[已经增加了实现的代码]
- OO——从不知到知道一点,从迷茫到豁然开朗 (迟来的我的2002到2007)
- 只在UnitTest和WebHost中的出现的关于LogicalCallContext的严重问题
- TEST LAB V8在线渗透实验室教程(三)
- CMQ请求域名
- 在Entity Framework中使用存储过程(一):实现存储过程的自动映射
- 在Entity Framework中使用存储过程(二):具有继承关系实体的存储过程如何定义?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 还在为 520 发愁吗?教你用 Python 写个表白神器!
- 用 Python 实现微信自动回复
- 一行命令给猎狐 F4 带口罩 & 检测是否带口罩
- 备战 618,用 Python 领取京东优惠券
- 一键生成你的微信社交数据报告
- 分析OutOfMemoryError异常
- 用 Python 制作关不掉的端午安康弹窗
- 使用JFR分析性能问题
- MyISAM 迁移至 InnoDB方案
- 解决Seafile局域网访问失败
- 一键解锁网易云音乐变灰歌曲
- 彻底理解 IO多路复用
- 分享Apache环境禁止目录浏览的方法
- DB2 Linux平台安装 Part 1 Linux环境配置
- DB2 Linux平台安装 Part 2 单机版软件安装