Vue2+monaco-editor实现代码编辑器

647 阅读1分钟

monaco-editor搭配Vue

方式一:Vue2安装(此版本已验证可使用)

npm install monaco-editor@0.30.1
npm install monaco-editor-webpack-plugin@6.0.0

vue.config.js配置

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
module.exports = defineConfig({
  transpileDependencies: true,
  //关闭eslint
  lintOnSave: false,
  configureWebpack: {
    plugins: [new MonacoWebpackPlugin()],
  },
})

方式二:index.html 利用CDN引入(推荐)

    <!-- monaco编辑器 -->
    <link rel="stylesheet" data-name="vs/editor/editor.main"
          href="https://cdn.staticfile.org/monaco-editor/0.33.0/min/vs/editor/editor.main.css">
    <script>self.require = { paths: { 'vs': 'https://cdn.staticfile.org/monaco-editor/0.33.0/min/vs' }, 'vs/nls': { availableLanguages: { '*': 'zh-cn' } } };</script>
    <script src="https://cdn.staticfile.org/monaco-editor/0.33.0/min/vs/loader.min.js"></script>
    <script src="https://cdn.staticfile.org/monaco-editor/0.33.0/min/vs/editor/editor.main.nls.zh-cn.js"></script>
    <script src="https://cdn.staticfile.org/monaco-editor/0.33.0/min/vs/editor/editor.main.js"></script>

封装组件CodeEditor

<template>
  <div class="editor-container">
    <div class="toolbar">
      <Select v-model="language" placeholder="请选择文件类型" style="width: 150px; padding-right: 10px">
        <Option :value="item" v-for="item in languages">{{ item }}</Option>
      </Select>
      <a class="space" @click="handleCopy">一键复制</a>
      <a class="space" @click="exportFile">导出文件</a>
    </div>
    <div ref="main" class="code-editor-container"></div>
  </div>
</template>

<script>
import * as monaco from 'monaco-editor'
import FileSaver from 'file-saver'

export default {
  name: 'CodeEditor',
  props: {
    language: {
      type: String,
      required: true,
    },
    value: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      monacoEditor: null,
      // 支持的语言
      languages: ['txt', 'js', 'xml', 'java'],
    }
  },
  watch: {
    value(newCode) {
      if (this.monacoEditor && newCode !== this.monacoEditor.getValue()) {
        this.monacoEditor.setValue(newCode)
      }
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.initMonaco()
    })
  },
  methods: {
    initMonaco() {
      this.monacoEditor = monaco.editor.create(this.$refs.main, {
        theme: 'vs-dark', // 主题
        value: this.value, // 默认显示的值
        language: this.language,
        folding: true, // 是否折叠
        foldingHighlight: true, // 折叠等高线
        foldingStrategy: 'auto', // 折叠方式
        showFoldingControls: 'always', // 是否一直显示折叠
        disableLayerHinting: true, // 等宽优化
        emptySelectionClipboard: false, // 空选择剪切板
        selectionClipboard: true, // 选择剪切板
        automaticLayout: true, // 自动布局
        codeLens: true, // 代码镜头
        scrollBeyondLastLine: false, // 滚动完最后一行后再滚动一屏幕
        colorDecorators: true, // 颜色装饰器
        accessibilitySupport: 'on', // 辅助功能支持"auto" | "off" | "on"
        lineNumbers: 'on', // 行号 取值: "on" | "off" | "relative" | "interval" | function
        lineNumbersMinChars: 4, // 行号最小字符   number
        enableSplitViewResizing: false,
        readOnly: false, //是否只读  取值 true | false
        fontSize: 18,
      })
      // 使用 requestAnimationFrame 包装 onDidChangeModelContent
      this.monacoEditor.onDidChangeModelContent(() => {
        requestAnimationFrame(() => {
          this.$emit('change', this.monacoEditor.getValue())
        })
      })
    },
    handleCopy() {
      const currentValue = this.monacoEditor.getValue()
      this.$copyText(currentValue).then(() => {
        this.$Message.success('复制成功')
      })
    },
    exportFile: function () {
      const content = this.monacoEditor.getValue()
      const blob = new Blob([content], { type: 'text/plain;charset=utf-8;' })
      const fileName = `code` + new Date().getTime() + `.${this.language}`
      FileSaver.saveAs(blob, fileName)
    },
  },
}
</script>

<style scoped>
.code-editor-container {
  width: 100%;
  height: 100%;
  text-align: initial;
}

.toolbar {
  display: flex;
  justify-content: flex-end;
  text-align: initial;
  padding: 2px 10px;
  background: #333;
  color: white;
}

.space {
  padding-right: 16px;
  margin: auto 0;
}
</style>

测试使用

<template>
  <div>
    <CodeEditor language="xml" v-model="code" @change="codeChange" style="height: 50vh" />
  </div>
</template>

<script>
import CodeEditor from '@/monaco/CodeEditor'
export default {
  components: {
    CodeEditor,
  },
  data() {
    return {
      code: 'hello world',
    }
  },
  methods: {
    codeChange(e) {
      console.log(e)
    },
  },
}
</script>

效果

image-20240530222549478.png