vue实现xml,sql,JSON自动格式化高亮

实现xml,json,sql代码组件格式化高亮:

需要下载的依赖:

javascript 复制代码
<template>
	<div class="box">
		<div class="top" v-if="flag">
			<span class="text">Theme:</span>
			<el-select v-model="defaultOptions.theme" placeholder="请选择编辑器主题" class="select" @change="changeTheme">
				<el-option v-for="(theme, index) in themes" :key="index" :label="theme.label"
					:value="theme.value"></el-option>
			</el-select>
			<span class="text">Language:</span>
			<el-select v-model="defaultOptions.language" placeholder="请选择格式化语言" class="select">
				<el-option v-for="(item, index) in languageList" :key="index" :label="item.label" :value="item.value">
				</el-option>
			</el-select>
			<el-button type="primary" plain class="btn" @click="formatCode">格式化</el-button>
			<el-button type="primary" plain class="btn" @click="clearSelection">清空</el-button>
		</div>
		<div :style="{ height, width }" :id="`monacoEditorContainer${index}`" class="container" @mouseleave="handleValue"></div>
	</div>
</template>
 
<script>
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
import 'monaco-editor/esm/vs/editor/contrib/folding/folding.js';
// 代码高亮(将所有支持的语言全部显示)
import 'monaco-editor/esm/vs/basic-languages/monaco.contribution'
import { format } from 'sql-formatter';
import prettyData from 'pretty-data/pretty-data';
// 用于xml语法校验
import xml2js from 'xml2js';


export default {
	props: {
		flag: { //顶部按钮是否显示
			type: Boolean,
			default: true
		},
		options: {
			type: Object,
			default: () => {
			}
		},
		code: {
			type: String,
		},
		height: {
			type: String,
			default: '90%'
		},
		width: {
			type: String,
			default: '100%'
		},
		index: {
			type: String,
			default: "01"
		},
	},
	data() {
		return {
			defaultOptions: {
				value: '', // 编辑器的值
				language: 'xml', //语言
				folding: true, // 是否折叠
				theme: 'vs-dark', // 编辑器主题:vs, hc-black, or vs-dark
				autoIndent: true, // 自动缩进
				wordWrap: 'on', // 启用自动换行
				readOnly: false, // 是否只读
			},
			languageList: [
				{ value: 'sql', label: 'SQL' },
				{ value: 'javascript', label: 'JSON' },
				{ value: 'xml', label: 'XML' },
			],
			themes: [
				{ value: 'vs', label: 'vs' },
				{ value: 'vs-dark', label: 'vs-dark' },
				{ value: 'hc-black', label: 'hc-black' }
			],
			monacoEditor: null
		};
	},
	mounted() {
		this.createMonacoEditor();
	},
	watch: {
		options: {
			handler() {
				this.$nextTick(() => {
					this.monacoEditor.updateOptions(this.standaloneEditorConstructionOptions)
				})
			},
			deep: true
		},
		code: {
			handler(newCode) {
			this.$nextTick(() => {
				// 将新数据显示在monacoEditor上
				this.monacoEditor.setValue(newCode);
				this.formatCode();
			});
			},
			deep: true,
			immediate: true,
		}
	},
	computed: {
		standaloneEditorConstructionOptions() {
			const options = Object.assign(this.defaultOptions, this.options);
			if (options.language.toUpperCase() === "JSON") {
				options.language = "javascript";
			}
			return options;
		}
	},
	methods: {
		formatCode() {
			const code = this.monacoEditor.getValue();
			if (!code.trim() || !this.defaultOptions.language) {
				//  值为空或者语言为空,不执行格式化操作
				return;
			}
			let formattedCode;
			switch (this.defaultOptions.language) {
				case 'sql':
					formattedCode = format(code);
					break;
				case 'javascript':
					try {
						JSON.parse(code); 
						formattedCode = prettyData.pd.json(code);
					} catch (error) {
						this.$message.error(`JSON 解析错误: ${error}`);
						return;
					}
					break;
				case 'xml':
					try {
						// 使用 xml2js 库进行 XML 校验
						const parser = new xml2js.Parser();
						parser.parseString(code, (error) => {
						if (error) {
							this.$message.error(`XML 解析错误: ${error}`);
							// Message.error(`XML 解析错误: ${error}`);
							return;
						}
						});
						formattedCode = prettyData.pd.xml(code);
					} catch (error) {
						return;
					}
					break;
				default:
					return;
			}
			monaco.editor.setModelLanguage(this.monacoEditor.getModel(), this.defaultOptions.language);
			const model = this.monacoEditor.getModel();
			const formattedContent = {
				range: model.getFullModelRange(),
				text: formattedCode,
			};
			this.monacoEditor.executeEdits('format', [formattedContent]);
		},
		createMonacoEditor() {
			const container = document.getElementById(`monacoEditorContainer${this.index}`);
			this.monacoEditor = monaco.editor.create(container, this.standaloneEditorConstructionOptions);
		},
		clearSelection() {
			this.monacoEditor.setValue('');
		},
		changeTheme() {
			monaco.editor.setTheme(this.defaultOptions.theme);
		},
		handleValue() {			
			this.formatCode();
			this.$emit('getValue', this.monacoEditor.getValue())
			// 鼠标失去焦点
			document.activeElement.blur();
		},
	},
};
</script>
 
<style scoped lang="less">
.box {
	width: 100%;
	height: 100%;

	.top {
		margin-bottom: 10px;
		.text {
			margin-right: 4px;
		}

		.btn {
			margin-right: 20px;
			margin-left: 0px;
		}

		.select {
			width: 200px!important;
			margin-right: 20px;
		}
	}

	.container {
		// width: 100%;
		// height: 90%;
		// margin-top: 20px;
	}
}
</style>
 

实现效果:

相关推荐
parade岁月4 小时前
为了给表格加虚拟滚动而选了 vxe-table?也可以考虑下这个
前端·vue.js
鹏多多10 小时前
PC 网站接入微信登录,这 10 个坑我替你踩完了!
前端·javascript·vue.js
染指111014 小时前
103.RAG-LLamaIndex后端rag问答-聊天接口
前端·javascript·vue.js·人工智能
九皇叔叔1 天前
《MySQL 体系架构详解:Server 层、SQL 执行流程与 InnoDB、MyISAM、MEMORY 存储引擎》
sql·mysql·架构
单线程_011 天前
从案例分析 Vue3 Tokenizer+Parser 源码三
前端·javascript·vue.js
jay神1 天前
【计算机毕业设计】基于SpringBoot的程序教学辅助系统
java·前端·vue.js·spring boot·后端·毕业设计·课程设计
OpenTiny社区1 天前
从流式消息到多会话:TinyRobot Kit 如何组织 AI 对话数据层
vue.js
这个DBA有点耶1 天前
SQL:2023新特性详解:JSON_TABLE、GREATEST/LEAST、QUALIFY 到底怎么用?
数据库·sql·mysql
卤蛋fg61 天前
vue表格组件 vxe-table 鼠标滑动表头选择整列与选择整行的配置详解
vue.js
阳火锅1 天前
老板要周报?我说不用,代码提交就是进度
前端·javascript·vue.js