【开箱即用】 内网环境使用Mathjax完成数学公式的展示

【开箱即用】 npm包使用Mathjax完成数学公式的展示

前言:查找网上资料,大部分MathJax的使用都是采用CDN分发的形式,没有npm包的使用教程,对于内网开发者或者一些安全监管限制比较严重的项目不太友好。本文针对此问题展示了一个开箱即用的demo演示。

  • 获取MathJax包

    1. 非内网开发者,直接采用npm下载安装,目前最新的版本应该是3.2.2
      npm install mathjax@3
    2. 对于网络受限的开发者,则需要特别处理
      • 首先向上级申请(你的上级或者运维部门)走对应的流程,拿到npm包;
      • 拷贝到node_modules文件夹内;
      • package.json文件中加入"mathjax": "^3.2.2",避免引入失败;
  • MathJax的引入

    这里第一个坑点就来了,mathjax包没有专门的入口配置文件,需要自己写。这一步询问大模型直接给出了答案;
window.MathJax = {
  tex: {
    inlineMath: [
      ["$", "$"],
      ["\\(", "\\)"],
    ], // 行内公式选择符
    displayMath: [
      ["$$", "$$"],
      ["\\[", "\\]"],
    ], // 段内公式选择符
  },
  startup: {
    ready() {
      window.MathJax.startup.defaultReady();
    },
  },
};

第二个坑点,导入的入口文件必须在引入mathjax之前,顺序很重要;

// 必须在引入mathjax前引入mathjax的配置文件
import "@/utils/mathjax";
// 使用tex-mml-svg   svg格式
import "mathjax/es5/tex-mml-svg";

import "@/utils/mathjax"此路径下的文件即为上一步配置的入口配置文件
这里以vue项目为例,直接在main.ts文件内写入上面的导入代码,即完成全局配置。

  • MathJax的使用

    对于直接在html结构中写入的LaTeX 语法的,直接在mounted中调用window.MathJax.typesetPromise()即可完成渲染。
window.MathJax.typesetPromise()

而对于在js代码中写入LaTeX 语法,或者使用了某些配置组件。则需要判断使用时机,需要在dom节点挂载之后,再调用方法完成渲染。
以虚拟长列表举例,由于视图是动态加载的,在滑动滚动条后发现,不在视图内的LaTeX语法并未被渲染成数学公式。

demo展示
需求:对部分表头加一个【?】,鼠标移入到【?】上时,展示数学公式。
代码实现如下

 // 初始化执行一次
 makeTitleToMathJax();
 // scrollContainer是获取到的滚动条,监听滚动事件
 const scrollContainer = this.$refs.table.$el.querySelector(".ag-body-horizontal-scroll-viewport");
 scrollContainer.addEventListener("scroll", onScroll);
 const onScroll = debounce(makeTitleToMathJax(), 300); // 防抖

 function makeTitleToMathJax() {
 	// 对于需要渲染的表头提前添加了#mathjaxText的id,这里就直接获取到
	const textList = this.$refs.table.$el.querySelectorAll("#mathjaxText");
	 // 给每一个元素设置鼠标移入移除事件
        textList.forEach((element) => {
        let currentTooltip = null;
        // 鼠标移入添加提示
         element.addEventListener("mouseover", (event) => {
        	// 在getMathJaxTemplate中每个元素都设置了一个 data-latex 属性,其中包含 LaTeX 代码
        	const latexCode = element.dataset.latex;
        	if (latexCode) {
            	currentTooltip = createTooltip(latexCode, event);
         	}
        });
        });
}

// 创建 tooltip 的函数
export function createTooltip(latexCode, event) {
    const tooltip = document.createElement("div");
    tooltip.className = "latex-tooltip";
    tooltip.style.position = "absolute";
    tooltip.style.padding = "5px";
    tooltip.style.backgroundColor = "#f0f0f0";
    tooltip.style.borderRadius = "5px";
    tooltip.style.zIndex = "1000";
    tooltip.style.top = `${event.pageY + 10}px`;
    // 创建包含LaTeX代码的span元素
    const latexSpan = document.createElement("span");
    latexSpan.className = "latex-code"; // 可以给LaTeX代码添加样式类
    latexSpan.textContent = latexCode;
    // 将span元素添加到tooltip中
    tooltip.appendChild(latexSpan);
    // 将tooltip添加到文档中
    document.body.appendChild(tooltip);
	// 使用 MathJax 渲染 tooltip 中的 LaTeX 代码
	window.MathJax.typesetPromise([tooltip]).then(() => {
		const elements = tooltip.querySelectorAll(".latex-code > .MathJax");
		elements.forEach((el: any) => {
        	el.style.textAlign = "left";
      	});
      	// 为防止产生的tooltip超出浏览器窗口,需要计算
      	// 获取浏览器窗口的视口宽度
        const x = event.pageX + 10;
		const viewportWidth =
        window.innerWidth || document.documentElement.clientWidth;
        const tooltipWidth = tooltip.offsetWidth;
      	// 检查提示框是否会超出视口右侧或底部 
      	if (x + tooltipWidth > viewportWidth) {
        	// 如果超出右侧,则将提示框放在视口右侧边缘内部,保持10px的间距
 			tooltip.style.left = `${viewportWidth - tooltipWidth - 10}px`;
    	} else {
        	// 否则,按原位置设置
        	tooltip.style.left = `${event.pageX + 10}px`;
		}
    });
    return tooltip;
}
 
   
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值