这几天使用业务中有一个需求是需要做代码在线编辑,因此对比了下首先想到了monaco-editor,但是实测引入到项目中会遇到一些坑点,因此将引入流程和坑点进行梳理。

        踩坑点:

        1、monaco-editor版本问题!!十分重要,首先,要找到跟当前vue版本匹配的monaco-editor版本,我是用的是vue2.x,尝试了最高支持的版本是monaco-editor 0.30.1,同时要实现代码提示需要引入与之匹配的的monaco-editor-webpack-plugin,这里我引入的是 6.0.0,亲测能完美实现代码提示。

        2、使用 this.$emit('input', this.monacoEditor.getValue()) 来实现双向绑定会导致光标乱跳动,所以最终还是使用this.$emit('change', this.monacoEditor.getValue())进行编辑器内代码内容传递。

        引入monaco-editor并封装成通用组件详细步骤:

        step1.安装与你vue版本匹配的monaco-editor和与之匹配的monaco-editor-webpack-plugin,这里我先用的是0.30.1+monaco-editor-webpack-plugin 6.0.0。

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

        step2.创建一个可复用的组件来实现自己想要的编辑器的一些逻辑及配置

<template>
  <div ref="main" style="width: 100%; height: 100%"></div>
</template>

<script>
import * as monaco from "monaco-editor";

export default {
  name:"CodeEditor",
  data() {
    return {
      monacoEditor: null,
    };
  },
  props:{
    language:String,
    value:String
  },
  created() {

  },
  watch:{
    value(newCode) {
      this.monacoEditor.setValue(newCode);
    }
  },
  mounted() {
    this.$nextTick(()=>{
      this.initMonaco();
      this.initCustomLanguage();
    })
  },
  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: false, // 选择剪切板
        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
      });
      this.monacoEditor.onDidChangeModelContent(() => {
        this.$emit('change', this.monacoEditor.getValue());
      });
    }
    
  },
};
</script>

        step3.实现一些自己常用语言的关键词提示功能,目测monaco-editor只有html,css和js的代码提示,所以我这边要想实现golang和python的下来提示就需要把常用关键词给它喂进去,先创建两个存放提示词的js文件。

// go-suggestion.js 用于存放golang的提示词
const goSuggestion=[
    "break", "case", "chan", "const", "continue", "default", "defer", "else",
    "fallthrough", "for", "func", "go", "goto", "if", "import", "interface",
    "map", "package", "range", "return", "select", "struct", "switch", "type",
    "var", "append", "cap", "close", "complex", "copy", "delete", "imag", "len",
    "make", "new", "panic", "print", "println", "real", "recover","string",
    // 常用库关键词
    "bufio", "bytes", "context", "crypto", "database", "encoding", "errors",
    "flag", "fmt", "io", "log", "math", "net", "os", "path", "reflect", "regexp",
    "runtime", "sort", "strconv", "strings", "sync", "syscall", "testing", "text",
    "time", "unicode", "unsafe"
];
export default goSuggestion;
// python-suggest.js 用于存放python的一些提示词
const suggestion=[
    "False", "None", "True", "and", "as", "assert", "async", "await",
    "break", "class", "continue", "def", "del", "elif", "else", "except",
    "finally", "for", "from", "global", "if", "import", "in", "is", "lambda",
    "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with",
    "yield", "abs", "all", "any", "ascii", "bin", "bool", "bytearray", "bytes",
    "callable", "chr", "classmethod", "compile", "complex", "delattr", "dict",
    "dir", "divmod", "enumerate", "eval", "exec", "filter", "float", "format",
    "frozenset", "getattr", "globals", "hasattr", "hash", "help", "hex", "id",
    "input", "int", "isinstance", "issubclass", "iter", "len", "list", "locals",
    "map", "max", "memoryview", "min", "next", "object", "oct", "open", "ord",
    "pow", "print", "property", "range", "repr", "reversed", "round", "set",
    "setattr", "slice", "sorted", "staticmethod", "str", "sum", "super", "tuple",
    "type", "vars", "zip","collections", "datetime", "email", "functools", "http", "json", "logging",
    "math", "os", "pathlib", "random", "re", "requests", "socket", "sys", "time",
    "unittest", "urllib", "uuid"
]
export default suggestion;

        然后在编辑器组件中对齐进行引入并添加提示词

<template>
  <div ref="main" style="width: 100%; height: 100%"></div>
</template>

<script>
import * as monaco from "monaco-editor";
// 引入自定义提示词
import pythonSuggestion from "@/components/codeeditor/python-suggestion";
import goSuggestion from "@/components/codeeditor/go-suggestion";
const customLanguage={
  "go":goSuggestion,
  "python":pythonSuggestion
}
export default {
  name:"CodeEditor",
  data() {
    return {
      monacoEditor: null,
    };
  },
  props:{
    language:String,
    value:String
  },
  created() {

  },
  watch:{
    value(newCode) {
      this.monacoEditor.setValue(newCode);
    }
  },
  mounted() {
    this.$nextTick(()=>{
      this.initMonaco();
      // 自定义提示词
      this.initCustomLanguage();
    })
  },
  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: false, // 选择剪切板
        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
      });
      this.monacoEditor.onDidChangeModelContent(() => {
        this.$emit('change', this.monacoEditor.getValue());
      });
    },
    initCustomLanguage(){
      let language=this.language;
      if(!(Object.keys(customLanguage)).includes(this.language)){
        return
      }
      monaco.languages.registerCompletionItemProvider(this.language, {
        provideCompletionItems: function() {
          let keywords = customLanguage[language];
          let suggestions = keywords.map(function(keyword) {
            return {
              label: keyword,
              kind: monaco.languages.CompletionItemKind.Keyword,
              insertText: keyword
            };
          });
          return { suggestions: suggestions };
        }
      });
    },
  },
};
</script>

        step5.配置vue.config.js,引入monaco-editor-webpack-plugin插件,只有加载了这个插件才有代码提示和高亮效果。

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
config.plugins.push(new MonacoWebpackPlugin({languages:['go','python','javascript','java','css','html']}));

        step6.在其他组件引入并使用封装好的代码编辑器。

<template>

  <div style="height: 100%;width: 100%">
    <CodeEditor @change="codeChange" v-model="code" language="go"></CodeEditor>
  </div>
</template>

<script>

import CodeEditor from "@/components/codeeditor/CodeEditor.vue";

export default {
  components: {CodeEditor},
  data() {
    return {
      code:"type user struct"
    };
  },
  created() {

  },
  mounted() {

  },
  methods: {
    codeChange(e){
      console.log(e)
    },
    
  },
};
</script>

最终实现的效果:

        以上便完成了monaco-editor简单的封装和使用,可根据自己的场景进行修改。

Logo

前往低代码交流专区

更多推荐