基於vue-codemirror實現的代碼編輯器 開發環境 jshint 2.11.1 jsonlint 1.6.3 script-loader 0.7.2 vue 2.6.11 vue-codemirror 4.0.6 element-ui 2.13.1 (使用到element-ui messag ...
基於vue-codemirror實現的代碼編輯器
開發環境
jshint 2.11.1
jsonlint 1.6.3
script-loader 0.7.2
vue 2.6.11
vue-codemirror 4.0.6
element-ui 2.13.1 (使用到element-ui message組件,提示錯誤消息,如果不想安裝該組件,替換編輯器中的this.$message所在行函數代碼即可)
功能介紹
1、 支持不同的代碼編輯模式
目前僅支持支持json, sql, javascript,css,xml, html,yaml, markdown, python編輯模式,預設為 json
2、 支持使用不同主題
支持62種主題,預設為 blackboard
3、 支持API編程
目前支持修改樣式,獲取內容,修改編輯框內容值
4、 支持複製,黏貼,剪切,撤銷等常見操作
5、 支持文件拖拽導入
支持滑鼠拖拽文件到編輯框,編輯框自動展示被拖拽文件的內容(當然,不是所有文件都可以,比如word文件,.exe文件就不行)
6、 支持json格式化
1)json編輯模式下,滑鼠失去焦點時自動格式化json字元串,支持定義開關該特性
2)支持自定義格式化化縮進,支持字元或數字,最大不超過10,預設縮進2個空格
3)json編輯模式下,黏貼json字元串到編輯框時,支持自動格式化編輯框內容
4)json編輯模式下,支持按Ctrl+Alt+L快捷鍵主動格式化當前json格式字元內容
7、 支持顯示代碼行號
8、 支持編輯時“智能”縮進
9、 支持代碼摺疊/展開
支持json, sql, javascript,css,xml, html,yaml, markdown, python等
10、 支持靜態代碼語法檢查
目前僅支持支持 json,javascript
11、 支持批量替換
操作方法:
按Ctrl + Shift + r鍵,彈出框中輸入要被替換的內容,回車,然後再次輸入用於替換的內容,回車即可。
12、 支持快速搜索
操作方法:
按Ctrl + F,彈出框中輸入要查找內容,回車
13、 支持跳轉到指定行
操作方法:
按Alt + G 快捷鍵, 彈出快對話框中輸入行號,回車即可
14、 支持滑鼠點擊高亮匹配單詞
使用場景舉例:滑鼠點擊某個單詞,高亮其它區域和被點擊單詞相同的單詞
15、 支持自動補全提示
目前僅支持 sql,javascript,html,python
備註:出現自動補全提示時,按tab鍵可自動補全
16、 支持自動補全括弧,單、雙引號
支持自動補全括弧:(),[],{},單引號,雙引號:'' ""
使用場景舉例:輸入 [ 時,自動顯示為[],並且把游標定位在括弧中間
17、 支持自動補全xml標簽
支持輸入完開放xml、html元素標簽時,自動補齊右側閉合標簽、或者輸入完 </ 時,自動補齊閉合標簽
使用場景舉例:輸入完<book>時自動補齊右側</book>
18、 支持自動匹配xml標簽
xml、html編輯模式下,支持自動匹配標簽
使用場景舉例:滑鼠點擊時xml標簽時(開放標簽或閉合標簽),自動高亮另一半標簽
19、 支持自動匹配括弧
使用場景舉例:游標點擊緊挨{、]括弧左、右側時,自動突出顯示匹配的括弧 }、]
20、 支持游標所在當前行背景高亮
21、 支持高亮選中內容
使用場景舉例:按下滑鼠左鍵,拖拽選擇內容時,高亮被選中內容,文字反白
主要依賴安裝
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";
import App from "./app/App"
...略
Vue.use(ElementUI);
Vue.use(codemirror);
...略
編輯器組件實現
<template>
<codemirror
ref="myCm"
:value="editorValue"
: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/html-lint.js";
// import "codemirror/addon/lint/css-lint.js";
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"],
data() {
return {
editorValue: "",
cmOptions: {
theme:
!this.cmTheme || this.cmTheme == "default"
? "blackboard"
: this.cmTheme,
mode:
!this.cmMode || this.cmMode == "default"
? "application/json"
: this.cmMode,
lineWrapping: true,
lineNumbers: true,
autofocus: true,
smartIndent: false,
autocorrect: true,
spellcheck: true,
extraKeys: {
Tab: "autocomplete",
"Ctrl-Alt-L": () => {
try {
if (
this.cmOptions.mode == "application/json" &&
this.editorValue
) {
this.editorValue = this.formatStrInJson(
this.editorValue
);
}
} catch (e) {
this.$message.error(
"格式化代碼出錯:" + e.toString()
);
}
}
},
lint: true,
gutters: [
"CodeMirror-lint-markers",
"CodeMirror-linenumbers",
"CodeMirror-foldgutter"
],
foldGutter: true,
autoCloseBrackets: true,
autoCloseTags: 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);
});
},
// 修改編輯框樣式
setStyle(style) {
try {
this.$nextTick(() => {
let cm = this.$refs.myCm.$el.querySelector(".CodeMirror");
if (cm) {
cm.style.cssText = style;
} else {
this.$message.error(
"未找到編輯器元素,修改編輯器樣式失敗"
);
}
});
} catch (e) {
this.$message.error("修改編輯器樣式失敗:" + e.toString());
}
},
// 獲取值
getValue() {
try {
return this.$refs.myCm.codemirror.getValue();
} catch (e) {
let errorInfo = e.toString();
this.$message.error("獲取編輯框內容失敗:" + errorInfo);
return errorInfo;
}
},
// 修改值
setValue(value) {
try {
if (typeof value != typeof "") {
this.$message.error(
"修改編輯框內容失敗:編輯寬內容只能為字元串"
);
return;
}
if (this.cmOptions.mode == "application/json") {
this.editorValue = this.formatStrInJson(value);
} else {
this.editorValue = value;
}
} catch (e) {
this.$message.error("修改編輯框內容失敗:" + e.toString());
}
},
// 黏貼事件處理函數
OnPaste(event) {
if (this.cmOptions.mode == "application/json") {
try {
this.editorValue = this.formatStrInJson(this.editorValue);
} 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();
},
// 格式化字元串為json格式字元串
formatStrInJson(strValue) {
return JSON.stringify(
JSON.parse(strValue),
null,
this.defaultJsonIndentation
);
}
},
created() {
try {
if (!this.editorValue) {
this.cmOptions.lint = false;
return;
}
if (this.cmOptions.mode == "application/json") {
if (!this.enableAutoFormatJson) {
return;
}
this.editorValue = this.formatStrInJson(this.editorValue);
}
} catch (e)&nb