math-renderer.blade.php 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. @once
  2. <link rel="stylesheet" href="/css/katex/katex.min.css">
  3. <style>
  4. /* 避免 $$ 块级公式强制换行,用 inline 展示方便题干内联 */
  5. .katex-display {
  6. display: inline;
  7. margin: 0;
  8. }
  9. </style>
  10. <script src="/js/katex.min.js"></script>
  11. <script src="/js/auto-render.min.js"></script>
  12. <script>
  13. (() => {
  14. const MAX_ATTEMPTS = 60;
  15. let attempts = 0;
  16. let observer;
  17. const renderOptions = {
  18. delimiters: [
  19. // 统一用 inline 渲染,避免题干中 $$ 造成强制换行
  20. {left: "$$", right: "$$", display: false},
  21. {left: "$", right: "$", display: false},
  22. {left: "\\(", right: "\\)", display: false},
  23. {left: "\\[", right: "\\]", display: false},
  24. ],
  25. strict: 'ignore',
  26. throwOnError: false,
  27. ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code', 'option']
  28. };
  29. const ready = () =>
  30. typeof window.renderMathInElement !== 'undefined' &&
  31. typeof window.katex !== 'undefined';
  32. const renderAll = () => {
  33. if (!ready()) return;
  34. document.querySelectorAll('.math-render').forEach(el => {
  35. el.removeAttribute('data-rendered');
  36. });
  37. window.renderMathInElement(document.body, renderOptions);
  38. };
  39. const debouncedRender = () => {
  40. clearTimeout(window.__mathRenderTimer);
  41. window.__mathRenderTimer = setTimeout(renderAll, 25);
  42. };
  43. const waitAndRender = () => {
  44. if (ready()) {
  45. renderAll();
  46. setupObserver();
  47. return;
  48. }
  49. if (attempts++ < MAX_ATTEMPTS) {
  50. setTimeout(waitAndRender, 50);
  51. }
  52. };
  53. const setupObserver = () => {
  54. if (observer) return;
  55. observer = new MutationObserver((mutations) => {
  56. for (const mutation of mutations) {
  57. if (mutation.addedNodes.length > 0) {
  58. debouncedRender();
  59. break;
  60. }
  61. }
  62. });
  63. observer.observe(document.body, { childList: true, subtree: true });
  64. };
  65. // Livewire 局部刷新后重渲染
  66. document.addEventListener('livewire:init', () => {
  67. if (window.Livewire?.hook) {
  68. Livewire.hook('message.processed', () => debouncedRender());
  69. }
  70. });
  71. // 手动触发事件
  72. document.addEventListener('math:render', () => debouncedRender());
  73. // 全局暴露便于调试
  74. window.renderMath = () => {
  75. waitAndRender();
  76. };
  77. // 初始渲染
  78. waitAndRender();
  79. })();
  80. </script>
  81. @endonce