使用前置安装依赖
{
"@monaco-editor/loader": "1.4.0",
"monaco-editor": "0.50.0",
"monaco-editor-webpack-plugin": "7.1.0",
"sql-formatter": "15.3.2",
"vue": "2.6.14",
"xml-formatter": "3.6.3"
},
webpack配置
const { defineConfig } = require('@vue/cli-service')
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
devtool: 'source-map'//调试模式
},
chainWebpack(config) {
config.plugin("monaco").use(new MonacoWebpackPlugin());
},
});
组件实际代码
<template>
<div class="editor-container">
<button @click="formatF">点我手动触发格式化</button>
<span> </span>
组件内部搜索
<input
v-model="searchText"
@input="searchF(searchText)"
@keypress.enter="searchF(searchText)"
placeholder="输入关键字回车搜索"
/>(可使用ctrl+f快速搜索 支持正则 批量替换等 )
<div class="editor-container" ref="editorContainer"></div>
</div>
</template>
<script>
import * as monaco from "monaco-editor";
import xmlFormat from "xml-formatter"; // xml 格式化库
import { format } from "sql-formatter"; // sql 格式化库
import loader from '@monaco-editor/loader';// 汉化加载器
export default {
name: "MonacoEditor",
props: {
value: {
type: String,
required: true,
},
language: {
type: String,
default: "javascript",
},
theme: {
type: String,
default: "vs-dark",
},
readOnly: {
type: Boolean,
default: false,
},
},
data() {
return {
editor: null, // 编辑器实例
searchText: "", // 搜索框输入内容
lastSearch: "", // 记录上一次搜索的关键字
searchIndex: 0, // 记录上一次搜索的索引
};
},
watch: {
language(v) {
monaco.editor.setModelLanguage(this.editor.getModel(), v);
},
theme(v) {
this.editor.updateOptions({
theme: v,
});
},
readOnly(v) {
this.editor.updateOptions({ readOnly: v });
},
},
async mounted() {
await this.initMonaco();
},
methods: {
async initMonaco() {
// 设置语言为中文并加载语言包
loader.config({ 'vs/nls': { availableLanguages: { '*': 'zh-cn' } } }); // availableLanguages中可以配置想要的语言,例如de、zh-cn等
let monacoNow = await loader.init(); // 加载monaco编辑器
this.editor = monacoNow.editor.create(this.$refs.editorContainer, {
value: this.value,
language: this.language,
automaticLayout: true, // 自动调整大小
minimap: {
enabled: false, // 关闭 右侧minimap
},
readOnly: this.readOnly,
scrollBeyondLastLine: false, // 用滚动到最后一行后继续滚动的功能 开启后会导致滚动条可以滚动到代码在页面上只显示一行
theme: this.theme,
wordWrap: "on", // 自动换行
contextmenu: true, // 禁用右键菜单 后续可拓展自定义右键命令 等
// formatOnType: true, // 输入时格式化
// formatOnPaste: true, // 粘贴时格式化
});
// json和html自带格式化不用额外写 后续有其他语言支持可以再补充
// 为 SQL 注册格式化器
monacoNow.languages.registerDocumentFormattingEditProvider("sql", {
provideDocumentFormattingEdits: (model) => {
const formatted = format(model.getValue(), {
language: "plsql", // 默认一种语言
});
return [
{
range: model.getFullModelRange(),
text: formatted,
},
];
},
});
// 为 XML 注册格式化器 对应的格式化方法需要增加trycatch
monacoNow.languages.registerDocumentFormattingEditProvider("xml", {
provideDocumentFormattingEdits: (model) => {
let valueOld = model.getValue();
let formatted = "";
try {
formatted = xmlFormat(model.getValue(), {
collapseContent: true,
});
} catch (error) {
console.log(error);
formatted = valueOld;
}
return [
{
range: model.getFullModelRange(),
text: formatted,
},
];
},
});
// 监听输入内容变化实现v-model双向绑定
this.editor.getModel().onDidChangeContent(() => {
this.$emit("input", this.editor.getValue());
});
},
/**
* 格式化函数
*
* @description 主动触发格式化命令
* @returns 无返回值
*/
formatF() {
// 主动触发格式化命令 格式化在只读不能使用 所以先改为编辑后 格式化完了 再改回原来的只读状态
// const commands = this.editor.getActions();
// console.log("Available commands:"); //获取当前支持的命令getAction 后run()可以手动触发
this.editor.updateOptions({ readOnly: false });
this.editor
.getAction("editor.action.formatDocument")
.run()
.then(() => {
this.editor.updateOptions({ readOnly: this.readOnly });
});
},
/**
* 在编辑器中搜索指定内容
* @description 支持查询结果循环选中 可在编辑器焦点时使用ctrl+f 功能更全 包括但不限于 搜索框快速搜索 支持正则 批量替换等
* @param v 要搜索的内容
* @returns 无返回值
*/
searchF(v) {
const model = this.editor.getModel();
const matches = model.findMatches(v, true, false, false, null, true);
if (matches.length > 0) {
if (
this.lastSearch === v &&
this.searchIndex !== matches.length - 1 // 匹配到最后一个时,下次搜索从头开始
) {
this.searchIndex++;
} else {
this.searchIndex = 0;
}
const match = matches[this.searchIndex];
this.editor.setSelection(match.range);
this.editor.revealRangeInCenter(match.range);
}
this.lastSearch = v;
},
},
/**
* 组件销毁前钩子函数
*
* @description 在组件销毁前,释放编辑器资源
*/
beforeDestroy() {
if (this.editor) {
this.editor.dispose();
}
},
};
</script>
<style>
.editor-container {
width: 100%;
height: 100%;
}
</style>
最后效果
录屏2024-08-06 11.46.52
注意事项
如果你的产品环境是不能连接外网的,无法加载外链的情况时 @monaco-editor/loader默认会加载cdn的js链接加载,需要根据它提供的配置 自己在项目中或者服务器放引用的文件
配置文档
import loader from '@monaco-editor/loader';
loader.config({ paths: { vs: '../path-to-monaco' } });