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

请添加图片描述

本项目使用的是
    "monaco-editor": "^0.30.0",
    "monaco-editor-webpack-plugin": "^6.0.0",

vue.config.js中配置

module.exports={
  configureWebpack: {
    plugins: [
      new MonacoWebpackPlugin({
        languages: ['sql', 'javascript', 'typescript', 'html', 'css', 'json', 'java'],
        features: ["coreCommands", "find"]
      })
    ]
  }
}

封装组件

my-monaco-editor.vue

<template>
    <div id="app" style="height: 80vh">
        <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";
// SQL语法校验
import { Parser } from 'node-sql-parser';
// SQL代码格式化
import { format } from 'sql-formatter';
// 从 monaco-editor 的 sql 里面拿到关键字
const { keywords } = language;
export default {
    name: "App",
    data() {
        return {
            // 编辑器实例
            editor: null,
            // 原本已经写入的数据
            value: "SELECT * FROM users;SELECT * FROM roles;",
            // 补全的数据,建议在编辑器初始化之间就请求回来放好
            tables: {
                users: ["name", "id", "email", "phone", "password"],
                roles: ["id", "name", "order", "created_at", "updated_at", "deleted_at"]
            },
            // 编辑器主题
            theme: "vs-dark", // 默认是 "vs"
        };
    },
    mounted() {
        // 建议在这里把表名和字段名先拿出来
        // ....
        // this.tables = res.data?.data
        // 首先初始化
        this.initAutoCompletion();
        // 初始化编辑器
        this.editor = monaco.editor.create(document.getElementById("code-editor"), {
            value: this.value, // 初始文字
            language: "sql", // 语言
            readOnly: false, // 是否只读
            automaticLayout: true, // 自动布局
            disableLayerHinting: true,
            theme: this.theme, // vs | hc-black | vs-dark
            minimap: {
                enabled: false,// 关闭小地图
            },
            // tabSize: 2, // tab缩进长度
            fontSize: 14, // 文字大小
        });
        // 是否开启sql格式化
        const formattedSQL = format(this.editor.getValue());
        this.editor.setValue(formattedSQL);
        // 监听编辑器内容变化
        this.editor.onDidChangeModelContent(() => {
            this.validateSQL(); // 在内容更改时进行语法验证
        });
    },

    beforeDestroy() {
        // 销毁之前把monaco的实例也销毁了,不然会多次注册
        if (this.editor) {
            this.editor.dispose();
        }
    },
    methods: {
        validateSQL() {
            const value = this.editor.getValue();
            const p = new Parser();
            try {
                p.astify(value); // 解析SQL语句
                // 清除之前的错误标记
                monaco.editor.setModelMarkers(this.editor.getModel(), 'sql', []);
            } catch (error) {
                const { line, column } = error.location.start;
                // 创建错误标记
                const marker = {
                    severity: monaco.MarkerSeverity.Error,
                    startLineNumber: line,
                    startColumn: column,
                    endLineNumber: line,
                    endColumn: column + 1,
                    message: error.message,
                };
                // 设置错误标记
                monaco.editor.setModelMarkers(this.editor.getModel(), 'sql', [marker]);
            }
        },
        /**
         * @description: 获取编辑器中填写的值
         */
        getValue() {
            return this.editor.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,
            }));
        },
    }
};
</script>
<style>
.sql-error-decoration {
    border-bottom: 1px solid red;
}
</style>

组件内使用

<template>
    <div>
        <monaco-edito ref="js"></monaco-edito>
        <div>
            <!-- <button @click="runCode">运行</button> -->
        </div>
    </div>
</template>
  
<script>
import MonacoEdito from "@/components/my-monaco-editor.vue";

export default {
    components: {
        MonacoEdito,
    },
    methods: {
        runCode() {
            var js = this.$refs.js.monacoEditor.getValue();
            console.log(js);
        },
    },
};
</script>
  
<style lang="scss" scoped>
</style>
  
GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 4 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐