美文网首页
Vue2的SQL编辑器 - monaco的基本使用

Vue2的SQL编辑器 - monaco的基本使用

作者: 思跃喵 | 来源:发表于2022-11-10 00:26 被阅读0次

    概述

    本文在vue中实现了一个基本的SQL编辑器,包括语法高亮,关键字补全,表名,字段名补全等功能

    细节功能等尚未进行完善,仅作学习使用

    效果如下:

    iShot_2022-11-11_00.02.50.gif

    准备工作

    本文在vue-cli创建的项目中,使用vue2
    需要安装两个包

        "monaco-editor": "0.30.0", // 编辑器主体
        "monaco-editor-webpack-plugin": "6.0.1", // 帮我们处理语法高亮等问题
    

    使用 yarn add 或者 npm install 等命令均可,但是版本会有很大的影响,monaco-editor 的版本与 monaco-editor-webpack-plugin 的版本有对应关系,如下:

    monaco-editor-webpack-plugin monaco-editor
    7.*.* >= 0.31.0
    6.*.* 0.30.*
    5.*.* 0.29.*
    4.*.* 0.25.*, 0.26.*, 0.27.*, 0.28.*
    3.*.* 0.22.*, 0.23.*, 0.24.*
    2.*.* 0.21.*
    1.9.* 0.20.*
    1.8.* 0.19.*
    1.7.* 0.18.*

    如果对应关系不正确会导致无法运行,各种莫名其妙的报错
    建议直接在package.json 文件里面添加上面的固定版本依赖项

    先处理 monaco-editor-webpack-plugin

    在 vue.config.js 中添加

    // 把 monaco webpack plugin 搞进去
    const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
    
    module.exports={
      configureWebpack: config => {
        config.plugins.push(
          new MonacoWebpackPlugin({
            languages:["sql"], // 目前只处理SQL语言
            features:["coreCommands","find"] // 基本命令和搜索功能
          })
        )
      },
    }
    

    代码编辑器主体

    SQLEditor.vue

    <template>
      <div id="app" style="height: 100vh">
        <div id="code-editor" ref="code-editor" style="height: 100%; width: 100%"></div>
      </div>
    </template>
    

    script 中的代码,全注释版

    import * as monaco from "monaco-editor";
    import { language } from "monaco-editor/esm/vs/basic-languages/sql/sql";
    // 从 monaco-editor 的 sql 里面拿到关键字
    const { keywords } = language;
    export default {
      name: "App",
      data() {
        return {
          // 编辑器实例
          monacoEditor: null,
          // 原本已经写入的数据
          value: "SELECT * FROM users;\n\nSELECT * FROM roles;",
          // 补全的数据,建议在编辑器初始化之间就请求回来放好
          tables: {
            users: ["name", "id","email","phone","password"],
            roles:["id","name","order","created_at","updated_at","deleted_at"]
          },
          // 编辑器主题
          theme: "vs-dark", // 默认是 "vs"
        };
      },
      methods: {
        /**
         * @description: 获取编辑器中填写的值
         */
        getValue() {
          return this.monacoEditor.getValue();
        },
    
        /**
         * @description: 初始化自动补全
         */
        initAutoCompletion() {
          monaco.languages.registerCompletionItemProvider("sql", {
            // 触发提示的字符
            triggerCharacters: [".", " ", ...keywords],
            provideCompletionItems: (model, position) => {
              let suggestions = [];
              // 行号,列号
              const { lineNumber, column } = position;
              // 光标之前的所有字符,即从这一行的 0 到当前的字符
              const textBeforePointer = model.getValueInRange({
                startLineNumber: lineNumber,
                startColumn: 0,
                endLineNumber: lineNumber,
                endColumn: column,
              });
    
              // trim() 取消两边空格,保证拆分出来前后都不是空值 
              // \s是指空白,包括空格、换行、tab缩进等所有的空白
              const words = textBeforePointer.trim().split(/\s+/);
    
              // 最后的一个有效词
              const lastWord = words[words.length - 1];
    
              if (lastWord.endsWith(".")) { // 如果这个词以 . 结尾,那么认为是希望补全表的字段
                // 拿到真实的表名,把 . 去掉
                const tableName = lastWord.slice(0, lastWord.length - 1);
                if (Object.keys(this.tables).includes(tableName)) {
                  suggestions = [...this.getFieldsSuggest(tableName)];
                }
              } else if (lastWord === ".") {
                // 如果这个词本身就是一个 . 即点前面是空的,那么什么都不用补全了
                // 按理说这应该是个语法错误
                suggestions = [];
              } else {
                // 其他时候都补全表名,以及关键字
                suggestions = [...this.getTableSuggest(), ...this.getKeywordsSuggest()];
              }
    
              return {
                suggestions,
              };
            },
          });
        },
        
        /**
         * @description: 获取关键字的补全列表
         * @tips: CompletionItemKind 的所有枚举可以在monaco.d.ts 文件中找到,有二十多个,取需即可
         */    
        getKeywordsSuggest() {
          return keywords.map((key) => ({
            label: key,// 显示的名称
            kind: monaco.languages.CompletionItemKind.Keyword,
            insertText: key,// 真实补全的值
          }));
        },
    
        /**
         * @description: 获取表名的补全列表
         */    
        getTableSuggest() {
          return Object.keys(this.tables).map((key) => ({
            label: key, // 显示的名称
            kind: monaco.languages.CompletionItemKind.Variable,
            insertText: key, // 真实补全的值
          }));
        },
    
        /**
         * @description: 根据表名获取字段补全列表
         * @param {*} tableName
         */    
        getFieldsSuggest(tableName) {
          const fields = this.tables[tableName];
          if (!fields) {
            return [];
          }
          return fields.map((name) => ({
            label: name,
            kind: monaco.languages.CompletionItemKind.Field,
            insertText: name,
          }));
        },
      },
    
      mounted() {
        // 建议在这里把表名和字段名先拿出来
        // ....
        // this.tables = res.data?.data
        // 首先初始化
        this.initAutoCompletion();
        // 初始化编辑器
        this.monacoEditor = monaco.editor.create(document.getElementById("code-editor"), {
          value: this.value, // 初始文字
          language: "sql", // 语言
          readOnly: false, // 是否只读
          automaticLayout: true, // 自动布局
          theme: this.theme, // vs | hc-black | vs-dark
          minimap: {
            enabled: false,// 关闭小地图
          },
          tabSize: 2, // tab缩进长度
          fontSize: 16, // 文字大小
        });
      },
    
      beforeDestroy() {
        // 销毁之前把monaco的实例也销毁了,不然会多次注册
        if (this.monacoEditor) {
          this.monacoEditor.dispose();
        }
      },
    };
    

    结果总结

    以上代码未进行组件封装,只是实现了基本功能

    还可以枚举更多的补全情况,让补全显得更加智能

    当然本文只是简单使用,尚未进行深入,待后续使用到了再继续研究

    相关文章

      网友评论

          本文标题:Vue2的SQL编辑器 - monaco的基本使用

          本文链接:https://www.haomeiwen.com/subject/raqztdtx.html