refactor: improve JSON editor functionality and styling, enhance input handling, and update button visibility
This commit is contained in:
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user