refactor: improve JSON editor functionality and styling, enhance input handling, and update button visibility

This commit is contained in:
wood911010 committed 2026-03-21 20:53:33 +08:00
1 parent 1ceff0ffa3
commit c0a6ee3cb0
3 files changed
+50 -12

No files matched your search

@@ -6,19 +6,23 @@
border-radius: $border-radius-base;
transition: all 0.3s ease;
&--primary {
// 仅「实心」主按钮用品牌色填充;plain / link / text 仍走 EP 默认(避免 plain 被铺成深底+主色字,对比度崩溃)
&--primary:not(.is-plain):not(.is-link):not(.is-text) {
background-color: $primary-color;
border-color: $primary-color;
color: #ffffff;
&:hover,
&:focus {
background-color: color.adjust($primary-color, $lightness: 10%);
border-color: color.adjust($primary-color, $lightness: 10%);
color: #ffffff;
}
&:active {
background-color: color.adjust($primary-color, $lightness: -10%);
border-color: color.adjust($primary-color, $lightness: -10%);
color: #ffffff;
}
}
+12 -4
View File
@@ -334,9 +334,9 @@ const handleImportConfirm = () => {
}
}
// 节点更新
// 节点更新(子节点输入 key/value 等时同步到 v-model)
const handleNodeUpdate = () => {
// 自动触发表单更新
emitUpdate()
}
// 节点删除
@@ -364,6 +364,7 @@ const handleAddChild = (parentId: string) => {
return false
}
findAndAdd(nodes.value)
emitUpdate()
}
// 切换展开
@@ -435,20 +436,27 @@ defineExpose({
setValue: initializeNodes
})
// 监听 modelValue 变化(仅用于初始化)
// 内部 emit 时跳过 modelValue 回灌,否则 buildJsonData 会丢掉「空 key」占位行,
// watch 再 initializeNodes 会把刚添加的行立刻清掉(表现为「添加字段」无效)。
const skipModelSync = ref(false)
watch(
() => props.modelValue,
(newValue) => {
if (skipModelSync.value) return
initializeNodes(newValue)
},
{ immediate: true }
)
// 手动触发更新的方法(供内部操作调用)
const emitUpdate = () => {
nextTick(() => {
skipModelSync.value = true
const newValue = buildJsonData(nodes.value)
emit('update:modelValue', newValue)
nextTick(() => {
skipModelSync.value = false
})
})
}
</script>
+33 -7
View File
@@ -22,7 +22,7 @@
v-model="node.key"
:placeholder="t('jsonEditor.keyPlaceholder')"
size="small"
@input="node.keyError = ''"
@input="onKeyInput"
/>
<p v-if="node.keyError" class="node-error">{{ node.keyError }}</p>
</div>
@@ -50,6 +50,7 @@
v-if="node.type === 'boolean'"
v-model="node.value"
size="small"
@change="emit('update')"
>
<el-option :label="'true'" value="true" />
<el-option :label="'false'" value="false" />
@@ -70,7 +71,7 @@
:placeholder="t('jsonEditor.valuePlaceholder')"
size="small"
type="number"
@input="node.valueError = ''"
@input="onNumberInput"
/>
<!-- 字符串类型 -->
@@ -79,27 +80,27 @@
v-model="node.value"
:placeholder="t('jsonEditor.valuePlaceholder')"
size="small"
@input="node.valueError = ''"
@input="onStringValueInput"
/>
<p v-if="node.valueError" class="node-error">{{ node.valueError }}</p>
</div>
<!-- 操作按钮 -->
<!-- 操作按钮:根级任意类型都显示删除(原先仅 depth>0 或 根级数组 才有,导致多余行无法删) -->
<div class="node-actions">
<el-button
v-if="isContainer"
link
type="primary"
size="small"
class="add-child-btn"
@click="$emit('add-child', node.id)"
>
{{ t('jsonEditor.addChild') }}
</el-button>
<el-button
v-if="depth > 0 || node.type === 'array'"
link
type="danger"
size="small"
class="remove-btn"
@click="$emit('delete')"
>
{{ t('jsonEditor.remove') }}
@@ -151,6 +152,21 @@ const typeOptions: JsonValueType[] = ['string', 'number', 'boolean', 'object', '
const isContainer = computed(() => props.node.type === 'object' || props.node.type === 'array')
const onKeyInput = () => {
props.node.keyError = ''
emit('update')
}
const onNumberInput = () => {
props.node.valueError = ''
emit('update')
}
const onStringValueInput = () => {
props.node.valueError = ''
emit('update')
}
const handleTypeChange = (newType: JsonValueType) => {
// 清空 children 如果切换到非容器类型
if (newType !== 'object' && newType !== 'array') {
@@ -235,10 +251,20 @@ const removeChild = (index: number) => {
.node-actions {
display: flex;
gap: 4px;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
/* 实心主色 + 白字由全局 element-theme 保证;此处仅做字重 */
.add-child-btn {
font-weight: 500;
}
.remove-btn {
font-weight: 500;
}
.node-error {
color: #f56c6c;
font-size: 11px;