|  | @@ -1,86 +1,88 @@
 | 
	
		
			
				|  |  |  <template>
 | 
	
		
			
				|  |  | -  <div id="editorContainer"></div>
 | 
	
		
			
				|  |  | +  <div :id="editorId" class="editorContainer"></div>
 | 
	
		
			
				|  |  |  </template>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  <script setup>
 | 
	
		
			
				|  |  | -import { ref, onMounted, watch, toRaw } from 'vue';
 | 
	
		
			
				|  |  | -import * as monaco from 'monaco-editor';
 | 
	
		
			
				|  |  | +import { ref, onMounted, onUnmounted, watch, computed, toRaw } from 'vue'
 | 
	
		
			
				|  |  | +import * as monaco from 'monaco-editor'
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const props = defineProps({
 | 
	
		
			
				|  |  | -  modelValue: String, // v-model 绑定
 | 
	
		
			
				|  |  | -  value: String,      // 兼容传统 value 绑定
 | 
	
		
			
				|  |  | +  value: String,
 | 
	
		
			
				|  |  |    language: String,
 | 
	
		
			
				|  |  | -});
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const emit = defineEmits(['update:modelValue', 'change']);
 | 
	
		
			
				|  |  | +const emit = defineEmits(['change'])
 | 
	
		
			
				|  |  | +const editor = ref(null)
 | 
	
		
			
				|  |  | +const editorId = computed(() => `editor_${Math.random().toString(36).slice(2, 11)}`)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const editor = ref(null);
 | 
	
		
			
				|  |  | -let isUpdatingFromParent = false; // 添加防止死循环的锁
 | 
	
		
			
				|  |  | +const getEditorValue = () => toRaw(editor.value)?.getValue() || ''
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// 获取当前值
 | 
	
		
			
				|  |  | -const getCurrentValue = () => props.modelValue ?? props.value;
 | 
	
		
			
				|  |  | -const getEditorValue = () => toRaw(editor.value)?.getValue() || '';
 | 
	
		
			
				|  |  | +let resizeObserver = null
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// 监听父组件传来的值变化(用于外部更新编辑器)
 | 
	
		
			
				|  |  | -watch(
 | 
	
		
			
				|  |  | -  () => getCurrentValue(),
 | 
	
		
			
				|  |  | -  (newValue) => {
 | 
	
		
			
				|  |  | -    const editorVal = getEditorValue();
 | 
	
		
			
				|  |  | -    const normalize = (s) => (s || '').trim();
 | 
	
		
			
				|  |  | +onMounted(() => {
 | 
	
		
			
				|  |  | +  const el = document.getElementById(editorId.value)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!el) {
 | 
	
		
			
				|  |  | +    // console.warn('[MonacoEdit]找不到容器元素')
 | 
	
		
			
				|  |  | +    return
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (editor.value && normalize(newValue) !== normalize(editorVal)) {
 | 
	
		
			
				|  |  | -      console.log('外部更新编辑器内容', newValue);
 | 
	
		
			
				|  |  | -      console.log('当前编辑器内容', editorVal);
 | 
	
		
			
				|  |  | +  const initEditor = () => {
 | 
	
		
			
				|  |  | +    if (editor.value || el.clientWidth === 0 || el.clientHeight === 0) return
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      isUpdatingFromParent = true;
 | 
	
		
			
				|  |  | +    // console.log('[MonacoEdit]尺寸可用,初始化编辑器')
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // 设置值
 | 
	
		
			
				|  |  | -      editor.value.setValue(newValue || '');
 | 
	
		
			
				|  |  | +    monaco.editor.defineTheme('custom-light', {
 | 
	
		
			
				|  |  | +      base: 'vs',
 | 
	
		
			
				|  |  | +      inherit: true,
 | 
	
		
			
				|  |  | +      rules: [],
 | 
	
		
			
				|  |  | +      colors: {
 | 
	
		
			
				|  |  | +        'editorGutter.background': '#EEEEEE',
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // 等当前宏任务结束后再解除锁
 | 
	
		
			
				|  |  | -      queueMicrotask(() => {
 | 
	
		
			
				|  |  | -        isUpdatingFromParent = false;
 | 
	
		
			
				|  |  | -        console.log('编辑器内容已更新', editor.value.getValue());
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      console.log('内容相同,跳过更新');
 | 
	
		
			
				|  |  | +    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]初始化完成')
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 使用 ResizeObserver 监听尺寸变化
 | 
	
		
			
				|  |  | +  resizeObserver = new ResizeObserver(() => {
 | 
	
		
			
				|  |  | +    if (el.clientWidth > 0 && el.clientHeight > 0 && !editor.value) {
 | 
	
		
			
				|  |  | +      initEditor()
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  resizeObserver.observe(el)
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +onUnmounted(() => {
 | 
	
		
			
				|  |  | +  if (editor.value) {
 | 
	
		
			
				|  |  | +    editor.value.dispose()
 | 
	
		
			
				|  |  | +    editor.value = null
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -onMounted(() => {
 | 
	
		
			
				|  |  | -  monaco.editor.defineTheme("custom-light", {
 | 
	
		
			
				|  |  | -    base: "vs",
 | 
	
		
			
				|  |  | -    inherit: true,
 | 
	
		
			
				|  |  | -    rules: [],
 | 
	
		
			
				|  |  | -    colors: {
 | 
	
		
			
				|  |  | -      "editorGutter.background": "#EEEEEE",
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  editor.value = monaco.editor.create(document.getElementById('editorContainer'), {
 | 
	
		
			
				|  |  | -    value: getCurrentValue() || '',
 | 
	
		
			
				|  |  | -    language: props.language || 'python',
 | 
	
		
			
				|  |  | -    minimap: { enabled: true },
 | 
	
		
			
				|  |  | -    colorDecorators: true,
 | 
	
		
			
				|  |  | -    readOnly: false,
 | 
	
		
			
				|  |  | -    theme: "custom-light",
 | 
	
		
			
				|  |  | -    automaticLayout: true,
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // 编辑器内容变化时触发
 | 
	
		
			
				|  |  | -  editor.value.onDidChangeModelContent(() => {
 | 
	
		
			
				|  |  | -    if (isUpdatingFromParent) return; // 阻止外部设置引起的触发
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    const newValue = getEditorValue();
 | 
	
		
			
				|  |  | -    emit('update:modelValue', newValue); // 通知父组件更新
 | 
	
		
			
				|  |  | -    emit('change', newValue);
 | 
	
		
			
				|  |  | -  });
 | 
	
		
			
				|  |  | -});
 | 
	
		
			
				|  |  | +  if (resizeObserver) {
 | 
	
		
			
				|  |  | +    resizeObserver.disconnect()
 | 
	
		
			
				|  |  | +    resizeObserver = null
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  |  </script>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  <style>
 | 
	
		
			
				|  |  | -#editorContainer {
 | 
	
		
			
				|  |  | +.editorContainer {
 | 
	
		
			
				|  |  |    height: 400px !important;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  </style>
 |