搞定 react-codemirror JSON高亮:与官方示例同步
2025-05-04 07:05:45
搞定 react-codemirror 样式:为什么你的 JSON 高亮和官方示例不一样?
用 react-codemirror
的时候,你可能希望代码编辑器的外观,尤其是语法高亮,能跟官方示例(比如 uiwjs.github.io/react-codemirror/
)里展示的一模一样。但有时候,事情并不如预期,特别是在配置特定主题(比如 dark
模式)和语言(比如 JSON
)时。
遇到的问题:JSON 颜色不对劲
咱们先看看具体情况。目标是实现官方 Demo 页面上那种 dark
主题下的 JSON
语法高亮效果。
理想效果 (官方 Demo):
注意看,像 "message"
(键) 和 "Network Error"
(值) 这两部分,它们的颜色明显不同,说明应用了不同的 CSS 样式。审查元素也能看到,它们各自拥有不同的 CSS 类名,比如键可能是 cm-property
,字符串值可能是 cm-string
。
实际效果 (本地环境):
但是,在本地项目中,使用类似下面的代码配置后:
import React, { useCallback } from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { basicDark } from '@uiw/codemirror-theme-basic'; // 假设从这里或react-codemirror导入
function MyEditor() {
const [value, setValue] = React.useState('{\n "message": "Network Error"\n}');
const onChange = useCallback((val, viewUpdate) => {
console.log('val:', val);
setValue(val);
}, []);
// 注意:这里的配置是 *不完整* 的,导致了问题
return (
<CodeMirror
value={value}
minHeight={"120px"}
// theme={basicDark} // Theme 应用方式可能有多种,直接用对象或作为 extension
extensions={[
basicDark, // 将主题作为 extension 添加
javascript({ jsx: true }), // 问题点:用了 JS 语言包处理 JSON
// EditorView.lineWrapping // 如果需要自动换行
]}
onChange={onChange}
/>
);
}
export default MyEditor;
得到的编辑器看起来却像是这样:
最明显的问题是,JSON
的键(Key)和值(Value)颜色一样了,都是一种单调的颜色。审查元素看看本地生成的 HTML:
果然,键和值被赋予了相同的、或者说非常通用的 CSS 类名(比如截图里都主要是 cm-line
内部,缺乏更具体的类),没有像官方示例那样细致地区分开。感觉就像编辑器根本没“认出”这是一个 JSON
文件,所以没能应用上针对性的高亮规则。
这到底是怎么回事?为什么本地的效果和官方演示差这么多?
刨根问底:样式差异怎么来的?
CodeMirror 6 ( react-codemirror
底层使用的版本) 和之前的版本有个很大的不同:它极其模块化。几乎所有功能,包括语法高亮、主题、自动补全、行号等等,都是通过 Extensions 来添加的。
问题的根源通常就在于你给 CodeMirror
组件传入的 extensions
数组配置。
回头看上面那段有问题的代码:
extensions={[
basicDark,
javascript({ jsx: true }), // <-- 这里是关键!
]}
我们想要高亮的是 JSON
,但 extensions
里却传入了 javascript({ jsx: true })
。这是用于 JavaScript (甚至支持 JSX) 的语言包,它并不专门为解析和高亮 JSON
设计。
虽然 JSON
语法上是 JavaScript 的一个子集,但 javascript
语言包在解析时,可能不会像专门的 JSON
解析器那样,精确地区分出 JSON
特有的结构,比如严格的键值对(键必须是双引号字符串)。因此,它无法为这些不同的部分(键、字符串值、数字值、布尔值、null)打上精确的、供主题使用的 CSS 标记(类名)。
没有精确的 CSS 类名,即使你应用了 basicDark
主题,主题中的那些针对 JSON
特定元素(如 cm-property
代表键,cm-string
代表字符串值)的颜色规则也无法生效。结果就是,所有东西看起来都是一个颜色,或者只有非常基础的区别。
简单说:你想让编辑器按 JSON
规则高亮,就得给它装上 JSON
的“语言插件”,光用 JavaScript
的不行。
动手解决:让 JSON 高亮起来
知道了原因,解决起来就直接多了。核心是确保为 JSON
内容加载正确的语言支持扩展。
方案一:添加 JSON 语言支持扩展
这是最关键的一步。你需要安装并使用 CodeMirror 官方提供的 JSON
语言包。
-
安装依赖:
打开你的项目终端,运行:npm install @codemirror/lang-json # 或者 yarn add @codemirror/lang-json
-
修改 CodeMirror 组件配置:
在你的 React 组件里,导入json
函数,并将其添加到extensions
数组中,替换掉之前的javascript()
。import React, { useCallback } from 'react'; import CodeMirror from '@uiw/react-codemirror'; // 导入正确的 JSON 语言包 import { json } from '@codemirror/lang-json'; // 导入你的主题,这里继续用 basicDark 作为例子 import { basicDark } from '@uiw/codemirror-theme-basic'; // 如果你希望从 @uiw/react-codemirror 直接导入主题对象也可以,确保其有效 // import { basicDark } from '@uiw/react-codemirror'; function MyJsonEditor() { const [value, setValue] = React.useState('{\n "message": "Network Error",\n "status": 404,\n "success": false,\n "data": null\n}'); const onChange = useCallback((val, viewUpdate) => { console.log('val:', val); setValue(val); }, []); return ( <CodeMirror value={value} minHeight={"120px"} // theme={basicDark} // 也可以这样应用主题,但推荐放入 extensions extensions={[ basicDark, // 应用主题 json(), // 应用 JSON 语言支持! // EditorView.lineWrapping // 需要自动换行的话,可以取消注释这个 ]} onChange={onChange} // 可以考虑添加 basicSetup 来获取一些基础功能(行号、括号匹配等),但它可能包含默认主题,要注意覆盖 // import { basicSetup } from 'codemirror'; // extensions={[basicSetup, basicDark, json()]} // 像这样组合,但注意 basicSetup 包含的内容 /> ); } export default MyJsonEditor;
原理和作用:
@codemirror/lang-json
包提供了专门用于解析JSON
文本的解析器 (Parser)。当这个扩展被添加到 CodeMirror 实例时:- 编辑器会使用这个解析器来分析
JSON
代码结构,理解哪里是键 (property),哪里是字符串 (string),哪里是数字 (number),布尔值 (boolean),等等。 - 解析器会根据分析结果,在生成的 HTML 结构中为这些不同的语法元素添加特定的 CSS 类名,例如
.cm-property
,.cm-string
,.cm-number
,.cm-boolean
,.cm-null
。 - 此时,你应用的
basicDark
主题(或其他任何支持 CodeMirror 6 的主题)中定义的针对这些类名的样式规则就能准确匹配并生效了。比如,basicDark
主题里会有类似.cm-property { color: #9CDCFE; }
和.cm-string { color: #CE9178; }
这样的规则,使得键和字符串值呈现出不同的颜色。
结果: 完成这一步后,你的
JSON
代码应该就能获得和官方示例非常接近(甚至完全一样)的语法高亮效果了。键和值会根据basicDark
主题的定义显示出不同的颜色。 - 编辑器会使用这个解析器来分析
方案二:确认并正确使用主题
虽然主要问题在于缺少 JSON
语言支持,但确保主题本身被正确加载和应用也很重要。
-
主题来源和导入:
react-codemirror
(uiwjs
) 提供了好几种主题包。@uiw/codemirror-theme-basic
: 包含basicLight
和basicDark
。@uiw/codemirror-themes
: 一个集合包,包含更多流行主题(如okaidia
,githubLight/Dark
,vscodeDark
等)。
你需要先安装对应的主题包:
npm install @uiw/codemirror-theme-basic # 或者包含更多主题的包 # npm install @uiw/codemirror-themes
然后像方案一的代码示例那样,从正确的包导入主题,并将其添加到
extensions
数组里。import { basicDark } from '@uiw/codemirror-theme-basic'; // 或者 import { vscodeDark } from '@uiw/codemirror-themes'; // ... 在 extensions 数组中使用 ... extensions={[ basicDark, json() ]}
原理和作用:
主题扩展本质上是提供了一系列 CSS 规则。这些规则定义了编辑器各个部分(背景、文本、选中区域、光标)以及各种语法元素(通过lang-
包添加的 CSS 类名)的颜色、字体样式等。把主题添加到extensions
数组,就是告诉 CodeMirror 应用这些 CSS 规则。检查点:
- 确认你安装了包含所需主题的 npm 包。
- 确认
import
语句指向了正确的包和主题对象/函数。 - 确认主题实例被加到了
extensions
数组中。
进阶使用技巧 - 自定义主题或微调:
如果你觉得某个主题的特定颜色不满意,CodeMirror 6 允许你基于现有主题进行扩展或完全自定义。你可以创建一个新的Extension
来覆盖特定highlightStyle
的样式规则。
例如,你想让basicDark
主题下的 JSON 属性(键)颜色更绿一点:import { EditorView } from '@codemirror/view'; import { HighlightStyle, syntaxHighlighting } from '@codemirror/language'; import { tags as t } from '@lezer/highlight'; // 需要安装 @lezer/highlight // 定义自定义高亮规则 const myCustomHighlight = HighlightStyle.define([ { tag: t.propertyName, color: '#77CC77' } // 让属性名(JSON key)变绿 // 你可以在这里添加更多自定义规则 ]); // ... 在你的组件里 ... extensions={[ basicDark, // 基础主题 json(), // JSON 语言支持 syntaxHighlighting(myCustomHighlight) // 应用自定义高亮规则(会覆盖basicDark中对propertyName的定义) ]}
这需要先安装
@lezer/highlight
(npm install @lezer/highlight
)。这种方式让你能精细控制每个语法元素的样式,而无需修改原始主题包。
方案三:检查 CodeMirror 相关库版本
极少数情况下,版本冲突也可能导致奇怪的问题。@uiw/react-codemirror
依赖于一系列 @codemirror/*
包。如果这些包的版本之间不兼容,可能会出现渲染或行为异常。
-
检查版本:
运行npm list
或查看package-lock.json
/yarn.lock
文件,确认@uiw/react-codemirror
,@codemirror/state
,@codemirror/view
,@codemirror/lang-json
,@uiw/codemirror-theme-basic
(或其他你用的主题/语言包) 等核心库的版本。 -
参考兼容性:
通常@uiw/react-codemirror
的文档或README
会指明它所兼容的@codemirror/*
版本范围。确保你的依赖都在推荐范围内。 -
清理和重装:
如果怀疑是版本问题,可以尝试删除node_modules
和锁文件 (package-lock.json
或yarn.lock
),然后重新运行npm install
或yarn install
。rm -rf node_modules package-lock.json # 或 yarn.lock npm install # 或 yarn install
安全建议:
更新或安装依赖时,留意版本号。主版本号(major version)的变更通常意味着可能有不兼容的 API 改动。小版本(minor)和补丁(patch)更新则相对安全。如果遇到问题,尝试锁定到一个已知可行的版本组合。
通过执行方案一(添加 json()
扩展),基本上就能解决最初的 JSON
高亮与官方示例不符的问题。方案二和三是辅助检查步骤,确保整个环境配置是健全的。现在,你的 react-codemirror
编辑器在处理 JSON
时应该能展现出预期的、色彩分明的高亮效果了。