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

时间:2024-04-15 07:20:40
<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>