| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- @props(['content' => '', 'class' => '', 'inline' => false])
- <span class="math-render {{ $class }}">
- {!! $content !!}
- </span>
- @push('scripts')
- <!-- 引入 KaTeX 核心库 -->
- <script src="/js/katex.min.js?v={{ time() }}"></script>
- <!-- 引入 auto-render 扩展 (本地) -->
- <script src="/js/auto-render.min.js?v={{ time() }}"></script>
- <!-- 引入数学公式预处理器 -->
- <script src="/js/math-formula-processor.js?v={{ time() }}"></script>
- <script>
- (function() {
- 'use strict';
- console.log('Math Render Script Loaded (Local Auto-Render)');
- // 防止无限递归的全局开关
- window.MATH_RENDER_LOCK = false;
- window.MATH_RENDER_COUNT = 0;
- const MAX_RENDER_COUNT = 50; // 最大渲染次数,防止死循环
- // 配置项
- const renderOptions = {
- delimiters: [
- {left: '$$', right: '$$', display: true},
- {left: '$', right: '$', display: false},
- {left: '\\(', right: '\\)', display: false},
- {left: '\\[', right: '\\]', display: true}
- ],
- throwOnError: false,
- ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code', 'option']
- };
- function renderAllMath() {
- // 防止无限递归
- if (window.MATH_RENDER_LOCK) {
- console.warn('Math render already in progress, skipping...');
- return;
- }
- if (window.MATH_RENDER_COUNT >= MAX_RENDER_COUNT) {
- console.warn('Max render count reached, stopping to prevent infinite loop');
- return;
- }
- window.MATH_RENDER_LOCK = true;
- window.MATH_RENDER_COUNT++;
- if (typeof renderMathInElement === 'undefined') {
- console.warn('auto-render extension not loaded yet');
- window.MATH_RENDER_LOCK = false;
- return;
- }
- if (typeof window.katex === 'undefined') {
- console.warn('katex core not loaded yet');
- window.MATH_RENDER_LOCK = false;
- return;
- }
- console.log(`Rendering math using auto-render... (attempt #${window.MATH_RENDER_COUNT})`);
- try {
- // 1. 优先渲染 .math-render 元素 (通常是经过后端处理的)
- const elements = document.querySelectorAll('.math-render');
- let renderedCount = 0;
- elements.forEach(elem => {
- // 避免重复渲染
- if (elem.dataset.rendered === 'true') {
- return;
- }
- try {
- // 预处理内容
- let originalContent = elem.textContent || elem.innerHTML || '';
- if (originalContent.includes('$') || originalContent.includes('\\(') || originalContent.includes('\\[')) {
- // 使用预处理器标准化内容
- const processedContent = window.MathFormulaProcessor ?
- window.MathFormulaProcessor.processContent(originalContent) : originalContent;
- // 避免重复处理
- if (processedContent !== originalContent) {
- if (elem.innerHTML !== processedContent) {
- elem.innerHTML = processedContent;
- }
- }
- renderMathInElement(elem, renderOptions);
- elem.dataset.rendered = 'true';
- renderedCount++;
- }
- } catch (e) {
- console.error('Auto-render failed for element:', elem, e);
- }
- });
- // 2. 只渲染特定的容器,避免全局渲染导致死循环
- const containers = [
- '.question-content',
- '.math-content',
- '.ocr-content',
- '.question-text'
- ];
- containers.forEach(selector => {
- const container = document.querySelector(selector);
- if (container && container.dataset.mathRendered !== 'true') {
- try {
- // 检查是否包含数学公式
- const content = container.textContent || '';
- if (content.includes('$') || content.includes('\\(') || content.includes('\\[')) {
- renderMathInElement(container, renderOptions);
- container.dataset.mathRendered = 'true';
- renderedCount++;
- }
- } catch (e) {
- console.warn('Auto-render failed for container:', selector, e);
- }
- }
- });
- console.log(`Rendered ${renderedCount} math elements (total attempts: ${window.MATH_RENDER_COUNT})`);
- } finally {
- // 延迟解锁,避免立即再次触发
- setTimeout(() => {
- window.MATH_RENDER_LOCK = false;
- }, 50);
- }
- }
- // 初始化
- document.addEventListener('DOMContentLoaded', () => {
- // 稍微延迟以确保脚本执行顺序
- setTimeout(checkAndRender, 100);
- });
- function checkAndRender() {
- if (typeof window.katex !== 'undefined' && typeof renderMathInElement !== 'undefined') {
- console.log('KaTeX and auto-render loaded');
- initMathRenderer();
- } else {
- console.log('Waiting for KaTeX/auto-render...');
- setTimeout(checkAndRender, 100);
- }
- }
- function initMathRenderer() {
- renderAllMath();
- setupObservers();
- }
- function setupObservers() {
- const observer = new MutationObserver((mutations) => {
- let shouldRender = false;
- let hasMathContent = false;
- mutations.forEach((mutation) => {
- if (mutation.addedNodes.length > 0) {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeType === 1) { // Element node
- // 检查是否包含数学公式标识符
- const textContent = node.textContent || '';
- if (textContent.includes('$') ||
- textContent.includes('\\(') ||
- textContent.includes('\\[') ||
- node.querySelector('.math-render') ||
- node.querySelector('.question-content') ||
- node.querySelector('.math-content') ||
- node.querySelector('.ocr-content') ||
- node.querySelector('.question-text')) {
- hasMathContent = true;
- shouldRender = true;
- }
- }
- });
- }
- });
- if (shouldRender && hasMathContent) {
- if (window.mathRenderTimeout) clearTimeout(window.mathRenderTimeout);
- window.mathRenderTimeout = setTimeout(() => {
- console.log('DOM mutation detected with math content');
- renderAllMath();
- }, 200); // 增加延迟,避免频繁触发
- }
- });
- // 只观察特定容器,减少全局观察的性能影响
- const containers = [
- '.question-content',
- '.math-content',
- '.ocr-content',
- '.question-text',
- '.math-render'
- ];
- containers.forEach(selector => {
- const elements = document.querySelectorAll(selector);
- elements.forEach(element => {
- observer.observe(element, {
- childList: true,
- subtree: true
- });
- });
- });
- // 限制全局观察的范围,只在必要时启用
- // observer.observe(document.body, {
- // childList: true,
- // subtree: true
- // });
- }
- // Livewire 兼容性 - 添加防抖机制
- function debouncedRender() {
- if (window.mathRenderDebounceTimeout) {
- clearTimeout(window.mathRenderDebounceTimeout);
- }
- window.mathRenderDebounceTimeout = setTimeout(() => {
- renderAllMath();
- }, 150);
- }
- document.addEventListener('livewire:initialized', () => {
- setTimeout(debouncedRender, 50);
- });
- if (typeof Livewire !== 'undefined' && Livewire.hook) {
- Livewire.hook('morph.updated', ({ el, component }) => {
- debouncedRender();
- });
- Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
- succeed(({ snapshot, effect }) => {
- debouncedRender();
- });
- });
- }
- document.addEventListener('livewire:navigated', () => {
- // 重置计数器,允许新页面重新开始渲染
- window.MATH_RENDER_COUNT = 0;
- setTimeout(debouncedRender, 100);
- });
- document.addEventListener('alpine:init', () => {
- setTimeout(debouncedRender, 50);
- });
- document.addEventListener('math:render', () => {
- debouncedRender();
- });
- })();
- </script>
- @endpush
- @push('styles')
- <link rel="stylesheet" href="/css/katex/katex.min.css">
- @endpush
|