InDesign脚本:复制组时保留嵌套PageItem的引用
解决InDesign复制嵌套文本框组时保留引用的高效方案
以下是几种比递归查找label更高效的实现思路,直接针对InDesign脚本的特性优化:
方法1:同步递归遍历原组与复制后的组
利用复制操作后,新组的嵌套结构、子项顺序与原组完全一致的特性,在复制完成后同步递归遍历原组和新组,直接建立原textFrame到新textFrame的映射表。整个过程仅需一次遍历,时间复杂度为O(n),n为组内总项数,效率最高。
// 递归遍历原组和新组,建立id映射 function buildFrameMap(originalParent, newParent, idMap) { const originalItems = originalParent.pageItems; const newItems = newParent.pageItems; for (let i = 0; i < originalItems.length; i++) { const originalItem = originalItems[i]; const newItem = newItems[i]; // 匹配文本框,记录映射 if (originalItem.constructor.name === "TextFrame") { idMap.set(originalItem.id, newItem); } // 如果是子组,递归处理内部项 if (originalItem.constructor.name === "Group") { buildFrameMap(originalItem, newItem, idMap); } } } // 使用示例 const originalGroup = app.activeDocument.groups.item(0); const newGroup = originalGroup.duplicate(); // 执行复制 const frameIdMap = new Map(); buildFrameMap(originalGroup, newGroup, frameIdMap); // 后续可通过原id直接获取新文本框:frameIdMap.get(originalId)
方法2:预存层级路径映射
提前遍历原组,记录每个textFrame在嵌套结构中的层级路径(比如[0,2,1]表示根组第0个子项的第2个子项的第1个文本框),复制完成后直接通过路径定位新组内的对应项,避免全局查找。
// 获取目标项在根组中的层级路径 function getFramePath(item, rootGroup) { const path = []; let current = item; while (current !== rootGroup) { const parent = current.parent; path.unshift(parent.pageItems.indexOf(current)); current = parent; } return path; } // 根据路径在新组中找到对应项 function getFrameByPath(rootGroup, path) { let current = rootGroup; for (const idx of path) { current = current.pageItems[idx]; } return current; } // 使用示例 const originalGroup = app.activeDocument.groups.item(0); const originalTextFrames = originalGroup.allPageItems.filter(item => item.constructor.name === "TextFrame"); // 预存原文本框的路径 const pathMap = new Map(); originalTextFrames.forEach(frame => { pathMap.set(frame.id, getFramePath(frame, originalGroup)); }); // 复制组并映射新文本框 const newGroup = originalGroup.duplicate(); const newFrameMap = new Map(); originalTextFrames.forEach(originalFrame => { const path = pathMap.get(originalFrame.id); newFrameMap.set(originalFrame.id, getFrameByPath(newGroup, path)); });
方法3:利用自定义属性标记
如果需要在复制完成后延迟查找,可以在复制前给原textFrame添加自定义属性,复制后该属性会保留,直接通过属性筛选定位,避免递归遍历整个组。
// 复制前给原文本框添加自定义标记 const originalGroup = app.activeDocument.groups.item(0); const originalTextFrames = originalGroup.allPageItems.filter(item => item.constructor.name === "TextFrame"); originalTextFrames.forEach(frame => { frame.customProperties.add("originalId", frame.id); }); // 复制组 const newGroup = originalGroup.duplicate(); // 根据自定义属性查找对应文本框 function findNewFrameByOriginalId(originalId) { return newGroup.allPageItems.find(item => item.constructor.name === "TextFrame" && item.customProperties.item("originalId")?.value === originalId ); } // 使用示例:const newFrame = findNewFrameByOriginalId(12345);
方案优先级
优先选择方法1,它完全避免了后续查找操作,性能最优;方法2适合需要提前保存映射关系的场景;方法3适合延迟查找的需求,但效率略低于前两者。
内容的提问来源于stack exchange,提问作者Pat_Morita
相关产品推荐
相关产品推荐

