一:安装monaco-editor
npm install monaco-editor
二:使用
import * as monaco from "monaco-editor";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
三:封装基本组件
<template>
<div class="codemirror">
<div id="monacoEditor" ref="editorRef" class="monaco-editor"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as monaco from "monaco-editor";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
// 定义从父组件接收的属性
const props = defineProps({
options: {
type: Object,
default: () => ({
theme: "dark",
}),
},
sqlCode: {
type: String,
},
});
const emits = defineEmits(["newSqlCode"]);
//解决 Monaco Editor 无法正确加载其所需的 Web Worker
self.MonacoEnvironment = {
getWorker(workerId, label) {
return new editorWorker();
},
};
//初始化
const init = () => {
editor = monaco.editor.create(document.getElementById("monacoEditor"), {
value: props.sqlCode, //值
wordBasedSuggestions: true, // 基于单词的自动完成
autoIndex: true, // 控制是否开启自动索引。当开启时,编辑器会自动创建索引以加速搜索和语义高亮。
fontSize: 14, // 字体大小
language: "sql", //语言
theme: props.options.theme, //主题
readOnly: false, // 是否只读
overviewRulerBorder: false, // 滚动是否有边框
cursorSmoothCaretAnimation: true, // 控制光标平滑动画的开启与关闭。当开启时,光标移动会有平滑的动画效果。
formatOnPaste: true, //设置是否在粘贴文本时自动格式化代码
mouseWheelZoom: true, //设置是否开启鼠标滚轮缩放功能
folding: true, //控制是否开启代码折叠功能
automaticLayout: true, // 控制编辑器是否自动调整布局以适应容器大小的变化
minimap: {
// 关闭代码缩略图
enabled: false, // 是否启用预览图
},
scrollBeyondLastLine: false, // 禁用额外滚动区
scrollbar: {
verticalScrollbarSize: 2, // 垂直滚动条宽度,默认px
horizontalScrollbarSize: 2, // 水平滚动条高度
},
glyphMargin: true, //字形边缘
wordWrap: "on", // 开启自动换行
...props.options,
});
// 监听编辑器内容变化
editor.onDidChangeModelContent(() => {
const value = handleValue();
// 更新父组件的值
emits("newSqlCode", value);
});
};
//获取编辑器的内容
const handleValue = () => {
return editor.getValue();
};
// 组件挂载后创建编辑器实例
onMounted(() => {
init();
});
onBeforeUnmount(() => {
if (editor) {
// 组件卸载前销毁编辑器实例
editor.dispose();
}
});
</script>
<style lang="less" scoped>
.monaco-editor {
height: 300px;
width: 100%;
}
</style>
注意:如果editor是用ref定义的,const editor = ref(null),在调用editor的方法的时候,需要使用toRaw(editor)。否则页面会卡死。
//获取编辑器的内容
const handleValue = () => {
//vue3中直接使用getValue会导致页面卡死,需要使用toRaw(),拿到原始数据,对原始数据进行修改,不会被追踪,不会更新UI界面
return toRaw(editor).getValue();
};
四:实现格式化功能
一:自动格式化
import { format } from "sql-formatter";
//在初始化函数里面
const init = () => {
editor = monaco.editor.create(document.getElementById("monacoEditor"), {
value: props.sqlCode, //值
autoIndex: true, // 控制是否开启自动索引。当开启时,编辑器会自动创建索引以加速搜索和语义高亮。
fontSize: 14, // 字体大小
language: "sql", //语言
theme: props.options.theme, //主题
readOnly: false, // 是否只读
glyphMargin: true, //字形边缘
wordWrap: "on", // 开启自动换行
...props.options,
});
// 监听编辑器内容变化
editor.onDidChangeModelContent(() => {
const value = handleValue();
// 更新父组件的值
emits("newSqlCode", value);
});
/*
* 自动格式化内容。由于放在初始化函数中去执行,有可能出现数据还没传递进来就调用了格式化代码,因此加了个定时器去延时调用。
*/
setTimeout(() => {
editor.setValue(format(editor.getValue()));
}, 0);
}
二:实现右键手动格式化
import { format } from "sql-formatter";
//在初始化函数里面
const init = () => {
editor = monaco.editor.create(document.getElementById("monacoEditor"), {
value: props.sqlCode, //值
autoIndex: true, // 控制是否开启自动索引。当开启时,编辑器会自动创建索引以加速搜索和语义高亮。
fontSize: 14, // 字体大小
language: "sql", //语言
theme: props.options.theme, //主题
readOnly: false, // 是否只读
glyphMargin: true, //字形边缘
wordWrap: "on", // 开启自动换行
...props.options,
});
// 监听编辑器内容变化
editor.onDidChangeModelContent(() => {
const value = handleValue();
// 更新父组件的值
emits("newSqlCode", value);
});
/**
* 添加右键格式化菜单
*/
// 用于控制切换该菜单键的显示
const shouldShowSqlRunnerAction = editor.createContextKey(
"shouldShowSqlRunnerAction",
false
);
// 前面已经定义了 editor
// 添加 action
editor.addAction({
// id
id: "sql-format",
// 该菜单键显示文本
label: "Format SQL",
// 控制该菜单键显示
precondition: "shouldShowSqlRunnerAction",
// 该菜单键位置
contextMenuGroupId: "navigation",
contextMenuOrder: 1.5,
// 点击该菜单键后运行
run: (event) => {
// 格式化代码
editor.setValue(format(editor.getValue()));
},
});
// 显示
shouldShowSqlRunnerAction.set(true);
}
格式化前
格式化后