Skip to content

拖拽导入增强功能使用指南 ​

概述 ​

拖拽导入增强功能是 Eagle2Ae 的核心特性之一,全面增强的拖拽导入功能支持文件夹拖拽、序列帧检测等高级特性,大幅提升素材处理效率。

主要特性 ​

1. 文件夹拖拽支持 ​

直接拖拽整个文件夹到扩展面板,系统会自动递归读取文件夹中的所有文件。

2. 序列帧自动检测 ​

智能识别图片序列并将其作为单个序列导入,避免导入成百上千张独立图片。

3. 项目内文件检测 ​

防止重复导入已在项目中的文件,确保项目面板的整洁性。

4. 增强的视觉反馈 ​

提供实时状态提示和进度显示,改善用户体验。

5. 拖拽悬浮选择导入行为(v2.5.0新增) ​

拖拽文件时,通过将鼠标悬浮到不同的导入行为按钮来动态切换导入方式,大幅提升操作效率和灵活性。

使用指南 ​

基本拖拽操作 ​

  1. 从文件管理器中选择一个或多个文件
  2. 拖拽到 Eagle2Ae 扩展面板的任意位置
  3. 等待系统处理并导入文件

文件夹拖拽操作 ​

  1. 从文件管理器中选择一个文件夹
  2. 拖拽到 Eagle2Ae 扩展面板
  3. 系统会自动分析文件夹内容
  4. 根据分析结果显示导入选项对话框

拖拽悬浮选择导入行为 ​

  1. 开始拖拽文件到扩展面板
  2. 在释放文件之前,将鼠标移动到想要的导入行为按钮上
  3. 按钮会自动显示高亮选中状态
  4. 可以继续移动鼠标到其他按钮切换导入行为
  5. 在目标按钮上方释放鼠标,文件将使用选中的导入行为进行导入

注意事项:

  • 拖拽悬浮功能仅在有文件被拖拽时激活
  • 导入行为按钮的选择是实时的,可以随时切换
  • 最终使用的导入行为取决于释放文件时鼠标悬浮的按钮
  • 该功能与点击按钮选择方式完全兼容

使用指南 ​

基本拖拽操作 ​

  1. 从文件管理器中选择一个或多个文件
  2. 拖拽到 Eagle2Ae 扩展面板的任意位置
  3. 等待系统处理并导入文件

文件夹拖拽操作 ​

  1. 从文件管理器中选择一个文件夹
  2. 拖拽到 Eagle2Ae 扩展面板
  3. 系统会自动分析文件夹内容
  4. 根据分析结果显示导入选项对话框

序列帧检测 ​

javascript
// 序列帧检测算法
detectImageSequence(files) {
    // 只检测图片文件
    const imageFiles = files.filter(file => this.getFileCategory(file) === 'image');

    if (imageFiles.length < 2) return null;

    // 按文件名排序
    imageFiles.sort((a, b) => a.name.localeCompare(b.name));

    // 尝试找到数字模式
    const patterns = [];

    for (const file of imageFiles) {
        const name = file.name;
        const nameWithoutExt = name.substring(0, name.lastIndexOf('.'));

        // 查找数字模式 - 支持多种数字格式,优先匹配最后一个数字序列
        const numberMatches = nameWithoutExt.match(/(.*?)(\d+)([^\d]*)$/);
        if (numberMatches) {
            const [, prefix, number, suffix] = numberMatches;
            patterns.push({
                prefix: prefix || '',
                number: parseInt(number),
                suffix: suffix || '',
                numberLength: number.length,
                originalNumber: number,
                file
            });
        }
    }

    // 找到最一致的模式
    const patternGroups = {};
    patterns.forEach(p => {
        const key = `${p.prefix}_${p.suffix}_${p.numberLength}`;
        if (!patternGroups[key]) {
            patternGroups[key] = [];
        }
        patternGroups[key].push(p);
    });

    // 找到最大的组
    let bestGroup = null;
    let maxSize = 0;

    for (const [key, group] of Object.entries(patternGroups)) {
        if (group.length > maxSize) {
            maxSize = group.length;
            bestGroup = group;
        }
    }

    // 排序并检查连续性
    bestGroup.sort((a, b) => a.number - b.number);

    const numbers = bestGroup.map(p => p.number);
    const start = numbers[0];
    const end = numbers[numbers.length - 1];

    // 检测步长
    let step = 1;
    if (numbers.length > 1) {
        const diffs = [];
        for (let i = 1; i < numbers.length; i++) {
            diffs.push(numbers[i] - numbers[i - 1]);
        }

        // 找到最常见的差值作为步长
        const diffCounts = {};
        diffs.forEach(diff => {
            diffCounts[diff] = (diffCounts[diff] || 0) + 1;
        });

        let maxCount = 0;
        for (const [diff, count] of Object.entries(diffCounts)) {
            if (count > maxCount) {
                maxCount = count;
                step = parseInt(diff);
            }
        }
    }

    // 构建模式字符串
    const firstPattern = bestGroup[0];
    const pattern = `${firstPattern.prefix}[${start}-${end}]${firstPattern.suffix}`;

    return {
        files: bestGroup.map(p => p.file),
        pattern,
        start,
        end,
        step,
        totalFiles: bestGroup.length
    };
}

导入选项对话框 ​

当检测到复杂文件结构时,系统会显示导入选项对话框:

1. 序列帧导入选项 ​

  • 作为序列导入: 将图片序列作为一个素材项导入
  • 作为独立文件导入: 将每张图片作为独立素材导入

2. 文件夹导入选项 ​

  • 保持文件夹结构: 在AE项目中保持原始文件夹结构
  • 扁平化导入: 将所有文件导入到同一文件夹中

3. 重复文件处理选项 ​

  • 跳过重复文件: 不导入已在项目中的文件
  • 覆盖现有文件: 替换项目中的同名文件
  • 保留两个版本: 同时保留新旧文件

最佳实践 ​

1. 大量素材处理 ​

处理大量素材时建议:

  • 使用文件夹拖拽功能批量导入
  • 启用序列帧检测功能优化图片序列处理
  • 合理设置导入模式避免文件重复

2. 项目组织 ​

  • 使用文件夹结构组织素材
  • 为不同类型的素材创建不同的文件夹
  • 定期清理项目中未使用的素材

3. 性能优化 ​

  • 避免同时拖拽过多文件
  • 合理使用序列帧检测功能
  • 定期重启AE释放内存资源

故障排除 ​

拖拽无响应 ​

如果拖拽操作无响应:

  1. 检查扩展面板是否为当前激活窗口
  2. 确认文件路径是否有效
  3. 查看控制台错误日志

序列帧未正确识别 ​

如果序列帧未被正确识别:

  1. 检查文件命名是否符合序列帧规范
  2. 确认文件格式是否支持
  3. 手动选择"作为序列导入"选项

重复文件导入 ​

如果出现重复文件导入:

  1. 启用项目内文件检测功能
  2. 检查导入模式设置
  3. 手动选择跳过重复文件选项

高级技巧 ​

1. 自定义序列帧模式 ​

支持自定义序列帧命名模式:

  • 标准模式: frame_001.png, frame_002.png, ...
  • 自定义模式: render_v1_001.jpg, render_v1_002.jpg, ...

2. 批量操作优化 ​

  • 使用Shift键选择连续文件
  • 使用Ctrl键选择不连续文件
  • 拖拽前预览选中文件列表

3. 快捷键支持 ​

  • Ctrl+A: 全选文件
  • Delete: 删除选中文件
  • Enter: 确认导入操作

技术实现 ​

拖拽悬浮选择导入行为实现 ​

概述 ​

拖拽悬浮选择导入行为是 v2.5.0 版本新增的功能,通过实时检测鼠标位置并动态切换导入行为按钮的选中状态,为用户提供更灵活的导入方式选择。

核心实现 ​

1. 拖拽事件监听器设置

javascript
// 在 setupDragAndDrop() 函数中设置拖拽监听
document.addEventListener('dragover', (e) => {
    e.preventDefault();
    e.stopPropagation();
    // 检测鼠标悬浮在哪个导入行为按钮上
    this.handleDragHoverBehaviorButton(e);
});

document.addEventListener('dragenter', (e) => {
    e.preventDefault();
    e.stopPropagation();
});

document.addEventListener('dragleave', (e) => {
    // 当鼠标指针离开窗口时清理状态
    if (!e.relatedTarget) {
        // 可以在这里添加其他清理逻辑
    }
});

document.addEventListener('drop', this.handleFileDrop.bind(this));

2. 鼠标位置检测函数

javascript
/**
 * 处理拖拽悬浮到导入行为按钮
 * @param {Event} event - 拖拽事件对象
 */
handleDragHoverBehaviorButton(event) {
    try {
        // 获取所有导入行为按钮
        const behaviorButtons = document.querySelectorAll('.import-behavior-button');

        // 检测鼠标位置是否在某个按钮上
        let hoveredButton = null;
        let hoveredIndex = -1;

        behaviorButtons.forEach((button, index) => {
            const rect = button.getBoundingClientRect();
            const isHovered = event.clientX >= rect.left && event.clientX <= rect.right &&
                             event.clientY >= rect.top && event.clientY <= rect.bottom;

            if (isHovered) {
                hoveredButton = button;
                hoveredIndex = index;
            }
        });

        if (hoveredButton) {
            // 先清除所有按钮的选中状态
            behaviorButtons.forEach(button => {
                const radio = button.querySelector('input[type="radio"]');
                if (radio) {
                    radio.checked = false;
                }
            });

            // 选中当前悬浮的按钮
            const radio = hoveredButton.querySelector('input[type="radio"]');
            if (radio) {
                radio.checked = true;
                // 只更新按钮视觉效果
                this.updateModeButtonStyles();
            }
        }
    } catch (error) {
        this.log(`处理拖拽悬浮失败: ${error.message}`, 'error');
    }
}

技术要点 ​

1. 性能优化

  • 使用 getBoundingClientRect() 获取按钮位置,避免重复查询
  • 每次拖拽事件只处理一次鼠标位置检测
  • 避免在拖拽过程中进行繁重的DOM操作

2. 状态管理

  • 临时状态:拖拽过程中的选中状态是临时的
  • 最终应用:释放文件时的选中状态被应用到导入操作
  • 不影响设置:不会永久改变用户的导入行为设置

3. 视觉反馈

  • 使用现有的高亮样式(橙色边框和文字)
  • 实时响应鼠标移动
  • 清晰的选中状态指示

4. 兼容性处理

  • 与点击按钮选择方式完全兼容
  • 不会影响预设管理和设置导出功能
  • 支持多面板独立配置

实现注意事项 ​

1. 避免状态冲突

javascript
// ❌ 错误做法:会根据内部设置重新覆盖选择
this.syncSettingsUI(); // 会根据内部设置重新覆盖我们的选择

// ✅ 正确做法:只更新视觉效果
this.updateModeButtonStyles(); // 只更新按钮的视觉样式

2. 确保单选逻辑

javascript
// 先清除所有按钮的选中状态
behaviorButtons.forEach(button => {
    const radio = button.querySelector('input[type="radio"]');
    if (radio) {
        radio.checked = false;
    }
});

// 然后选中当前悬浮的按钮
const radio = hoveredButton.querySelector('input[type="radio"]');
if (radio) {
    radio.checked = true;
}

3. 错误处理

javascript
try {
    // 处理拖拽悬浮逻辑
} catch (error) {
    // 捕获并记录错误,避免拖拽功能失效
    this.log(`处理拖拽悬浮失败: ${error.message}`, 'error');
}

扩展性考虑 ​

1. 支持更多按钮类型

javascript
// 可以扩展为支持其他类型的按钮
const allButtons = document.querySelectorAll('.interactive-button');
allButtons.forEach(button => {
    // 统一处理所有交互按钮的悬浮逻辑
});

2. 添加更多交互效果

javascript
// 可以添加更丰富的视觉效果
if (hoveredButton) {
    hoveredButton.classList.add('drag-hover');
    hoveredButton.classList.add('pulse-effect');
    // 添加更多动画效果
}

3. 集成到其他功能

javascript
// 可以将此机制应用到其他需要选择的功能
function handleGenericHoverSelection(event, selector, callback) {
    const elements = document.querySelectorAll(selector);
    // 通用化的悬浮选择逻辑
    // ...
}

最佳实践 ​

1. 代码组织 ​

  • 将拖拽相关的功能模块化
  • 使用清晰的函数命名和注释
  • 保持函数职责单一

2. 性能优化 ​

  • 避免在拖拽事件中进行复杂计算
  • 使用防抖技术处理频繁事件
  • 及时清理临时对象和状态

3. 用户体验 ​

  • 提供清晰的视觉反馈
  • 保持操作的直观性和一致性
  • 考虑不同用户的使用习惯

4. 测试覆盖 ​

  • 测试各种边界情况
  • 验证不同屏幕尺寸的显示效果
  • 确保跨浏览器兼容性

Released under the MIT License.