延迟刷新
本来想延迟100毫秒的,但是会出现样式向左偏移的情况,于是试了试500毫秒,发现就没有问题了,可能是样式什么是需要一个加载过程吧。
javascript
useEffect(() => {
editorRef.current?.setValue(value || '');
setTimeout(() => {
editorRef.current?.refresh();
}, 500);
}, [value]);
另外记录一下写的编辑器组件
npm install codemirror --save
javascript
import CodeMirror, { EditorFromTextArea } from 'codemirror';
import 'codemirror/lib/codemirror.css';
import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
// 导入需要的语言模式和样式主题
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/hint/javascript-hint.js'; // 自动提示
import 'codemirror/mode/htmlmixed/htmlmixed';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/xml/xml';
import 'codemirror/theme/material.css'; // 加载的样式主题 https://codemirror.net/5/theme/
// 折叠代码块
import 'codemirror/addon/fold/brace-fold.js';
import 'codemirror/addon/fold/comment-fold.js';
import 'codemirror/addon/fold/foldcode.js';
import 'codemirror/addon/fold/foldgutter.js';
import 'codemirror/addon/selection/active-line.js'; // 当前行高亮
import 'codemirror/addon/hint/anyword-hint.js'; // end
import 'codemirror/addon/hint/show-hint.css'; // start-ctrl+空格代码提示补全
import 'codemirror/addon/hint/show-hint.js';
// 定义组件属性类型
interface CodeMirrorEditorProps {
ref: any;
readOnly: boolean;
value: string;
language: string;
theme?: 'default' | 'material';
height?: number;
width?: number;
onChange: (value: string) => void;
onShiftEnter?: () => void;
onBlur?: (value: string) => void;
onChangeLine?: () => void;
}
const CodeMirrorEditor: React.FC<CodeMirrorEditorProps> = forwardRef((props, ref) => {
const { language, readOnly, value, theme, width, height } = props;
const textareaRef = useRef<HTMLTextAreaElement>(null);
const editorRef = useRef<EditorFromTextArea>();
useImperativeHandle(ref, () => ({
refresh: () => {
editorRef.current?.refresh();
},
}));
/** 失焦 */
const blur = (instance: any) => {
if (props.onBlur) {
props.onBlur(instance.doc.getValue());
}
};
/** 键盘按键按下 */
const keydown = (_: any, change: any) => {
if (change.shiftKey === true && change.keyCode === 13) {
if (props.onShiftEnter) {
props.onShiftEnter();
}
change.preventDefault();
}
};
/** 编辑内容变化 */
const codemirrorValueChange = (doc: any, change: any) => {
doc.eachLine((line: any) => {
if (line.text.startsWith('//') || line.text.startsWith('#')) {
doc.addLineClass(line, 'wrap', 'notes');
} else if (line.wrapClass === 'notes') {
doc.removeLineClass(line, 'wrap', 'notes');
}
});
if (change.origin !== 'setValue') {
if (props.onChange) {
props.onChange(doc.getValue());
}
}
};
const initCodeMirror = () => {
const editorConfig = {
readOnly: readOnly,
tabSize: 4, // 制表符的宽度。默认为 4。
fontSize: '16px', // 字体大小
styleActiveLine: !readOnly, // 选中行高亮
autoCloseBrackets: true, // 在键入时自动关闭括号和引号
showCursorWhenSelecting: true, // 当选择处于活动状态时是否应绘制光标。默认为 false。这里设置成自动补全
lineWrapping: true, // ,CodeMirror 是否应该滚动或换行。默认为false(滚动)。这里设置成换行
lineNumbers: true, // 是否在编辑器左侧显示行号
firstLineNumber: 1,
fullScreen: true, //当设置为 时true,将使编辑器全屏显示(如占据整个浏览器窗口)。
mode: language, // 使用模式
// theme: 'default' // 编辑器样式的主题 必须确保.cm-s-[name] 加载定义相应样式的 CSS 文件。默认值为"default",颜色包含在 中codemirror.css。可以一次使用多个主题类,例如将和类"foo bar"都分配给编辑器。cm-s-foocm-s-bar
theme: theme || 'default', // 编辑器样式的主题 必须确保.cm-s-[name] 加载定义相应样式的 CSS 文件。默认值为"default",颜色包含在 中codemirror.css。可以一次使用多个主题类,例如将和类"foo bar"都分配给编辑器。cm-s-foocm-s-bar
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
extraKeys: { Ctrl: 'autocomplete' },
};
editorRef.current = CodeMirror.fromTextArea(textareaRef.current!, editorConfig);
// 监听编辑器内容变化事件
editorRef.current.on('change', codemirrorValueChange);
editorRef.current.on('keydown', keydown);
editorRef.current.on('blur', blur);
// const { value, width, height } = props;
editorRef.current.setValue(value || '');
if (width || height) {
editorRef.current.setSize(width, height);
}
};
useEffect(() => {
if (textareaRef.current) {
initCodeMirror();
}
return () => {
// 清理和销毁编辑器实例
editorRef.current?.toTextArea();
};
}, [readOnly, textareaRef, theme, width, height, language]);
useEffect(() => {
editorRef.current?.setValue(value || '');
setTimeout(() => {
editorRef.current?.refresh();
}, 500);
}, [value]);
return <textarea ref={textareaRef} />;
});
export default CodeMirrorEditor;
使用
javascript
import { CodeMirrorEditor } from '@/components';
<CodeMirrorEditor
height={550}
theme={'default'}
readOnly={false}
value={content || ''}
language="javascript"
onChange={(value) => {
console.log('值',value)
}}
/>