You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:01:22