1安装 npm install monaco-editor -S
2.组件引用
属性:
- language:默认值 javascript
- height:默认值400
- value/v-model
- disabled:是否禁用
<template>
<monaco-editor v-model="code" height="200"></monaco-editor>
</template>
<script>
import MonacoEditor from "@/components/monacoEditor/index.vue";
export default {
components: { MonacoEditor },
data() {
return {
code: "",
};
},
watch: {
code(val) {
console.log(val);
},
},
};
</script>
3.组件代码:新建monacoEditor文件夹,文件夹里面分别建index.vue和index.js
index.vue代码如下
<template>
<monaco-editor
v-model="code"
:read-only="disabled"
:language="language"
:options="options"
:height="height"
></monaco-editor>
</template>
<script>
import MonacoEditor from "./index";
export default {
components: { MonacoEditor },
data() {
return {
code: "",
options: {
fontSize: 14,
},
};
},
props: {
language: {
type: String,
default: "javascript",
},
disabled: Boolean,
height: {
type: [String, Number],
default: 400,
},
value: [String, Object, Array],
},
watch: {
code(val) {
this.$emit("input", val);
},
value: {
handler(val) {
if (typeof val == "object") {
this.code = JSON.stringify(val, null, 4);
} else {
this.code = val || "";
}
},
immediate: true,
deep: true,
},
},
};
</script>
index.js代码如下
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution';
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution';
import 'monaco-editor/esm/vs/editor/contrib/find/findController.js';
let
escapable = /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
keyable = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
"'": "\\'",
'\\': '\\\\'
},
rep;
function beautifier(object, options = {}) {
var space = options.space || 2,
dropQuotesOnKeys = options.dropQuotesOnKeys == false ? false : true,
dropQuotesOnNumbers = options.dropQuotesOnNumbers || false,
inlineShortArrays = options.inlineShortArrays || false,
inlineShortArraysDepth = options.inlineShortArraysDepth || 1,
quoteType = options.quoteType || 'single',
minify = options.minify || false;
if (dropQuotesOnNumbers) walkObjectAndDropQuotesOnNumbers(object);
var result = stringify(object, null, minify ? undefined : space, dropQuotesOnKeys, quoteType);
if (inlineShortArrays && !minify) {
var newResult = inlineShortArraysInResult(result);
if (inlineShortArraysDepth > 1) {
for (var i = 1; i < inlineShortArraysDepth; i++) {
result = newResult;
newResult = inlineShortArraysInResult(result);
if (newResult == result) break;
}
}
result = newResult;
}
return result;
}
function walkObjectAndDropQuotesOnNumbers(object) {
if (!isObject(object)) return;
var keys = Object.keys(object);
if (!keys) return;
keys.forEach(function (key) {
var value = object[key];
if (typeof value == 'string') {
var number = value - 0;
object[key] = isNaN(number) ? value : number;
} else if (isObject(value) || Array.isArray(value)) {
walkObjectAndDropQuotesOnNumbers(value);
}
});
}
function isObject(o) {
return o && typeof o == 'object';
}
// Collapses arrays inline when they fit inside the specified width
// in characters (including indentation).
function inlineShortArraysInResult(result, width) {
width || (width = 80);
if (typeof width != 'number' || width < 20) {
throw "Invalid width '" + width + "'. Expecting number equal or larger than 20."
}
var list = result.split('\n'),
i = 0,
start = null,
content = [];
while (i < list.length) {
var startMatch = !!list[i].match(/\[/),
endMatch = !!list[i].match(/\],?/);
if (startMatch && !endMatch) {
content = [list[i]];
start = i;
} else if (endMatch && !startMatch && start) {
content.push((list[i] || '').trim());
var inline = content.join(' ');
if (inline.length < width) {
list.splice(start, i - start + 1, inline);
i = start;
}
start = null;
content = [];
} else {
if (start) content.push((list[i] || '').trim());
}
i += 1;
}
return list.join('\n');
}
function stringify(value, replacer, space, dropQuotesOnKeys, quoteType) {
var i;
gap = '';
indent = '';
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
} else if (typeof space === 'string') {
indent = space;
}
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
return str('', { '': value }, dropQuotesOnKeys, quoteType);
}
function str(key, holder, dropQuotesOnKeys, quoteType) {
var i,
k,
v,
length,
mind = gap,
partial,
value = holder[key];
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
switch (typeof value) {
case 'function':
return value;
case 'string':
return quote(value, quoteType);
case 'number':
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
return String(value);
case 'object':
if (!value) {
return 'null';
}
gap += indent;
partial = [];
if (Object.prototype.toString.apply(value) === '[object Array]') {
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value, dropQuotesOnKeys, quoteType) || 'null';
}
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value, dropQuotesOnKeys, quoteType);
if (v) {
partial.push((dropQuotesOnKeys ? condQuoteKey(k, quoteType) : quote(k, quoteType)) + (gap ? ': ' : ':') + v);
}
}
}
} else {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value, dropQuotesOnKeys, quoteType);
if (v) {
partial.push((dropQuotesOnKeys ? condQuoteKey(k, quoteType) : quote(k, quoteType)) + (gap ? ': ' : ':') + v);
}
}
}
}
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
function quote(string, quoteType) {
escapable.lastIndex = 0;
var surroundingQuote = '"';
if (quoteType === 'single') {
surroundingQuote = "'";
}
return escapable.test(string) ? surroundingQuote + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + surroundingQuote : surroundingQuote + string + surroundingQuote;
}
function condQuoteKey(string, quoteType) {
return keyable.test(string) ? string : quote(string, quoteType);
}
function noop() { }
export { monaco };
export default {
name: 'MonacoEditor',
props: {
diffEditor: { type: Boolean, default: false }, //是否使用diff模式
width: { type: [String, Number], default: '100%' },
height: { type: [String, Number], default: '100%' },
original: String, //只有在diff模式下有效
value: [String, Object],
language: { type: String, default: 'javascript' },
theme: { type: String, default: 'vs-dark' },
readOnly: { type: Boolean, default: false },
options: { type: Object, default() { return {}; } },
editorMounted: { type: Function, default: noop },
editorBeforeMount: { type: Function, default: noop },
keyIndex: { type: String }
},
watch: {
options: {
deep: true,
handler(options) {
this.editor && this.editor.updateOptions(options);
}
},
value() {
let data = this.value
if (this.editor && data !== this._getValue()) {
this._setValue(data)
}
},
language() {
if (!this.editor) return;
if (this.diffEditor) { //diff模式下更新language
const { original, modified } = this.editor.getModel();
monaco.editor.setModelLanguage(original, this.language);
monaco.editor.setModelLanguage(modified, this.language);
} else
monaco.editor.setModelLanguage(this.editor.getModel(), this.language);
},
theme() {
this.editor && monaco.editor.setTheme(this.theme);
},
style() {
this.editor && this.$nextTick(() => {
this.editor.layout();
});
}
},
computed: {
style() {
return {
width: !/^\d+$/.test(this.width) ? this.width : `${this.width}px`,
height: !/^\d+$/.test(this.height) ? this.height : `${this.height}px`
}
}
},
mounted() {
this.initMonaco();
},
beforeDestroy() {
this.editor && this.editor.dispose();
},
render() {
return (
<div class="monaco_editor_container" style={this.style}></div>
);
},
methods: {
initMonaco() {
const { value, language, theme, readOnly, options } = this;
Object.assign(options, this._editorBeforeMount()); //编辑器初始化前
this.editor = monaco.editor[this.diffEditor ? 'createDiffEditor' : 'create'](this.$el, {
value: (typeof value == 'string') ? value : beautifier(value),
language: language,
theme: theme,
readOnly: readOnly,
...options
});
this.diffEditor && this._setModel(this.value, this.original);
this._editorMounted(this.editor); //编辑器初始化后
},
_getEditor() {
if (!this.editor) return null;
return this.diffEditor ? this.editor.modifiedEditor : this.editor;
},
_setModel(value, original) { //diff模式下设置model
const { language } = this;
const originalModel = monaco.editor.createModel(original, language);
const modifiedModel = monaco.editor.createModel(value, language);
this.editor.setModel({
original: originalModel,
modified: modifiedModel
});
},
_setValue(value) {
let editor = this._getEditor();
if (editor) return editor.setValue(value);
},
_getValue() {
let editor = this._getEditor();
if (!editor) return '';
return editor.getValue();
},
_editorBeforeMount() {
const options = this.editorBeforeMount(monaco);
return options || {};
},
_editorMounted(editor) {
this.editorMounted(editor, monaco);
if (this.diffEditor) {
editor.onDidUpdateDiff((event) => {
const value = this._getValue();
this._emitChange(value, event);
});
} else {
editor.onDidChangeModelContent(event => {
const value = this._getValue();
this._emitChange(value, event);
});
}
},
_emitChange(value, event) {
this.$emit('change', value, event);
this.$emit('input', value);
}
}
}