基于Vue下的Monaco Editor库用法

133 阅读3分钟

使用场景:项目中需要手动输入SQL字段,根据后台返回字段进行提示

官网地址: dream2023.gitee.io/monaco-edit…

1. index.html 下引用(我使用的是静态文件)

文件位置 node_modules\monaco-editor\min

    <body>
        <div id="app"></div>
        <script defer src="./static/monaco/min/vs/loader.js"></script>
        <script defer>
            window.addEventListener('DOMContentLoaded',function(){
                require.config({ paths: { 'vs': './static/monaco/min/vs' } });
                require(['vs/editor/editor.main'], function () {})
            })
        </script>
    </body>

2. 具体场景使用

<template>
    <div class="sql-editor"></div>
</template>
   
<script>
export default {
    name: 'ExecuteAction',
    data() {
        return {
            KEYWORDS: [
                {
                    label: "*",
                    insertText: "*",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "SELECT",
                    insertText: "SELECT",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "FROM",
                    insertText: "FROM",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "ORDER",
                    insertText: "ORDER",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "BY",
                    insertText: "BY",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "ASC",
                    insertText: "ASC",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "UPDATE",
                    insertText: "UPDATE",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "WHERE",
                    insertText: "WHERE",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "INSERT",
                    insertText: "INSERT",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "MAX",
                    insertText: "MAX",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "MIN",
                    insertText: "MIN",
                    kind: 17,
                    detail: '关键字'
                },
                {
                    label: "SUM",
                    insertText: "SUM",
                    kind: 17,
                    detail: '关键字'
                }
            ],
            DBNAMES: [
               
            ],
            DB_FIELDS: {
              
            }
        }
    },
    mounted() {
        this.ColumnTableName()
        
        // 初始化编辑器
        const container = document.querySelector('.sql-editor')
        this.editor = monaco.editor.create(container, {
            minimap: { enabled: false },
            value: '', // 默认语句
            language: 'sql',
            contextmenu: false, // 禁用右键菜单
            theme: 'BlackTheme', // 自定义主题(默认主题为vs、vs-dask、hc-black)
        })
        // 设置自定义主题
        monaco.editor.defineTheme('BlackTheme', {
            base: 'vs', //指定父级主题
            inherit: true, //继承父级主题中未定义的颜色值
            rules: [{ background: '#000000' }], //高亮规则
            colors: {
                // 相关颜色属性配置
                "editor.background": "#f7f8fa",     //背景色
                "editorWidget.background": "#ffffff",//编辑器组件(如查找/替换)背景颜色。
                "editor.foreground": "#000000", //输入内容的颜色。
                "editorSuggestWidget.background": "#f3f3f3",//代码提示的背景色。
                "list.highlightForeground": "#ff4444",//匹配内容的高亮颜色。
                "list.hoverBackground": "#e3e2e2",//使用鼠标移动时,代码提示中鼠标经过项时的背景颜色。
                "list.activeSelectionBackground": "#0060c0", //代码提示选中项背景颜色。
            }
        });
        
        // 注册代码提示事件
        this.completionItemProvider = monaco.languages.registerCompletionItemProvider('sql', {
            provideCompletionItems: this.CompletionItemKindController,
            triggerCharacters: [' '] // 当输入空格时,自动弹出代码提示
        })
        
       
        // 监听编辑器内容变化
        this.editor.onDidChangeModelContent(() => {
            const newValue = this.editor.getValue()
            this.$emit('changeTextarea', newValue)
            console.log(newValue)
        })

        monaco.editor.setTheme('BlackTheme');
        
    },
    beforeDestroy() {
        if (this.editor) {
            this.editor.dispose()
            this.editor = null
        }
        if (this.completionItemProvider) {
            this.completionItemProvider.dispose()
            this.editor = null
        }
    },
    methods: {
        // 控制代码提示逻辑
        CompletionItemKindController(model, position) {
            console.log(model,position);
            let suggestions = []
            const { lineNumber, column } = position
            const textBeforePointer = model.getValueInRange({
                startLineNumber: lineNumber,
                startColumn: 0,
                endLineNumber: lineNumber,
                endColumn: column,
            })

            const contents = textBeforePointer.trim().split(/\s+/)
            const lastContents = contents[contents?.length - 1] // 获取最后一段非空字符串
            if (lastContents) {
                const lowerContent = lastContents.toLowerCase()

                if (lowerContent === 'from') {
                    // 如果最后输入的字符串是from
                    suggestions = this.copyObj(this.DBNAMES)
                } else if (lowerContent === 'where') {
                    // 如果最后输入的字符串是where

                    // 先找到最后一个from字符串出现后的数据库名称
                    const DBNAMEIDX = contents.findLastIndex((item) => (item.toLowerCase() === 'from'))
                    const DBNAME = contents[DBNAMEIDX + 1]
                    const DBNAME_ARR = DBNAME.split(',')

                    // 根据数据库名称匹配查找字段名
                    let fieldsTmp = []
                    for (let i = 0; i < DBNAME_ARR.length; i++) {
                        const fields = this.DB_FIELDS[DBNAME_ARR[i]]
                        fieldsTmp = fieldsTmp.concat(fields)
                    }
                    suggestions = this.copyObj(fieldsTmp)
                } else {
                    // 其它情况
                    suggestions = this.copyObj(this.KEYWORDS)
                }
            }
            console.log(suggestions) // 代码提示数组
            return {
                suggestions
            }
        },
        // 获取编辑器内容
        GetEditorValue() {
            if (!this.editor) return
            return this.editor.getValue()
        },
        
        // 设置编辑器内容
        SetEditorValue(value) {
            if (!this.editor) return
            this.editor.setValue(value)
        },
        // 拷贝数组对象
        copyObj(obj) {
            return JSON.parse(JSON.stringify(obj))
        }
    }
}
</script>
   
   

注意1

  • KEYWORDS 为默认代码提示语句(根据具体业务)
  • DBNAMES 为一级代码提示
  • DB_FIELDS 为二级代码提示
  • 具体提示方法通过CompletionItemKindController方法处理

注意2

二级代码需要用一级代码的id为键名
举例
DBNAMES = [    {        label: "current_db1",        insertText: "current_catalog_db1",        kind: 1,        detail: '数据库表名'    },]
DB_FIELDS = {
    current_db1:[
        {
            label: "id",
            insertText: "id",
            kind: 3,
            detail: '字段名'
        },
    ]
}