在线代码编辑器 CodeMirror 使用简介
CodeMirror是一款在线的支持语法高亮的代码编辑器 github源码
特点:
使用: 基本的用法
<!-- 引入codemirror 外部基本资源js css -->
<link rel="stylesheet" href="http://codemirror.net/lib/codemirror.css">
<script src="http://codemirror.net/lib/codemirror.js"></script>
<!-- 引入mode 此处为js mode-->
<script src="http://codemirror.net/mode/javascript/javascript.js"></script>
<body>
<!-- 创建编辑区域1 -->
<form>
<textarea id="myTextarea"></textarea>
</form>
<!-- 创建编辑区域2 -->
<div id="code"></div>
</body>
推荐的使用方法
编辑器将会替换textarea
,和textarea平级
,自动把textarea
隐藏掉(display: none)
// 创建实例 这种方法在options 里写value属性是没有用的,自3.0版本改掉了
// 对于生成实例的步骤,react用户注意,要在真实dom生成之后再调用
const myTextarea = document.getElementById('myTextarea')
const editor = CodeMirror.fromTextArea(myTextarea, {
lineNumbers: true,
mode: 'javascript' // 设置mode 对应的也要这之前引入相应的js
});
编辑器将被追加到div里边
// 编辑器将被追加到div 里边
var myCodeMirror2 = CodeMirror(document.getElementById("code"), {
lineNumbers: true,
value: "function myScript(){return 100;}\n",
mode: "javascript"
});
编辑器将替换
元素
var myTextArea = document.getElementById("code");
var editor = CodeMirror(function(elt) {
myTextArea.parentNode.replaceChild(elt, myTextArea);
}, {
value: 'select * from table6666',
lineNumbers: true,
});
更多场景,就要通过options
配置 和 eitor
的方法去实现了
常用Configuration options 配置介绍
CodeMirror
提供了很多的快捷键去完成编写 具体参考
实际应用实例
-
value: string | CodeMirror.Doc
编辑器的初始值(文本),可以是字符串或者CodeMirror文档对象
-
mode: string | object
通用的或者在
CodeMirror
中使用的与mode
相关联的MIME,当不设置这个值的时候,会默认使用第一个载入的mode
定义文件。一般地,会使用关联的mime类型来设置这个值;除此之外,也可以使用一个带有name属性的对象来作为值(如:{name: “javascript”, json: true})
。可以通过访问CodeMirror.modes
和CodeMirror.mime
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
宽度个空格替换成n
个tab
字符,默认为false
-
keyMap: string
配置快捷键图,编辑模式。默认
defaul
,这是codemirror.js
本身定义的唯一键映射。其他选项参考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
editor.on('change', (instance, change) => { // instance 指CodeMirror实例对象 // ..... do what you want })
CodeMirror 提供了很多的方法,这些方法允许客户端对各种情况做出不同的行为,这些事件可以通过
on
和off
来绑定和解除绑定处理函数 -
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 文档操作
editor.getValue() // 当前编辑器的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}
对象,也可以将这两个值作为两个参数传入。将在给定位置用一个空的选择来替换所有的选择,options
同setSelection
的options
参数 -
setSelections (ranges: array<{anchor, head}>, ?primary: integer, ?options: object)
设置一组新的选择。给定数组中至少有一个选择。当
primary
是一个数字,它决定哪个选择是主要的。如果没有给出,则主索引从前一个选择中获取,如果前一个选择的范围小于新的范围,则将其设置为最后一个范围。options
同setSelection
的options
参数 -
addSelection (anchor: {line, ch}, ?head: {line, ch})
添加一个新的选择到现有的选择,并使其成为主要的选择
-
extendSelection (from: {line, ch}, ?to: {line, ch}, ?options: object)
与
setSelection
类似。区别在于,当按下shift键或设置了extending标志时(指的是设置为true),只会移动head的位置,anchor
会被留在当前位置。参数to
是可选的,传此参数用于确保区域(region
,比如单词或段落)能被完整选择。当前有多个选区时,会清除掉主选区。参数options
同setSelection
-
extendSelections (heads: array<{line, ch}>, ?options: object)
相当于一次执行所有选择的extendSelection
-
extendSelectionsBy(f: function(range: {anchor, head}) → {line, ch}), ?options: object)
将给定的函数应用于所有现有的选择,并调用
extendSelections
-
hasFocus() → boolean
编辑器当前是否有焦点
// 映射Tab键以插入空格而不是制表符 editor.setOption("extraKeys", { Tab: function(cm) { var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); cm.replaceSelection(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)
主动让编辑器滚动
-
CodeMirror
在mobx
、react
中的应用demo场景:编辑器支持可编辑,代码高亮,代码提示
-
getScrollInfo () → {left, top, width, height, clientWidth, clientHeight}
获取表示当前滚动位置,可滚动区域的大小以及可见区域的大小(减号滚动条)的
{left,top,width,height,clientWidth,clientHeight}
-
getMode () → object
获取编辑器的模式对象。请注意,这不同于
getOption(“mode”)
。当前返回的是模式实例化对象 -
isReadOnly() → boolean
返回编辑器当前是否允许编辑。
-
getWrapperElement () → Element
返回代表当前编辑器的
DOM
-
CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)
,这个方法创建的实例有以下几个方法:-
save ()
将编辑器的内容复制到
textarea
中,这样表单中的textarea的值就会和编辑器同步,以方便表单验证 -
toTextArea ()
删除编辑器,并恢复原始文本区(内容与编辑器的当前内容保持一致)
-
getTextArea () → TextAreaElement
返回实例所基于的
textarea
-
CodeMirror
在mobx
、react
中的应用demo -
场景:编辑器支持可编辑,代码高亮,代码提示
// code.js 此处codemirror是npm包 import {Component} from 'react' import {observer} from 'mobx-react' // 如果是安装包的形式,这样引入 import CodeMirror from 'codemirror' import 'codemirror/lib/codemirror.css' import 'codemirror/' // 引入mode import 'codemirror/mode/sql/sql' // 引入代码提示 import 'codemirror/addon/hint/show-hint.css' 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 => this.codeDom = p}> placeholder="code goes here..." > { value // 如果是异步获取的value,可以通过setValue赋值 } </textarea> </form> ) } componentDidMount() { this.editor = CodeMirror.fromTextArea(this.codeDom, { lineNumbers: true, keyMap: 'sublime', indentUnit: 4, tabSize: 4, mode: 'text/x-mysql', showCursorWhenSelecting: true, // 这是针对sql有自定义表和字段的,这样可以把自己的表和字段也放入提示里。如果数据是异步请求获取的,可以通过editor.setOption('hintOptions', data) hintOptions: { tables: { table1: [ 'col_A', 'col_B', 'col_C' ], table2: [ 'other_columns1', 'other_columns2' ], }, } }) // 将自动提示绑定到change事件上,这样输入的时候就可以看到联想的关键词 this.editor.on('change', (instance, change) => { // 自动补全的时候,也会触发change事件,所有坐下判断,以免死循环,正则是为了不让空格,换行之类的也提示 // 通过change对象你可以自定义一些规则去判断是否提示 if (change.origin !== 'complete' && /\w|\./g.test(change.text[0])) { instance.showHint() } }) } // 获取编辑器的内容,以便提交 getTextareaCode = () => this.editor.getValue() }
-
自动提示的时候,当只有一个匹配选项
CodeMirror
会自动帮你选,这样会影响用户输入其他前几个字符一样的单词,导致无法编辑相应的词,所以应该让用户自己去选。改掉源码
show-hint.js
中的选中逻辑。finishUpdate: function(data, first) { if (this.data) CodeMirror.signal(this.data, "update"); var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); if (this.widget) this.widget.close(); if (data && this.data && isNewCompletion(this.data, data)) return; this.data = data; if (data && data.list.length) { // 将这几行注释掉 // if (picked && data.list.length == 1) { // this.pick(data, 0); // } else { this.widget = new Widget(this, data); CodeMirror.signal(data, "shown"); // } } }
CodeMirror
提供了很多内置的API
,提高了可扩展性,可自定义mode
,可自定义hint
,等等,在此都不一一列举了。就整理这么多了,还有很多很多我没有涉及到的,欢迎补充,谢谢^_^
。
-