【功能新增】基于 https://github.com/josdejong/jsoneditor 二次封装 JsonEditor 组件,提供 JSON 编辑器功能

This commit is contained in:
puhui999 2025-03-28 13:54:16 +08:00
parent 7cb4c48d47
commit 6265d6d923
5 changed files with 225 additions and 29 deletions

View File

@ -51,6 +51,7 @@
"fast-xml-parser": "^4.3.2",
"highlight.js": "^11.9.0",
"jsencrypt": "^3.3.2",
"jsoneditor": "^10.1.3",
"lodash-es": "^4.17.21",
"markdown-it": "^14.1.0",
"markmap-common": "^0.16.0",
@ -67,7 +68,6 @@
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0",
"url": "^0.11.3",
"v3-jsoneditor": "^0.0.6",
"video.js": "^7.21.5",
"vue": "3.5.12",
"vue-dompurify-html": "^4.1.4",
@ -85,6 +85,7 @@
"@iconify/json": "^2.2.187",
"@intlify/unplugin-vue-i18n": "^2.0.0",
"@purge-icons/generated": "^0.9.0",
"@types/jsoneditor": "^9.9.5",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.11.21",
"@types/nprogress": "^0.2.3",

View File

@ -86,6 +86,9 @@ importers:
jsencrypt:
specifier: ^3.3.2
version: 3.3.2
jsoneditor:
specifier: ^10.1.3
version: 10.1.3
lodash-es:
specifier: ^4.17.21
version: 4.17.21
@ -134,9 +137,6 @@ importers:
url:
specifier: ^0.11.3
version: 0.11.4
v3-jsoneditor:
specifier: ^0.0.6
version: 0.0.6
video.js:
specifier: ^7.21.5
version: 7.21.6
@ -183,6 +183,9 @@ importers:
'@purge-icons/generated':
specifier: ^0.9.0
version: 0.9.0
'@types/jsoneditor':
specifier: ^9.9.5
version: 9.9.5
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@ -1693,6 +1696,9 @@ packages:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
'@types/ace@0.0.52':
resolution: {integrity: sha512-YPF9S7fzpuyrxru+sG/rrTpZkC6gpHBPF14W3x70kqVOD+ks6jkYLapk4yceh36xej7K4HYxcyz9ZDQ2lTvwgQ==}
'@types/conventional-commits-parser@5.0.1':
resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==}
@ -1804,6 +1810,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/jsoneditor@9.9.5':
resolution: {integrity: sha512-+Wex7QCirPcG90WA8/CmvDO21KUjz63/G7Yk52Yx/NhWHw5DyeET/L+wjZHAeNeNCCnMOTEtVX5gc3F4UXwXMQ==}
'@types/lodash-es@4.17.12':
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
@ -2336,8 +2345,8 @@ packages:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
hasBin: true
ace-builds@1.39.0:
resolution: {integrity: sha512-MqoZojv4gpc5QyTMor/dS6kmruDV9db9LVZbCiT4qYz6WsDiv4qyG5f7ZPc+wjUl6oLMqgCAsBjo1whdSVyMlQ==}
ace-builds@1.39.1:
resolution: {integrity: sha512-HcJbBzx8qY66t9gZo/sQu7pi0wO/CFLdYn1LxQO1WQTfIkMfyc7LRnBpsp/oNCSSU/LL83jXHN1fqyOTuIhUjg==}
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
@ -4069,8 +4078,8 @@ packages:
resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
jsoneditor@9.10.5:
resolution: {integrity: sha512-fVZ0NMt+zm4rqTKBv2x7zPdLeaRyKo1EjJkaR1QjK4gEM1rMwICILYSW1OPxSc1qqyAoDaA/eeNrluKoxOocCA==}
jsoneditor@10.1.3:
resolution: {integrity: sha512-zvbkiduFR19vLMJN1sSvBs9baGDdQRJGmKy6+/vQzDFhx//oEd6WAkrmmTeU4NNk9MAo+ZirENuwbtJXvS9M5g==}
jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
@ -4079,8 +4088,8 @@ packages:
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
engines: {'0': node >= 0.2.0}
jsonrepair@3.1.0:
resolution: {integrity: sha512-idqReg23J0PVRAADmZMc5xQM3xeOX5bTB6OTyMnzq33IXJXmn9iJuWIEvGmrN80rQf4d7uLTMEDwpzujNcI0Rg==}
jsonrepair@3.12.0:
resolution: {integrity: sha512-SWfjz8SuQ0wZjwsxtSJ3Zy8vvLg6aO/kxcp9TWNPGwJKgTZVfhNEQBMk/vPOpYCDFWRxD6QWuI6IHR1t615f0w==}
hasBin: true
katex@0.16.11:
@ -4402,9 +4411,6 @@ packages:
mlly@1.7.3:
resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
mobius1-selectr@2.4.13:
resolution: {integrity: sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==}
moddle-xml@10.1.0:
resolution: {integrity: sha512-erWckwLt+dYskewKXJso9u+aAZ5172lOiYxSOqKCPTy7L/xmqH1PoeoA7eVC7oJTt3PqF5TkZzUmbjGH6soQBg==}
@ -5561,9 +5567,6 @@ packages:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
hasBin: true
v3-jsoneditor@0.0.6:
resolution: {integrity: sha512-9G0sXWXUn67SBkn46ycWfwPwjuJu/lcsQaNzMtXAR2/95hMV21WfcRNsqJ+vVVrSHQehohB/9fVLwYEXz0u/KA==}
vanilla-picker@2.12.3:
resolution: {integrity: sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==}
@ -7334,6 +7337,8 @@ snapshots:
'@trysound/sax@0.2.0': {}
'@types/ace@0.0.52': {}
'@types/conventional-commits-parser@5.0.1':
dependencies:
'@types/node': 20.17.9
@ -7468,6 +7473,11 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/jsoneditor@9.9.5':
dependencies:
'@types/ace': 0.0.52
ajv: 6.12.6
'@types/lodash-es@4.17.12':
dependencies:
'@types/lodash': 4.17.13
@ -7830,7 +7840,7 @@ snapshots:
'@unocss/rule-utils@0.58.9':
dependencies:
'@unocss/core': 0.58.9
magic-string: 0.30.14
magic-string: 0.30.17
'@unocss/rule-utils@66.1.0-beta.5':
dependencies:
@ -8272,7 +8282,7 @@ snapshots:
jsonparse: 1.3.1
through: 2.3.8
ace-builds@1.39.0: {}
ace-builds@1.39.1: {}
acorn-jsx@5.3.2(acorn@8.14.0):
dependencies:
@ -10179,15 +10189,14 @@ snapshots:
espree: 9.6.1
semver: 7.6.3
jsoneditor@9.10.5:
jsoneditor@10.1.3:
dependencies:
ace-builds: 1.39.0
ace-builds: 1.39.1
ajv: 6.12.6
javascript-natural-sort: 0.7.1
jmespath: 0.16.0
json-source-map: 0.6.1
jsonrepair: 3.1.0
mobius1-selectr: 2.4.13
jsonrepair: 3.12.0
picomodal: 3.0.0
vanilla-picker: 2.12.3
@ -10199,7 +10208,7 @@ snapshots:
jsonparse@1.3.1: {}
jsonrepair@3.1.0: {}
jsonrepair@3.12.0: {}
katex@0.16.11:
dependencies:
@ -10550,8 +10559,6 @@ snapshots:
pkg-types: 1.2.1
ufo: 1.5.4
mobius1-selectr@2.4.13: {}
moddle-xml@10.1.0:
dependencies:
min-dash: 4.2.2
@ -11811,10 +11818,6 @@ snapshots:
uuid@10.0.0: {}
v3-jsoneditor@0.0.6:
dependencies:
jsoneditor: 9.10.5
vanilla-picker@2.12.3:
dependencies:
'@sphinxxxx/color-conversion': 2.2.2

View File

@ -0,0 +1,3 @@
import JsonEditor from './src/JsonEditor.vue'
export { JsonEditor }

View File

@ -0,0 +1,109 @@
<template>
<div ref="jsonEditorContainer" class="json-editor" :style="{ height }"></div>
</template>
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import JSONEditor, { JSONEditorMode, JSONEditorOptions } from 'jsoneditor'
import 'jsoneditor/dist/jsoneditor.min.css'
import { JsonEditorEmits, JsonEditorExpose, JsonEditorProps } from '../types'
/** 基于 https://github.com/josdejong/jsoneditor 二次封装组件,提供 JSON 编辑器功能。 */
defineOptions({ name: 'JsonEditor' })
const props = withDefaults(defineProps<JsonEditorProps>(), {
mode: 'tree' as JSONEditorMode,
height: '400px',
showModeSelection: false,
showNavigationBar: false,
showStatusBar: false,
showMainMenuBar: true
})
const emits = defineEmits<JsonEditorEmits>()
const jsonObj = useVModel(props, 'modelValue', emits) as Ref<any>
const jsonEditorContainer = ref<HTMLElement | null>(null)
let jsonEditor: JSONEditor | null = null
//
const height = props.height
// JSONEditor
const initJsonEditor = () => {
if (!jsonEditorContainer.value) return
//
const options: JSONEditorOptions = {
mode: props.mode,
modes: props.showModeSelection
? (['tree', 'code', 'form', 'text', 'view', 'preview'] as JSONEditorMode[])
: undefined,
navigationBar: props.showNavigationBar,
statusBar: props.showStatusBar,
mainMenuBar: props.showMainMenuBar,
onChangeJSON: (json: any) => {
jsonObj.value = json
emits('change', json)
},
onValidationError: (errors: any) => {
emits('error', errors)
},
...props.options
} as JSONEditorOptions
// JSONEditor
jsonEditor = new JSONEditor(jsonEditorContainer.value, options)
//
if (jsonObj.value) {
jsonEditor.set(jsonObj.value)
}
}
//
watch(
() => jsonObj.value,
(newValue) => {
if (!jsonEditor) return
try {
//
const currentJson = jsonEditor.get()
if (JSON.stringify(currentJson) !== JSON.stringify(newValue)) {
jsonEditor.update(newValue)
}
} catch (error) {
console.error('JSON更新失败:', error)
}
},
{ deep: true }
)
//
onMounted(() => {
initJsonEditor()
})
onBeforeUnmount(() => {
if (jsonEditor) {
jsonEditor.destroy()
jsonEditor = null
}
})
//
defineExpose<JsonEditorExpose>({
// 便JSONEditor
getEditor: () => jsonEditor
})
</script>
<style lang="scss" scoped>
/* 隐藏 Ace 编辑器的 powered by ace 标记 */
:deep(.jsoneditor-menu) {
/* 隐藏 powered by ace 标记 */
.jsoneditor-poweredBy {
display: none !important;
}
}
</style>

View File

@ -0,0 +1,80 @@
import { JSONEditorOptions, JSONEditorMode } from 'jsoneditor'
export interface JsonEditorProps {
/**
* JSON数据
*/
modelValue: any
/**
*
* @default 'tree'
*/
mode?: JSONEditorMode
/**
*
* @default '400px'
*/
height?: string
/**
*
* @default false
*/
showModeSelection?: boolean
/**
*
* @default false
*/
showNavigationBar?: boolean
/**
*
* @default true
*/
showStatusBar?: boolean
/**
*
* @default true
*/
showMainMenuBar?: boolean
/**
* JSONEditor配置选项
* @see https://github.com/josdejong/jsoneditor/blob/develop/docs/api.md
*/
options?: Partial<JSONEditorOptions>
}
/**
* JsonEditor组件触发的事件
*/
export interface JsonEditorEmits {
/**
*
*/
(e: 'update:modelValue', value: any): void
/**
*
*/
(e: 'change', value: any): void
/**
*
*/
(e: 'error', errors: any): void
}
/**
* JsonEditor组件暴露的方法
*/
export interface JsonEditorExpose {
/**
* JSONEditor实例
*/
getEditor: () => any
}