# 相关网址
- Vue 官方插件库推荐的集成实现- 这个实现做的比较全面,但不支持动态语法高亮的切换
 
- codemirror 支持的语言类型
- codemirror 官网
# 具体实现
- 首先需要运行 npm i codemirror --save在项目中安装对应组件
| <template> | |
| <div class="in-coder-panel"> | |
| <textarea ref="textarea"></textarea> | |
| <el-select class="code-mode-select" v-model="mode" | |
| @change="changeMode"> | |
| <el-option v-for="mode in modes" | |
| :key="mode.value" :label="mode.label" :value="mode.value"> | |
| </el-option> | |
| </el-select> | |
| </div> | |
| </template> | |
| <script type="text/ecmascript-6"> | |
|   // 引入全局实例 | |
| import _CodeMirror from 'codemirror' | |
|   // 核心样式 | |
| import 'codemirror/lib/codemirror.css' | |
|   // 引入主题后还需要在 options 中指定主题才会生效 | |
| import 'codemirror/theme/cobalt.css' | |
|   // 需要引入具体的语法高亮库才会有对应的语法高亮效果 | |
|   //codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库 | |
|   // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入 | |
| import 'codemirror/mode/javascript/javascript.js' | |
| import 'codemirror/mode/css/css.js' | |
| import 'codemirror/mode/xml/xml.js' | |
| import 'codemirror/mode/clike/clike.js' | |
| import 'codemirror/mode/markdown/markdown.js' | |
| import 'codemirror/mode/python/python.js' | |
| import 'codemirror/mode/r/r.js' | |
| import 'codemirror/mode/shell/shell.js' | |
| import 'codemirror/mode/sql/sql.js' | |
| import 'codemirror/mode/swift/swift.js' | |
| import 'codemirror/mode/vue/vue.js' | |
|   // 尝试获取全局实例 | |
| const CodeMirror = window.CodeMirror || _CodeMirror | |
| export default { | |
| name: 'in-coder', | |
| props: { | |
|       // 外部传入的内容,用于实现双向绑定 | |
| value: String, | |
|       // 外部传入的语法类型 | |
| language: { | |
| type: String, | |
| default: null | |
|       } | |
| }, | |
| data () { | |
| return { | |
|         // 内部真实的内容 | |
| code: '', | |
|         // 默认的语法类型 | |
| mode: 'javascript', | |
|         // 编辑器实例 | |
| coder: null, | |
|         // 默认配置 | |
| options: { | |
|           // 缩进格式 | |
| tabSize: 2, | |
|           // 主题,对应主题库 JS 需要提前引入 | |
| theme: 'cobalt', | |
|           // 显示行号 | |
| lineNumbers: true, | |
| line: true | |
| }, | |
|         // 支持切换的语法高亮类型,对应 JS 已经提前引入 | |
|         // 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了 | |
| modes: [{ | |
| value: 'css', | |
| label: 'CSS' | |
| }, { | |
| value: 'javascript', | |
| label: 'Javascript' | |
| }, { | |
| value: 'html', | |
| label: 'XML/HTML' | |
| }, { | |
| value: 'x-java', | |
| label: 'Java' | |
| }, { | |
| value: 'x-objectivec', | |
| label: 'Objective-C' | |
| }, { | |
| value: 'x-python', | |
| label: 'Python' | |
| }, { | |
| value: 'x-rsrc', | |
| label: 'R' | |
| }, { | |
| value: 'x-sh', | |
| label: 'Shell' | |
| }, { | |
| value: 'x-sql', | |
| label: 'SQL' | |
| }, { | |
| value: 'x-swift', | |
| label: 'Swift' | |
| }, { | |
| value: 'x-vue', | |
| label: 'Vue' | |
| }, { | |
| value: 'markdown', | |
| label: 'Markdown' | |
| }] | |
|       } | |
| }, | |
| mounted () { | |
|       // 初始化 | |
| this._initialize() | |
| }, | |
| methods: { | |
|       // 初始化 | |
| _initialize () { | |
|         // 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置 | |
| this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.options) | |
|         // 编辑器赋值 | |
| this.coder.setValue(this.value || this.code) | |
|         // 支持双向绑定 | |
| this.coder.on('change', (coder) => { | |
| this.code = coder.getValue() | |
| if (this.$emit) { | |
| this.$emit('input', this.code) | |
|           } | |
| }) | |
|         // 尝试从父容器获取语法类型 | |
| if (this.language) { | |
|           // 获取具体的语法类型对象 | |
| let modeObj = this._getLanguage(this.language) | |
|           // 判断父容器传入的语法是否被支持 | |
| if (modeObj) { | |
| this.mode = modeObj.label | |
|           } | |
|         } | |
| }, | |
|       // 获取当前语法类型 | |
| _getLanguage (language) { | |
|         // 在支持的语法类型列表中寻找传入的语法类型 | |
| return this.modes.find((mode) => { | |
|           // 所有的值都忽略大小写,方便比较 | |
| let currentLanguage = language.toLowerCase() | |
| let currentLabel = mode.label.toLowerCase() | |
| let currentValue = mode.value.toLowerCase() | |
|           // 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较 | |
| return currentLabel === currentLanguage || currentValue === currentLanguage | |
| }) | |
| }, | |
|       // 更改模式 | |
| changeMode (val) { | |
|         // 修改编辑器的语法配置 | |
| this.coder.setOption('mode', `text/${val}`) | |
|         // 获取修改后的语法 | |
| let label = this._getLanguage(val).label.toLowerCase() | |
|         // 允许父容器通过以下函数监听当前的语法值 | |
| this.$emit('language-change', label) | |
|       } | |
|     } | |
|   } | |
| </script> | |
| <style lang="stylus" rel="stylesheet/stylus"> | |
| .in-coder-panel | |
| flex-grow 1 | |
| display flex | |
| position relative | |
|     .CodeMirror | |
| flex-grow 1 | |
| z-index 1 | |
| .CodeMirror-code | |
| line-height 19px | |
| .code-mode-select | |
| position absolute | |
| z-index 2 | |
|       right 10px | |
|       top 10px | |
| max-width 130px | |
| </style> | 
# options 可以使用的参数
CodeMirror 函数和它的 fromTextArea 方法都可以使用一个配置对象作为第二个参数。
# value: string | CodeMirror.Doc
编辑器的初始值(文本),可以是字符串或者 CodeMirror 文档对象 (不同于 HTML 文档对象)。
# mode: string | object
通用的或者在 CodeMirror 中使用的与 mode 相关联的 mime,当不设置这个值的时候,会默认使用第一个载入的 mode 定义文件。一般地,会使用关联的 mime 类型来设置这个值;除此之外,也可以使用一个带有 name 属性的对象来作为值(如:{name: “JavaScript”, json: true})。可以通过访问 CodeMirror.modes 和 CodeMirror.mimeModes 获取定义的 mode 和 MIME。
# lineSeparator: string|null
明确指定编辑器使用的行分割符(换行符)。默认(值为 null)情况下,文档会被 CRLF (以及单独的 CR, LF) 分割,单独的 LF 会在所有的输出中用作换行符(如:getValue)。当指定了换行字符串,行就只会被指定的串分割。
# theme: string
配置编辑器的主题样式。要使用主题,必须保证名称为 .cm-s-[name] (name 是设置的 theme 的值) 的样式是加载上了的。当然,你也可以一次加载多个主题样式,使用方法和 html 和使用类一样,如: theme: foo bar,那么此时需要 cm-s-foo cm-s-bar 这两个样式都已经被加载上了。
# indentUnit: integer
缩进单位,值为空格数,默认为 2 。
# smartIndent: boolean
自动缩进,设置是否根据上下文自动缩进(和上一行相同的缩进量)。默认为 true。
# abSize: integer
tab 字符的宽度,默认为 4 。
# indentWithTabs: boolean
在缩进时,是否需要把 n*tab 宽度个空格替换成 n 个 tab 字符,默认为 false 。
# electricChars: boolean
在输入可能改变当前的缩进时,是否重新缩进,默认为 true (仅在 mode 支持缩进时有效)。
# specialChars: RegExp
需要被占位符 (placeholder) 替换的特殊字符的正则表达式。最常用的是非打印字符。默认为:/[\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/。
# specialCharPlaceholder: function(char) → Element
这是一个接收由 specialChars 选项指定的字符作为参数的函数,此函数会产生一个用来显示指定字符的 DOM 节点。默认情况下,显示一个红点(・),这个红点有一个带有前面特殊字符编码的提示框。
# keyMap: string
配置快捷键。默认值为 default,即 codemorrir.js 内部定义。其它在 key map 目录下。
# extraKeys: object
给编辑器绑定与前面 keyMap 配置不同的快捷键。
# lineWrapping: boolean
在长行时文字是换行 (wrap) 还是滚动 (scroll),默认为滚动 (scroll)。
# lineNumbers: boolean
是否在编辑器左侧显示行号。
# firstLineNumber: integer
行号从哪个数开始计数,默认为 1 。
# lineNumberFormatter: function(line: integer) → string
使用一个函数设置行号。
# gutters: array
用来添加额外的 gutter(在行号 gutter 前或代替行号 gutter)。值应该是 CSS 名称数组,每一项定义了用于绘制 gutter 背景的宽度(还有可选的背景)。为了能明确设置行号 gutter 的位置(默认在所有其它 gutter 的右边),也可以包含 CodeMirror-linenumbers 类。类名是用于传给 setGutterMarker 的键名 (keys)。
# fixedGutter: boolean
设置 gutter 跟随编辑器内容水平滚动(false)还是固定在左侧(true 或默认)。
# scrollbarStyle: string
设置滚动条。默认为”native”,显示原生的滚动条。核心库还提供了”null” 样式,此样式会完全隐藏滚动条。Addons 可以设置更多的滚动条模式。
# coverGutterNextToScrollbar: boolean
当 fixedGutter 启用,并且存在水平滚动条时,在滚动条最左侧默认会显示 gutter,当此项设置为 true 时,gutter 会被带有 CodeMirror-gutter-filler 类的元素遮挡。
# inputStyle: string
选择 CodeMirror 处理输入和焦点的方式。核心库定义了 textarea 和 contenteditable 输入模式。在移动浏览器上,默认是 contenteditable,在桌面浏览器上,默认是 textarea。在 contenteditable 模式下对 IME 和屏幕阅读器支持更好。
# readOnly: boolean|string
编辑器是否只读。如果设置为预设的值 “nocursor”,那么除了设置只读外,编辑区域还不能获得焦点。
# showCursorWhenSelecting: boolean
在选择时是否显示光标,默认为 false。
# lineWiseCopyCut: boolean
启用时,如果在复制或剪切时没有选择文本,那么就会自动操作光标所在的整行。
# undoDepth: integer
最大撤消次数,默认为 200(包括选中内容改变事件) 。
# historyEventDelay: integer
在输入或删除时引发历史事件前的毫秒数。
# tabindex: integer
编辑器的 tabindex。
# autofocus: boolean
是否在初始化时自动获取焦点。默认情况是关闭的。但是,在使用 textarea 并且没有明确指定值的时候会被自动设置为 true。
# 低级选项
下面的选项仅用于一些特殊情况。
# dragDrop: boolean
是否允许拖放,默认为 true。
# allowDropFileTypes: array
默认为 null。当设置此项时,只接收包含在此数组内的文件类型拖入编辑器。文件类型为 MIME 名称。
# cursorBlinkRate: number
光标闪动的间隔,单位为毫秒。默认为 530。当设置为 0 时,会禁用光标闪动。负数会隐藏光标。
# cursorScrollMargin: number
当光标靠近可视区域边界时,光标距离上方和下方的距离。默认为 0 。
# cursorHeight: number
光标高度。默认为 1,也就是撑满行高。对一些字体,设置 0.85 看起来会更好。
# resetSelectionOnContextMenu: boolean
设置在选择文本外点击打开上下文菜单时,是否将光标移动到点击处。默认为 true。
# workTime, workDelay: number
通过一个假的后台线程高亮 workTime 时长,然后使用 timeout 休息 workDelay 时长。默认为 200 和 300 。
# pollInterval: number
指明 CodeMirror 向对应的 textarea 滚动(写数据)的速度(获得焦点时)。大多数的输入都是通过事件捕获,但是有的输入法(如 IME)在某些浏览器上并不会生成事件,所以使用数据滚动。默认为 100 毫秒。
# flattenSpans: boolean
默认情况下,CodeMirror 会将使用相同 class 的两个 span 合并成一个。通过设置此项为 false 禁用此功能。
# addModeClass: boolean
当启用时(默认禁用),会给每个标记添加额外的表示生成标记的 mode 的以 cm-m 开头的 CSS 样式类。例如,XML mode 产生的标记,会添加 cm-m-xml 类。
# maxHighlightLength: number
当需要高亮很长的行时,为了保持响应性能,当到达某些位置时,编辑器会直接将其他行设置为纯文本 (plain text)。默认为 10000,可以设置为 Infinity 来关闭此功能。
# viewportMargin: integer
指定当前滚动到视图中内容上方和下方要渲染的行数。这会影响到滚动时要更新的行数。通常情况下应该使用默认值 10。可以设置值为 Infinity 始终渲染整个文档。注意:这样设置在处理大文档时会影响性能。
