使用 Monaco Editor 开发 SQL 编辑器

2024-04-22 18:20

本文主要是介绍使用 Monaco Editor 开发 SQL 编辑器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

安装

安装依赖,这里请注意版本

yarn add monaco-editor@0.29.1
yarn add monaco-editor-webpack-plugin@5.0.0

配置 webpack 插件

// vue.config.js
...
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')module.export = {...configureWebpack: {name: name,resolve: {alias: {'@': resolve('src'),},},plugins: [new MonacoWebpackPlugin()],},...
}

请注意 monaco-editor-webpack-plugin 和 monaco-editor 的对应关系,否则可能会出现无法运行的情况。

monaco-editor-webpack-pluginmonaco-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.*

简易 SQL 编辑器

先上干货!

<template><div ref="codeContainer" class="editor-container" :style="{ height: height + 'px' }" />
</template><script>
import * as monaco from 'monaco-editor'/*** VS Code 编辑器** 通过 getEditorVal 函数向外传递编辑器即时内容* 通过 initValue 用于初始化编辑器内容。* 编辑器默认 sql 语言,支持的语言请参考 node_modules\monaco-editor\esm\vs\basic-languages 目录下~* 编辑器样式仅有   'vs', 'vs-dark', 'hc-black' 三种*/
export default {name: 'MonacoEditor',props: {initValue: {type: String,default: '',},readOnly: Boolean,language: {type: String,default: 'sql',},height: {type: Number,default: 300,},theme: {type: String,default: 'vs',},},data() {return {monacoEditor: null, // 语言编辑器}},computed: {inputVal() {return this.monacoEditor?.getValue()},},watch: {inputVal() {if (this.monacoEditor) {this.$emit('change', this.monacoEditor.getValue())}},theme() {this.setTheme(this.theme)},height() {this.layout()},},mounted() {this.initEditor()},beforeDestroy() {if (this.monacoEditor) {this.monacoEditor.dispose()}},methods: {initEditor() {if (this.$refs.codeContainer) {this.registerCompletion()// 初始化编辑器,确保dom已经渲染this.monacoEditor = monaco.editor.create(this.$refs.codeContainer, {value: '', // 编辑器初始显示文字language: 'sql', // 语言readOnly: this.readOnly, // 是否只读 Defaults to false | trueautomaticLayout: true, // 自动布局theme: this.theme, // 官方自带三种主题vs, hc-black, or vs-darkminimap: {// 关闭小地图enabled: false,},tabSize: 2, // tab缩进长度})}this.setInitValue()},focus() {this.monacoEditor.focus()},layout() {this.monacoEditor.layout()},getValue() {return this.monacoEditor.getValue()},// 将 initValue Property 同步到编辑器中setInitValue() {this.monacoEditor.setValue(this.initValue)},setTheme() {monaco.editor.setTheme(this.theme)},getSelectionVal() {const selection = this.monacoEditor.getSelection() // 获取光标选中的值const { startLineNumber, endLineNumber, startColumn, endColumn } = selectionconst model = this.monacoEditor.getModel()return model.getValueInRange({startLineNumber,startColumn,endLineNumber,endColumn,})},setPosition(column, lineNumber) {this.monacoEditor.setPosition({ column, lineNumber })},getPosition() {return this.monacoEditor.getPosition()},},
}
</script><style lang="scss" scoped></style>

相关功能

获取选中代码

    getSelectionVal() {const selection = this.monacoEditor.getSelection() // 获取光标选中的值const { startLineNumber, endLineNumber, startColumn, endColumn } = selectionconst model = this.monacoEditor.getModel()return model.getValueInRange({startLineNumber,startColumn,endLineNumber,endColumn,})},

替换选中代码

insertStringInTemplate(str) {const selection = this.monacoEditor.getSelection() // 获取光标选中的值const { startLineNumber, endLineNumber, startColumn, endColumn } = selectionconst model = this.monacoEditor.getModel()const textBeforeSelection = model.getValueInRange({startLineNumber: 1,startColumn: 0,endLineNumber: startLineNumber,endColumn: startColumn,})const textAfterSelection = model.getValueInRange({startLineNumber: endLineNumber,startColumn: endColumn,endLineNumber: model.getLineCount(),endColumn: model.getLineMaxColumn(model.getLineCount()),})this.monacoEditor.setValue(textBeforeSelection + str + textAfterSelection)this.monacoEditor.focus()this.monacoEditor.setPosition({lineNumber: startLineNumber,column: startColumn + str.length,})},

处理光标位置

  setPosition(column, lineNumber) {this.monacoEditor.setPosition({ column, lineNumber })},getPosition() {return this.monacoEditor.getPosition()},

自定义 SQL 库表提示,并保留原有 SQL 提示

首先由后端提供具体的库表信息:

export const hintData = {adbs: ['dim_realtime_recharge_paycfg_range', 'dim_realtime_recharge_range'],dimi: ['ads_adid', 'ads_spec_adid_category'],
}

然后根据已有库表信息进行自定义 AutoComplete

import * as monaco from 'monaco-editor'
import { language } from 'monaco-editor/esm/vs/basic-languages/sql/sql'const { keywords } = languageexport default {...mounted() {this.initEditor()},methods: {...registerCompletion() {const _that = thismonaco.languages.registerCompletionItemProvider('sql', {triggerCharacters: ['.', ...keywords],provideCompletionItems: (model, position) => {let suggestions = []const { lineNumber, column } = positionconst textBeforePointer = model.getValueInRange({startLineNumber: lineNumber,startColumn: 0,endLineNumber: lineNumber,endColumn: column,})const tokens = textBeforePointer.trim().split(/\s+/)const lastToken = tokens[tokens.length - 1] // 获取最后一段非空字符串if (lastToken.endsWith('.')) {const tokenNoDot = lastToken.slice(0, lastToken.length - 1)if (Object.keys(_that.hintData).includes(tokenNoDot)) {suggestions = [..._that.getTableSuggest(tokenNoDot)]}} else if (lastToken === '.') {suggestions = []} else {suggestions = [..._that.getDBSuggest(), ..._that.getSQLSuggest()]}return {suggestions,}},})},// 获取 SQL 语法提示getSQLSuggest() {return keywords.map((key) => ({label: key,kind: monaco.languages.CompletionItemKind.Enum,insertText: key,}))},getDBSuggest() {return Object.keys(this.hintData).map((key) => ({label: key,kind: monaco.languages.CompletionItemKind.Constant,insertText: key,}))},getTableSuggest(dbName) {const tableNames = this.hintData[dbName]if (!tableNames) {return []}return tableNames.map((name) => ({label: name,kind: monaco.languages.CompletionItemKind.Constant,insertText: name,}))},initEditor() {if (this.$refs.codeContainer) {this.registerCompletion()// 初始化编辑器,确保dom已经渲染this.monacoEditor = monaco.editor.create(this.$refs.codeContainer, {value: '', // 编辑器初始显示文字language: 'sql', // 语言readOnly: this.readOnly, // 是否只读 Defaults to false | trueautomaticLayout: true, // 自动布局theme: this.theme, // 官方自带三种主题vs, hc-black, or vs-darkminimap: {// 关闭小地图enabled: false,},tabSize: 2, // tab缩进长度})}this.setValue(this.value)},}
}

编辑器 resize

    resize() {this.monacoEditor.layout()},

编辑器设置主题

注意!设置主题并非在编辑器实例上修改的哦!

    setTheme() {monaco.editor.setTheme(this.theme)},

SQL 代码格式化

编辑器自身不支持 sql 格式化(试了下 JavaScript 是支持的),所以用到了 sql-formatter 这个库。

import { format } from 'sql-formatter'...format() {this.monacoEditor.setValue(format(this.monacoEditor.getValue(), {indentStyle: 'tabularLeft',}),)},
...

右键菜单汉化

需要安装以下两个库

npm install monaco-editor-nls --save
npm install monaco-editor-esm-webpack-plugin --save-dev

具体用法可以直接去 https://www.npmjs.com/package/monaco-editor-esm-webpack-plugin 里面看,我就不搬运了~

记得销毁编辑器对象哦

  beforeDestroy() {if (this.monacoEditor) {this.monacoEditor.dispose()}},

踩坑

下面是我遇到的几个坑。

  • 最新版本的 Monaco Editor 已经使用了 ES2022 的语法,所以老项目可能会出现编译不过的问题。所以我把版本调低了一些。
  • 在最初调试编辑器的时候出现了无法编辑的情况,后来发现是同事用到了 default-passive-events 这个库来关闭 chrome 的 Added non-passive event listener to a scroll-blocking <some> event. Consider marking event handler as 'passive' to make the page more responsive 警告。结果拦截一些 event。

如何快速去看懂 Monaco Editor

一开始我看它的官方文档是非常懵的,各种接口、函数、对象的定义,完全不像是个前端库那么好理解。鼓捣了好久才慢慢找到门路。

  • 先看示例
    • 查看它的 playground,上面其实是有一些功能可以直接找到的。
    • 查看它在 github 上的 /samples 目录,里面也有不少示例。
    • 去掘金这类网站上找别人写的示例,能有不少启发。
  • 再看 API
    • 了解了自己所需要的功能相关的代码,再去看它文档的 API 就会发现容易理解多了。逐步发散理解更多关联功能。

参考资料

  • 官方文档
    • https://microsoft.github.io/monaco-editor/index.html
  • 相关库
    • Monaco Editor https://www.npmjs.com/package/monaco-editor
    • 右键菜单汉化 https://www.npmjs.com/package/monaco-editor-nls
    • webpack 插件 https://www.npmjs.com/package/monaco-editor-webpack-plugin
    • 汉化 webpack 插件 https://www.npmjs.com/package/monaco-editor-esm-webpack-plugin
    • SQL 代码格式化 https://www.npmjs.com/package/sql-formatter
  • 博客
    • https://blog.csdn.net/m0_37986789/article/details/121135519
    • https://juejin.cn/post/6986907628937379871

这篇关于使用 Monaco Editor 开发 SQL 编辑器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/926518

相关文章

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置