Vue中使用Monaco Editor代码编辑器

一、安装依赖

npm install editor@1.0.0
npm install monaco-editor@0.19.3
npm install monaco-editor-webpack-plugin@1.9.1

二、配置vue.config.js文件

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = {
    configureWebpack: {
        plugins: [
            new MonacoWebpackPlugin()
        ]
    }
}

三、新增jsonpath.js

const colType = { Object, Array }

export function getJsonPath(text, offSet) {
    // console.log(text, offSet);
    let pos = 0
    let stack = []
    let isInKey = false

    while (pos < offSet) {
        const startPos = pos
        switch (text[pos]) {
            case '"':
                var { text: s, pos: newPos } = readString(text, pos)
                if (stack.length) {
                    const frame = stack[stack.length - 1]
                    if (frame.colType === colType.Object && isInKey) {
                        frame.key = s
                        isInKey = false
                    }
                }
                pos = newPos
                break
            case '{':
                stack.push({ colType: colType.Object })
                isInKey = true
                break
            case '[':
                stack.push({ colType: colType.Array, index: 0 })
                break
            case '}':
            case ']':
                stack.pop()
                break
            case ',':
                if (stack.length) {
                    const frame = stack[stack.length - 1]
                    if (frame.colType === colType.Object) {
                        isInKey = true
                    } else {
                        frame.index++
                    }
                }
                break
        }
        if (pos === startPos) {
            pos++
        }
    }
    return pathToString(stack);
}

function pathToString(path) {
    let s = '$'
    try {
        for (const frame of path) {
            if (frame.colType === colType.Object) {
                if (!frame.key.match(/^[a-zA-Z$_][a-zA-Z\d$_]*$/)) {
                    // const key = frame.key.replace('"', '\\"')
                    s += `["${frame.key}"]`
                } else {
                    if (s.length) {
                        s += '.'
                    }
                    s += frame.key
                }
            } else {
                s += `[${frame.index}]`
            }
        }
        return s;
    } catch (ex) {
        return '';
    }
}

function isEven(n) {
    return n % 2 === 0;
}

function readString(text, pos) {
    let i = pos + 1
    i = findEndQuote(text, i)
    var textpos = {
        text: text.substring(pos + 1, i),
        pos: i + 1
    }
    return textpos
}

// Find the next end quote
function findEndQuote(text, i) {
    while (i < text.length) {
        // console.log('findEndQuote: ' + i + ' : ' + text[i])
        if (text[i] === '"') {
            var bt = i
            // Handle backtracking to find if this quote is escaped (or, if the escape is escaping a slash)
            while (0 <= bt && text[bt] == '\\') {
                bt--
            }
            if (isEven(i - bt)) {
                break;
            }
        }
        i++
    }
    return i
}

四、新增组件 monacoEditor.vue

<template>
  <div>
    <div
      id="code-editor"
      :style="{
        width: '100%',
        height: height + 'px',
        border: '1px solid grey',
      }"
    ></div>
  </div>
</template>

<script>
import * as monaco from "monaco-editor";
import { getJsonPath } from "./jsonpath";

export default {
  name: "monacoEditor",
  model: {
    prop: "content",
    event: "change",
  },
  props: {
    content: null,
    language: {
      default: "javascript", //json、css、html、typescript、javascript、sql
    },
    readOnly: {
      default: false,
    },
    height: {
      default: 300
    }
  },
  data: function() {
    return {
      editor: null,
      jsonPath: null,
    };
  },
  watch: {
    content: function(newValue) {
      // console.debug("Code editor: content change");
      if (this.editor) {
        if (newValue !== this.editor.getValue()) {
          // console.log(newValue);
          monaco.editor.setModelLanguage(this.editor.getModel(), this.language);
          this.editor.setValue(newValue);
          this.editor.trigger(
            this.editor.getValue(),
            "editor.action.formatDocument"
          );
        }
      }
    },
  },
  mounted: function() {
    const copyToClipboard = this.copyToClipboard;
    this.editor = monaco.editor.create(this.$el.querySelector("#code-editor"), {
      value: this.content,
      language: this.language,
      theme: "vs",
      readOnly: this.readOnly,
      automaticLayout: true,
    });
    this.editor.addAction({
      id: "json-path",
      label: "Copy JsonPath",
      keybindings: [
        monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_J),
      ],
      precondition: "editorLangId == 'json'",
      keybindingContext: "editorLangId == 'json'",
      contextMenuGroupId: "9_cutcopypaste",
      contextMenuOrder: 2,
      run: copyToClipboard,
    });
    this.editor.onDidChangeModelContent((event) => {
      const value = this.editor.getValue();
      if (this.value !== value) {
        // console.log(value,'====on-change-change');
        this.$emit("change", value, event);
      }
    });
    this.editor.onDidChangeCursorPosition((event) => {
      const value = this.editor.getValue();
      const offSet = this.editor.getModel().getOffsetAt(event.position);
      const language = this.language;
      if (this.value !== value && language === "json") {
        // console.log(value,'====on-cursor-change');
        this.$emit("on-cursor-change", { offSet: offSet });
      }
      if (language == "json" && offSet !== 0) {
        this.jsonPath = getJsonPath(value, offSet);
        // console.log(value,'====on-jsonpath-change');
        this.$emit("on-jsonpath-change", { jsonPath: this.jsonPath });
      }
    });
  },
  methods: {
    copyToClipboard() {
      const notification = this.$Notice;
      if (this.jsonPath) {
        navigator.clipboard.writeText(this.jsonPath).then(
          function() {},
          function() {
            notification.error({
              title: "jsonpath copy failed.",
            });
          }
        );
      } else {
        notification.warning({
          title: "There is no jsonpath that can be copied.",
        });
      }
    },
  },
};
</script>

</script>

五、组件调用

import MonacoEditor from '@/components/MonacoEditor';

components: {
	MonacoEditor,
}

<monaco-editor 
      v-model="content"
      language="json"
      :readOnly="false" >
</monaco-editor>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值