在线echarts编辑器实现

一、简介

本文主要介绍如何开发一个同echarts官网里面在线echarts编辑工具,通过页面中的代码编辑器修改echarts的option属性来实时渲染echarts的展示效果。其中主要使用到了【monaco-editor】这个组件。

github地址: https://github.com/1277463718lmt/echarts-editor-demo.git
下图为完成的效果图:


gitdizhi

二、如何实现

  • 引入monaco-editor包

    npm install monaco-editor
    npm install monaco-editor-webpack-plugin
    
  • 编辑器组件封装

    通过引入monaco-editor组件,然后进行指定dom节点以及配置进行页面渲染,该组件通过v-model绑定编辑器的内容。

    monaco-editor官方文档:https://microsoft.github.io/monaco-editor/docs.html

    <template>
      <div id="jsMonacoEditor" ref="main" />
    </template>
    
    <script>
    import * as monaco from 'monaco-editor'
    
    /*
    * @Description: monacoEditor组件封装
    * @Author: linmt
    * @Date: @Date: 2022-09-11 08:45:55
    */
    export default {
      name: 'JsMonacoEditor',
      components: {
      },
      model: { // 使用v-model绑定编辑器的内容
        prop: 'value',
        event: 'change'
      },
      props: {
        value: {
          type: String,
          default: ''
        }
      },
      data() {
        return {
          monacoEditor: null
        }
      },
      computed: {
    
      },
      watch: {
        value() {
          this.init()
        }
      },
      created() {
    
      },
      mounted() {
        this.init()
      },
      methods: {
        /**
         * 初始化
         */
        init() {
          if (this.monacoEditor) {
            if (this.value !== this.monacoEditor.getValue()) {
              this.monacoEditor.getModel().setValue(this.value)
            }
            return
          }
    
          this.monacoEditor = monaco.editor.create(this.$refs.main, {
            theme: 'vs', // 主题
            value: this.value, // 默认显示的值
            language: 'javascript',
            folding: true, // 是否折叠
            foldingHighlight: true, // 折叠等高线
            foldingStrategy: 'indentation', // 折叠方式  auto | indentation
            showFoldingControls: 'always', // 是否一直显示折叠 always | mouseover
            disableLayerHinting: true, // 等宽优化
            emptySelectionClipboard: false, // 空选择剪切板
            selectionClipboard: false, // 选择剪切板
            automaticLayout: true, // 自动布局
            codeLens: false, // 代码镜头
            scrollBeyondLastLine: false, // 滚动完最后一行后再滚动一屏幕
            colorDecorators: true, // 颜色装饰器
            accessibilitySupport: 'off', // 辅助功能支持  "auto" | "off" | "on"
            lineNumbers: 'on', // 行号 取值: "on" | "off" | "relative" | "interval" | function
            lineNumbersMinChars: 5, // 行号最小字符   number
            enableSplitViewResizing: false,
            readOnly: false, // 是否只读  取值 true | false
            minimap: {
              enabled: true // 是否启用预览图
            } // 预览图设置
          })
    
          const self = this
          
          // _.debounce为lodashjs工具包的方法,见https://www.lodashjs.com/
          // 主要用来防抖动
          const changeValueFun = _.debounce(function() {
            self.changeValue()
          }, 500)
    
    	  // 监听编辑器内容改变事件
          this.monacoEditor.onDidChangeModelContent((e) => {
            changeValueFun()
          })
        },
        changeValue() {
          this.$emit('change', this.monacoEditor.getValue())
        }
      }
    }
    
    </script>
    <style lang='scss' scoped>
    #jsMonacoEditor{
      height: 100%;
      width: 100%;
    }
    </style>
    
    
  • 将代码编辑器和echarts渲染结合

    实现逻辑:通过监听编辑器的组件的change事件来刷新echarts图,用编辑器里面的内容使用new Function(code)方式实现js动态的代码执行并获取返回值,也就是echarts的option属性,然后通过option的值进行echarts渲染,再通过通过定时的方式进行echarts的大小重绘。

    <template>
      <div id="codeEditor">
        <div class="code-box">
          <JsMonacoEditor v-model="code" @change="changeCode" />
        </div>
        <div class="view-box">
          <el-button type="primary" size="small" @click="refreshChart">运行/刷新</el-button>
          <div ref="chart" class="chart" />
        </div>
      </div>
    </template>
    
    <script>
    import JsMonacoEditor from '@/businessComponents/jsMonacoEditor'
    
    let timer = null
    /*
    * @Description: 代码编辑器
    * @Author: linmt
    * @Date: @Date: 2022-09-11 09:01:31
    */
    export default {
      name: 'CodeEditor',
      components: {
        JsMonacoEditor
      },
      props: {
        echartDemoData: {
          type: Object,
          default: null
        }
      },
      data() {
        return {
          code: 'const option = {};',
          chart: null
        }
      },
      computed: {
    
      },
      watch: {
    
      },
      created() {
        if (this.echartDemoData) {
          this.code = this.echartDemoData.code
        }
      },
      mounted() {
        this.refreshChart()
      },
      beforeDestroy() {
        if (timer) window.clearInterval(timer)
      },
      methods: {
        changeCode() {
          this.refreshChart()
        },
        refreshChart() {
          let _option = null
          try {
            const funCode = new Function(`option=null;${this.code};return option;`)
            _option = funCode()
          } catch (e) {
            console.error(e)
          }
    
          if (!_option) {
            this.$message.error('代码存在问题')
            if (this.chart) {
              this.chart.clear()
            }
            return
          }
    
          if (_option) {
            if (!this.chart) {
              this.chart = window.echarts.init(this.$refs.chart)
            } else {
              this.chart.clear()
            }
    
            // 通过定时的方式进行echarts的大小重绘
            if (timer) window.clearInterval(timer)
            timer = setInterval(() => {
              if (this.chart) {
                this.chart.resize()
              }
            }, 200)
    
            this.chart.setOption(_option, true)
          }
        }
      }
    }
    
    </script>
    <style lang='scss' scoped>
    #codeEditor{
      height: 100%;
      width: 100%;
      display: flex;
      .code-box{
        width: 50%;
        height: 100%;
      }
      .view-box{
        width: 50%;
        height: 100%;
        padding-left: 10px;
        .chart{
          margin-top: 20px;
          height: calc(100% - 80px);
          width: 100%;
        }
      }
    }
    </style>
    
posted @ 2022-11-11 17:58  linmt  阅读(3317)  评论(6编辑  收藏  举报