如何在HTML/JavaScript中动态高亮GPT API返回的Markdown代码语法?
问题原因
highlight.js 只对 <pre><code> 标签包裹的代码生效,你页面里的三重反引号代码块只是普通文本,没有被转换成对应的HTML结构,所以自然不会触发高亮。
解决方法
核心是把流式返回的 Markdown 格式代码块,转换成 highlight.js 能识别的 HTML 标签,再触发高亮逻辑。
1. 手动正则替换(适合简单场景)
写一个函数识别文本中的 [语言]\n代码内容 结构,替换成对应的 <pre><code class="language-[语言]"> 标签,插入页面后调用 highlight.js 处理新内容。
模拟流式处理的测试代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Code Highlight Demo</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> </head> <body> <div id="content" style="white-space: pre-wrap"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <script> // 模拟GPT流式返回的文本内容 const streamText = `这是一段普通说明文本 \`\`\`javascript var s = "JavaScript syntax highlighting"; window.alert(s); var num = 42; \`\`\` 这是另一段普通文本 \`\`\`python print("Hello World") \`\`\``; // 将Markdown代码块转换为HTML标签的函数 function convertCodeBlock(text) { // 匹配三重反引号包裹的代码块,捕获语言类型和代码内容 return text.replace(/```(\w+)\n([\s\S]*?)```/g, (match, lang, code) => { // 转义HTML特殊字符,避免格式错乱和XSS风险 const escapedCode = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); return `<pre><code class="language-${lang}">${escapedCode}</code></pre>`; }); } // 模拟流式追加内容的逻辑 let currentIndex = 0; const contentEl = document.getElementById('content'); const interval = setInterval(() => { if (currentIndex >= streamText.length) { clearInterval(interval); hljs.highlightAll(); return; } // 每次追加一个字符,模拟流式返回效果 const chunk = streamText[currentIndex]; contentEl.textContent += chunk; currentIndex++; // 检查是否出现完整代码块标记,触发转换和高亮 if (contentEl.textContent.includes('```')) { const htmlContent = convertCodeBlock(contentEl.textContent); contentEl.innerHTML = htmlContent; hljs.highlightAll(); } }, 50); </script> </body> </html>
2. 使用Markdown解析库(更省心)
如果返回内容包含复杂Markdown格式(比如标题、列表),直接用成熟的解析库(如marked)把文本转成HTML,同时集成highlight.js高亮逻辑。
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Code Highlight Demo</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> </head> <body> <div id="content"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script> // 配置marked,让它生成带语言类的code标签并自动高亮 marked.setOptions({ highlight: function(code, lang) { const targetLang = hljs.getLanguage(lang) ? lang : 'plaintext'; return hljs.highlight(code, { language: targetLang }).value; } }); // 模拟流式返回的文本 const streamText = `这是一段普通文本 \`\`\`javascript var s = "JavaScript syntax highlighting"; window.alert(s); var num = 42; \`\`\` ### 这是一个标题 - 列表项1 - 列表项2 \`\`\`python print("Hello World") \`\``; let currentIndex = 0; const contentEl = document.getElementById('content'); const interval = setInterval(() => { if (currentIndex >= streamText.length) { clearInterval(interval); return; } const chunk = streamText[currentIndex]; contentEl.textContent += chunk; currentIndex++; // 实时解析Markdown并渲染 contentEl.innerHTML = marked.parse(contentEl.textContent); }, 50); </script> </body> </html>
注意事项
- 流式处理时尽量避免重复解析已处理内容,否则会导致性能问题或重复渲染高亮代码,可以记录已处理的位置,只处理新追加的片段。
- 如果涉及用户生成内容,要做好XSS防护,比如转义特殊字符或使用支持安全解析的Markdown库。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

