React+TypeScript项目中如何使用CodeMirror?

文章目录

前言

之前做需求用到过codeMirror这个工具,觉得还不错,功能很强大,所以记录一下改工具的基础用法,分享给大家。

CodeMirror被广泛应用于许多Web应用程序和开发工具,例如代码编辑器、集成开发环境(IDE)、在线教育平台等。它提供了一个可嵌入的、灵活的解决方案,让开发者可以轻松地在网页中实现功能强大的代码编辑器。

使用codeMirror

步骤1:安装依赖

首先,你需要在React项目中安装CodeMirror及其相关依赖。可以使用以下命令进行安装:

bash 复制代码
npm install codemirror react-codemirror2 @types/codemirror

步骤2:导入所需模块、创建CodeMirror组件

javascript 复制代码
import React, { useRef, useEffect } from 'react';
import CodeMirror, { EditorFromTextArea } from 'codemirror';
import 'codemirror/lib/codemirror.css';

// 导入需要的语言模式和样式主题
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/xml/xml';
import 'codemirror/mode/css/css';
import 'codemirror/mode/htmlmixed/htmlmixed';
import 'codemirror/theme/material.css';  // 加载的样式主题 https://codemirror.net/5/theme/

// 定义组件属性类型
interface CodeMirrorEditorProps {
  value: string;
  language: string;
  theme?: string;
  height?:Number;
  width?:Number;
  onChange: (value: string) => void;
  onShiftEnter?: () => void;
  onBlur?: (value: string) => void;
  onChangeLine?: () => void;
}

const CodeMirrorEditor: React.FC<CodeMirrorEditorProps> = (props) => {
  const { language } = props;
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const editorRef = useRef<EditorFromTextArea>();

  useEffect(() => {
    const textarea = textareaRef.current;
    if (!textarea) return;
    initCodeMirror();
   
    return () => {
      // 清理和销毁编辑器实例
      editorRef.current?.toTextArea();
    };
  }, []);

  const initCodeMirror = ()=>{
    const editorConfig = {
      tabSize: 2, // 制表符的宽度。默认为 4。
      fontSize: '16px', // 字体大小
      autoCloseBrackets: true, // 在键入时自动关闭括号和引号
      showCursorWhenSelecting: true, // 当选择处于活动状态时是否应绘制光标。默认为 false。这里设置成自动补全
      lineWrapping: true, // ,CodeMirror 是否应该滚动或换行。默认为false(滚动)。这里设置成换行
      lineNumbers: true, // 是否在编辑器左侧显示行号
      fullScreen: true, //当设置为 时true,将使编辑器全屏显示(如占据整个浏览器窗口)。
      mode:language, // 使用模式
      theme: 'material' // 编辑器样式的主题 必须确保.cm-s-[name] 加载定义相应样式的 CSS 文件。默认值为"default",颜色包含在 中codemirror.css。可以一次使用多个主题类,例如将和类"foo bar"都分配给编辑器。cm-s-foocm-s-bar
    };

    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);
     }
  }


  /** 失焦 */
  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());
      }
    }
  };

  
  return (
    <textarea ref={textareaRef} />
  );
};

export default CodeMirrorEditor;

步骤:使用CodeMirror组件

在你的应用程序中,使用MyComponent组件来渲染CodeMirror。

javascript 复制代码
import React, { useState } from 'react';
import CodeMirrorEditor from 'CodeMirror';

const CodeEditor: React.FC = () => {
  const [code, setCode] = useState<string>('');

  const handleCodeChange = (value: string) => {
    setCode(value);
  };

  return (
    <div>
      <CodeMirrorEditor
        value={code}
        language="javascript"
        onChange={handleCodeChange}
      />
      <pre>{code}</pre>
    </div>
  );
};

export default CodeEditor;

步骤4:添加样式

在添加了CodeMirror所需的样式。

css 复制代码
.CodeMirror {
  height: 300px;
}

注册Js代码提示

因为上面完整的基础代码已有,下面的代码我只写一些需要额外加进去的部分。

关键字可以自己添加,这里只是给个例子看看。当然也可以添加其他语言的提示,registerHelper函数的第二个参数就是所配置的语言,和editorConfig 里面的mode保持一致。

javascript 复制代码
// 注册JavaScript代码提示
const registerHelp = () =>{
	CodeMirror.registerHelper('hint', 'javascript', (editor, options) => {
	  const cursor = editor.getCursor();
	  const token = editor.getTokenAt(cursor);
	  const word = token.string;
	
	  // 假设你的关键字列表存储在keywords数组中
	  const keywords = ['if', 'else', 'for', 'while', 'function', 'class'];
	
	  const list = keywords.filter((keyword) => keyword.startsWith(word));
	
	  return {
	    list,
	    from: CodeMirror.Pos(cursor.line, token.start),
	    to: CodeMirror.Pos(cursor.line, token.end),
	  };
	});
}

1、需要将上面的代码放在初始化codeMirror之上

javascript 复制代码
useEffect(() => {
    const textarea = textareaRef.current;
    if (!textarea) return;
    registerHelp(); // 注册代码提示
    initCodeMirror();
   
    return () => {
      // 清理和销毁编辑器实例
      editorRef.current?.toTextArea();
    };
  }, []);

2、在codemirrorValueChange函数里加入下面代码

javascript 复制代码
 /** 编辑内容变化 */
  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 === '+input') {
      CodeMirror.commands.autocomplete(editor.current, undefined, {
        completeSingle: false,
      });
    }

    if (change.origin !== 'setValue') {
      if (props.onChange) {
        props.onChange(doc.getValue());
      }
    }
  };

使用了 CodeMirror库的autocomplete命令来触发自动完成功能。

CodeMirror.commands.autocomplete接受三个参数:

  1. editor.current:一个CodeMirror编辑器实例,它是你创建的编辑器对象的引用。

  2. 第二个参数是可选的,用于指定触发自动完成的原因。可以传入一个字符串作为原因,例如"explicit"表示显式触发,或者传入undefined表示由编辑器自动触发。

  3. 第三个参数是可选的配置对象,用于自动完成的选项。在这里,{ completeSingle: false }设置了completeSingle选项为false,表示自动完成功能不会在只有一个建议项时立即完成,而是等待更多的输入或手动触发。

更多配置请自行去官网文档查看https://codemirror.net/5/doc/manual.html#config

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
光头程序员7 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me7 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者7 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架