vue-cli3 , elementui ,typescript ,使用monaco-editor

 
npm install monaco-editor -S
 

封装了一个组件  

// \src\components\MonacoEditor.vue

<template>
  <div ref="container" class="app-monaco"></div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import * as monaco from "monaco-editor";
import { createWrapper } from "@vue/test-utils";

@Component
export default class MonacoEditor extends Vue {
  // 组件属性,用v-model来传递。
  // 代码的内容
  @Prop()
  public value!: string;

  // monaco 实例
  private editor: monaco.editor.IStandaloneCodeEditor | null = null;

  // 监听value变化,若变化则设置到 monaco 实例中
  @Watch("value")
  private async onValueChanged(newValue: string) {
    if (this.editor == null) return;
    // 更改editor内容
    this.editor.setValue(newValue);
    this.editor.getAction("editor.action.formatDocument").run();
  }

  mounted() {
    // 创建 monaco 实例
    this.editor = monaco.editor.create(<HTMLElement>this.$refs.container, {
      /**
       * 根据你们自己的喜欢,将下面的内容作为prop
       */
      value: this.value,
      // readOnly: true,
      // theme: "vs-dark",
      language: "typescript",
    });

    // 监听内容改变,改变之后更新value
    // @ts-ignore
    this.editor.onDidChangeModelContent((event: any) => {
      //编辑器内容changge事件
      // @ts-ignore
      this.$emit("input", this.editor.getValue());
    });
  }

  /**
   * 销毁monaco实例
   */
  destroyEditor() {
    if (this.editor == null) return;
    // 销毁编辑器
    this.editor.dispose();
    this.editor = null;
  }

  /**
   * vue 组件销毁钩子
   */
  beforeDestroy() {
    this.destroyEditor();
  }
}
</script>

<style scoped lang="scss">
.app-monaco {
  width: 100%;
  min-height: 300px;
  border: 1px solid grey;
}
</style>

使用相关代码

<template>
  <div class="interface-serarch">
    <el-row>
      <el-col :span="16" :offset="4">
        <h1>模拟断言脚本</h1>
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <h4 style="padding: 0px; margin: 0px; display: inline-block">
              基本测试
            </h4>
            <el-button style="float: right; padding: 3px 0" type="text">
              测试
            </el-button>
          </div>
        </el-card>
      </el-col>
      <el-col :span="16" :offset="4" style="margin-top: 50px">
        <MonacoEditor v-model="codeStr"></MonacoEditor>
      </el-col>

      <el-col :span="16" :offset="4" style="margin-top: 50px">
        <pre>{{ codeStr }}</pre>
        <el-button
          style="float: right; padding: 3px 0"
          type="text"
          @click="resetCode"
        >
          重置
        </el-button>
      </el-col>
    </el-row>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import MonacoEditor from "@/components/MonacoEditor.vue";

@Component({ components: { MonacoEditor } })
export default class AssertionTest extends Vue {
  private codeStr: string = [
    "function x() {",
    '\tconsole.log("Hello world!");',
    "}",
  ].join("\n");

  private resetCode() {
    this.codeStr = 'var sss="sdfs"';
  }
}
</script> 

页面效果

如下图,还蛮美好的,但实际上糟糕透了,报着错,还没有提示

editorSimpleWorker.js?ccf6:459 
Uncaught (in promise) Error: Unexpected usage
    at EditorSimpleWorker.loadForeignModule (editorSimpleWorker.js?ccf6:459)
    at eval (webWorker.js?af50:38)



errors.js?fdcc:12 
Uncaught Error: Unexpected usage
Error: Unexpected usage
    at EditorSimpleWorker.loadForeignModule (editorSimpleWorker.js?ccf6:459)
    at eval (webWorker.js?af50:38)
    at eval (errors.js?fdcc:12)

 

参考了下官方的列子,发现我少一些代码,通过代码也确定了一个事情,就是有些东西没有加载到【下面这个代码可以不用抄】【因为后面我的特殊性下面路径我加了/js/】【☞☞☞参考

// 参考 https://github.com/microsoft/monaco-editor-samples/blob/master/browser-esm-webpack-typescript/src/index.ts
// @ts-ignore
self.MonacoEnvironment = {
	getWorkerUrl: function (moduleId, label) {
		if (label === 'json') {
			return './js/json.worker.bundle.js';
		}
		if (label === 'css' || label === 'scss' || label === 'less') {
			return './js/css.worker.bundle.js';
		}
		if (label === 'html' || label === 'handlebars' || label === 'razor') {
			return './js/html.worker.bundle.js';
		}
		if (label === 'typescript' || label === 'javascript') {
			return './js/ts.worker.bundle.js';
		}
		return './js/editor.worker.bundle.js';
	}
};

加上去之后错误的确发生了变化,如下

editor.worker.bundle.js:1 Uncaught SyntaxError: Unexpected token '<'

上面的代码的确被执行了,并且Monaco给出了反应,他去请求了对应的资源。无奈vue-cli有一个默认配置,请求到404的时候返回index.html,所以被当做js执行的他,报了个<的错误。

继续发现官方samples的特别之处,被我发现了webpack.config.js有一串代码【☞☞☞参考

// 参考 https://github.com/microsoft/monaco-editor-samples/blob/master/browser-esm-webpack-typescript/webpack.config.js
entry: {
	app: './index.js',
	'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
	'json.worker': 'monaco-editor/esm/vs/language/json/json.worker',
	'css.worker': 'monaco-editor/esm/vs/language/css/css.worker',
	'html.worker': 'monaco-editor/esm/vs/language/html/html.worker',
	'ts.worker': 'monaco-editor/esm/vs/language/typescript/ts.worker'
}

亏我吧vue-cli关于webpack的配置资料翻了一波,配置之后有变化,但还是泡沫【下面这个代码可以不用抄】【这个的修改需要重启npm run】【cli3添加webpack相关配置参考

// vue.config.js
module.exports = {
    configureWebpack: {
        // externals: {
        //     vue: 'Vue',
        //     'vue-router': 'VueRouter',
        //     'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
        //     'json.worker': 'monaco-editor/esm/vs/language/json/json.worker',
        //     'css.worker': 'monaco-editor/esm/vs/language/css/css.worker',
        //     'html.worker': 'monaco-editor/esm/vs/language/html/html.worker',
        //     'ts.worker': 'monaco-editor/esm/vs/language/typescript/ts.worker'
        //     // axios: 'axios'
        // }
        entry: {
            'editor.worker.bundle': 'monaco-editor/esm/vs/editor/editor.worker.js',
            'json.worker.bundle': 'monaco-editor/esm/vs/language/json/json.worker',
            'css.worker.bundle': 'monaco-editor/esm/vs/language/css/css.worker',
            'html.worker.bundle': 'monaco-editor/esm/vs/language/html/html.worker',
            'ts.worker.bundle': 'monaco-editor/esm/vs/language/typescript/ts.worker'
        }
    },
    chainWebpack: config => {

        // 移除 prefetch 插件
        config.plugins.delete('prefetch')
    }
}

但不幸的是,依然不行。这里就不加原文了,他说的意思是webpack4以上就不用加插件了,我就真的没有加,其实只是缺了那个插件,可笑的是我看到官方samples也没有明确说明要那个东西,最后还是加上插件解决问题的

安装依赖

npm install monaco-editor-webpack-plugin

修改vue.config.js,【这个的修改需要重启npm run

// vue.config.js
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

module.exports = {
    configureWebpack: {
        plugins: [
            new MonacoWebpackPlugin()
        ]
    },
    chainWebpack: config => {
        // 移除 prefetch 插件
        config.plugins.delete('prefetch')
    }
}

哈哈哈,没错,到这里还有一个问题,就是v-model和watch把自己坑了一波,在互相影响设置,改造上面封装的Monaco组件

// 代码就不贴完整ts文件了,我也坑坑你们,哈哈哈


/**
 * 定义vm参考变量
 */
private vmValue!: string;


/**
 * 监听的时候丢弃自身的触发
 */
// vmValue==newValue 的时候,其实就是monaco使用input更新value造成的Watch,所以要丢弃
if (this.vmValue != newValue) {
	this.vmValue = this.value;
	// 更改editor内容
	this.editor.setValue(newValue);
	this.editor.getAction("editor.action.formatDocument").run();
}


/**
 * 初始化
 */
this.vmValue = this.value;

/**
 * 设置的时候
 */
this.vmValue = this.editor.getValue();
await this.$nextTick();
this.$emit("input", this.vmValue);

完美了!!!

 

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值