Vue 基于vue-codemirror实现的代码编辑器

功能介绍

1、 支持不同的代码编辑模式
目前仅支持支持json, sql, javascript,css,xml, html,yaml, markdown, python编辑模式,默认为 json

2、 支持使用不同主题
支持62种主题,默认为 blackboard

3、 支持文件拖拽导入
支持鼠标拖拽文件到编辑框,编辑框自动展示被拖拽文件的内容(当然,不是所有文件都可以,比如word文件,.exe文件就不行)

4、 支持json格式化
1)json编辑模式下,鼠标失去焦点时自动格式化json字符串,支持定义开关该特性
2)支持自定义格式化化缩进,支持字符或数字,最大不超过10,默认缩进2个空格
3)json编辑模式下,黏贴json字符串到编辑框时,支持自动格式化编辑框内容
4)json编辑模式下,支持按Ctrl+Alt+L快捷键主动格式化当前json格式字符内容
5、 支持显示代码行号

6、 支持编辑时“智能”缩进

7、 支持代码折叠/展开
支持json, sql, javascript,css,xml, html,yaml, markdown, python等

8、 支持静态代码语法检查
目前仅支持支持 json,javascript

9、 支持批量替换
操作方法:
按Ctrl + Shift + r键,弹出框中输入要被替换的内容,回车,然后再次输入用于替换的内容,回车即可。

10、 支持快速搜索
操作方法:
按Ctrl + F,弹出框中输入要查找内容,回车

11 、 支持跳转到指定行
操作方法:
按Alt + G 快捷键, 弹出快对话框中输入行号,回车即可

12、 支持鼠标点击高亮匹配单词
使用场景举例:鼠标点击某个单词,高亮其它区域和被点击单词相同的单词

13、 支持自动补全提示
目前仅支持 sql,javascript,html,python
备注:出现自动补全提示时,按tab键可自动补

14、 支持自动补全xml标签
支持输入完开放xml、html元素标签时,自动补齐右侧闭合标签、或者输入完 </ 时,自动补齐闭合标签
使用场景举例:输入完时自动补齐右侧

15、 支持自动匹配xml标签
xml、html编辑模式下,支持自动匹配标签
使用场景举例:鼠标点击时xml标签时(开放标签或闭合标签),自动高亮另一半标签

16、 支持自动匹配括号
使用场景举例:光标点击紧挨{、]括号左、右侧时,自动突出显示匹配的括号 }、]

17、 支持光标所在当前行背景高亮

18、 支持高亮选中内容
使用场景举例:按下鼠标左键,拖拽选择内容时,高亮被选中内容,文字反白

主要依赖安装

npm install jsonlint
npm install jshint
npm install script-loader
npm install vue-codemirror
npm install element-ui

src/main.js配置

添加以下带背景色的部分的配置
import Vue from “vue”
import ElementUI from “element-ui”
import “element-ui/lib/theme-chalk/index.css”
// 引入jshint用于实现js自动补全提示
import jshint from “jshint”;
window.JSHINT = jshint.JSHINT;
// 引入代码编辑器
import { codemirror } from “vue-codemirror”;
import “codemirror/lib/codemirror.css”;
Vue.use(ElementUI);
Vue.use(codemirror);

编辑器组件实现

<template>
    <codemirror
        ref="myCm"
        :value="value"
        :options="cmOptions"
        @changes="onCmCodeChanges"
        @blur="onCmBlur"
        @keydown.native="onKeyDown"
        @mousedown.native="onMouseDown"
        @paste.native="OnPaste"
    ></codemirror>
</template>
<script>
	import {
    
     codemirror } from "vue-codemirror";
	import "codemirror/theme/blackboard.css";
	import "codemirror/mode/javascript/javascript.js"; 
	import "codemirror/mode/xml/xml.js";
	import "codemirror/mode/htmlmixed/htmlmixed.js"; 
	import "codemirror/mode/css/css.js";
	import "codemirror/mode/yaml/yaml.js";
	import "codemirror/mode/sql/sql.js";
	import "codemirror/mode/python/python.js";
	import "codemirror/mode/markdown/markdown.js";
	import "codemirror/addon/hint/show-hint.css";                                
	import "codemirror/addon/hint/show-hint.js"; 
	import "codemirror/addon/hint/javascript-hint.js";
	import "codemirror/addon/hint/xml-hint.js";
	import "codemirror/addon/hint/css-hint.js"; 
	import "codemirror/addon/hint/html-hint.js";
	import "codemirror/addon/hint/sql-hint.js";
	import "codemirror/addon/hint/anyword-hint.js"; 
	import "codemirror/addon/lint/lint.css";
	import "codemirror/addon/lint/lint.js"; 
	import "codemirror/addon/lint/json-lint"; 
	require("script-loader!jsonlint");
	import "codemirror/addon/lint/javascript-lint.js"; 
	import "codemirror/addon/fold/foldcode.js"; 
	import "codemirror/addon/fold/foldgutter.js"; 
	import "codemirror/addon/fold/foldgutter.css";
	import "codemirror/addon/fold/brace-fold.js"; 
	import "codemirror/addon/fold/xml-fold.js";
	import "codemirror/addon/fold/comment-fold.js"; 
	import "codemirror/addon/fold/markdown-fold.js"; 
	import "codemirror/addon/fold/indent-fold.js"; 
	import "codemirror/addon/edit/closebrackets.js"; 
	import "codemirror/addon/edit/closetag.js";
	import "codemirror/addon/edit/matchtags.js"; 
	import "codemirror/addon/edit/matchbrackets.js";
	import "codemirror/addon/selection/active-line.js"; 
	import "codemirror/addon/search/jump-to-line.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/addon/display/autorefresh.js"; 
	import "codemirror/addon/selection/mark-selection.js"; 
	import "codemirror/addon/search/match-highlighter.js"; 
	export default {
    
    
	    components: {
    
    
	        codemirror
	    },
	    props: ["cmTheme", "cmMode", "autoFormatJson", "jsonIndentation","value"],
	    data() {
    
    
	        return {
    
    
	            editorValue: "",
	            cmOptions: {
    
    
	                theme:!this.cmTheme || this.cmTheme == "default"? "blackboard": this.cmTheme, 
	                mode:!this.cmMode || this.cmMode == "default"? "application/json": this.cmMode, 
					extraKeys: {
    
    
	                    Tab: "autocomplete", 
	                    "Ctrl-Alt-L": () => {
    
    
	                        try {
    
    
	                            if (this.cmOptions.mode == "application/json" &&this.value) {
    
    
	                                this.editorValue = this.formatStrInJson(this.value);
	                            }
	                        } catch (e) {
    
    
	                            this.$message.error("格式化代码出错:" + e.toString());
	                        }
	                    }                    
	                },
	                lineWrapping: true,//代码折叠
                    lineNumbers: true,//是否显示行号
                    autofocus: true,
                    smartIndent: 4,// 自动缩进
                    indentUnit: 4, //缩进单位
                    tabSize: 4, //tab字符的宽度
                    autocorrect: true,//自动更正
                    spellcheck: true,//拼写检查
                    lint: true,
                    gutters: [
                        "CodeMirror-lint-markers",//代码错误检测
                        "CodeMirror-linenumbers",
                        "CodeMirror-foldgutter",//展开收起
                    ],
                    foldGutter: true,
                    matchTags: {
    
     bothTags: true },
                    matchBrackets: true,
                    styleActiveLine: true,
                    autoRefresh: true,
                    highlightSelectionMatches: {
    
    //显示当前所选单词
	                    minChars: 2,
	                    style: "matchhighlight", 
	                    showToken: true 
	                },
                	styleSelectedText: true,
               	 	enableAutoFormatJson:this.autoFormatJson == null ? true : this.autoFormatJson,
                	defaultJsonIndentation:!this.jsonIndentation ||typeof this.jsonIndentation != typeof 1? 2: this.jsonIndentation 
            	},
	            enableAutoFormatJson:this.autoFormatJson == null ? true : this.autoFormatJson, 
	            defaultJsonIndentation: !this.jsonIndentation || typeof this.jsonIndentation != typeof 1? 2: this.jsonIndentation 
	        };
	    },
	    watch: {
    
    
	        cmTheme: function(newValue, oldValue) {
    
    
	            try {
    
    
	                let theme = this.cmTheme == "default" ? "blackboard" : this.cmTheme;
	                require("codemirror/theme/" + theme + ".css");
	                this.cmOptions.theme = theme;
	                this.resetLint();
	            } catch (e) {
    
    
	                this.$message.error("切换编辑器主题出错:" + e.toString());
	            }
	        },
	        cmMode: function(newValue, oldValue) {
    
    
	            this.$set(this.cmOptions, "mode", this.cmMode);
	            this.resetLint();
	            this.resetFoldGutter();
	        }
	    },
	    methods: {
    
    
	        resetLint() {
    
    
	            if (!this.$refs.myCm.codemirror.getValue()) {
    
    
	                this.$nextTick(() => {
    
    
	                    this.$refs.myCm.codemirror.setOption("lint", false);
	                });
	                return;
	            }
	            this.$refs.myCm.codemirror.setOption("lint", false);
	            this.$nextTick(() => {
    
    
	                this.$refs.myCm.codemirror.setOption("lint", true);
	            })
	        },
	        resetFoldGutter() {
    
    
	           	this.$refs.myCm.codemirror.setOption("foldGutter", false);
	            this.$nextTick(() => {
    
    
	                this.$refs.myCm.codemirror.setOption("foldGutter", true);
	            });
	        },

	        // 黏贴事件处理函数
	        OnPaste(event) {
    
    
	            if (this.cmOptions.mode == "application/json") {
    
    
	                try {
    
    
	                    this.editorValue = this.formatStrInJson(this.value);
	                } catch (e) {
    
    
	                    // 啥都不做
	                }
	            }
	        },
	        // 失去焦点时处理函数
	        onCmBlur(cm, event) {
    
    
	            try {
    
    
	                let editorValue = cm.getValue();
	                if (this.cmOptions.mode == "application/json" && editorValue) {
    
    
	                    if (!this.enableAutoFormatJson) {
    
    
	                        return;
	                    }
	                    this.editorValue = this.formatStrInJson(editorValue);
	                }
	            } catch (e) {
    
    
	                // 啥也不做
	            }
	        },
	        // 按下键盘事件处理函数
	        onKeyDown(event) {
    
    
	            const keyCode = event.keyCode || event.which || event.charCode;
	            const keyCombination = event.ctrlKey || event.altKey || event.metaKey;
	            if (!keyCombination && keyCode > 64 && keyCode < 123) {
    
    
	                this.$refs.myCm.codemirror.showHint({
    
     completeSingle: false });
	            }
	        },
	        // 按下鼠标时事件处理函数
	        onMouseDown(event) {
    
    
	            this.$refs.myCm.codemirror.closeHint();
	        },
	        onCmCodeChanges(cm, changes) {
    
    
	            this.editorValue = cm.getValue();
	            this.resetLint();
				this.$emint('onChangeCode',cm.getValue())
	        },
	        // 格式化字符串为json格式字符串
	        formatStrInJson(strValue) {
    
    
	            return JSON.stringify( JSON.parse(strValue),null, this.defaultJsonIndentation)
	        }
	    },
	    created() {
    
    
	        try {
    
    
	            if (!this.value) {
    
    
	                this.cmOptions.lint = false;
	                return;
	            }
	            if (this.cmOptions.mode == "application/json") {
    
    
	                if (!this.enableAutoFormatJson) {
    
    
	                    return;
	                }
	                this.editorValue = this.formatStrInJson(this.value);
	            }
	        } catch (e) {
    
    
	            console.log("初始化codemirror出错:" + e); 
	    }
	};
</script>
<style>
.CodeMirror-selected {
    
    
    background-color: blue !important;
}
.CodeMirror-selectedtext {
    
    
    color: white !important;
}
.cm-matchhighlight {
    
    
    background-color: #ae00ae;
}
</style>

引用编辑器组件

<template>
    <div class="code-mirror-div">
        <div class="tool-bar">
            <span>请选择主题</span>
            <el-select v-model="cmTheme" placeholder="请选择" size="small" style="width:150px">
                <el-option v-for="item in cmThemeOptions" :key="item" :label="item" :value="item"></el-option>
            </el-select>
            <span style="margin-left: 10px">请选择编辑模式</span>
            <el-select
                v-model="cmEditorMode"
                placeholder="请选择"
                size="small"
                style="width:150px"
                @change="onEditorModeChange"
            >
                <el-option
                    v-for="item in cmEditorModeOptions"
                    :key="item"
                    :label="item"
                    :value="item"
                ></el-option>
            </el-select>
        </div>
        <code-mirror-editor
            ref="cmEditor"
            :cmTheme="cmTheme"
            :cmMode="cmMode"
            :autoFormatJson="autoFormatJson"
            :jsonIndentation="jsonIndentation"
            :value="codeValue
			@onChangeCode="changeCode"
        ></code-mirror-editor>
    </div>
</template>
<script>
	// 使用时需要根据CodeMirrorEditor.vue的实际存放路径,调整from后面的组件路径,以便正确引用
	import CodeMirrorEditor from "@/common/components/public/CodeMirrorEditor";
	export default {
    
    
	    components: {
    
    
	        CodeMirrorEditor
	    },
	    data() {
    
    
	        return {
    
    
	            cmTheme: "default", // codeMirror主题
	            // codeMirror主题选项
	            cmThemeOptions: [
	                "default",
	                "3024-day",
	                "3024-night",
	                "abcdef",
	                "ambiance",
	                "ayu-dark",
	                "ayu-mirage",
	                "base16-dark",
	                "base16-light",
	                "bespin",
	                "blackboard",
	                "cobalt",
	                "colorforth",
	                "darcula",
	                "dracula",
	                "duotone-dark",
	                "duotone-light",
	                "eclipse",
	                "elegant",
	                "erlang-dark",
	                "gruvbox-dark",
	                "hopscotch",
	                "icecoder",
	                "idea",
	                "isotope",
	                "lesser-dark",
	                "liquibyte",
	                "lucario",
	                "material",
	                "material-darker",
	                "material-palenight",
	                "material-ocean",
	                "mbo",
	                "mdn-like",
	                "midnight",
	                "monokai",
	                "moxer",
	                "neat",
	                "neo",
	                "night",
	                "nord",
	                "oceanic-next",
	                "panda-syntax",
	                "paraiso-dark",
	                "paraiso-light",
	                "pastel-on-dark",
	                "railscasts",
	                "rubyblue",
	                "seti",
	                "shadowfox",
	                "solarized dark",
	                "solarized light",
	                "the-matrix",
	                "tomorrow-night-bright",
	                "tomorrow-night-eighties",
	                "ttcn",
	                "twilight",
	                "vibrant-ink",
	                "xq-dark",
	                "xq-light",
	                "yeti",
	                "yonce",
	                "zenburn"
	            ],
	            cmEditorMode: "default", // 编辑模式
	            // 编辑模式选项
	            cmEditorModeOptions: [
	                "default",
	                "json",
	                "sql",
	                "javascript",
	                "css",
	                "xml",
	                "html",
	                "yaml",
	                "markdown",
	                "python"
	            ],
	            cmMode: "application/json", //codeMirror模式
	            jsonIndentation: 2, // json编辑模式下,json格式化缩进 支持字符或数字,最大不超过10,默认缩进2个空格
	            autoFormatJson: true // json编辑模式下,输入框失去焦点时是否自动格式化,true 开启, false 关闭,
	            codeValue:'[{text:"text1",value:"value1"}]',//代码
	        };
	    },
	    methods: {
    
    
	        // 切换编辑模式事件处理函数
	        onEditorModeChange(value) {
    
    
	            switch (value) {
    
    
	                case "json":
	                    this.cmMode = "application/json";
	                    break;
	                case "sql":
	                    this.cmMode = "sql";
	                    break;
	                case "javascript":
	                    this.cmMode = "javascript";
	                    break;
	                case "xml":
	                    this.cmMode = "xml";
	                    break;
	                case "css":
	                    this.cmMode = "css";
	                    break;
	                case "html":
	                    this.cmMode = "htmlmixed";
	                    break;
	                case "yaml":
	                    this.cmMode = "yaml";
	                    break;
	                case "markdown":
	                    this.cmMode = "markdown";
	                    break;
	                case "python":
	                    this.cmMode = "python";
	                    break;
	                default:
	                    this.cmMode = "application/json";
	            }
	        },
			//代码修改
			changeCode(value){
    
    
				this.codeValue = value;
			}
	    }
	
	};

</script>
<style>
.CodeMirror {
    
    
    position: absolute;
    top: 80px;
    left: 2px;
    right: 5px;
    bottom: 0px;
    padding: 2px;
    height: auto; 
    overflow-y: auto;
}
.code-mirror-div {
    
    
    position: absolute;
    top: 0px;
    left: 2px;
    right: 5px;
    bottom: 0px;
    padding: 2px;
}
.tool-bar {
    
    
    top: 20px;
    margin: 30px 2px 0px 20px;
 }
</style>

 


猜你喜欢

转载自blog.csdn.net/yxgd_1442962728/article/details/114145146