|
@@ -1,88 +1,127 @@
|
|
|
-<template>
|
|
|
- <div :id="editorId" class="editorContainer"></div>
|
|
|
-</template>
|
|
|
-
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, onUnmounted, watch, computed, toRaw } from 'vue'
|
|
|
-import * as monaco from 'monaco-editor'
|
|
|
+import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
|
|
|
+import loader from "@monaco-editor/loader";
|
|
|
|
|
|
const props = defineProps({
|
|
|
value: String,
|
|
|
- language: String,
|
|
|
-})
|
|
|
-
|
|
|
-const emit = defineEmits(['change'])
|
|
|
-const editor = ref(null)
|
|
|
-const editorId = computed(() => `editor_${Math.random().toString(36).slice(2, 11)}`)
|
|
|
-
|
|
|
-const getEditorValue = () => toRaw(editor.value)?.getValue() || ''
|
|
|
-
|
|
|
-let resizeObserver = null
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- const el = document.getElementById(editorId.value)
|
|
|
-
|
|
|
- if (!el) {
|
|
|
- // console.warn('[MonacoEdit]找不到容器元素')
|
|
|
- return
|
|
|
+ language: {
|
|
|
+ type: String,
|
|
|
+ default: "python",
|
|
|
+ },
|
|
|
+ theme: {
|
|
|
+ type: String,
|
|
|
+ default: "vs-light",
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits(["update:value"]);
|
|
|
+
|
|
|
+const editorContainer = ref(null);
|
|
|
+let editorInstance = null;
|
|
|
+
|
|
|
+// 调试:打印容器尺寸
|
|
|
+const logContainerSize = () => {
|
|
|
+ if (!editorContainer.value) {
|
|
|
+ // console.log('Editor container not yet mounted');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const rect = editorContainer.value.getBoundingClientRect();
|
|
|
+ // console.log('Container size:', rect.width, 'x', rect.height);
|
|
|
+};
|
|
|
+
|
|
|
+// 初始化 Monaco 编辑器
|
|
|
+const initEditor = async () => {
|
|
|
+ const monaco = await loader.init();
|
|
|
+
|
|
|
+ // 等待容器渲染完成
|
|
|
+ await nextTick();
|
|
|
+
|
|
|
+ // 添加额外延迟确保布局完成(仅开发时需要)
|
|
|
+ if (process.env.NODE_ENV === 'development') {
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 50));
|
|
|
}
|
|
|
|
|
|
- const initEditor = () => {
|
|
|
- if (editor.value || el.clientWidth === 0 || el.clientHeight === 0) return
|
|
|
-
|
|
|
- // console.log('[MonacoEdit]尺寸可用,初始化编辑器')
|
|
|
-
|
|
|
- monaco.editor.defineTheme('custom-light', {
|
|
|
- base: 'vs',
|
|
|
- inherit: true,
|
|
|
- rules: [],
|
|
|
- colors: {
|
|
|
- 'editorGutter.background': '#EEEEEE',
|
|
|
- },
|
|
|
- })
|
|
|
-
|
|
|
- editor.value = monaco.editor.create(el, {
|
|
|
- value: props.value || '',
|
|
|
- language: props.language || 'python',
|
|
|
- minimap: { enabled: true },
|
|
|
- colorDecorators: true,
|
|
|
- readOnly: false,
|
|
|
- theme: 'custom-light',
|
|
|
- automaticLayout: true,
|
|
|
- })
|
|
|
-
|
|
|
- editor.value.onDidChangeModelContent(() => {
|
|
|
- emit('change', getEditorValue())
|
|
|
- })
|
|
|
-
|
|
|
- console.log('[MonacoEdit]初始化完成')
|
|
|
+ // 再次检查尺寸
|
|
|
+ const rect = editorContainer.value.getBoundingClientRect();
|
|
|
+ // console.log('Final container size:', rect.width, 'x', rect.height);
|
|
|
+
|
|
|
+ editorInstance = monaco.editor.create(editorContainer.value, {
|
|
|
+ value: props.value || "",
|
|
|
+ language: props.language,
|
|
|
+ theme: props.theme,
|
|
|
+ });
|
|
|
+
|
|
|
+ editorInstance.onDidChangeModelContent(() => {
|
|
|
+ const value = editorInstance.getValue();
|
|
|
+ emit("update:value", value); // 触发v-model更新
|
|
|
+ });
|
|
|
+
|
|
|
+ // 强制立即布局
|
|
|
+ editorInstance.layout();
|
|
|
+};
|
|
|
+
|
|
|
+// 处理窗口大小变化
|
|
|
+const handleResize = () => {
|
|
|
+ if (editorInstance) {
|
|
|
+ // console.log('Window resized, updating editor layout');
|
|
|
+ editorInstance.layout();
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- // 使用 ResizeObserver 监听尺寸变化
|
|
|
- resizeObserver = new ResizeObserver(() => {
|
|
|
- if (el.clientWidth > 0 && el.clientHeight > 0 && !editor.value) {
|
|
|
- initEditor()
|
|
|
+onMounted(() => {
|
|
|
+ // console.log('Component mounted, initializing editor...');
|
|
|
+ initEditor();
|
|
|
+});
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ // console.log('Component unmounting, disposing editor...');
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ editorInstance?.dispose();
|
|
|
+});
|
|
|
+
|
|
|
+// 监听语言变化
|
|
|
+watch(
|
|
|
+ () => props.language,
|
|
|
+ (newLanguage) => {
|
|
|
+ if (editorInstance) {
|
|
|
+ console.log('Language changed to:', newLanguage);
|
|
|
+ loader.init().then((monaco) => {
|
|
|
+ monaco.editor.setModelLanguage(editorInstance.getModel(), newLanguage);
|
|
|
+ });
|
|
|
}
|
|
|
- })
|
|
|
-
|
|
|
- resizeObserver.observe(el)
|
|
|
-})
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- if (editor.value) {
|
|
|
- editor.value.dispose()
|
|
|
- editor.value = null
|
|
|
}
|
|
|
-
|
|
|
- if (resizeObserver) {
|
|
|
- resizeObserver.disconnect()
|
|
|
- resizeObserver = null
|
|
|
+);
|
|
|
+
|
|
|
+// 监听值变化
|
|
|
+watch(
|
|
|
+ () => props.value,
|
|
|
+ (newValue) => {
|
|
|
+ if (editorInstance && editorInstance.getValue() !== newValue) {
|
|
|
+ console.log('Value updated programmatically');
|
|
|
+ editorInstance.setValue(newValue);
|
|
|
+ }
|
|
|
}
|
|
|
-})
|
|
|
+);
|
|
|
</script>
|
|
|
|
|
|
-<style>
|
|
|
+<template>
|
|
|
+ <div ref="editorContainer" class="editorContainer"></div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
.editorContainer {
|
|
|
- height: 400px !important;
|
|
|
+ height: 400px;
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid #ccc; /* 调试边框 */
|
|
|
+ position: relative; /* 确保正确的定位上下文 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 强制设置 Monaco 容器尺寸 */
|
|
|
+.editorContainer :deep(.monaco-editor) {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
}
|
|
|
</style>
|