增加CodeEdiotr组件,调整MonocaEditor全局样式

This commit is contained in:
fofolee 2025-01-11 11:44:02 +08:00
parent 9eee3d1b14
commit a954cf0764
3 changed files with 310 additions and 2 deletions

View File

@ -0,0 +1,228 @@
<template>
<div class="code-editor" :style="{ height: height }">
<div ref="editorContainer" class="editor-container"></div>
</div>
</template>
<script>
import * as monaco from "monaco-editor";
import { toRaw } from "vue";
export default {
name: "CodeEditor",
props: {
// v-model
modelValue: {
type: String,
default: "",
},
//
language: {
type: String,
default: "plaintext",
},
//
height: {
type: String,
default: "200px",
},
//
theme: {
type: String,
default: "vs",
},
//
options: {
type: Object,
default: () => ({}),
},
},
emits: ["update:modelValue", "change"],
data() {
return {
editor: null,
value: null,
resizeTimeout: null,
defaultOptions: {
value: "",
//
automaticLayout: true,
//
foldingStrategy: "indentation",
//
autoClosingBrackets: true,
//
tabSize: 2,
//
minimap: {
enabled: false,
},
//
formatOnType: true,
//
formatOnPaste: true,
//
autoIndent: "full",
//
scrollBeyondLastLine: false,
//
fontSize: 14,
//
lineNumbers: "on",
//
lineNumbersMinChars: 3,
//
renderLineNumbers: "on",
//
lineDecorationsWidth: 0,
//
roundedSelection: false,
//
renderLineHighlight: "all",
//
renderLineHighlightOnlyWhenFocus: true,
//
hideCursorInOverviewRuler: true,
//
overviewRulerBorder: false,
// 线
overviewRulerLanes: 0,
//
scrollBars: {
vertical: "visible",
horizontal: "visible",
},
//
readOnly: false,
//
cursorStyle: "line",
},
};
},
watch: {
// v-model
modelValue: {
immediate: true,
handler(newValue) {
if (this.value !== newValue) {
this.value = newValue;
if (this.editor && this.editor.getValue() !== newValue) {
this.editor.setValue(newValue || "");
}
}
},
},
//
language: {
immediate: true,
handler(newValue) {
if (this.editor) {
monaco.editor.setModelLanguage(this.editor.getModel(), newValue);
}
},
},
"$q.dark.isActive": {
immediate: true,
handler(newValue) {
monaco.editor.setTheme(newValue ? "vs-dark" : "vs");
},
},
},
mounted() {
this.initEditor();
// MonacoResizeObserver loop limit exceeded
window.addEventListener("resize", this.resizeEditor);
},
beforeUnmount() {
this.destroyEditor();
},
methods: {
//
initEditor() {
const options = {
...this.defaultOptions,
...this.options,
value: this.value || "",
language: this.language,
theme: this.theme,
};
this.editor = monaco.editor.create(this.$refs.editorContainer, options);
this.listenEditorValue();
//
this.$nextTick(() => {
this.resizeEditor();
});
},
//
listenEditorValue() {
this.rawEditor().focus();
this.rawEditor().onDidChangeModelContent(() => {
this.value = this.getEditorValue();
this.$emit("update:modelValue", this.value);
this.$emit("change", this.value);
});
},
//
resizeEditor() {
if (this.resizeTimeout) {
clearTimeout(this.resizeTimeout);
}
this.resizeTimeout = setTimeout(() => {
this.rawEditor().layout();
}, 50);
},
//
destroyEditor() {
if (this.editor) {
window.removeEventListener("resize", this.resizeEditor);
this.rawEditor().dispose();
this.editor = null;
}
},
//
rawEditor() {
return toRaw(this.editor);
},
//
getEditor() {
return this.editor;
},
//
setValue(value) {
if (this.editor) {
this.editor.setValue(value || "");
}
},
//
getValue() {
return this.editor ? this.editor.getValue() : "";
},
//
getEditorValue() {
return this.rawEditor().getValue();
},
//
focus() {
if (this.editor) {
this.editor.focus();
}
},
},
};
</script>
<style scoped>
.code-editor {
width: 100%;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 4px;
overflow: hidden;
}
.editor-container {
width: 100%;
height: 100%;
}
</style>

View File

@ -59,16 +59,39 @@ export default {
initEditor() {
let monacoEditorPreferences = {
value: "",
//
automaticLayout: true,
//
foldingStrategy: "indentation",
//
autoClosingBrackets: true,
//
tabSize: 2,
minimap: {
enabled: false,
},
//
formatOnType: true,
formatOnPaste: true,
//
autoIndent: "full",
//
lineNumbersMinChars: 3,
renderLineNumbers: "on",
//
lineDecorationsWidth: 0,
//
roundedSelection: false,
//
renderLineHighlight: "all",
//
renderLineHighlightOnlyWhenFocus: true,
//
hideCursorInOverviewRuler: true,
//
overviewRulerBorder: false,
// 线
overviewRulerLanes: 0,
// JavaScript
"javascript.format.insertSpaceAfterSemicolonInForStatements": true,
"javascript.format.insertSpaceBeforeAndAfterBinaryOperators": true,

View File

@ -13,10 +13,63 @@ body {
color: #333;
}
.q-tooltip {
font-size: 11px;
/* Monaco Editor 调整行号栏样式 */
.monaco-editor .margin {
width: 40px !important;
}
.monaco-editor .line-numbers {
text-align: center !important;
width: 40px !important;
padding-right: 5px !important;
left: 0 !important;
}
/* Monaco Editor 当前行高亮样式 */
.monaco-editor .current-line {
border: none !important;
background-color: rgba(0, 0, 0, 0.03);
}
.monaco-editor .line-numbers {
color: rgba(0, 0, 0, 0.5) !important;
}
.body--dark .monaco-editor .line-numbers {
color: rgba(255, 255, 255, 0.5) !important;
}
.monaco-editor .current-line~.line-numbers {
color: var(--q-primary) !important;
}
.body--dark .monaco-editor .current-line {
background-color: rgba(255, 255, 255, 0.05);
}
.monaco-editor .margin-view-overlays .current-line {
background-color: transparent !important;
}
/* Monaco Editor 滚动条样式 */
.monaco-editor .scrollbar {
width: 5px !important;
height: 5px !important;
}
.monaco-editor .scrollbar.vertical .slider {
width: 5px !important;
border-radius: 2px !important;
background: rgba(0, 0, 0, 0.2) !important;
}
.monaco-editor .scrollbar.horizontal .slider {
height: 5px !important;
border-radius: 2px !important;
background: rgba(0, 0, 0, 0.2) !important;
}
/* 标签样式 */
.q-chip {
background: #e3e3e39a;
}
@ -54,6 +107,10 @@ body {
}
/* 优化 Tooltip 样式 */
.q-tooltip {
font-size: 11px;
}
.q-tooltip {
background: rgba(255, 255, 255, 0.18) !important;
border-radius: 6px;