• vue3集成jsoneditor


    一、背景

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

    最后做出来的效果图 alt

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

    二、参考方案

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

    三、代码实现

    • 安装依赖 jsoneditor
    npm install --save jsoneditor
    • 1

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

    • 编写组件

    目录结构如下 alt

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

    import { ComponentPublicInstance, defineComponent, getCurrentInstance, onMounted, reactive, watch } from 'vue'
    // @ts-ignore
    // eslint-disable-next-line import/extensions
    import JsonEditor from 'jsoneditor';
    import 'jsoneditor/dist/jsoneditor.min.css';
    // eslint-disable-next-line import/prefer-default-export
    export const Vue3JsonEditor = defineComponent({
      props: {
        modelValue: [StringBooleanObjectArray],
        showBtns: [Boolean],
        expandedOnStart: {
          typeBoolean,
          defaultfalse
        },
        navigationBar: {
          typeBoolean,
          defaulttrue
        },
        mode: {
          typeString,
          default'tree'
        },
        modes: {
          typeArray,
          default () {
            return ['tree''code''form''text''view']
          }
        },
        lang: {
          typeString,
          default'en'
        },
        onNodeName: {
          typeFunction,
          default()=>{}
        }
      },
      setup (props: any, { emit }) {
        const root = getCurrentInstance()?.root.proxy as ComponentPublicInstance

        const state = reactive({
          editornull as any,
          errorfalse,
          json: {},
          internalChangefalse,
          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()
            }
          }, { immediatetrue })

        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 (
            <div>
              <div id={state.uid} class={'jsoneditor-vue'}>div>

            div>
          )
        }
      }
    })

    • 1

    style.css

    .ace_line_group {
      text-align: left;
    }
    .json-editor-container {
      display: flex;
      width100%;
    }
    .json-editor-container .tree-mode {
      width50%;
    }
    .json-editor-container .code-mode {
      flex-grow1;
    }
    .jsoneditor-btns {
      text-align: center;
      margin-top10px;
    }
    .jsoneditor-vue .jsoneditor-outer {
      min-height150px;
    }
    .jsoneditor-vue div.jsoneditor-tree {
      min-height350px;
    }
    .json-save-btn {
      background-color#20a0ff;
      border: none;
      color#fff;
      padding5px 10px;
      border-radius5px;
      cursor: pointer;
    }
    .json-save-btn:focus {
      outline: none;
    }
    .json-save-btn[disabled] {
      background-color#1d8ce0;
      cursor: not-allowed;
    }
    code {
      background-color#f5f5f5;
    }
    • 1

    index.ts

    export * from './vue3-json-editor';
    • 1

    四、如何使用