前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >monaco-editor做自己的代码测试工具

monaco-editor做自己的代码测试工具

作者头像
lzugis
发布2020-03-12 10:40:59
1.9K0
发布2020-03-12 10:40:59
举报

概述

本文说的是如何通过monaco-editor实现一个类似于codepen一样的在线代码测试工具。

微软之前有个项目叫做Monaco Workbench,后来这个项目变成了VSCode,而Monaco Editor(下文简称monaco)就是从这个项目中成长出来的一个web编辑器,他们很大一部分的代码(monaco-editor-core)都是共用的,所以monaco和VSCode在编辑代码,交互以及UI上几乎是一摸一样的,有点不同的是,两者的平台不一样,monaco基于浏览器,而VSCode基于electron,所以功能上VSCode更加健全,并且性能比较强大。

实现效果

实现效果
实现效果

实现代码

1、引入包

npm install monaco-editor --save

2、封装一个组件

<template>
<div class="the-code-editor-container" ref="container"></div>
</template>

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

export default {
  name: "codeEditor",
  props: {
    options: {
      type: Object,
      default () {
        return {
          language: "javascript",
          readOnly: true
        };
      }
    },

    value: {
      type: String,
      default: ""
    }
  },

  data() {
    return {
      monacoInstance: null,
      provider: null
    };
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.dispose();
  },

  methods: {
    dispose() {
      if (this.monacoInstance) {
        if (this.monacoInstance.getModel()) {
          this.monacoInstance.getModel().dispose();
        }
        this.monacoInstance.dispose();
        this.monacoInstance = null;
        if (this.provider) {
          this.provider.dispose();
          this.provider = null
        }
      }
    },
    init() {
      let that = this;
      // console.log(monaco.languages.CompletionItemKind)
      this.dispose();
      let createCompleters = textUntilPosition => {
        //过滤特殊字符
        let _textUntilPosition = textUntilPosition
          .replace(/[\*\[\]@\$\(\)]/g, "")
          .replace(/(\s+|\.)/g, " ");
        //切割成数组
        let arr = _textUntilPosition.split(" ");
        //取当前输入值
        let activeStr = arr[arr.length - 1];
        //获得输入值的长度
        let len = activeStr.length;

        //获得编辑区域内已经存在的内容
        let rexp = new RegExp('([^\\w]|^)' + activeStr + '\\w*', "gim");
        let match = that.value.match(rexp);
        let _hints = !match ? [] : match.map(ele => {
          let rexp = new RegExp(activeStr, "gim");
          let search = ele.search(rexp);
          return ele.substr(search)
        })

        //查找匹配当前输入值的元素
        let hints = Array.from(new Set([...that.hints, ..._hints])).sort().filter(ele => {
          let rexp = new RegExp(ele.substr(0, len), "gim");
          return match && match.length === 1 && ele === activeStr || ele.length === 1 ?
            false :
            activeStr.match(rexp);
        });
        //添加内容提示
        let res = hints.map(ele => {
          return {
            label: ele,
            kind: that.hints.indexOf(ele) > -1 ? monaco.languages.CompletionItemKind.Keyword : monaco.languages.CompletionItemKind.Text,
            documentation: ele,
            insertText: ele
          };
        });
        return res;
      };
      this.provider = monaco.languages.registerCompletionItemProvider("sql", {
        provideCompletionItems(model, position) {
          var textUntilPosition = model.getValueInRange({
            startLineNumber: position.lineNumber,
            startColumn: 1,
            endLineNumber: position.lineNumber,
            endColumn: position.column
          });
          var suggestions = createCompleters(textUntilPosition);
          return {
            suggestions: suggestions
          };

          return createCompleters(textUntilPosition);
        }
      });

      // 初始化编辑器实例
      this.monacoInstance = monaco.editor.create(this.$refs["container"], {
        value: this.value,
        theme: "vs-dark",
        autoIndex: true,
        ...this.options
      });

      // 监听编辑器content变化事件
      this.monacoInstance.onDidChangeModelContent(() => {
        this.$emit("contentChange", this.monacoInstance.getValue(), this.options.language);
      });
    }
  }
};
</script>

<style scope lang="stylus">
.the-code-editor-container
  width: 100%
  height: 100%
  overflow: hidden
  border: 1px solid #eaeaea
  text-align: left
  .monaco-editor .scroll-decoration
    box-shadow: none
</style>

3.引用实现

 <template>
  <div class="container">
    <div class="panel">
      <div class="code">
        <div class="title">html</div>
        <code-editor
          :options="htmlOptions"
          :value="htmlContent"
          class="code-panel"
          @contentChange="contentChange"
        ></code-editor>
      </div>
      <div class="code">
        <div class="title">css</div>
        <code-editor
          :options="cssOptions"
          :value="cssContent"
          class="code-panel"
          @contentChange="contentChange"
        ></code-editor>
      </div>
      <div class="code">
        <div class="title">js</div>
        <code-editor
          :options="jsOptions"
          :value="jsContent"
          class="code-panel"
          @contentChange="contentChange"
        ></code-editor>
      </div>
    </div>
    <div class="panel">
      <iframe class="view-panel" id="preview" frameborder="0"></iframe>
    </div>
  </div>
</template>

<script>
import CodeEditor from '@/components/codeview/index.vue'
export default {
  name: 'HelloWorld',
  components: {
    CodeEditor
  },
  data() {
    return {
      htmlContent: `<div id="map"></div>`,
      cssContent: `html,
body,
#map {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}`,
      jsContent: `var osm = new ol.layer.Tile({
  source: new ol.source.OSM()
});
var map = new ol.Map({
  controls: ol.control.defaults({
    attribution: false
  }),
  target: 'map',
  layers: [osm],
  view: new ol.View({
    minZoom: 2,
    maxZoom: 18,
    center: [0, 0],
    zoom: 3
  })
});`,
      htmlOptions: {
        language: "html"
      },
      cssOptions: {
        language: "css"
      },
      jsOptions: {
        language: "javascript"
      }
    }
  },
  methods: {
    contentChange(val, type) {
      switch (type) {
        case 'html': {
          this.htmlContent = val;
          break;
        }
        case 'css': {
          this.cssContent = val;
          break;
        }
        default: {
          this.jsContent = val;
          break;
        }
      }
      this.runAllCodes();
    },
    runAllCodes() {
      var html = this.htmlContent;
      var css = this.cssContent;
      var js = this.jsContent;

      var code = "<!DOCTYPE html>\n" +
        "<html lang=\"en\">\n" +
        "<head>\n" +
        "  <meta charset=\"UTF-8\">\n" +
        "  <title>Editor</title>\n" +
        "  <style>";
      code += "\n" + css;

      code +=
        "\n  </style>\n" +
        "</head>\n" +
        "<body>\n";
      code += "\n" + html;

      code +=
        "\n  <script>\n";
      code += "\n" + js;
      code +=
        "\n  <\/script>\n" +
        "<\/body>\n" +
        "</html>";
      const preview = document.getElementById('preview')
      preview.setAttribute("srcdoc", code);
    }
  }
}
</script>

<style scope lang="stylus">
$font-size = 30px
$color = red
.container
  width: 100%
  height: 100%
  margin: 0
  padding: 0

.view-panel
  width: 100%
  height: 100%
.panel
  width: 100%
  height: 50%
  .title
    height: 30px
    line-height: 30px
    padding: 0 10px
    border-left: 4px solid #00f
  .code
    width: calc(100% / 3 - 2px)
    height: 100%
    float: left
    margin-left: 3px
    &:first-child
      margin-left: 0
  .code-panel
    width: 100%
    height: calc(100% - 30px)
</style>

技术博客 CSDN:http://blog.csdn.NET/gisshixisheng 联系方式

类型

内容

qq

1004740957

公众号

lzugis15

e-mail

niujp08@qq.com

webgis群

452117357

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 实现效果
  • 实现代码
    • 1、引入包
      • 2、封装一个组件
        • 3.引用实现
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档