To achieve the effect, the ui library chooses the latest naive-ui library. You can choose the appropriate library according to your needs
1. Install dependencies
npm install vue-codemirror --save
At the same time, install a code editor using sql/javascript language and choose according to your needs.
npm install @codemirror/lang-sql npm install @codemirror/lang-javascript
If you want a black editor theme, you can install it from the command line
npm i @codemirror/theme-one-dark
Format/clear function for SQL code
1. npm install sql-formatter plug-in
npm install sql-formatter --save
2. Introduce the sql-formatter.js file
import sqlFormatter from 'sql-formatter';
2. Encapsulate the public component MyCodeEdit.vue. The complete code is as follows:
<template> <codemirror ref="codeEdit" v-model="sqlCode" :placeholder="editorPlaceholder" :style="{ height: editorHeight + 'px' }" :autofocus="true" :indent-with-tab="true" :tabSize="tabSize" :extensions="extensions" :scrollbarStyle="null" @change="emit('change', $event)" /> <div class="sql-format"> <div class="theme"> <span style="margin-right: 6px">Theme</span> <n-switch :size="'small'" :value="theme" @click="handleTheme"></n-switch> </div> <span @click="formatSql" style="margin: 0 10px">Format SQL</span> <span @click="clearVal">Clear with one click</span> </div> </template> <script setup> import { Codemirror } from "vue-codemirror"; import { sql } from "@codemirror/lang-sql"; import { defineEmits, ref, defineProps, computed, watch } from "vue"; import { NSwitch, NSpace } from "naive-ui"; import * as sqlFormatter from "sql-formatter"; import { oneDark } from "@codemirror/theme-one-dark"; const emit = defineEmits(); const props = defineProps({ value: { type: String, default: "", }, editorPlaceholder: { type: String, default: "Please enter the code", }, editorHeight: { type: String, default: "300", }, tabSize: { type: Number, default: 2, }, }); const codeEdit = ref(); const theme = ref(false); const sqlCode = ref(); watch( () => props.value, () => { sqlCode.value = props.value; }, { immediate: true, deep: true, } ); const extensions = ref([sql()]); function handleTheme() { console.log(theme.value); theme.value = !theme.value; theme.value ? (extensions.value = [sql(), oneDark]) : (extensions.value = [sql()]); } //Code formatting const formatSql = () => { sqlCode.value = sqlFormatter.format(sqlCode.value); }; // clear value const clearVal = () => { sqlCode.value = ""; }; </script> <style scoped lang="scss"> .sql-format { background-color: #f7f7f7; display: flex; justify-content: flex-end; color: #2a99ff; padding: 10px; .theme { display: flex; justify-content: center; align-items: center; } & amp; > span:hover { cursor: pointer; text-decoration: underline; } > span:first-child { margin-right: 10px; } } </style>
3. Used in the page, I use it in the pop-up box and modify it as needed
<template> <n-modal v-model:show="props.show" :show-icon="false" @update:show="$emit('update:show')" preset="dialog" style="width: 80%" :title="title" > <div class="code-editor"> <n-form :model="formParams" :rules="rules" ref="formRef" label-placement="top" :label-width="120" class="py-4" :label-align="'left'" > <n-form-item label="Custom query name" path="sqlName"> <n-input v-model:value="formParams.sqlName" clearable /> </n-form-item> </n-form> <div class="code-label">SQL editing area</div> <sql-code-edit :value="formParams.sqlCode" :editor-placeholder="'Please enter the sql statement'" :editor-height="'300'" :tab-size="4" @change="changeSqlCode" /> </div> <template #action> <n-space> <n-button v-show="view === false" type="primary" :loading="formBtnLoading" @click="confirmForm" >Save</n-button > <n-button @click="emit('update:show')">Cancel</n-button> </n-space> </template> </n-modal> </template> <script lang="ts" setup> import { computed, onBeforeUpdate, onMounted, reactive, ref, watch, withDefaults, unref, onUpdated, watchEffect, } from "vue"; import { useMessage, FormItemRule, TreeSelectOption, NLog, NScrollbar, NText, NH6, NInputNumber, Button, } from "naive-ui"; import { each, cloneDeep, filter, find, groupBy } from "lodash-es"; import SqlCodeEdit from "./coms/MyCodeEdit.vue"; const isEdit = computed(() => !!props.current?.id); const title = computed(() => (isEdit.value ? "Edit" : "New")); const message = useMessage(); interface IProps { show?: boolean; current?: Record<string, any> | null; view?: boolean; params?: any; } const props = withDefaults(defineProps<IProps>(), { show: false, view: false, }); const formRef = ref(); // Child component passes value to parent component const emit = defineEmits<{ (e: "update:show"): void; (e: "reloadTable"): void; }>(); const formParams = reactive<any>({ sqlName: "", sqlCode: "", }); // define form const INIT_MODEL = { id: "", sqlName: "", sqlCode: "", }; // Get sql statements in real time const changeSqlCode = (val: any) => { formParams.sqlCode = val; }; function handleSave() { console.log(formParams); } // Validation rules const rules = { sqlName: { required: true, trigger: ["blur", "input"], message: "Please enter the query name", }, }; const formBtnLoading = ref(false); // form submission function confirmForm(e: any) { e.preventDefault(); formBtnLoading.value = true; formRef.value.validate(async (errors: any) => { if (!errors) { setTimeout(() => { const params = { ...formParams }; console.log(params); emit("update:show"); emit("reloadTable"); }); } else { message.error("Please fill in the complete information"); } formBtnLoading.value = false; }); } watchEffect(() => { if (props.show) { each(INIT_MODEL, (v, field) => { formParams[field] = props.current?.[field]; }); } else { Object.keys(formParams).forEach((item) => { formParams[item] = null; }); } }); </script> <style scoped lang="scss"> .sql-format { background-color: #f7f7f7; text-align: right; color: #2a99ff; padding: 10px; span:hover { cursor: pointer; text-decoration: underline; } > span:first-child { margin-right: 10px; } } </style>