
本文介绍在 React 中将含换行符( )的长代码字符串渲染为带缩进、换行及语法高亮的 HTML 内容,重点解决如何在已用 split(' ') 处理换行的基础上,进一步对关键词(如 export、const、变量名等)进行精准着色。
本文介绍在 react 中将含换行符(` `)的长代码字符串渲染为带缩进、换行及语法高亮的 html 内容,重点解决如何在已用 `split(' ')` 处理换行的基础上,进一步对关键词(如 `export`、`const`、变量名等)进行精准着色。
在 React 中直接插入含 HTML 标签的字符串(如 <br/> 或 <span>)是不安全的,也违背了 JSX 的设计原则。你当前通过 split(' ').map(...) 实现换行与基础缩进是合理的第一步,但若要在每行中进一步高亮关键词(如 export、const、fadeAnimation、opacity 等),就不能停留在“整行染色”层面,而需对每行文本做词法级解析——即:先按行分割,再对每行内容进行正则匹配或分词,包裹对应 <span> 并赋予语义化 class。
以下是一个健壮、可维护、且符合 React 最佳实践的实现方案:
✅ 推荐方案:逐行分词 + 正则高亮
// 定义关键词映射:key 为正则模式,value 为 CSS 类名
const HIGHLIGHT_RULES = [
{ pattern: /(export|import|default)/g, className: 'keyword-declaration' },
{ pattern: /(const|let|var|function|class)/g, className: 'keyword-statement' },
{ pattern: /(fadeAnimation|initial|animate|exit|opacity|transition)/g, className: 'identifier' },
{ pattern: /"[^"]*"/g, className: 'string-literal' },
{ pattern: /:[s]*[^,
}]+(?=,|}|$)/g, className: 'property-key' }, // 匹配对象键后的值(简化版)
];
const formatCodeString = (code: string): React.ReactNode[] => {
return code.split('
').map((line, lineIndex) => {
// 首行无缩进,其余行缩进 20px(或使用 em/rem 更佳)
const indentStyle = lineIndex === 0 ? {} : { marginLeft: '20px' };
// 对每一行应用所有高亮规则
let processedLine: React.ReactNode = line;
for (const { pattern, className } of HIGHLIGHT_RULES) {
processedLine = String(processedLine).split(pattern).map((segment, i) => {
if (i % 2 === 0) return segment; // 非匹配段落(普通文本)
return (
<span key={i} className={className}>
{segment}
</span>
);
});
}
return (
<div key={lineIndex} style={indentStyle} className="code-line">
{processedLine}
</div>
);
});
};
// 在组件中使用
function CodePreview() {
const codeString = `export const fadeAnimation = {\n initial: {opacity: 0, transition: { duration: 0.4, ease: "easeOut", delay: 0.5 }, },\n animate: { opacity: 1, transition: { duration: 0.4, ease: "easeIn", delay: 0.3 }, },\n exit: {opacity: 0, transition: { duration: 0.4, ease: "easeOut", delay: 0 },}\n}`;
return (
<pre className="code-block" style={{ fontFamily: 'monospace', fontSize: '14px', lineHeight: '1.5' }}>
{formatCodeString(codeString)}
</pre>
);
}? 关键说明与注意事项
- 避免 dangerouslySetInnerHTML:虽然可用,但会绕过 React 的 XSS 防护,且无法对关键词做动态样式控制,不推荐。
- 正则注意边界:使用 确保匹配完整单词(如防止 const 匹配到 constant 中的 const),并启用全局标志 g。
- 顺序敏感:高亮规则应从高优先级(如字符串字面量)到低优先级(如标识符)排列,避免嵌套干扰。
- 性能考量:对于超长代码(>100 行),可考虑 useMemo 缓存处理结果;简单场景无需过度优化。
-
CSS 示例(供参考):
.keyword-declaration { color: #007acc; font-weight: bold; } .keyword-statement { color: #d73a49; } .identifier { color: #6f42c1; } .string-literal { color: #032f62; } .property-key { color: #24292e; } .code-line { whiteSpace: pre; }
✅ 替代思路(适用于静态/低频更新内容)
若该代码块完全静态且不随 props/state 变化,更简洁的方式是预定义 JSX 数组(如答案中提到的方案):
const FadeAnimationCode = [
<span className="keyword-declaration">export</span>,
<span> </span>,
<span className="keyword-statement">const</span>,
<span> </span>,
<span className="identifier">fadeAnimation</span>,
<span> = {</span>,
<br />,
<span style={{ marginLeft: '20px' }}> </span>,
<span className="identifier">initial</span>,
<span>: {</span>,
// ... 其余内容
];但此方式牺牲了可维护性与复用性,仅建议用于极简演示或常量级代码片段。
综上,基于正则的逐行分词高亮 + split(' ') 结构化渲染,是在保持 React 安全性、可读性与扩展性前提下的最优解。它既延续了你已有的换行逻辑,又自然融入了细粒度样式控制能力。










