欢迎光临散文网 会员登陆 & 注册

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

2023-07-24 22:47 作者:chaojilaji123  | 我要投稿

原文合集地址如下,有需要的朋友可以关注

本文地址

合集地址

@


    前言

    之前做需求用到过codeMirror这个工具,觉得还不错,功能很强大,所以记录一下改工具的基础用法,分享给大家。 CodeMirror被广泛应用于许多Web应用程序和开发工具,例如代码编辑器、集成开发环境(IDE)、在线教育平台等。它提供了一个可嵌入的、灵活的解决方案,让开发者可以轻松地在网页中实现功能强大的代码编辑器。

    使用codeMirror

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

    npm install codemirror react-codemirror2 @types/codemirror

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

    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 = {
          tabSize2// 制表符的宽度。默认为 4。
          fontSize'16px'// 字体大小
          autoCloseBracketstrue// 在键入时自动关闭括号和引号
          showCursorWhenSelectingtrue// 当选择处于活动状态时是否应绘制光标。默认为 false。这里设置成自动补全
          lineWrappingtrue// ,CodeMirror 是否应该滚动或换行。默认为false(滚动)。这里设置成换行
          lineNumberstrue// 是否在编辑器左侧显示行号
          fullScreentrue//当设置为 时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。

    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所需的样式。

    .CodeMirror {
      height300px;
    }

    注册Js代码提示

    因为上面完整的基础代码已有,下面的代码我只写一些需要额外加进去的部分。 关键字可以自己添加,这里只是给个例子看看。当然也可以添加其他语言的提示,registerHelper函数的第二个参数就是所配置的语言,和editorConfig 里面的mode保持一致。

    // 注册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之上

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

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

     /** 编辑内容变化 */
      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, {
            completeSinglefalse,
          });
        }

        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


    React+TypeScript项目中如何使用CodeMirror?的评论 (共 条)

    分享到微博请遵守国家法律