feat: add more event for jsonViewer (#5546)

* 为JsonViewer添加事件支持
This commit is contained in:
Netfan 2025-02-17 10:41:09 +08:00 committed by GitHub
parent 799934171a
commit b6b97accb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 112 additions and 31 deletions

View File

@ -3,7 +3,12 @@ import type { SetupContext } from 'vue';
import type { Recordable } from '@vben/types';
import type { JsonViewerProps } from './types';
import type {
JsonViewerAction,
JsonViewerProps,
JsonViewerToggle,
JsonViewerValue,
} from './types';
import { computed, useAttrs } from 'vue';
// @ts-ignore
@ -11,7 +16,7 @@ import VueJsonViewer from 'vue-json-viewer';
import { $t } from '@vben/locales';
import { isBoolean, isString } from '@vben-core/shared/utils';
import { isBoolean } from '@vben-core/shared/utils';
defineOptions({ name: 'JsonViewer' });
@ -25,15 +30,44 @@ const props = withDefaults(defineProps<JsonViewerProps>(), {
previewMode: false,
showArrayIndex: true,
showDoubleQuotes: false,
parseString: true,
});
const emit = defineEmits<{
parseError: [error: Error];
click: [event: MouseEvent];
copied: [event: JsonViewerAction];
keyClick: [key: string];
toggle: [param: JsonViewerToggle];
valueClick: [value: JsonViewerValue];
}>();
const attrs: SetupContext['attrs'] = useAttrs();
function handleClick(event: MouseEvent) {
if (
event.target instanceof HTMLElement &&
event.target.classList.contains('jv-item')
) {
const pathNode = event.target.closest('.jv-push');
if (!pathNode || !pathNode.hasAttribute('path')) {
return;
}
const param: JsonViewerValue = {
path: '',
value: '',
depth: 0,
el: event.target,
};
param.path = pathNode.getAttribute('path') || '';
param.depth = Number(pathNode.getAttribute('depth')) || 0;
param.value = event.target.textContent || undefined;
param.value = JSON.parse(param.value);
emit('valueClick', param);
}
emit('click', event);
}
const bindProps = computed<Recordable<any>>(() => {
const copyable = {
copyText: $t('ui.jsonViewer.copy'),
@ -45,28 +79,15 @@ const bindProps = computed<Recordable<any>>(() => {
return {
...props,
...attrs,
onCopied: (event: JsonViewerAction) => emit('copied', event),
onKeyclick: (key: string) => emit('keyClick', key),
onClick: (event: MouseEvent) => handleClick(event),
copyable: props.copyable ? copyable : false,
};
});
const modelValue = defineModel();
const jsonToShow = computed(() => {
if (props.parseString && isString(modelValue.value)) {
try {
return JSON.parse(modelValue.value);
} catch (error) {
emit('parseError', error as Error);
console.error('Error parsing JSON:', error);
return modelValue.value;
}
} else {
return modelValue.value;
}
});
</script>
<template>
<VueJsonViewer :value="jsonToShow" v-bind="bindProps">
<VueJsonViewer v-bind="bindProps">
<template #copy="slotProps">
<slot name="copy" v-bind="slotProps"></slot>
</template>

View File

@ -1,4 +1,6 @@
export interface JsonViewerProps {
/** 要展示的结构数据 */
value: any;
/** 展开深度 */
expandDepth?: number;
/** 是否可复制 */
@ -19,6 +21,24 @@ export interface JsonViewerProps {
showArrayIndex?: boolean;
/** 显示双引号 */
showDoubleQuotes?: boolean;
/** 解析字符串 */
parseString?: boolean;
}
export interface JsonViewerAction {
action: string;
text: string;
trigger: HTMLElement;
}
export interface JsonViewerValue {
value: any;
path: string;
depth: number;
el: HTMLElement;
}
export interface JsonViewerToggle {
/** 鼠标事件 */
event: MouseEvent;
/** 当前展开状态 */
open: boolean;
}

View File

@ -26,8 +26,8 @@ export const json1 = {
],
};
export const json2 = `
{
export const json2 = JSON.parse(`
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
@ -46,6 +46,21 @@ export const json2 = `
"completion_tokens": 12,
"total_tokens": 21,
"debug_mode": true
}
},
"debug": {
"startAt": "2021-08-01T00:00:00Z",
"logs": [
{
"timestamp": "2021-08-01T00:00:00Z",
"message": "This is a debug message",
"extra":[ "extra1", "extra2" ]
},
{
"timestamp": "2021-08-01T00:00:01Z",
"message": "This is another debug message",
"extra":[ "extra3", "extra4" ]
}
]
}
}
`;
`);

View File

@ -1,9 +1,23 @@
<script lang="ts" setup>
import type { JsonViewerAction, JsonViewerValue } from '@vben/common-ui';
import { JsonViewer, Page } from '@vben/common-ui';
import { Card } from 'ant-design-vue';
import { Card, message } from 'ant-design-vue';
import { json1, json2 } from './data';
function handleKeyClick(key: string) {
message.info(`点击了Key ${key}`);
}
function handleValueClick(value: JsonViewerValue) {
message.info(`点击了Value ${JSON.stringify(value)}`);
}
function handleCopied(_event: JsonViewerAction) {
message.success('已复制JSON');
}
</script>
<template>
<Page
@ -11,16 +25,27 @@ import { json1, json2 } from './data';
description="一个渲染 JSON 结构数据的组件,支持复制、展开等,简单易用"
>
<Card title="默认配置">
<JsonViewer v-model="json1" />
<JsonViewer :value="json1" />
</Card>
<Card title="可复制、默认展开3层、显示边框" class="mt-4">
<Card title="可复制、默认展开3层、显示边框、事件处理" class="mt-4">
<JsonViewer
v-model="json2"
:value="json2"
:expand-depth="3"
copyable
:sort="false"
@key-click="handleKeyClick"
@value-click="handleValueClick"
@copied="handleCopied"
boxed
/>
</Card>
<Card title="预览模式" class="mt-4">
<JsonViewer
:value="json2"
copyable
preview-mode
:show-array-index="false"
/>
</Card>
</Page>
</template>