• 对于注定会优秀的人来说,他所需要的,只是时间!
  • 手懒得,必受贫穷,手勤的,必得富足----《圣经》
  • 帮助别人,成就自己。愿君在本站能真正有所收获!
  • 如果你在本站中发现任何问题,欢迎留言指正!
  • 宝剑锋从磨砺出,梅花香自苦寒来!

<一>Vue学习实践笔记-基于codemirror在页面中嵌入代码编辑器

Vue eryajf 2个月前 (08-06) 162°C 已收录 0个评论
本文预计阅读时间 26 分钟

1,基础信息

  • 名字:codemirror
  • 资料
    • Git地址:https://github.com/codemirror/codemirror
    • 官方文档:https://codemirror.net/
    • 支持的高亮语言:https://codemirror.net/mode/
    • 主题选择:https://codemirror.net/demo/theme.html#default
  • 衍生

2,用法简言

官方文档的阅读性并不是很好,因此简单记录一些几个使用的注意点。没有尝试过直接引用原生的包的效果,目前是基于ele-form这个二次封装的库来做的。不过有许多东西,还可以基于原生的一些特性,进行自定义。

1,高亮语言

一般直接拷贝上边示例中的一些案例即可满足需求,如果想要自定义,有如下注意点,因为我需要的是shell输入框,因此引入语言改成如下内容:

// language
import 'codemirror/mode/shell/shell.js'

需要注意的一个点是,在引用中配置(options)参数(mode)时,并不是shell,而是 x-sh,这个可以在高亮语言中点击进去的示例下边看到,因为这个上下不一致,让我踩了挺长时间的坑(因为网上大多示例都是采用的JavaScript高亮,而这个模块儿引入又刚好是text/javascript,因此造成了一定的误导),截图示例如下:

2,主题选择

主题选择可以根据如下demo选择适合自己的,引入主题的方式如下:

// theme css
import 'codemirror/theme/base16-light.css'

然后在引用中配置(options)参数(theme)中定义即可,这里测试名字是上下一致的,没有其他坑点。不过我引入的shell语言,测试之后发现默认的主题反而最好看,因此不需引入css,直接设置为default即可。

3,案例分享

接下来分享一下我个人的使用案例,整理内容,大致如下:


<template> <!-- 代码输入区域 --> <ele-form :formDesc="formDesc" v-model="formData" :request-fn="handleRequest" @request-success="handleRequestSuccess"></ele-form> </template> <script> // 引入外部包 import EleForm from 'vue-ele-form' import EleFormCodemirror from 'vue-ele-form-codemirror' // language import 'codemirror/mode/shell/shell.js' // require active-line.js import'codemirror/addon/selection/active-line.js' // closebrackets import'codemirror/addon/edit/closebrackets.js' // keyMap import'codemirror/mode/clike/clike.js' import'codemirror/addon/edit/matchbrackets.js' import'codemirror/addon/comment/comment.js' import'codemirror/addon/dialog/dialog.js' import'codemirror/addon/dialog/dialog.css' import'codemirror/addon/search/searchcursor.js' import'codemirror/addon/search/search.js' import'codemirror/keymap/emacs.js' export default { data() { return { formData: {}, // 定制样式 formDesc: { option: { label: "命令", // 说明文字 type: "codemirror", // 选择这个类型 tabSize: 4, line: true, theme: 'default', // 主题选择默认 mode: 'text/x-sh', // 此处定义高亮语言风格 lineNumbers: true, styleActiveLine: true, autoCloseBrackets: true, } }, } }, methods: { handleRequest (data) { console.log(data) return Promise.resolve() }, handleRequestSuccess () { this.$message.success('发送成功') }, handleSelectionChange(val) { console.log("选择成功"); this.multipleSelection = val; }, } } </script> <style> .CodeMirror-focused .cm-matchhighlight { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); background-position: bottom; background-repeat: repeat-x; } .cm-matchhighlight { background-color: lightgreen; } .CodeMirror-selection-highlight-scrollbar { background-color: green; } </style>

在自己的项目中,可根据实际情况将引入的内容放到公共的部分。

4,最终效果

出来的效果大致如下:

image-20200716120451455

3,原生使用

上边通过引入了一个第三方组件来实现的,其实也可以直接通过 vue-codemirror来实现,效果基本上是差不多的。

代码大概如下:


<template> <!-- 代码输入区域 --> <codemirror v-model="formData.task_content" :options="cmOptions"/> </template> <script> // language import 'codemirror/mode/shell/shell.js' // require active-line.js import'codemirror/addon/selection/active-line.js' // closebrackets import'codemirror/addon/edit/closebrackets.js' // keyMap import'codemirror/mode/clike/clike.js' import'codemirror/addon/edit/matchbrackets.js' import'codemirror/addon/comment/comment.js' import'codemirror/addon/dialog/dialog.js' import'codemirror/addon/dialog/dialog.css' import'codemirror/addon/search/searchcursor.js' import'codemirror/addon/search/search.js' import'codemirror/keymap/emacs.js' export default { data() { return { formData: {}, cmOptions: { tabSize: 4, mode: 'text/x-sh', lineNumbers: true, line: true, matchBrackets: true, scrollbarStyle: 'overlay', theme: 'default' }, } }, methods: { } } </script> <style> </style>

这种更加原生的状态,更能方便我们将输入框作为表单的一环来应用,不过默认情况下,代码的行间距有点大,光标太大,不是很好看,可以通过如下代码进行美化:

.code-mirror{
    font-size : 13px;
    line-height : 150%;
}

然后将这个样式引用即可。

4,其他参数

1,常用配置

  • 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<string>
    用来添加额外的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<string>
    默认为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始终渲染整个文档。注意:这样设置在处理大文档时会影响性能。

2,编辑器事件

编辑器实例会触发以下这些事件。其中的instance参数总是指向编辑器本身。

  • change: (instance: CodeMirror, changeObj: object)
    每当编辑器内容发生变化时触发。参数changeObj是一个{from, to, text, removed, origin}对象,包含内容变化的信息。其中from和to是内容改变发生的起止位置(改变发生之前),举个例子,如果改变始于第19行之初,则from为{ch:0, line:18}。text替换起止位置之间内容的文字,按行分割开,组成数组。removed则是被替换掉的内容。这个事件会在operation临结束前,在DOM更新之前触发。
  • changes: (instance: CodeMirror, changes: array:)
    类似于change事件,不过是在每次operation后,将改变一次过打包成数组传出来。而展现这些改变,又将出发一次新的operation。
  • beforeChange: (instance: CodeMirror, changeObj:object)
    这个事件在内容改变生效前触发,它的handler可以此来修改或取消这次改变。其中的changeObj对象有from, to, text属性。它还包含一个cancel()方法,用于取消这次改变,而且如果这次改变不是来自撤销(undo)与重做(redo)操作的画,它还会有一个update(from, to, text)方法,用来修改这次改变。update方法的3个参数都不是必填的,可以不传入,以直接使用原先的值。注意:你不该在beforeChange的handler中做任务会导致document或其视觉表现的操作。
  • cursorActivity: (instance: CodeMirror)
    每当光标或内容选择移动时出发,因此编辑器中任务内容的改变也会出发。
  • keyHandled: (instance: CodeMirror, name: string, event: Event)
    每当一个快捷键被通过key map handled时触发。name是被handled的键(例如”ctrl-x”或者“‘q’”),而event则是DOM的keydown或keypress事件。
  • inputRead: (instance: CodeMirror, changeObj: object)
    每当被因此对textarea中有新的输入被读取到时触发(可能是来自键盘输入或粘贴)。
  • electricInput: (instance: CodeMirror, line: integer)
    当输入的文字匹配mode的electric模式时触发,这会导致该行的缩进发生改变。
  • beforeSelectionChange: (instance: CodeMirror, obj: {range, origin, update})
  • viewportChange: (instance: CodeMirror, from: number, to: number)
    当可视区发生变化时触发(这可能是由于滚动、编辑内容等原因造成)。其参数from和to给出了可视区新的起始位置。
  • swapDoc: (instance: CodeMirror, oldDoc: Doc)
    当编辑器的document被使用swapDoc方法更换掉时触发。
  • gutterClick: (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)
    每当编辑器的gutter被点击时触发。其参数分别为编辑器实例;为被点击的行数,从0开始计数;+ gutter的CSS class名;mousedown的原始事件。
  • gutterContextMenu: (instance: CodeMirror, line: integer, gutter: string, contextMenu: Event)
    每当编辑器的gutter收到contextmenu事件时触发。与gutterClick不同的是,最后一个参数是contextmenu事件。你可以preventDefault这个事件,这会通知CodeMirror不再进一步handle。
  • focus: (instace: CodeMirror)
    当编辑器获得焦点时触发。
  • blur: (instance: CodeMirror)
    当编辑器失去焦点时触发。
  • scroll: (instance: CodeMirror)
    当编辑器滚动时触发。
  • scrollCursorIntoView (instance: CodeMirror, event: Event)
  • update: (instance: CodeMirror)
    每当CodeMirror更新它的DOM展示时触发。
  • renderLine (instance: CodeMirror, line: LineHandle, element: Element)
    每当一行需要被绘制(重绘)成DOM时触发。它触发在DOM元素建立好之后,但在加入document之前。handler可以改动该元素的样式,或是为其添加event handlers,但不该尝试改变编辑器的状态。
  • mousedown, dbclick, touchstart, contextmenu, keydown, keypress, keyup, cut, copy ,paste, dragstart, dragenter, dragover, dragleave, drop: (instance: CodeMirror, event: Event)
    当CodeMirrorhandle这些DOm事件时触发。你可以preventDefault这些事件,也可以把它们的codemirrorIgnore属性设为真值,以告知CodeMirror不要再继续handle。文档对象(Document objects, CodeMirror.Doc的实例)
  • change: (doc: CodeMirror.Doc, changeObj: object)
    每当document发生改变时触发。参数changeObj类似于编辑器change事件的changeObj。
  • beforeChange: (doc: CodeMirror.Doc, change: object)
    参见编辑器的同名事件。
  • cursorActivity: (doc: CodeMirror.Doc)
    每当document中的光标和选区变化时触发。
  • beforeSelectionChange: (doc: CodeMirror.Doc, selection: {head, anchor})
    参见编辑器的同名事件。
  • Line handles as returned by, for example, getLineHandle
    可以理解为行对象
  • delete: ()
    当行对象被删除时触发。
  • change: (line: LineHandle, changeObj: object) 当行对象中的内容发生改变(但这一行并没有被完全删除)时触发。changeObj跟编辑器对象的同名事件一样。

5,参考


weinxin
扫码订阅本站,第一时间获得更新
微信扫描二维码,订阅我们网站的动态,另外不定时发送WordPress小技巧,你可以随时退订,欢迎订阅哦~

二丫讲梵 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明<一>Vue学习实践笔记-基于codemirror在页面中嵌入代码编辑器
喜欢 (0)
[如果想支持本站,可支付宝赞助]
分享 (0)
eryajf
关于作者:
学无止境,我愿意无止境学。书山有路,我愿意举身投火,淬炼成金!永远不要忘记,激情的奋进,就是美好的未来!

您必须 登录 才能发表评论!