diff --git a/packages/amis-editor-core/src/util.ts b/packages/amis-editor-core/src/util.ts index 58ae71446..e80d4cb95 100644 --- a/packages/amis-editor-core/src/util.ts +++ b/packages/amis-editor-core/src/util.ts @@ -575,7 +575,17 @@ export function JSONDuplicate( } /** - * 用于复制或粘贴的时候重新生成 + * 用于复制或粘贴的时候重新生成组件id + * 【备注】需考虑以下两类使用场景: + * 1. 组件模板插入到页面中,组件模板含事件动作,事件动作中的componentId需替换成最新的; + * 2. 页面中的复制&粘贴,复制的组件含事件动作,且componentId关联的是页面其他组件,此时无需重置componentId。 + * 【逻辑说明】 + * 1. 第一次遍历,确保重置所有组件id,并记录下当前所有组件的新旧id对应关系(reIds); + * 2. 第一次遍历中,如果遇到事件动作,则将componentId替换成reIds中的新id,如果reIds中不存在对应的id,则重置componentId,并记录在reComptIds中; + * 3. 完成第一次遍历后,检测reComptIds中是否存在reIds中没有的组件id(识别第2种场景),并将不在reIds种的id记录到resetComptIds,然后开始第二次遍历; + * 4. 第二次遍历,恢复resetComptIds中的componentId。 + * 【额外说明】 + * 1. 仅第二类使用场景会触发第二次遍历,如果是第一类使用情况或者其他通用场景,则不会触发第二次遍历。 * @param json */ export function reGenerateID( @@ -583,21 +593,46 @@ export function reGenerateID( // 有时候复制时因为局部会有事件动作等内容,需要改为复制部分的新id,这里把老id与新id的关系存下来 reIds: {[propKey: string]: string} = {} ) { + const reComptIds: {[propKey: string]: string} = {}; // 记录事件动作中的id JSONTraverse(json, (value: any, key: string, host: any) => { const isNodeIdFormat = typeof value === 'string' && value.indexOf('u:') === 0; if ((key === 'id' || key === 'componentId') && isNodeIdFormat && host) { if (reIds[value]) { host[key] = reIds[value]; + } else if (reComptIds[value]) { + host[key] = reComptIds[value]; + reIds[value] = reComptIds[value]; } else { const newID = generateNodeId(); - reIds[value] = newID; host[key] = newID; + if (key === 'id') { + reIds[value] = newID; + } else if (key === 'componentId') { + reComptIds[value] = newID; + } } } return value; }); + + const resetComptIds: {[propKey: string]: string} = {}; + Object.keys(reComptIds).forEach((uidKey: string) => { + if (!reIds[uidKey]) { + resetComptIds[reComptIds[uidKey]] = uidKey; // 以新id为key + } + }); + + // 恢复resetComptIds中的componentId,避免事件动作失效 + JSONTraverse(json, (value: any, key: string, host: any) => { + const isNodeIdFormat = + typeof value === 'string' && value.indexOf('u:') === 0; + if (key === 'componentId' && isNodeIdFormat && resetComptIds[value]) { + host.componentId = resetComptIds[value]; + } + return value; + }); return json; }