一、背景

之前在做录制回放平台的时候,需要前端展示子调用信息,子调用是一个请求列表数组结构,jsoneditor对数组的默认展示结构是[0].[1].[2]..的方式,为了达到如下的效果,必须用到 onNodeName的钩子函数,因此深入调研了下vue3如何集成jsoneditor

最后做出来的效果图

onNodeName的参考文档 https://github.com/josdejong/jsoneditor/blob/master/docs/api.md

二、参考方案

json-editor-vue3 感谢这位老哥的方案,我看了下源码,没有满足我的需要,核心就是属性需要自己加,因此我拿着他的代码改了下

三、代码实现

安装依赖 jsoneditor

npm install --save jsoneditor

jsoneditor是个开源的js的组件,参考文档 https://github.com/josdejong/jsoneditor

编写组件

目录结构如下

vue3-json-editor.tsx: 其中options的定义是完全参考jsoneditor的api文档的,具体需要什么功能,自己去实现对应的options即可!

import { ComponentPublicInstance, defineComponent, getCurrentInstance, onMounted, reactive, watch } from 'vue'// @ts-ignore// eslint-disable-next-line import/extensionsimport JsonEditor from 'jsoneditor';import 'jsoneditor/dist/jsoneditor.min.css';// eslint-disable-next-line import/prefer-default-exportexport const Vue3JsonEditor = defineComponent({  props: {    modelValue: [String, Boolean, Object, Array],    showBtns: [Boolean],    expandedOnStart: {      type: Boolean,      default: false    },    navigationBar: {      type: Boolean,      default: true    },    mode: {      type: String,      default: 'tree'    },    modes: {      type: Array,      default () {        return ['tree', 'code', 'form', 'text', 'view']      }    },    lang: {      type: String,      default: 'en'    },    onNodeName: {      type: Function,      default: ()=>{}    }  },  setup (props: any, { emit }) {    const root = getCurrentInstance()?.root.proxy as ComponentPublicInstance    const state = reactive({      editor: null as any,      error: false,      json: {},      internalChange: false,      expandedModes: ['tree', 'view', 'form'],      uid: `jsoneditor-vue-${getCurrentInstance()?.uid}`    })    watch(      () => props.modelValue as unknown as any,      async (val) => {        if (!state.internalChange) {          state.json = val          // eslint-disable-next-line no-use-before-define          await setEditor(val)          state.error = false          // eslint-disable-next-line no-use-before-define          expandAll()        }      }, { immediate: true })    onMounted(() => {      //这个options的定义是完全参考jsoneditor的api文档的      const options = {        mode: props.mode,        modes: props.modes,        onChange () {          try {            const json = state.editor.get()            state.json = json            state.error = false            // eslint-disable-next-line vue/custom-event-name-casing            emit('json-change', json)            state.internalChange = true            emit('input', json)            root.$nextTick(function () {              state.internalChange = false            })          } catch (e) {            state.error = true            // eslint-disable-next-line vue/custom-event-name-casing            emit('has-error', e)          }        },        onNodeName(v: object) {          // eslint-disable-next-line vue/custom-event-name-casing            return props.onNodeName(v);        },        onModeChange () {          // eslint-disable-next-line no-use-before-define          expandAll()        },        navigationBar: props.navigationBar      }      state.editor = new JsonEditor(        document.querySelector(`#${state.uid}`),        options,        state.json      )      // eslint-disable-next-line vue/custom-event-name-casing      emit('provide-editor', state.editor)    })    function expandAll () {      if (props.expandedOnStart && state.expandedModes.includes(props.mode)) {        (state.editor as any).expandAll()      }    }    function onSave () {      // eslint-disable-next-line vue/custom-event-name-casing      emit('json-save', state.json)    }    function setEditor (value: any): void {      if (state.editor) state.editor.set(value)    }    return () => {      // @ts-ignore      // @ts-ignore      return (