Monaco Editor 作为 VS Code 的编辑器核心,功能强大,在前端项目中集成它可以为代码展示、编辑等场景提供出色的体验。本文将详细介绍如何在 Vue 3 项目中集成 Monaco Editor,并封装一个具备代码高亮、跳转到指定行等实用功能的可复用组件。
基础安装与使用
首先,在项目中安装 monaco-editor:
npm install monaco-editor
接下来,创建一个基础的 Vue 组件来初始化编辑器。以下是一个使用 <script setup> 语法的示例:
<template>
<div class="monaco" id="monaco" ref="monacoRef"></div>
</template>
<script setup>
import * as monaco from 'monaco-editor'
let editor = null
const init = () => {
editor = monaco.editor.create(monacoRef.value, {
value: props.code,
language: props.language,
theme: 'vs-dark',
automaticLayout: true, // 自动调整大小
lineHeight: 24,
tabSize: 2,
minimap: {
// 关闭小地图
enabled: false,
},
readOnly: true,
domReadOnly: true
})
}
onMounted(() => {
init()
})
</script>
完成上述步骤后,你将得到一个使用 vs-dark 主题的黑色代码编辑器。
注意:这里有一个与 Vue 3 响应式系统相关的常见问题。如果你使用 ref 来接收 monaco-editor 创建的实例,之后直接调用其内部方法可能会遇到问题。正确的做法是在调用前使用 toRaw 获取原始对象:
const editor = ref(null)
toRaw(editor.value).xxx(); // 使用 toRaw 处理
封装增强业务组件
基础的编辑器功能通常无法满足复杂的业务需求。我们可以将其封装成一个更强大的组件,实现诸如跳转到指定行、高亮特定行以及动态切换编程语言等功能。
1. 跳转到指定行
通过 revealLineInCenter 方法,可以轻松实现将视图滚动到代码的特定行并使其居中显示。
const setPosition = () => {
if (!editor) {
return;
}
editor.revealLineInCenter(Number(props.line));
}
2. 高亮指定代码行
使用编辑器的装饰器(Decorations)API 可以为指定行添加背景色等高亮效果。
let decorations = [] // 存储装饰器的ID
const highlightLine = () => {
const lineNumber = Number(props.line);
if (lineNumber === 0) {
decorations = editor.deltaDecorations(decorations, []);
return
}
decorations = editor.deltaDecorations(decorations, [
{
range: new monaco.Range(lineNumber, 1, lineNumber, 1),
options: {
isWholeLine: true,
className: 'highlight-line'
}
}
]);
}
需要在全局样式中为高亮类名定义样式:
#monaco .highlight-line {
background-color: rgba(140, 143, 255, 0.7) !important; /* 设置高亮背景颜色 */
}
3. 动态设置编辑语言
有时需要根据加载的代码类型动态切换编辑器的语言模式。注意,设置语言的方法应通过 monaco.editor 命名空间调用,而非编辑器实例本身。
const setLanguage = () => {
if (!editor) {
return;
}
const model = editor.getModel()
if (!model) {
return
}
// 正确用法:通过 monaco.editor 命名空间调用
monaco.editor.setModelLanguage(model, props.language)
}
注意:这里有一个容易踩的坑。你不能直接使用 editor.setModelLanguage(...),因为此方法并不直接存在于编辑器实例上,调用会报“找不到函数”的错误。正确的方式是使用 monaco.editor.setModelLanguage(...),这是在 Composition API 中调用 Monaco 全局方法的方式。
完整组件封装代码
将以上功能整合,并接收外部传入的代码、语言和高亮行等属性,我们就得到了一个功能相对完善的 Monaco Editor 封装组件。组件会监听代码变化,并自动更新编辑器内容、语言、视图位置和高亮行。
<template>
<div class="monaco" id="monaco" ref="monacoRef"></div>
</template>
<script setup>
import * as monaco from 'monaco-editor'
import {onMounted, ref, onBeforeUnmount, watch} from 'vue'
const props = defineProps({
code: {
type: String,
required: true
},
language: {
type: String,
default: 'xml'
},
line: {
type: Number,
default: 0
}
})
const monacoRef = ref(null)
let editor = null
let decorations = [] // 存储装饰的ID
const highlightLine = () => {
const lineNumber = Number(props.line);
if (lineNumber === 0) {
decorations = editor.deltaDecorations(decorations, []);
return
}
decorations = editor.deltaDecorations(decorations, [
{
range: new monaco.Range(lineNumber, 1, lineNumber, 1),
options: {
isWholeLine: true,
className: 'highlight-line'
}
}
]);
}
const setLanguage = () => {
if (!editor) {
return;
}
const model = editor.getModel()
if (!model) {
return
}
monaco.editor.setModelLanguage(model, props.language)
}
const setPosition = () => {
if (!editor) {
return;
}
editor.revealLineInCenter(Number(props.line));
}
const init = () => {
editor = monaco.editor.create(monacoRef.value, {
value: props.code,
language: props.language,
theme: 'vs-dark',
automaticLayout: true, // 自动调整大小
lineHeight: 24,
tabSize: 2,
minimap: {
// 关闭小地图
enabled: false,
},
readOnly: true,
domReadOnly: true
})
}
const assignmentCode = () => {
if (!editor) {
return
}
editor.setValue(props.code)
if (props.code) {
setLanguage();
setPosition();
highlightLine();
}
}
watch(() => props.code, assignmentCode, { immediate: true, deep: true });
onMounted(() => {
init()
})
onBeforeUnmount(() => {
if (editor) {
editor.dispose();
editor = null
}
});
</script>
<style scoped lang="scss">
.monaco{
width: 100%;
height: 100%;
}
</style>
<style>
#monaco .highlight-line {
background-color: rgba(140, 143, 255, 0.7) !important; /* 设置高亮背景颜色 */
}
</style>
通过以上步骤,我们成功在 Vue 3 项目中集成了 Monaco Editor,并封装了一个具备基础编辑、代码高亮、定位和语言切换功能的组件。这个组件可以直接在你的项目中复用,用于展示代码片段、构建简单的在线代码编辑器等场景。如果你对更深入的 Monaco Editor API 或 Vue 3 的高级用法感兴趣,欢迎在技术社区深入探讨。