在线代码编辑器 CodeMirror 使用简介

时间:2025-04-10 08:00:28
  • value: string |

    编辑器的初始值(文本),可以是字符串或者CodeMirror文档对象

  • mode: string | object

    通用的或者在CodeMirror中使用的与mode相关联的MIME,当不设置这个值的时候,会默认使用第一个载入的mode定义文件。一般地,会使用关联的mime类型来设置这个值;除此之外,也可以使用一个带有name属性的对象来作为值(如:{name: “javascript”, json: true})。可以通过访问Modes`获取定义的mode和MIME

  • lineSeparator: string | null

    明确指定编辑器使用的行分割符(换行符)。默认(值为null)情况下,文档会被 CRLF(以及单独的CR, LF)分割,单独的LF会在所有的输出中用作换行符(如:getValue)。当指定了换行字符串,行就只会被指定的串分割。

  • theme: string

    主题样式,主题对应的样式类名为.cm-s-[name],参考其他主题,也可以自定义主题样式

  • indentUnit: integer

    缩进为多少个空格,默认为2

  • smartIndent: boolean

    换行的时候是否使用模式提供的上下文相关的缩进(或只是缩进与之前的行对其), 默认true

  • tabSize: integer

    一个tab有几个空格,默认是4

  • indentWithTabs: boolean

    在缩进时,是否需要把 n*tab宽度个空格替换成ntab字符,默认为false

  • keyMap: string

    配置快捷键图,编辑模式。默认defaul,这是本身定义的唯一键映射。其他选项参考key map

  • extraKeys: object

    可以为编辑器绑定额外的键盘事件。

  • lineWrapping: boolean

    当一行特别长的时候,是滚动还是换行。默认为false(滚动)

  • lineNumbers: boolean

    是否在编辑器左侧显示行号

  • firstLineNumber: interger

    第一行的行号,默认为1

  • lineNumberFormatter: function(line: integer) → string

    自定义行号

  • fixedGutter: boolean

    是否在内容水平滚动的时候,行号也跟着滚动,(默认为true)

  • readOnly: boolean

    编辑器是否可以编辑(默认false)

  • showCursorWhenSelecting: boolean

    选中的时候,是否显示光标,默认false

  • lineWiseCopyCut: boolean

    在没有选择时进行复制或剪切,将复制或剪切光标所在的行

  • undoDepth: integer

    编辑器存储的撤消级别的最大数量,默认200

  • autofocus: boolean

    自动获取焦点

  • dragDrop: boolean

    是否启用拖放功能,就是把文件拖进来自动打开。

  • allowDropFileTypes: array

    设置可以拖放的文件类型


    常用的可绑定的事件 Events

        ('change', (instance, change) => {
            // instance  指CodeMirror实例对象
            // .....
            do what you want
        })
    

    CodeMirror 提供了很多的方法,这些方法允许客户端对各种情况做出不同的行为,这些事件可以通过onoff来绑定和解除绑定处理函数

  • change (instance: CodeMirror, changeObj: object)

    编辑器发生改变的时候触发(不建议在change事件中做过多的操作,比如setState,否则会导致卡顿)

  • beforeChange (instance: CodeMirror, changeObj: object)

    在更改之前触发,可以选择修改更改的内容或者取消更改,changeObj提供了cancel()update的方法

  • cursorActivity (instance: CodeMirror)

    当改变、光标移动、选择的时候触发

  • keyHandled (instance: CodeMirror, name: string, event: Event)

    快捷键映射(key map)中的快捷键被处理(handle)后触发

  • inputRead (instance: CodeMirror, changeObj: object)

    当用户输入,或者粘贴时触发,(和change区别:撤销,恢复不会触发)

  • viewportChange (instance: CodeMirror, from: number, to: number)

    每当编辑器的视图窗口发生更改(由于滚动,编辑或其他因素)时触发

  • gutterClick (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)

    当编辑区域的行号被点击时触发,line是从0开始的, gutter为行号的class

  • gutterContextMenu (instance: CodeMirror, line: integer, gutter: string, contextMenu: Event: Event)

    编辑器行号(contextmenu)右键出现上下午菜单的时候触发

  • focus (instance: CodeMirror, event: Event)

    编辑器获取到焦点的时候触发

  • blur (instance: CodeMirror, event: Event)

    失去焦点时触发

  • scroll (instance: CodeMirror)

    滚动的时候触发

  • optionChange (instance: CodeMirror, option: string)

    当配置项别改变的时候触发(setOption)

  • update (instance: CodeMirror)

    CodeMirror更新其DOM显示时触发


  • CodeMirror API 文档操作
    
        () // 当前编辑器的content
    
    
  • getValue (?separator: string) → string

    获取编辑器的内容,你可以传入一个特殊的字符串,去分割行,默认'\n'

  • setValue (content: string)

    设置编辑器的内容,实例初始化的时候可以通过option:value,或者写入textarea里指定编辑器的内容。实例生成之后,通过这个方法去设置编辑器的内容。

  • getRange (from: {line, ch}, to: {line, ch}, ?separator: string) → string

    获取编辑器指定位置的内容,可以传入特定的行分割符,line第几行,ch第几列,都是从0开始

  • replaceRange (replacement: string, from: {line, ch}, to: {line, ch}, ?origin: string)

    用给定的字符串替换或插入指定的地方

  • getLine (n: integer) → string

    获取指定行的内容(0 开始)

  • lineCount () → integer

    获取编辑器一共有多少行

  • getLineHandle (num: integer) → LineHandle

    获取指定行的实例对象

  • getLineNumber (handle: LineHandle) → integer

    根据行的实例,获取行的行号(0开始)

  • eachLine(f: (line: LineHandle)) 或者 (start: integer, end: integer, f: (line: LineHandle))

    遍历整个文档,或者如果给出了开始和结束行号,则从开始到(不包括)结束的范围,并且为每一行调用f,传递行句柄。这是访问一系列行处理程序比为每个行调用getLineHandle更快的方法


    光标和选择
  • getSelection (?lineSep: string) → string

    获取选中的内容,可以传入一个行分割符默认'\n',返回的是字符串。当有有多个选中的区域,他们之间的链接就是这个分割符

  • getSelections (?lineSep: string) → array

    获取多个选中的内容,返回的是一个数组,其他同上。

  • replaceSelection (replacement: string, ?select: string)

    用给定的字符串替换选中的。可选的select 当传入'around'时,替换完成后会自动选中新插入的文本,'start'时,替换完后光标在最开始的位置

  • replaceSelections(replacements: array, ?select: string)

    用数组中的字符替换选中的内容,替换的数组的长度应该和选中的数组的长度保持一致

  • getCursor (?start: string) → {line, ch}

    返回光标所在的位置

  • listSelections () → array<{anchor, head}>

    返回当前被选中的Range实例

  • somethingSelected () → boolean

    当选中任何内容,将会返回true

  • setSelection (anchor: {line, ch}, ?head: {line, ch}, ?options: object)

    给定位置,设置选中的区域,如果head没传,head默认为anchor
    options有以下选项:

    • scroll: boolean

      是否将选中的区域滚动到可视范围。

    • origin: string

      确定选择历史事件是否可以与前一个合并。具体:

      Determines whether the selection history event may be merged with the previous one. When an origin starts with the character +, and the last recorded selection had the same origin and was similar (close in time, both collapsed or both non-collapsed), the new one will replace the old one. When it starts with *, it will always replace the previous event (if that had the same origin). Built-in motion uses the “+move” origin. User input uses the “+input” origin.

    • bias: number

      确定选择端点落入原子范围内时应调整的方向(具体我也不清楚)

      Determine the direction into which the selection endpoints should be adjusted when they fall inside an atomic range. Can be either -1 (backward) or 1 (forward). When not given, the bias will be based on the relative position of the old selection—the editor will try to move further away from that, to prevent getting stuck.

  • setCursor (pos: {line, ch}|number, ?ch: number, ?options: object)

    设置光标位置。可以传参数 {line, ch}对象,也可以将这两个值作为两个参数传入。将在给定位置用一个空的选择来替换所有的选择,optionssetSelectionoptions参数

  • setSelections (ranges: array<{anchor, head}>, ?primary: integer, ?options: object)

    设置一组新的选择。给定数组中至少有一个选择。当primary是一个数字,它决定哪个选择是主要的。如果没有给出,则主索引从前一个选择中获取,如果前一个选择的范围小于新的范围,则将其设置为最后一个范围。optionssetSelectionoptions参数

  • addSelection (anchor: {line, ch}, ?head: {line, ch})

    添加一个新的选择到现有的选择,并使其成为主要的选择

  • extendSelection (from: {line, ch}, ?to: {line, ch}, ?options: object)

    setSelection类似。区别在于,当按下shift键或设置了extending标志时(指的是设置为true),只会移动head的位置,anchor会被留在当前位置。参数to是可选的,传此参数用于确保区域(region,比如单词或段落)能被完整选择。当前有多个选区时,会清除掉主选区。参数optionssetSelection

  • extendSelections (heads: array<{line, ch}>, ?options: object)

    相当于一次执行所有选择的extendSelection

  • extendSelectionsBy(f: function(range: {anchor, head}) → {line, ch}), ?options: object)

    将给定的函数应用于所有现有的选择,并调用extendSelections

  • hasFocus() → boolean

    编辑器当前是否有焦点


        // 映射Tab键以插入空格而不是制表符
        ("extraKeys", {
          Tab: function(cm) {
            var spaces = Array(("indentUnit") + 1).join(" ");
            (spaces);
          }
        });
    

  • setOption (option: string, value: any)

    更改编辑器的配置。option应该是一个选项的名称,value应该是该选项的有效值

  • getOption (option: string) → any

    检索此编辑器实例option的值

  • setSize (width: number|string, height: number|string)

    设置编辑器的宽高

  • scrollTo(x: number, y: number)

    主动让编辑器滚动

  • CodeMirrormobxreact中的应用demo

    场景:编辑器支持可编辑,代码高亮,代码提示

  • getScrollInfo () → {left, top, width, height, clientWidth, clientHeight}

    获取表示当前滚动位置,可滚动区域的大小以及可见区域的大小(减号滚动条)的{left,top,width,height,clientWidth,clientHeight}

  • getMode () → object

    获取编辑器的模式对象。请注意,这不同于getOption(“mode”)。当前返回的是模式实例化对象

  • isReadOnly() → boolean

    返回编辑器当前是否允许编辑。

  • getWrapperElement () → Element

    返回代表当前编辑器的DOM

  • (textArea: TextAreaElement, ?config: object),这个方法创建的实例有以下几个方法:

    • save ()

      将编辑器的内容复制到textarea中,这样表单中的textarea的值就会和编辑器同步,以方便表单验证

    • toTextArea ()

      删除编辑器,并恢复原始文本区(内容与编辑器的当前内容保持一致)

    • getTextArea () → TextAreaElement

      返回实例所基于的textarea

    • CodeMirrormobxreact中的应用demo
    • 场景:编辑器支持可编辑,代码高亮,代码提示

      //  此处codemirror是npm包
      import {Component} from 'react'
      import {observer} from 'mobx-react'
      // 如果是安装包的形式,这样引入
      import CodeMirror from 'codemirror'
      import 'codemirror/lib/'
      import 'codemirror/'
      // 引入mode
      import 'codemirror/mode/sql/sql'
      // 引入代码提示
      import 'codemirror/addon/hint/'
      import 'codemirror/addon/hint/show-hint'
      // 上边两个是定义提示的前提,下边定义自动提示是哪种模式,此处为sql
      import 'codemirror/addon/hint/sql-hint'
      // 引入keymap
      import 'codemirror/addon/comment/comment'
      import 'codemirror/keymap/sublime'
      
      @observer
      export default class Code extends Component {
          render() {
              return (
                  <form>
                  <textarea ref={p =>  = p}> placeholder="code goes here..." >
                      {
                          value // 如果是异步获取的value,可以通过setValue赋值
                      }
                  </textarea>
                </form>
              )
          }
          componentDidMount() {
               = (, {
                  lineNumbers: true,
                  keyMap: 'sublime',
                  indentUnit: 4,
                  tabSize: 4,         
                  mode: 'text/x-mysql',
                  showCursorWhenSelecting: true,
                  //  这是针对sql有自定义表和字段的,这样可以把自己的表和字段也放入提示里。如果数据是异步请求获取的,可以通过('hintOptions', data)
                  hintOptions: {
                    tables: {
                          table1: [ 'col_A', 'col_B', 'col_C' ],
                          table2: [ 'other_columns1', 'other_columns2' ],
                      },
                  }
              })
      
              // 将自动提示绑定到change事件上,这样输入的时候就可以看到联想的关键词
              ('change', (instance, change) => {
                  // 自动补全的时候,也会触发change事件,所有坐下判断,以免死循环,正则是为了不让空格,换行之类的也提示
                  // 通过change对象你可以自定义一些规则去判断是否提示
                  if ( !== 'complete' && /\w|\./([0])) {
                      ()
                  }
              })
          }
      
          // 获取编辑器的内容,以便提交
          getTextareaCode = () => ()
      
      }
      
    • 自动提示的时候,当只有一个匹配选项CodeMirror会自动帮你选,这样会影响用户输入其他前几个字符一样的单词,导致无法编辑相应的词,所以应该让用户自己去选。改掉源码  中的选中逻辑。

      
      finishUpdate: function(data, first) {
        if () (, "update");
      
        var picked = ( && ) || (first && );
        if () ();
      
        if (data &&  && isNewCompletion(, data)) return;
         = data;
      
        if (data && ) {
          // 将这几行注释掉
          // if (picked &&  == 1) {
          //   (data, 0);
          // } else {
             = new Widget(this, data);
            (data, "shown");
          // }
        }
      }
      

      CodeMirror提供了很多内置的API,提高了可扩展性,可自定义mode,可自定义hint,等等,在此都不一一列举了。就整理这么多了,还有很多很多我没有涉及到的,欢迎补充,谢谢 ^_^