司素浏览器
61.24M · 2026-02-07
在 Vite 中集成 Monaco Editor 主要有两种方式:
?worker 特性,但汉化极其困难。vite-plugin-monaco-editor) :推荐。配置简单,自带汉化支持,但需要处理导入兼容性问题。Bash
# 核心库
npm install monaco-editor
# Vite 插件 (用于处理 Worker 和汉化)
npm install -D vite-plugin-monaco-editor
在使用插件时,可能会遇到以下报错:
TypeError: monacoEditorPlugin is not a functionTypeError: Cannot read properties of undefined (reading 'entry')这是因为 ESM/CommonJS 模块导入兼容性问题。
vite.config.js)JavaScript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
export default defineConfig({
plugins: [
vue(),
// 核心修复:兼容写法,防止报错
(monacoEditorPlugin.default || monacoEditorPlugin)({
// 需要加载 Worker 的语言 (JSON, TS/JS, HTML, CSS 有独立 Worker)
languageWorkers: ['json', 'editorWorkerService'],
// 开启中文汉化
locale: 'zh-cn',
})
],
})
MonacoEditor.vue)封装一个支持 双向绑定 (v-model) 、语言切换、自定义主题 的通用组件。
defineTheme,再 create 实例,并在配置中显式指定 theme。monaco.editor.setModelLanguage 动态切换。v-model) 和 语言 (v-model:language)。代码段
<template>
<div class="monaco-wrapper">
<select :value="language" class="lang-select" @change="handleLanguageChange">
<option value="json">JSON</option>
<option value="sql">SQL</option>
<option value="javascript">JS</option>
<option value="css">CSS</option>
</select>
<div ref="editorContainer" class="editor-container"></div>
</div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref, watch, toRaw } from 'vue'
import * as monaco from 'monaco-editor'
// 定义 Props
const props = defineProps({
modelValue: { type: String, default: '' },
language: { type: String, default: 'json' },
readOnly: { type: Boolean, default: false }
})
// 定义 Emits (支持双 v-model)
const emit = defineEmits(['update:modelValue', 'update:language', 'change'])
const editorContainer = ref(null)
let editorInstance = null
// 1. 切换语言逻辑
const handleLanguageChange = (e) => {
const newLang = e.target.value
emit('update:language', newLang) // 通知父组件
if (editorInstance) {
monaco.editor.setModelLanguage(editorInstance.getModel(), newLang)
}
}
onMounted(() => {
if (!editorContainer.value) return
// 2. 定义自定义主题 (必须在 create 之前)
monaco.editor.defineTheme('my-dark-theme', {
base: 'vs-dark',
inherit: true,
rules: [
{ token: 'key', foreground: 'dddddd' },
{ token: 'string.key.json', foreground: 'dddddd' },
{ token: 'string.value.json', foreground: 'b4e98c' },
],
colors: {
'editor.background': '#0e1013', // 背景色
'editor.lineHighlightBackground': '#1f2329',
},
})
// 3. 创建编辑器实例
editorInstance = monaco.editor.create(editorContainer.value, {
value: props.modelValue,
language: props.language,
theme: 'my-dark-theme', // 显式引用主题
readOnly: props.readOnly,
automaticLayout: true, // 自动适应宽高
minimap: { enabled: false }, // 关闭小地图
scrollBeyondLastLine: false,
})
// 4. 内容变化 -> 通知父组件
editorInstance.onDidChangeModelContent(() => {
const value = editorInstance.getValue()
emit('update:modelValue', value)
emit('change', value)
})
})
// 5. Props 变化 (外部修改 -> 同步到编辑器)
watch(() => props.modelValue, (newValue) => {
if (editorInstance && newValue !== editorInstance.getValue()) {
// toRaw 避免 Vue 代理对象干扰 Monaco 内部逻辑
toRaw(editorInstance).setValue(newValue)
}
})
watch(() => props.language, (newLang) => {
if (editorInstance) {
monaco.editor.setModelLanguage(editorInstance.getModel(), newLang)
}
})
// 销毁
onBeforeUnmount(() => {
editorInstance?.dispose()
})
</script>
<style scoped>
.monaco-wrapper {
position: relative;
width: 100%;
height: 100%;
min-height: 300px;
}
.editor-container {
width: 100%;
height: 100%;
}
.lang-select {
position: absolute;
right: 15px;
top: 10px;
z-index: 20;
background: #1f2329;
color: #ddd;
border: 1px solid #555;
border-radius: 4px;
}
</style>
node_modules 里找不到 SQL 的 Worker 文件?原因:Monaco 将语言分为两类。
esm/vs/language。esm/vs/basic-languages。结论:配置插件时,languageWorkers 不需要加 SQL。
import 'monaco-editor/esm/nls.messages.zh-cn.js' 汉化不生效?vite-plugin-monaco-editor 并配置 locale: 'zh-cn',插件会在编译构建阶段自动注入语言包。@/... 路径无法跳转?原因:VS Code 需要配置文件来理解别名。对于 Vue+JS 项目,根目录缺少 jsconfig.json。
解决:在根目录创建 jsconfig.json:
JSON
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
},
"include": ["src/**/*"]
}
设置完后记得重启 VS Code。
使用 Vue 3 的多 v-model 特性,代码语义最清晰:
HTML
<template>
<div class="page">
<MonacoEditor
v-model="codeContent"
v-model:language="currentLang"
/>
<button @click="runCode">运行</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import MonacoEditor from '@/components/MonacoEditor/index.vue'
const codeContent = ref('SELECT * FROM users;')
const currentLang = ref('sql') // 切换下拉框会自动更新此变量
const runCode = () => {
console.log(`正在运行 ${currentLang.value} 代码:`, codeContent.value)
}
</script>