找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

629

积分

0

好友

81

主题
发表于 5 天前 | 查看: 25| 回复: 0

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 的高级用法感兴趣,欢迎在技术社区深入探讨。




上一篇:Go事件驱动与全链路追踪在PCB智能工厂调度系统中的应用实践
下一篇:DeepSeek-V4模型架构前瞻:基于DSA、mHC与Engram的稀疏化设计
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 04:07 , Processed in 0.399186 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表