Files
mayfly-go/mayfly_go_web/src/components/monaco/MonacoEditor.vue

268 lines
7.2 KiB
Vue
Raw Normal View History

2022-11-05 15:13:40 +08:00
<template>
2022-11-05 22:18:59 +08:00
<div class="monaco-editor" style="border: 1px solid #ccc;">
2022-11-05 15:13:40 +08:00
<div ref="monacoTextarea" :style="{ height: height }"></div>
<el-select v-if="canChangeMode" class="code-mode-select" v-model="languageMode" @change="changeLanguage">
<el-option v-for="mode in languages" :key="mode.value" :label="mode.label" :value="mode.value"> </el-option>
</el-select>
</div>
</template>
<script lang="ts" setup>
2022-11-05 21:08:01 +08:00
import { ref, watch, toRefs, reactive, onMounted, onBeforeUnmount } from 'vue';
2022-11-05 15:13:40 +08:00
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
import * as monaco from 'monaco-editor';
import { editor } from 'monaco-editor';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
2022-11-22 00:34:42 +08:00
// 主题仓库 https://github.com/brijeshb42/monaco-themes
2022-11-05 15:13:40 +08:00
// 主题例子 https://editor.bitwiser.in/
// import Monokai from 'monaco-themes/themes/Monokai.json'
// import Active4D from 'monaco-themes/themes/Active4D.json'
// import ahe from 'monaco-themes/themes/All Hallows Eve.json'
// import bop from 'monaco-themes/themes/Birds of Paradise.json'
// import krTheme from 'monaco-themes/themes/krTheme.json'
// import Dracula from 'monaco-themes/themes/Dracula.json'
import SolarizedLight from 'monaco-themes/themes/Solarized-light.json'
2022-11-05 21:08:01 +08:00
import { language as shellLan } from 'monaco-editor/esm/vs/basic-languages/shell/shell.js';
2022-11-05 15:13:40 +08:00
import { ElOption, ElSelect } from 'element-plus';
const props = defineProps({
modelValue: {
type: String,
},
language: {
type: String,
default: null,
},
height: {
type: String,
default: '500px',
},
width: {
type: String,
default: 'auto',
},
canChangeMode: {
type: Boolean,
default: false,
},
options: {
type: Object,
default: null,
},
})
//定义事件
const emit = defineEmits(['update:modelValue'])
const languages = [
{
value: 'shell',
label: 'Shell',
},
{
value: 'yaml',
label: 'Yaml',
},
{
value: 'dockerfile',
label: 'Dockerfile',
},
{
value: 'html',
label: 'XML/HTML',
},
{
value: 'python',
label: 'Python',
},
{
value: 'sql',
label: 'SQL',
},
{
value: 'css',
label: 'CSS',
},
{
value: 'javascript',
label: 'Javascript',
},
{
value: 'json',
2022-11-05 21:08:01 +08:00
label: 'JSON',
2022-11-05 15:13:40 +08:00
},
{
value: 'java',
label: 'Java',
},
{
value: 'markdown',
label: 'Markdown',
},
{
value: 'text',
label: 'text',
},
];
2022-11-05 21:08:01 +08:00
const options = {
language: 'shell',
theme: 'SolarizedLight',
automaticLayout: true, //自适应宽高布局
foldingStrategy: 'indentation',//代码可分小段折叠
roundedSelection: false, // 禁用选择文本背景的圆角
matchBrackets: 'near',
linkedEditing: true,
cursorBlinking: 'smooth',// 光标闪烁样式
mouseWheelZoom: true, // 在按住Ctrl键的同时使用鼠标滚轮时在编辑器中缩放字体
overviewRulerBorder: false, // 不要滚动条的边框
tabSize: 4, // tab 缩进长度
2022-11-22 00:34:42 +08:00
// fontFamily: 'JetBrainsMono', // 字体 暂时不要设置,否则光标容易错位
2022-11-05 21:08:01 +08:00
fontWeight: 'bold',
// fontSize: 12,
// letterSpacing: 1, 字符间距
// quickSuggestions:false, // 禁用代码提示
minimap: {
enabled: false, // 不要小地图
},
}
2022-11-05 15:13:40 +08:00
const state = reactive({
languageMode: 'shell',
})
const {
languageMode,
} = toRefs(state)
onMounted(() => {
2022-11-05 21:08:01 +08:00
state.languageMode = props.language;
2022-11-05 22:18:59 +08:00
initMonacoEditorIns();
2022-11-05 21:08:01 +08:00
setEditorValue(props.modelValue);
registerCompletionItemProvider();
2022-11-05 15:13:40 +08:00
});
2022-11-05 21:08:01 +08:00
onBeforeUnmount(() => {
2022-11-05 22:18:59 +08:00
if (monacoEditorIns) {
monacoEditorIns.dispose();
2022-11-05 21:08:01 +08:00
}
if (completionItemProvider) {
completionItemProvider.dispose();
}
})
watch(() => props.modelValue, (newValue: any) => {
2022-11-05 22:18:59 +08:00
if (!monacoEditorIns.hasTextFocus()) {
state.languageMode = props.language;
monacoEditorIns?.setValue(newValue);
2022-11-05 21:08:01 +08:00
}
})
watch(() => props.language, (newValue: any) => {
changeLanguage(newValue);
})
2022-11-05 21:08:01 +08:00
2022-11-05 15:13:40 +08:00
const monacoTextarea: any = ref(null);
2022-11-05 21:08:01 +08:00
2022-11-05 22:18:59 +08:00
let monacoEditorIns: editor.IStandaloneCodeEditor = null;
2022-11-05 21:08:01 +08:00
let completionItemProvider: any = null;
2022-11-05 15:13:40 +08:00
self.MonacoEnvironment = {
getWorker(_: any, label: string) {
if (label === 'json') {
return new JsonWorker()
}
2022-11-05 15:13:40 +08:00
return new EditorWorker();
}
};
2022-11-05 22:18:59 +08:00
const initMonacoEditorIns = () => {
2022-11-05 15:13:40 +08:00
console.log('初始化monaco编辑器')
// options参数参考 https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html#language
// 初始化一些主题
monaco.editor.defineTheme('SolarizedLight', SolarizedLight);
2022-11-05 21:08:01 +08:00
options.language = state.languageMode;
2022-11-05 22:18:59 +08:00
// 从localStorage中获取通过store可能存在父子组件都使用store报错
options.theme = JSON.parse(localStorage.getItem('themeConfig') as string).editorTheme || 'vs';
monacoEditorIns = monaco.editor.create(monacoTextarea.value, Object.assign(options, props.options));
2022-11-05 15:13:40 +08:00
// 监听内容改变,双向绑定
2022-11-05 22:18:59 +08:00
monacoEditorIns.onDidChangeModelContent(() => {
emit('update:modelValue', monacoEditorIns.getModel().getValue());
2022-11-05 15:13:40 +08:00
})
// 动态设置主题
// monaco.editor.setTheme('hc-black');
};
const changeLanguage = (value: any) => {
console.log('change lan');
// 获取当前的文档模型
2022-11-05 22:18:59 +08:00
let oldModel = monacoEditorIns.getModel()
2022-11-05 15:13:40 +08:00
// 创建一个新的文档模型
let newModel = monaco.editor.createModel(oldModel.getValue(), value)
// 设置成新的
2022-11-05 22:18:59 +08:00
monacoEditorIns.setModel(newModel)
2022-11-05 15:13:40 +08:00
// 销毁旧的模型
if (oldModel) {
oldModel.dispose()
}
2022-11-05 21:08:01 +08:00
registerCompletionItemProvider();
2022-11-05 15:13:40 +08:00
}
const setEditorValue = (value: any) => {
2022-11-05 22:18:59 +08:00
monacoEditorIns.getModel().setValue(value)
2022-11-05 15:13:40 +08:00
}
2022-11-05 21:08:01 +08:00
/**
* 注册联想补全提示
*/
const registerCompletionItemProvider = () => {
if (completionItemProvider) {
completionItemProvider.dispose();
}
if (state.languageMode == 'shell') {
registeShell()
}
}
const registeShell = () => {
completionItemProvider = monaco.languages.registerCompletionItemProvider('shell', {
provideCompletionItems: async () => {
let suggestions: languages.CompletionItem[] = []
shellLan.keywords.forEach((item: any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: item,
});
})
shellLan.builtins.forEach((item: any) => {
suggestions.push({
label: item,
kind: monaco.languages.CompletionItemKind.Property,
insertText: item,
});
})
return {
suggestions: suggestions
};
}
})
};
2022-11-05 15:13:40 +08:00
</script>
<style lang="scss">
.monaco-editor {
.code-mode-select {
position: absolute;
z-index: 2;
right: 10px;
top: 10px;
max-width: 130px;
}
}
2022-11-22 00:34:42 +08:00
</style>