页面编辑器CodeMirror初始化不显示行号或文本内容

延迟刷新

本来想延迟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)
   }}
 />
相关推荐
极客密码5 小时前
感谢雷总!Mimo大模型价值¥659/月的 MAX 套餐,让我免费领到了!
前端·ai编程·claude
深念Y6 小时前
我明白为什么B站没法在浏览器开直播了——Windows Chrome推流踩坑全记录
前端·chrome·webrtc·浏览器·srs·直播·flv
zhangxingchao7 小时前
AI应用开发七:可以替代 RAG 的技术
前端·人工智能·后端
Sun@happy7 小时前
现代 Web 前端渗透——基础篇(1)
前端·web安全
希冀1237 小时前
【CSS学习第十一篇】
前端·css·学习
隔窗听雨眠7 小时前
doctype、charset、meta如何控制整个渲染流水线
java·服务器·前端
kyriewen7 小时前
写组件文档写到吐?我用AI自动生成Storybook,同事以后直接抄
前端·javascript·面试
excel8 小时前
🧠 Prisma 表名大写 vs SQL 导出小写问题深度解析(附踩坑与解决方案)
前端·后端
周淳APP8 小时前
【前端工程化原理通识:从源头到运行时的理论阐述】
前端·编译·打包·前端工程化
五点六六六8 小时前
你敢信这是非Native页面写出来的渐变效果吗🌝(底层原理解析
前端·javascript·面试