之前在做录制回放平台的时候,需要前端展示子调用信息,子调用是一个请求列表数组结构,jsoneditor对数组的默认展示结构是[0].[1].[2]..的方式,为了达到如下的效果,必须用到 onNodeName的钩子函数,因此深入调研了下vue3如何集成jsoneditor
最后做出来的效果图
onNodeName的参考文档 https://github.com/josdejong/jsoneditor/blob/master/docs/api.md
json-editor-vue3 感谢这位老哥的方案,我看了下源码,没有满足我的需要,核心就是属性需要自己加,因此我拿着他的代码改了下
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/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: [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 (
<div>
<div id={state.uid} class={'jsoneditor-vue'}>div>
div>
)
}
}
})
style.css
.ace_line_group {
text-align: left;
}
.json-editor-container {
display: flex;
width: 100%;
}
.json-editor-container .tree-mode {
width: 50%;
}
.json-editor-container .code-mode {
flex-grow: 1;
}
.jsoneditor-btns {
text-align: center;
margin-top: 10px;
}
.jsoneditor-vue .jsoneditor-outer {
min-height: 150px;
}
.jsoneditor-vue div.jsoneditor-tree {
min-height: 350px;
}
.json-save-btn {
background-color: #20a0ff;
border: none;
color: #fff;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
}
.json-save-btn:focus {
outline: none;
}
.json-save-btn[disabled] {
background-color: #1d8ce0;
cursor: not-allowed;
}
code {
background-color: #f5f5f5;
}
index.ts
export * from './vue3-json-editor';
class="container">
v-model="json"
mode='view'
:show-btns="true"
:on-node-name="onNodeName"
/>
</div>
template>