mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-05-30 04:08:04 +00:00
feat(editor): vs-code 字段对比模式改用 monaco diff 编辑器
- Container.vue 新增「自接管对比」字段类型白名单(当前含 vs-code),命中时只渲染一次组件并透传 model/lastValues/isCompare,由字段内部展示差异 - Code.vue 在 isCompare 模式下切换到 type='diff',使用 monaco 内置 diff 视图替代两个独立编辑器实例 - CodeEditor.vue 补充对 modifiedValues 的 watch,避免 diff 模式下右侧值停留在初始快照
This commit is contained in:
parent
59f4e0edac
commit
c854dfa8bf
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<MagicCodeEditor
|
||||
:height="config.height"
|
||||
:init-values="model[name]"
|
||||
:type="diffMode ? 'diff' : undefined"
|
||||
:init-values="diffMode ? (lastValues || {})[name] : model[name]"
|
||||
:modified-values="diffMode ? model[name] : undefined"
|
||||
:language="config.language"
|
||||
:options="{
|
||||
...config.options,
|
||||
readOnly: disabled,
|
||||
readOnly: diffMode ? true : disabled,
|
||||
}"
|
||||
:autosize="config.autosize"
|
||||
:parse="config.parse"
|
||||
@ -15,6 +17,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
import type { CodeConfig, FieldProps } from '@tmagic/form';
|
||||
|
||||
import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
|
||||
@ -27,10 +31,22 @@ const emit = defineEmits<{
|
||||
change: [value: string | any];
|
||||
}>();
|
||||
|
||||
withDefaults(defineProps<FieldProps<CodeConfig>>(), {
|
||||
const props = withDefaults(defineProps<FieldProps<CodeConfig>>(), {
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 对比模式判定:
|
||||
*
|
||||
* - 当 `isCompare === true` 时,由父级 `MFormContainer` 统一渲染一次本字段(不再渲染前后两份独立组件),
|
||||
* 并把 `model`(当前值)与 `lastValues`(历史值)一并传入;
|
||||
* - 此时本字段切换到 monaco 自带的 diff 编辑器(左侧旧、右侧新),相比"两个独立 monaco 实例"更直观,
|
||||
* 也避免了同一表单内重复实例化重型编辑器带来的开销。
|
||||
*
|
||||
* 仅当存在历史值(lastValues)且开启了对比模式时启用 diff,避免在 lastValues 缺失时退化为空对比。
|
||||
*/
|
||||
const diffMode = computed(() => Boolean(props.isCompare && props.lastValues));
|
||||
|
||||
const save = (v: string | any) => {
|
||||
emit('change', v);
|
||||
};
|
||||
|
||||
@ -330,6 +330,21 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
// diff 模式下,对比的"当前值"(modifiedValues)也可能在外部变化(例如 lastValues 不变、当前 model 变了),
|
||||
// 此时同样需要重新设置编辑器值,否则右侧编辑器内容会停留在初始化时的快照。
|
||||
watch(
|
||||
() => props.modifiedValues,
|
||||
(v, preV) => {
|
||||
if (props.type !== 'diff') return;
|
||||
if (v !== preV) {
|
||||
setEditorValue(props.initValues, props.modifiedValues);
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
(v) => {
|
||||
|
||||
@ -73,10 +73,11 @@
|
||||
|
||||
<!-- 对比 -->
|
||||
<template v-else-if="type && display && showDiff">
|
||||
<!-- 上次内容 -->
|
||||
<!-- 自接管对比的字段类型(如 vs-code):只渲染一次组件,由字段内部用 diff 编辑器/视图自行展示前后差异 -->
|
||||
<TMagicFormItem
|
||||
v-if="isSelfDiffField"
|
||||
v-bind="formItemProps"
|
||||
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
||||
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true, 'self-diff': true }"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" :config="config" :type="type" :text="text" :prop="itemProp" :disabled="disabled">
|
||||
@ -90,55 +91,105 @@
|
||||
</slot>
|
||||
</template>
|
||||
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
||||
<component v-bind="fieldsProps" :is="tagName" :model="lastValues" @change="onChangeHandler"></component>
|
||||
<component
|
||||
v-bind="fieldsProps"
|
||||
:is="tagName"
|
||||
:model="model"
|
||||
:last-values="lastValues"
|
||||
:is-compare="isCompare"
|
||||
@change="onChangeHandler"
|
||||
></component>
|
||||
<template #content>
|
||||
<div v-html="tooltip.text"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
|
||||
<component v-else v-bind="fieldsProps" :is="tagName" :model="lastValues" @change="onChangeHandler"></component>
|
||||
<component
|
||||
v-else
|
||||
v-bind="fieldsProps"
|
||||
:is="tagName"
|
||||
:model="model"
|
||||
:last-values="lastValues"
|
||||
:is-compare="isCompare"
|
||||
@change="onChangeHandler"
|
||||
></component>
|
||||
</TMagicFormItem>
|
||||
|
||||
<TMagicTooltip v-if="config.tip && type === 'checkbox' && !(config as CheckboxConfig).useLabel" placement="top">
|
||||
<TMagicIcon style="line-height: 40px; margin-left: 5px"><warning-filled /></TMagicIcon>
|
||||
<template #content>
|
||||
<div v-html="config.tip"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
<!-- 普通字段:渲染前后两份独立的组件用于对比 -->
|
||||
<template v-else>
|
||||
<!-- 上次内容 -->
|
||||
<TMagicFormItem
|
||||
v-bind="formItemProps"
|
||||
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" :config="config" :type="type" :text="text" :prop="itemProp" :disabled="disabled">
|
||||
<FormLabel
|
||||
:tip="config.tip"
|
||||
:type="type"
|
||||
:use-label="(config as CheckboxConfig).useLabel"
|
||||
:label-title="config.labelTitle"
|
||||
:text="text"
|
||||
></FormLabel>
|
||||
</slot>
|
||||
</template>
|
||||
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
||||
<component v-bind="fieldsProps" :is="tagName" :model="lastValues" @change="onChangeHandler"></component>
|
||||
<template #content>
|
||||
<div v-html="tooltip.text"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
|
||||
<!-- 当前内容 -->
|
||||
<TMagicFormItem
|
||||
v-bind="formItemProps"
|
||||
:style="config.tip ? 'flex: 1' : ''"
|
||||
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" :config="config" :type="type" :text="text" :prop="itemProp" :disabled="disabled">
|
||||
<FormLabel
|
||||
:tip="config.tip"
|
||||
:type="type"
|
||||
:use-label="(config as CheckboxConfig).useLabel"
|
||||
:label-title="config.labelTitle"
|
||||
:text="text"
|
||||
></FormLabel>
|
||||
</slot>
|
||||
</template>
|
||||
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
||||
<component v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
||||
<component
|
||||
v-else
|
||||
v-bind="fieldsProps"
|
||||
:is="tagName"
|
||||
:model="lastValues"
|
||||
@change="onChangeHandler"
|
||||
></component>
|
||||
</TMagicFormItem>
|
||||
|
||||
<TMagicTooltip v-if="config.tip && type === 'checkbox' && !(config as CheckboxConfig).useLabel" placement="top">
|
||||
<TMagicIcon style="line-height: 40px; margin-left: 5px"><warning-filled /></TMagicIcon>
|
||||
<template #content>
|
||||
<div v-html="tooltip.text"></div>
|
||||
<div v-html="config.tip"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
|
||||
<component v-else v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
||||
</TMagicFormItem>
|
||||
<!-- 当前内容 -->
|
||||
<TMagicFormItem
|
||||
v-bind="formItemProps"
|
||||
:style="config.tip ? 'flex: 1' : ''"
|
||||
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" :config="config" :type="type" :text="text" :prop="itemProp" :disabled="disabled">
|
||||
<FormLabel
|
||||
:tip="config.tip"
|
||||
:type="type"
|
||||
:use-label="(config as CheckboxConfig).useLabel"
|
||||
:label-title="config.labelTitle"
|
||||
:text="text"
|
||||
></FormLabel>
|
||||
</slot>
|
||||
</template>
|
||||
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
||||
<component v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
||||
<template #content>
|
||||
<div v-html="tooltip.text"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
|
||||
<TMagicTooltip v-if="config.tip && type === 'checkbox' && !(config as CheckboxConfig).useLabel" placement="top">
|
||||
<TMagicIcon style="line-height: 40px; margin-left: 5px"><warning-filled /></TMagicIcon>
|
||||
<template #content>
|
||||
<div v-html="config.tip"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
<component v-else v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
||||
</TMagicFormItem>
|
||||
|
||||
<TMagicTooltip v-if="config.tip && type === 'checkbox' && !(config as CheckboxConfig).useLabel" placement="top">
|
||||
<TMagicIcon style="line-height: 40px; margin-left: 5px"><warning-filled /></TMagicIcon>
|
||||
<template #content>
|
||||
<div v-html="config.tip"></div>
|
||||
</template>
|
||||
</TMagicTooltip>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-else-if="items && display">
|
||||
@ -281,6 +332,21 @@ const tagName = computed(() => {
|
||||
return getField(type.value || 'container') || `m-${items.value ? 'form' : 'fields'}-${type.value}`;
|
||||
});
|
||||
|
||||
/**
|
||||
* 自接管对比的字段类型白名单。
|
||||
*
|
||||
* 这类字段在 `isCompare === true` 且存在差异时,不再由 Container 渲染前后两份独立组件来对比,
|
||||
* 而是只渲染一次组件,将 `model` / `lastValues` / `isCompare` 一并传给字段组件,
|
||||
* 由字段组件内部自行展示前后差异(典型场景:vs-code 字段使用 monaco 自带的 diff 编辑器)。
|
||||
*
|
||||
* 这样做的好处:
|
||||
* 1. 避免重型字段(如 monaco 编辑器)在对比模式下被实例化两次,节省资源;
|
||||
* 2. 提供更专业的对比视觉效果(如 monaco diff 的行级高亮、左右滚动同步等)。
|
||||
*/
|
||||
const SELF_DIFF_FIELD_TYPES = new Set(['vs-code']);
|
||||
|
||||
const isSelfDiffField = computed(() => SELF_DIFF_FIELD_TYPES.has(type.value));
|
||||
|
||||
const disabled = computed(() => props.disabled || filterFunction(mForm, props.config.disabled, props));
|
||||
|
||||
const text = computed(() => filterFunction(mForm, props.config.text, props));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user