vue3 使用 monaco 编辑器卡顿问题解决


💥 可能原因一:createModel 频繁创建未限制数量#

每次打开新文件都会 createModel,但 Monaco Editor 的模型数量多了会导致性能骤降,尤其是在文件大或内存有限的情况下。

虽然你在关闭时 dispose() 掉模型,但如果用户连续打开了很多文件又不关闭(或文件太大),仍然可能导致卡顿。


✅ 解决建议一:限制最大模型缓存数量(比如 10 个)#

const MAX_MODELS = 10;

const handleFileOpened = async (payload: FileSystemEventPayloads[FileSystemEvents.FILE_OPENED]) => {
  try {
    const path = payload.path;
    currentFilePath.value = path;

    // 有模型就直接用
    if (fileModels.value.has(path)) {
      const model = fileModels.value.get(path);
      if (model && editor) {
        editor.setModel(model);
      }
      return;
    }

    // 控制缓存数量,超过就清理最早的
    if (fileModels.value.size >= MAX_MODELS) {
      const firstKey = fileModels.value.keys().next().value;
      const oldModel = fileModels.value.get(firstKey);
      oldModel?.dispose();
      fileModels.value.delete(firstKey);
    }

    // 获取文件内容
    const fileName = path.split(/[\\/]/).pop() || '';
    const dirPath = path.substring(0, path.length - fileName.length - 1);
    const response = await getFileContent(dirPath, fileName);
    const language = getLanguageByExtension(path);

    const model = monaco.editor.createModel(response.content || '', language);
    fileModels.value.set(path, model);
    editor?.setModel(model);
  } catch (error) {
    console.error('加载文件内容失败:', error);
  }
};

💥 可能原因二:编辑器自动布局开销高#

你启用了 automaticLayout: true,这会在容器大小变化时频繁触发 layout(),在打开多个标签页、切换等复杂场景下会带来性能问题。


✅ 解决建议二:关闭自动布局,手动触发 layout#

editor = monaco.editor.create(editorContainer.value, {
  value: '',
  language: 'javascript',
  theme: 'vs-dark',
  minimap: { enabled: true },
  scrollBeyondLastLine: false,
  fontSize: 14,
  fontFamily: 'Menlo, Monaco, Consolas, "Courier New", monospace',
  automaticLayout: false
});

// 在切换标签或窗口大小变化时手动调用
window.addEventListener('resize', () => {
  editor?.layout();
});

💥 可能原因三:文件太大 + 编辑器没有优化配置#

Monaco 默认不限制加载的文件大小,如果用户点击了一个特别大的 .log.json 文件,可能瞬间拖垮前端。


✅ 解决建议三:加载前做文件大小检查(从后端接口拿 size)#

if (response.size > 1024 * 1024 * 2) { // >2MB 警告或不打开
  alert('文件太大,不建议在浏览器中打开');
  return;
}

💥 可能原因四:Vue 的响应式系统拖慢了文件切换#

你用了 ref(Map),Vue 会对 Map 的一些操作做响应式处理,虽然现代 Vue 已经优化了不少,但也可能导致额外开销。


✅ 解决建议四:使用 shallowRef 代替 ref#

import { shallowRef } from 'vue';
const fileModels = shallowRef(new Map<string, monaco.editor.ITextModel>());

🧪 你可以做一个简单测试:#

  1. 打开 5~10 个文件,观察内存和卡顿;

  2. 注释掉 createModel 改成一个统一的共享 model 看看卡不卡;

  3. automaticLayout 改成 false 看是否缓解。


使用 shallowRef 代替 ref 解决问题#

本作品采用《CC 协议》,转载必须注明作者和本文链接
九九一十八,一步一个脚印