Vue3 + Element Plus 集成 JSON Editor 实现实时校验 JSON 编辑器(高亮/暗亮主题/分栏回显/组件复用) - 附完整示例

在中后台管理系统、配置中心、接口联调等开发场景中,传统原生 <textarea> 仅支持纯文本录入,难以实现语法高亮、括号匹配与实时校验,JSON 格式错误往往要提交后才暴露。而社区常见 JSON 编辑方案样式固化、暗色适配差、缺乏即时回显,无法满足中后台高阶交互需求。针对以上痛点,本文基于 Vue3 + TypeScript + @axolo/json-editor-vue 进行深度封装,通过组件化抽离、失焦解析回显、左右分栏数据展示与暗/亮主题切换,实现带语法高亮的实时校验 JSON 编辑器,接到你自己的 Vue3 中后台项目里基本开箱即用。

效果

最终实现适配中后台管理系统的 JSON 编辑器效果,包含 CodeMirror 6 语法高亮、暗/亮主题一键切换、左右分栏实时数据回显、边敲边校验与红色告警、格式化/复制/重置工具栏,具备窗口自适应缩放、组件独立封装复用、TypeScript 类型补丁等特性。

一、介绍

1、官方包主页

@axolo/json-editor-vue 是一个基于 CodeMirror 6 的极简 JSON 编辑组件,开箱即用、样式随包自动注入,无需手动引入 CSS。包分发与版本信息可参考 npm / jsDelivr:

2、源码仓库

组件底层基于 CodeMirror 6,源码与示例持续维护于 GitHub,可自行阅读实现细节或提 Issue:

3、实现效果亮点

  • **语法高亮与括号匹配:**基于 CodeMirror 6 引擎,内置行号、括号匹配与 JSON 语法高亮,编辑体验接近专业 IDE
  • 暗/亮主题一键切换: 内置 oneDark 暗色主题,通过 dark 属性开关即用,亮色适配浅色后台页面
  • 实时校验: 监听库内部编辑器实例的 input 事件,在每次按键后立即解析当前文本,非法时实时弹出红色告警,避免把错误 JSON 提交到后端
  • **左右分栏实时回显:**左侧编辑、右侧实时回显解析后的数据,JSON 非法时右侧弹出红色告警,所见即所得
  • 组件化抽离复用: 页面独立封装于 src/components/JsonEditor,菜单、文案、类型声明解耦,业务层仅需挂载即可使用
  • **TypeScript 类型补丁:**补充模块声明后自带语法提示,规避 vue-tsc 类型报错,代码更规范健壮
  • **自适应布局适配:**基于 Element Plus 栅格与弹性布局,移动端自动上下堆叠,宽屏左右分栏
  • 样式零配置注入: 包的 dist 已自动引入 CSS,无需手动 import 样式文件

二、准备工作

1、安装依赖包

项目需安装 @axolo/json-editor-vue 核心依赖,底层 CodeMirror 相关依赖(@codemirror/lang-json、@codemirror/theme-one-dark)会随包自动拉取:

复制代码
# 安装核心依赖
npm i @axolo/json-editor-vue

2、示例版本

本文组件适配技术版本如下,兼容性稳定、可直接用于生产:

复制代码
{
  "@axolo/json-editor-vue": "^0.3.2",
  "element-plus": "^2.10.2",
  "vue": "^3.5.17",
  "typescript": "^5.8.3",
  "vite": "^6.3.5"
}

三、使用步骤

1、在单页面引入组件

采用分层引入方案,业务组件直接引入 @axolo/json-editor-vue 核心模块与 Element Plus 图标资源,配合 Vue3 响应式 API 完成状态管理与事件绑定。路由层面通过懒加载异步引入页面组件,降低首屏加载压力。

复制代码
import { ref, computed } from 'vue'
import JsonEditor from '@axolo/json-editor-vue'
import { Document, CopyDocument, RefreshLeft } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

注:上面的代码会引入 json-editor-vue 组件及其底层 CodeMirror 6 依赖。如果你项目里 vite-plugin-components / unplugin-vue-components 已经自动生成了组件类型,跳过后续类型声明步骤也行;手写声明最稳。

2、指定容器并设置布局结构

采用双层容器结构,外层为业务布局容器(顶部工具栏 + 左右分栏编辑区),内层为编辑器渲染 DOM 容器。通过 Element Plus 栅格系统与 Tailwind CSS 原子类实现自适应宽高与响应式布局,内置深色预览面板提升视觉质感。

外层业务布局容器定义:

复制代码
<template>
  <div class="json-editor-page">
    <!-- 顶部操作区 -->
    <el-card shadow="never" class="mb-4">
      <div class="flex items-center justify-between flex-wrap gap-3">
        <div class="min-w-0">
          <h2 class="text-lg font-semibold text-gray-800">JSON 编辑器</h2>
          <p class="text-sm text-gray-500 mt-1 leading-relaxed">
            基于 CodeMirror 6 的轻量 JSON 编辑组件(@axolo/json-editor-vue),支持语法高亮、暗色主题与实时校验。
          </p>
        </div>
        <div class="flex items-center gap-3 flex-wrap">
          <el-switch v-model="isDark" inline-prompt active-text="暗色" inactive-text="亮色"
            style="--el-switch-on-color: #409eff" @change="syncJsonFromRaw" />
          <el-button type="primary" :icon="Document" @click="handleFormat">格式化</el-button>
          <el-button :icon="CopyDocument" @click="handleCopy">复制</el-button>
          <el-button :icon="RefreshLeft" @click="handleReset">重置</el-button>
        </div>
      </div>
    </el-card>

    <!-- 编辑区 + 预览区 -->
    <el-row :gutter="16">
      <el-col :xs="24" :lg="14" class="mb-4 lg:mb-0">
        <el-card shadow="never" :body-style="{ padding: '0' }" class="h-full">
          <JsonEditor ref="editorRef" :key="editorKey" v-model="json" :codec="true" :dark="isDark"
            placeholder="请输入 JSON 格式的数据" />
        </el-card>
      </el-col>
      <el-col :xs="24" :lg="10">
        <el-card shadow="never" header="实时数据" class="h-full">
          <!-- 校验状态 + 数据预览 -->
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

3、数据处理(关键点)

1)模块类型声明补丁

该包当前版本未携带 .d.ts 类型声明,直接 import 会在 vue-tsc 阶段报「找不到模块」。在已有的 src/shims-vue.d.ts 末尾补一段模块声明即可,自带语法提示:

复制代码
// @axolo/json-editor-vue 当前版本未携带 TS 类型声明,补充模块声明以保证类型检查通过
declare module '@axolo/json-editor-vue' {
  import type { DefineComponent } from 'vue'
  const JsonEditor: DefineComponent<{
    modelValue?: any
    placeholder?: string
    readonly?: boolean
    dark?: boolean
    codec?: boolean | any[]
    format?: boolean | ((json: any) => any)
    extensions?: any[]
  }>
  export default JsonEditor
}

2)编辑器初始化与状态管理

通过 codec=true 模式让 v-model 直接绑定 JS 对象而非字符串,组件内部负责 JSON.stringify / JSON.parse 编解码。默认数据采用对象形态,包含多层嵌套结构以完整展示语法高亮效果,支持自定义替换后端接口数据;实时文本 rawText 由编辑器每次内容变化时同步驱动,作为预览与校验的唯一可信源:

复制代码
// 深拷贝工具(避免使用 structuredClone 以兼容更多运行环境)
const clone = <T,>(value: T): T => JSON.parse(JSON.stringify(value)) as T

// 默认 JSON 数据(对象形态,配合 codec=true 使用)
const defaultJson = {
  required: true,
  message: '请输入内容',
  options: ['email', 'phone'],
  rules: { min: 6, max: 20 }
}

const initialText = JSON.stringify(clone(defaultJson), null, 2)

// codec=true 时,v-model 绑定的是 JS 对象;rawText 是编辑器实时写入的当前文本
const json = ref<any>(clone(defaultJson))
const isDark = ref<boolean>(false)

// 库组件实例:其内部维护着真正创建的 CodeMirror EditorView(见 editorRef.value.editor)
const editorRef = ref<any>(null)
const rawText = ref<string>(initialText)

// 切换暗色时强制重建编辑器以应用主题
const editorKey = computed(() => (isDark.value ? 'dark' : 'light'))

3)实时解析与回显派生

@axolo/json-editor-vue 只在 onblur 时回写 v-model 并触发 change / error,预览与复制都会卡在"上一次失焦"那一刻。最初尝试用 CodeMirror 的 updateListener 扩展(extensions prop)实时取文本,实测发现并不生效------原因是该库的 dist 打包时内联了一份 @codemirror/view,外部传入的扩展属于另一份实例,facet 不匹配会被静默忽略,预览与复制依旧停留在初始值。稳妥的解法是绕开扩展机制:用 ref 拿到库组件实例,直接监听其内部 EditorView.contentDOMinput 事件同步文本。注意 input 触发时 CodeMirror 的 state.doc 还是异步更新的旧值,同步读会丢字,所以改从 DOM 行节点(.cm-line)重建文本------DOM 在输入瞬间即最新,快速连续输入也不丢内容。预览与错误信息由 computedrawText 实时派生,做到「边敲边看」:

复制代码
// 实时解析:每次 rawText 变化都重算;非法时直接抛错让上层渲染告警
const parsed = computed<{ ok: boolean; value?: any; error?: string }>(() => {
  try {
    return { ok: true, value: JSON.parse(rawText.value) }
  } catch (e) {
    return { ok: false, error: (e as Error).message }
  }
})

const previewText = computed(() =>
  parsed.value.ok
    ? JSON.stringify(parsed.value.value, null, 2)
    : rawText.value
)

const errorMsg = computed(() => (parsed.value.ok ? '' : parsed.value.error || 'JSON 格式有误'))

// ------ 实时同步的核心(绕开 extensions 机制)------
// 直接拿库内部创建的 EditorView 实例,监听 contentDOM 的 input 事件。
// input 触发时 DOM 已是最新,而 state.doc 是异步更新的旧值(同步读会丢字),
// 因此从 .cm-line 行节点重建文本,快速连续输入也不丢内容。
const syncFromEditor = () => {
  const ed = editorRef.value?.editor
  if (ed) {
    const lines = ed.contentDOM.querySelectorAll('.cm-line')
    const text = Array.from(lines, (l) => (l as HTMLElement).textContent || '').join('\n')
    if (text !== rawText.value) rawText.value = text
  }
}

const bindEditorListener = () => {
  const ed = editorRef.value?.editor
  if (ed && !ed.__jsonSyncBound) {
    ed.__jsonSyncBound = true
    ed.contentDOM.addEventListener('input', syncFromEditor)
  }
}

// 兜底轮询:setup 执行即启动,即使 HMR 保留旧实例 / input 监听未绑定,
// 也能在 150ms 内把 DOM 最新文本同步到 rawText,保证预览、复制、格式化永远基于当前内容。
let syncTimer: ReturnType<typeof setInterval> | null = null
const startSyncPolling = () => {
  if (syncTimer) return
  syncTimer = setInterval(syncFromEditor, 150)
}
startSyncPolling()

// 子组件(库组件)先于父组件完成 mounted,此时 editor 已就绪,可直接绑定
onMounted(bindEditorListener)

onBeforeUnmount(() => {
  if (syncTimer) {
    clearInterval(syncTimer)
    syncTimer = null
  }
})

// 暗色切换时 :key 重建库组件,ref 指向新实例 → 重新绑定监听(post:确保新实例已挂载完成)。
// immediate:true 兜底任何时序问题(HMR / 父组件复用等场景)。
watch(editorRef, () => bindEditorListener(), { flush: 'post', immediate: true })

4)暗色主题切换机制

主题(oneDark)仅在 mounted 时决定,运行时改 dark 不会即时换肤。解决方法是用 :key 绑定暗色状态,切换时让组件重挂载------代价只是丢失当前光标位置,对"切主题"这个动作完全可接受。为避免重建前丢掉未失焦的编辑,@change 回调里先做一次"实时文本 → json"的同步:

复制代码
// 切换暗色时强制重建编辑器以应用主题;重建前会先把当前文本同步进 json
const editorKey = computed(() => (isDark.value ? 'dark' : 'light'))

// 切换主题前:把当前编辑器文本同步进 json;若内容非法则放弃未提交编辑,回退到上一份有效内容
const syncJsonFromRaw = () => {
  try {
    const parsed = JSON.parse(rawText.value)
    json.value = parsed
    rawText.value = JSON.stringify(parsed, null, 2)
  } catch {
    rawText.value = JSON.stringify(json.value, null, 2)
  }
}

5)工具方法封装

内置格式化、复制到剪贴板、重置三项工具操作,开箱即用,无需业务层额外封装。复制走 rawText,保证你修改了啥就复制啥;格式化基于实时文本重新解析后回写,非法输入时直接拒绝。注意:格式化 / 重置是程序化回写(不触发 input 事件),所以回写后要手动同步一次 rawText

复制代码
// 格式化:基于当前实时文本解析后,以 2 空格缩进回写;程序化 dispatch 不触发 input,手动同步 rawText
const handleFormat = () => {
  const p = parsed.value
  if (!p.ok) {
    ElMessage.error('当前 JSON 格式有误,无法格式化:' + (p.error || ''))
    return
  }
  json.value = clone(p.value)
  rawText.value = JSON.stringify(p.value, null, 2)
  ElMessage.success('已格式化')
}

const handleReset = () => {
  json.value = clone(defaultJson)
  rawText.value = initialText
  ElMessage.success('已重置为默认数据')
}

const handleCopy = async () => {
  try {
    await navigator.clipboard.writeText(rawText.value)
    ElMessage.success('已复制当前编辑器内容')
  } catch {
    ElMessage.error('复制失败,请手动复制')
  }
}

四、完整可复用源码

1、JSON 编辑器业务组件 @/components/JsonEditor/Index.vue

复制代码
<template>
  <div class="json-editor-page">
    <!-- 顶部操作区 -->
    <el-card shadow="never" class="mb-4">
      <div class="flex items-center justify-between flex-wrap gap-3">
        <div class="min-w-0">
          <h2 class="text-lg font-semibold text-gray-800">JSON 编辑器</h2>
          <p class="text-sm text-gray-500 mt-1 leading-relaxed">
            基于 CodeMirror 6 的轻量 JSON 编辑组件(@axolo/json-editor-vue),支持语法高亮、暗色主题与实时校验。
          </p>
        </div>
        <div class="flex items-center gap-3 flex-wrap">
          <el-switch
            v-model="isDark"
            inline-prompt
            active-text="暗色"
            inactive-text="亮色"
            style="--el-switch-on-color: #409eff"
            @change="syncJsonFromRaw"
          />
          <el-button type="primary" :icon="Document" @click="handleFormat">格式化</el-button>
          <el-button :icon="CopyDocument" @click="handleCopy">复制</el-button>
          <el-button :icon="RefreshLeft" @click="handleReset">重置</el-button>
        </div>
      </div>
    </el-card>

    <!-- 编辑区 + 预览区 -->
    <el-row :gutter="16">
      <el-col :xs="24" :lg="14" class="mb-4 lg:mb-0">
        <el-card shadow="never" :body-style="{ padding: '0' }" class="h-full">
          <!--
            key 绑定 isDark:组件在 mounted 时才应用主题,
            切换暗色时通过变更 key 强制重建编辑器,从而即时生效。
          -->
          <JsonEditor
            ref="editorRef"
            :key="editorKey"
            v-model="json"
            :codec="true"
            :dark="isDark"
            placeholder="请输入 JSON 格式的数据"
          />
        </el-card>
      </el-col>

      <el-col :xs="24" :lg="10">
        <el-card shadow="never" header="实时数据" class="h-full">
          <el-alert
            v-if="errorMsg"
            type="error"
            :closable="false"
            show-icon
            title="JSON 解析失败"
            :description="errorMsg"
            class="mb-3"
          />
          <el-alert
            v-else
            type="success"
            :closable="false"
            show-icon
            title="JSON 格式有效"
            class="mb-3"
          />
          <pre class="preview">{{ previewText }}</pre>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts" name="jsonEditor">
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import JsonEditor from '@axolo/json-editor-vue'
import { Document, CopyDocument, RefreshLeft } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// 深拷贝工具(避免使用 structuredClone 以兼容更多运行环境)
const clone = <T,>(value: T): T => JSON.parse(JSON.stringify(value)) as T

// 默认 JSON 数据(对象形态,配合 codec=true 使用)
const defaultJson = {
  required: true,
  message: '请输入内容',
  options: ['email', 'phone'],
  rules: { min: 6, max: 20 }
}

const initialText = JSON.stringify(clone(defaultJson), null, 2)

// codec=true 时,v-model 绑定的是 JS 对象而非字符串;主要用于「格式化 / 重置」时把新值回写进编辑器
const json = ref<any>(clone(defaultJson))
const isDark = ref<boolean>(false)

// 库组件实例:其内部维护着真正创建的 CodeMirror EditorView(见 editorRef.value.editor)
const editorRef = ref<any>(null)

// 实时文本:每次编辑器内容变化后立即同步,作为预览与校验的唯一可信源
const rawText = ref<string>(initialText)

// 切换暗色时强制重建编辑器以应用主题;重建前会先把当前文本同步进 json,避免丢失未提交的编辑
const editorKey = computed(() => (isDark.value ? 'dark' : 'light'))

// 以 rawText 为唯一可信源:实时解析、派生预览与错误信息
const parsed = computed<{ ok: boolean; value?: any; error?: string }>(() => {
  try {
    return { ok: true, value: JSON.parse(rawText.value) }
  } catch (e) {
    return { ok: false, error: (e as Error).message }
  }
})

const previewText = computed(() =>
  parsed.value.ok
    ? JSON.stringify(parsed.value.value, null, 2)
    : rawText.value
)

const errorMsg = computed(() => (parsed.value.ok ? '' : parsed.value.error || 'JSON 格式有误'))

// ------ 实时同步的核心(绕开 extensions 机制)------
// @axolo/json-editor-vue 的 dist 打包时内联了一份 @codemirror/view;
// 若通过 extensions prop 传入 updateListener,它属于另一份实例,facet 不匹配会被静默忽略,
// 表现为「预览/复制永远停留在初始值」。因此这里直接拿库内部创建的 EditorView 实例,
// 监听其 contentDOM 的 input 事件。input 触发时 DOM 已是最新,而 state.doc 是异步更新的
// 旧值(同步读会丢字),故从 .cm-line 行节点重建文本,快速连续输入也不丢内容。
const syncFromEditor = () => {
  const ed = editorRef.value?.editor
  if (ed) {
    const lines = ed.contentDOM.querySelectorAll('.cm-line')
    const text = Array.from(lines, (l) => (l as HTMLElement).textContent || '').join('\n')
    if (text !== rawText.value) rawText.value = text
  }
}

const bindEditorListener = () => {
  const ed = editorRef.value?.editor
  if (ed && !ed.__jsonSyncBound) {
    ed.__jsonSyncBound = true
    ed.contentDOM.addEventListener('input', syncFromEditor)
  }
}

// 兜底轮询:setup 执行即启动,即使 HMR 保留旧实例 / input 监听未绑定,
// 也能在 150ms 内把 DOM 最新文本同步到 rawText,保证预览、复制、格式化永远基于当前内容。
let syncTimer: ReturnType<typeof setInterval> | null = null
const startSyncPolling = () => {
  if (syncTimer) return
  syncTimer = setInterval(syncFromEditor, 150)
}
startSyncPolling()

// 子组件(库组件)先于父组件完成 mounted,此时 editor 已就绪,可直接绑定
onMounted(bindEditorListener)

onBeforeUnmount(() => {
  if (syncTimer) {
    clearInterval(syncTimer)
    syncTimer = null
  }
})

// 暗色切换时 :key 重建库组件,ref 指向新实例 → 重新绑定监听(post:确保新实例已挂载完成)。
// immediate:true 兜底任何时序问题(HMR / 父组件复用等场景)。
watch(editorRef, () => bindEditorListener(), { flush: 'post', immediate: true })

// 切换主题前:把当前编辑器文本同步进 json;若内容非法则放弃未提交编辑,回退到上一份有效内容
const syncJsonFromRaw = () => {
  try {
    const parsed = JSON.parse(rawText.value)
    json.value = parsed
    rawText.value = JSON.stringify(parsed, null, 2)
  } catch {
    rawText.value = JSON.stringify(json.value, null, 2)
  }
}

// 格式化:基于当前实时文本解析后,以 2 空格缩进回写;程序化 dispatch 不触发 input,手动同步 rawText
const handleFormat = () => {
  const p = parsed.value
  if (!p.ok) {
    ElMessage.error('当前 JSON 格式有误,无法格式化:' + (p.error || ''))
    return
  }
  json.value = clone(p.value)
  rawText.value = JSON.stringify(p.value, null, 2)
  ElMessage.success('已格式化')
}

const handleReset = () => {
  json.value = clone(defaultJson)
  rawText.value = initialText
  ElMessage.success('已重置为默认数据')
}

const handleCopy = async () => {
  try {
    await navigator.clipboard.writeText(rawText.value)
    ElMessage.success('已复制当前编辑器内容')
  } catch {
    ElMessage.error('复制失败,请手动复制')
  }
}
</script>

<style scoped>
.json-editor-page {
  padding: 16px;
}
.preview {
  margin: 0;
  max-height: 460px;
  overflow: auto;
  background: #0f172a;
  color: #e2e8f0;
  border-radius: 8px;
  padding: 12px;
  font-size: 13px;
  line-height: 1.6;
  font-family: Consolas, 'Courier New', monospace;
  white-space: pre;
}
/* 让编辑器与卡片融为一体 */
:deep(.axolo-json-editor) {
  border: none;
  border-radius: 0;
}
:deep(.axolo-json-editor .editor .cm-editor) {
  min-height: 460px;
}
:deep(.axolo-json-editor .editor .cm-scroller) {
  font-family: Consolas, 'Courier New', monospace;
}
</style>

补充说明

  1. 本组件页面样式基于 Element Plus + Tailwind CSS 原子类开发,若无相关依赖,可直接替换为原生 CSS 样式,不影响编辑器的语法高亮、主题切换、数据解析与实时回显等核心功能与交互逻辑;Tailwind CSS 可参考:CSS框架 - Tailwind CSS - 附示例-CSDN博客。
  2. 本示例基于 @axolo/json-editor-vue v0.3.2 开发,底层依托 CodeMirror 6 开源编辑引擎强劲能力,支持语法高亮、括号匹配、行号显示等特性,可放心用于各类正式项目。编辑器配色、主题切换、预览面板样式等参数均支持自定义拓展,可快速适配不同风格的中后台管理系统界面主题。
  3. 组件完全解耦、复用性极强,基于 Vue3 + TS 完整类型约束开发,支持父组件动态传参(通过 v-model 双向绑定),搭配深度监听逻辑,可实现数据变更实时刷新预览,兼容性优异,可直接复用至任意 Vue3 + Vite + TS 技术栈项目。
  4. format 属性当前版本仍为 TODO 状态,官方尚未实现内置格式化功能;本文通过「重新赋值 ref → 触发组件内部 watch → 以 2 空格缩进重写文档」的方式绕行实现,简单可靠,效果一致。

五、核心模块解析

1、编辑器集成核心优化

  • 通过 key 绑定暗色状态,切换主题时强制重建编辑器实例,规避 CodeMirror 仅在 mounted 应用主题的限制,实现暗/亮即时换肤
  • 样式随包自动注入,无需手动 import CSS,Vite 构建时由 dist/index.js 内联引入,零配置接入
  • 补充 shims-vue.d.ts 模块声明,规避 vue-tsc「找不到模块」报错,组件调用自带语法提示
  • codec=truev-model 直接绑定 JS 对象,组件内部负责 JSON.stringify / JSON.parse,业务层无需手动编解码

2、实时解析回显核心亮点

  • 实时解析回显:监听库内部编辑器实例的 input 事件 + Vue computed,在每次按键后即时解析 rawText,派生预览文本与错误状态,非法 JSON 立即弹红色告警
  • 左右分栏实时回显:右侧面板随编辑结果同步刷新,JSON 非法时弹出红色 el-alert 告警,合法时显示绿色提示,所见即所得
  • 工具方法齐备:内置格式化、复制到剪贴板、重置为默认数据,开箱即用,无需业务层额外封装
  • 暗色切换零丢失:仅丢失当前光标位置,对「切主题」动作完全可接受,无副作用

六、性能优化方案

  • **组件复用:**编辑器封装为独立业务组件,全站统一复用,消除重复样板代码
  • **按需加载:**路由懒加载异步引入页面,减少首屏 JS 打包体积
  • **自适应布局:**Element Plus 栅格 + 弹性布局,移动端自动上下堆叠,宽屏左右分栏,无需额外媒体查询
  • **样式零成本:**CSS 随包注入,无额外样式文件与构建开销
  • **依赖精简:**仅依赖 CodeMirror 轻量内核,无冗余运行时监听,渲染开销低

七、二次扩展适配指南

  • 默认数据替换: 修改 defaultJson,或对接后端接口数据后传入 v-model,自动监听重绘
  • 暗色默认开启:isDark 初始值置为 true,首屏即为暗色编辑器
  • 只读模式: 传入 readonly 属性,适用于展示型场景(如接口响应查看)
  • 自定义编解码:codec 传为 [encode, decode] 数组,实现非标准 JSON 的双向转换
  • 扩展 CodeMirror: 通过 extensions 属性注入额外插件(如搜索、折叠),增强编辑能力
  • 实时校验: 默认即边敲边校验;若想换成"编辑完再校验",可改为监听 rawTextwatch 节流,或直接通过 validate/formatter 自定义

八、总结

本文基于 Vue3 + TypeScript + Element Plus 与 @axolo/json-editor-vue,实现了一套即插即用的 JSON 编辑组件。通过左右分栏、语法高亮、暗/亮主题切换与实时校验,把"写"和"看"拆开,错误在提交后端前就能拦住。组件收在 src/components/JsonEditor 下,菜单、文案、类型各自独立,可直接挂进任意中后台项目。

两点踩坑提醒:该库现版本尚未自带 TS 类型,记得补一份 shims 声明;内置格式化仍是 TODO,不过用「重新赋值触发 watch」这个绕行法实测稳定,可放心用。

欢迎关注:【前端小知识营地】

相关推荐
码云骑士1 小时前
116-Python调用GPT-4V分析图片-Base64编码-多图-JSON结构化输出
开发语言·python·json
斯内普吖2 小时前
(开源)农产品电商系统实战指南 基于 Java + SpringBoot + Vue + MySQL
java·vue.js·spring boot·mysql·开源
daols882 小时前
vue 甘特图 vxe-gantt 紧前紧后依赖关系连接线配置详解
前端·vue.js·甘特图
龙虾PRO14 小时前
大模型稳定输出 JSON 的四层防线:2026 生产环境落地避坑指南
json
剑胆琴心静水深流14 小时前
全栈之路6---web集成与呈现
前端·vue.js·spring boot·分布式·spring·前端框架·npm
迷路爸爸1801 天前
cursor资源管理器修改为与vscode一样的纵向布局
ide·vscode·编辑器
TO_ZRG1 天前
Unity 编辑器之 EditorTool、EditorToolBar、Overlay属性
编辑器
星羽XingYu1 天前
esp32 vscode clangd 无法索引库函数解决方案
ide·vscode·编辑器
北漂燕郊杨哥1 天前
DotMD:一款基于 Go + Wails 的轻量开源 Markdown 桌面编辑器
golang·开源·编辑器·markdown·md