JavaScript如何在textarea的keyup事件中调用函数实现MathJax转PNG展示
问题原因
你的代码存在3个核心问题,导致keyup事件无法实时输出PNG:
- MathJax全局配置被放在了每次keyup触发的
myFunction函数中,MathJax仅会在首次加载时读取配置,重复覆写window.MathJax不会生效,也无法重复触发初始化逻辑 - 每次转换后直接追加图片到容器,没有清空上一次生成的旧内容
- 没有处理MathJax未加载完成就触发转换的异常场景,也没有防抖逻辑,输入过快会产生大量冗余转换任务
修正后代码
JS代码
// 全局存储转换方法和MathJax加载状态 let mj2img = null; let mathJaxLoaded = false; // 防抖定时器 let debounceTimer = null; window.MathJax = { jax: ["input/TeX", "output/SVG"], extensions: ["tex2jax.js", "MathMenu.js", "MathZoom.js"], showMathMenu: false, showProcessingMessages: false, messageStyle: "none", SVG: { useGlobalCache: false }, TeX: { extensions: ["AMSmath.js", "AMSsymbols.js", "autoload-all.js"] }, AuthorInit: function() { MathJax.Hub.Register.StartupHook("End", function() { // 初始化转换方法 mj2img = function(texstring, callback) { var input = texstring; var wrapper = document.createElement("div"); wrapper.innerHTML = input; var output = { svg: "", img: ""}; MathJax.Hub.Queue(["Typeset", MathJax.Hub, wrapper]); MathJax.Hub.Queue(function() { var mjOut = wrapper.getElementsByTagName("svg")[0]; if(!mjOut) return callback(output); mjOut.setAttribute("xmlns", "http://www.w3.org/2000/svg"); output.svg = mjOut.outerHTML; var image = new Image(); image.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(output.svg))); image.onload = function() { var canvas = document.createElement('canvas'); canvas.width = image.width; canvas.height = image.height; var context = canvas.getContext('2d'); context.drawImage(image, 0, 0); output.img = canvas.toDataURL('image/png'); callback(output); }; }); } mathJaxLoaded = true; }); } }; // 加载MathJax资源 (function(d, script) { script = d.createElement('script'); script.type = 'text/javascript'; script.async = true; script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js'; d.getElementsByTagName('head')[0].appendChild(script); }(document)); // 输入触发的转换函数 function myFunction(eqn){ // MathJax未加载完成时不执行 if(!mathJaxLoaded || !mj2img) return; // 清空上一次的防抖定时器 clearTimeout(debounceTimer); // 300ms防抖,输入停止后再执行转换 debounceTimer = setTimeout(() => { const target = document.getElementById("target"); // 清空上一次的转换结果 target.innerHTML = ''; if(!eqn.trim()) return; mj2img(eqn, function(output){ if(output.img) { const i = document.createElement('img'); i.src = output.img; target.append(i); } }); }, 300) }
HTML代码
<textarea onkeyup="myFunction(this.value)" placeholder="输入LaTeX公式"></textarea> <div id="target"></div>
逻辑说明
- MathJax的全局配置和初始化仅执行一次,启动完成后会暴露全局可用的转换方法
- 给keyup事件增加了300ms防抖逻辑,输入停止后才触发转换,大幅减少不必要的性能消耗
- 每次转换前先清空target容器的旧内容,页面仅会保留最新的公式转换结果
- 增加了MathJax加载状态判断,加载完成前触发的输入事件会被忽略,避免控制台报错
内容的提问来源于stack exchange,提问作者J C
相关产品推荐
相关产品推荐

