如何在Next.js应用中使用PrismJS实现代码自动缩进?
解决React中PrismJS代码片段单行显示与自动缩进问题
问题根源
renderToString生成的是无缩进、无换行的压缩HTML字符串,直接传给Prism会导致单行显示。- 当前Prism组件的
useEffect仅在组件挂载时执行一次,若code或language更新,不会重新触发高亮。
修复步骤
1. 优化PrismJS组件
修改组件,监听code和language的变化,确保每次内容更新都重新高亮:
import React, { useEffect, useRef } from "react"; import Prism from "prismjs"; import "prismjs/themes/prism-tomorrow.css"; export default function Code({ code, language }) { const codeRef = useRef(null); useEffect(() => { if (codeRef.current) { Prism.highlightElement(codeRef.current); } }, [code, language]); // 监听内容和语言变化 return ( <div className="Code"> <pre> <code ref={codeRef} className={`language-${language}`} dangerouslySetInnerHTML={{ __html: code }} /> </pre> </div> ); }
这里用dangerouslySetInnerHTML避免HTML转义问题,同时用highlightElement精准高亮目标元素,比highlightAll更高效。
2. 格式化HTML字符串(添加缩进和换行)
renderToString的压缩输出需要格式化,可使用轻量工具html-prettify:
npm install html-prettify
修改Hero1Code组件:
import React from "react"; import { renderToString } from "react-dom/server"; import prettify from "html-prettify"; import Code from "../../../components/prism/code"; export const Hero1Code = () => { const rawContent = renderToString(<Hero1/>); const formattedContent = prettify(rawContent, { indent_size: 2, indent_char: ' ', preserve_newlines: true }); return ( <div className="App"> <Code code={formattedContent} language="html" /> </div> ); };
若不想额外安装包,可手动用正则处理:
const formatHTML = (str) => { let prevIndent = 0; return str .replace(/></g, '>\n<') .replace(/^\s*\n/gm, '') .split('\n') .map((line) => { const closeTags = (line.match(/<\/[^>]+>/g) || []).length; const selfCloseTags = (line.match(/<[^>]+\/>/g) || []).length; const openTags = (line.match(/<[^\/>]+>/g) || []).length - selfCloseTags; const indent = Math.max(0, prevIndent + openTags - closeTags); prevIndent = indent; return ' '.repeat(indent) + line.trim(); }) .join('\n'); }; // 使用示例 const formattedContent = formatHTML(rawContent);
3. 验证效果
修改后,Prism会渲染带正确缩进和换行的代码块,同时语法高亮正常工作。
替代工具推荐
如果PrismJS使用繁琐,可考虑:
- React Syntax Highlighter:基于Prism封装的React组件,无需手动处理高亮触发,支持自动格式化:
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism'; <SyntaxHighlighter language="html" style={tomorrow}> {formattedContent} </SyntaxHighlighter> - Highlight.js:生态成熟,React集成简单,同样支持代码格式化。
内容的提问来源于stack exchange,提问作者MikeManzanas
相关产品推荐
相关产品推荐

