1. 首先在composables中创建useMonaco.ts
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
export default function useMonaco(language = 'json') {
let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
let initReadOnly = false
const updateVal = async (val: string) => {
monacoEditor?.setValue(val)
setTimeout(async () => {
initReadOnly && monacoEditor?.updateOptions({ readOnly: false })
await monacoEditor?.getAction('editor.action.formatDocument').run()
initReadOnly && monacoEditor?.updateOptions({ readOnly: true })
}, 100)
}
const createEditor = (el: HTMLElement | null, editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}) => {
if (monacoEditor) {
return
}
initReadOnly = !!editorOption.readOnly
monacoEditor = el && monaco.editor.create(el, {
language,
minimap: { enabled: false },
theme: 'vs-light',
multiCursorModifier: 'ctrlCmd',
scrollbar: {
verticalScrollbarSize: 8,
horizontalScrollbarSize: 8,
},
tabSize: 2,
automaticLayout: true,
...editorOption
})
return monacoEditor
}
const onFormatDoc = () => {
monacoEditor?.getAction('editor.action.formatDocument').run()
}
return {
updateVal,
getEditor: () => monacoEditor,
createEditor,
onFormatDoc
}
}
2. 在components中创建MonacoEditor.vue
<template>
<div class="editor-area" :class="isFull ? 'full' : ''" :style="{ width, height }">
<div class="tools">
<ElTooltip placement="right" :content="isFull ? '缩小' : '放大'">
<div class="expand" @click="isFull = !isFull">
<i :class="isFull ? 'el-icon-close' : 'el-icon-full-screen'"></i>
</div>
</ElTooltip>
<ElTooltip placement="right" content="格式化">
<div class="expand" @click="onFormatDoc">
<i class="el-icon-finished"></i>
</div>
</ElTooltip>
</div>
</div>
</template>
<script lang='ts'>
import useMonaco from '@/composables/useMonaco'
import { defineComponent, ref } from 'vue'
import { ElTooltip } from 'element-plus'
export default defineComponent({
components: {
ElTooltip
},
props: {
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '90vh'
},
language: {
type: String,
default: 'json'
},
preComment: {
type: String,
default: ''
},
modelValue: {
type: String,
default: ''
},
editorOptions: {
type: Object,
default: () => ({})
},
},
watch: {
modelValue(val) {
val !== this.getEditor()?.getValue() && this.updateMonacoVal(val)
}
},
setup(props) {
const { updateVal, getEditor, createEditor, onFormatDoc } = useMonaco(props.language)
const isFull = ref(false)
return {
isFull,
updateVal,
getEditor,
createEditor,
onFormatDoc
}
},
methods: {
updateMonacoVal(_val?: string) {
const { modelValue, preComment } = this.$props
const val = preComment ? `${preComment}\n${_val || modelValue}` : (_val || modelValue)
this.updateVal(val)
}
},
mounted() {
if (this.$el) {
const monacoEditor = this.createEditor(this.$el, this.$props.editorOptions)
this.updateMonacoVal()
monacoEditor!.onDidChangeModelContent(() => {
this.$emit('update:modelValue', monacoEditor!.getValue())
})
monacoEditor!.onDidBlurEditorText(() => {
this.$emit('blur')
})
}
}
})
</script>
<style lang="less" scoped>
.editor-area {
position: relative;
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
padding: 5px;
padding-left: 0;
background-color: #fff;
box-sizing: border-box;
&.full {
position: fixed;
left: calc(10vw / 2);
top: calc(10vh / 2);
box-shadow: 0 0 22px 10px rgba(0, 0, 0, .3);
width: 90vw!important;
height: 90vh!important;
z-index: 9999;
}
.tools {
z-index: 888;
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
padding: 0 2px;
border-right: 1px solid rgba(0, 0, 0, .1);
left: 0;
bottom: 0px;
top: 0;
.expand {
cursor: pointer;
line-height: 0;
margin-top: 5px;
}
}
}
</style>
3. 在需要用到MonacoEditor的文件中直接引入即可
<MonacoEditor
height="100px"
v-model="editorData"
language="json"
/>