吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 878|回复: 8
上一主题 下一主题
收起左侧

[其他原创] 没啥用软件 - 《文件重命名》--纯前端

  [复制链接]
跳转到指定楼层
楼主
快乐的小驹 发表于 2026-3-6 18:49 回帖奖励
本帖最后由 快乐的小驹 于 2026-3-6 18:51 编辑

亲爱的朋友们,半年多没发布软件了~这个软件是想法也是根据一个吾爱的坛友想法重写的~他好像用python开发的~好像已经删除了~因为我找不到了!
免费的评分给一个吧!
再说一下为什么我喜欢用前端的html+js~
1、对于一个快五十岁的老家伙来说,纯前端运行不用配置环境。
2、最重要来说我不是程序员,是AI圆梦了。

3、用html+js写程序,因为浏览器安全问题谷歌给限制的实在是太多了,确实不容易。

这是js代码~算是核心呗?最下面下载使用,你要是复制使用是不行的!
[JavaScript] 纯文本查看 复制代码
document.addEventListener('DOMContentLoaded', function() {
    // 获取DOM元素
    const fileInput = document.getElementById('file-input');
    const uploadBtn = document.getElementById('upload-btn');
    const uploadArea = document.getElementById('upload-area');
    const previewContainer = document.getElementById('preview-container');
    const filenameList = document.getElementById('filename-list');
    const filenameActions = document.getElementById('filename-actions');
    const generateBtn = document.getElementById('generate-btn');
    const resetBtn = document.getElementById('reset-btn');
    const newFilenameTextarea = document.getElementById('new-filename');
    const clearAllBtn = document.getElementById('clear-all');
    const downloadAllBtn = document.getElementById('download-all');
	const filenameSearch = document.getElementById('filename-search');  // 新增搜索框元素
    
    // 初始化PDF.js(确保已通过CDN引入)
    pdfjsLib.GlobalWorkerOptions.workerSrc = 'js/pdf.worker.min.js';
    
    // 初始化变量
    let files = [];
    let selectedPreviewIndex = -1;
    let selectedFilenameIndex = -1;
    let generatedNames = [];
    let originalNames = [];
    
    // 显示操作按钮区域
    filenameActions.style.display = 'flex';
    
    // 初始化上传区域状态
    updateUploadAreaState();
    
    // 点击上传按钮触发文件选择(无文件时才响应)
    uploadBtn.addEventListener('click', () => {
        if (files.length === 0) fileInput.click();
    });
    
    // 文件选择处理
    fileInput.addEventListener('change', handleFiles);
    
    // 上传区域点击事件(无文件时才响应)
    uploadArea.addEventListener('click', function(e) {
        if (e.target.closest('.preview-item')) return;
        if (files.length === 0) fileInput.click();
    });
    
    // 拖放区域事件处理
    uploadArea.addEventListener('dragover', (e) => {
        e.preventDefault();
        if (files.length === 0) {
            uploadArea.style.borderColor = '#3498db';
            uploadArea.style.backgroundColor = '#f8f9fa';
        }
    });
    
    uploadArea.addEventListener('dragleave', () => {
        uploadArea.style.borderColor = '#bdc3c7';
        uploadArea.style.backgroundColor = 'transparent';
    });
    
    uploadArea.addEventListener('drop', (e) => {
        e.preventDefault();
        uploadArea.style.borderColor = '#bdc3c7';
        uploadArea.style.backgroundColor = 'transparent';
        
        if (e.dataTransfer.files.length && files.length === 0) {
            fileInput.files = e.dataTransfer.files;
            handleFiles({ target: fileInput });
        }
    });
    
    // 更新上传区域状态
    function updateUploadAreaState() {
        if (files.length > 0) {
            uploadArea.style.cursor = 'default';
            uploadArea.style.borderColor = '#e0e0e0';
            uploadArea.title = '请先清空现有文件再上传新文件';
            uploadArea.classList.add('disabled');
        } else {
            uploadArea.style.cursor = 'pointer';
            uploadArea.style.borderColor = '#bdc3c7';
            uploadArea.title = '点击或拖放文件到此处上传';
            uploadArea.classList.remove('disabled');
        }
    }
    
    // 在这里添加搜索功能 ↓
    filenameSearch.addEventListener('input', function() {
        const searchTerm = this.value.trim().toLowerCase();
        const buttons = document.querySelectorAll('.filename-btn');
        
        let firstMatch = null;
        
        buttons.forEach(button => {
            const text = button.textContent.toLowerCase();
            const isMatch = searchTerm === '' || text.includes(searchTerm);
            
            button.classList.toggle('highlight', isMatch && searchTerm !== '');
            
            if (isMatch && searchTerm !== '' && !firstMatch) {
                firstMatch = button;
            }
        });
        
        // 滚动到第一个匹配项
        if (firstMatch) {
            firstMatch.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        }
    });
    
    	
    // 处理选择的文件
    function handleFiles(e) {
        const newFiles = Array.from(e.target.files);
        if (newFiles.length === 0) return;
        
        newFiles.forEach(file => {
            file.previewHidden = false;
            file.buttonHidden = false;
            file.customName = null;
            file.isRenamed = false;
        });
        
        files = [...files, ...newFiles];
        originalNames = files.map(file => file.name);
        generatedNames = [];
        renderPreviews();
        renderFilenameList();
        updateUploadAreaState();
        fileInput.value = '';
    }
    
async function renderPDFPreview(file, container) {
    try {
        container.innerHTML = '<div class="pdf-loading">加载PDF中...</div>';
        
        const pdfData = await readFileAsArrayBuffer(file);
        const pdf = await pdfjsLib.getDocument({
            data: pdfData,
            cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.11.338/cmaps/',
            cMapPacked: true
        }).promise;

        const page = await pdf.getPage(1);
        const viewport = page.getViewport({ scale: 1.0 });
        
        // 计算高质量缩略图的缩放比例
        const targetWidth = 250; // 缩略图宽度
        const scale = (targetWidth * 2) / viewport.width; // 2倍分辨率提高清晰度
        const scaledViewport = page.getViewport({ scale });

        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d', { willReadFrequently: true });
        
        // 设置高质量画布
        canvas.width = scaledViewport.width;
        canvas.height = scaledViewport.height;
        canvas.style.width = `${targetWidth}px`; // 显示尺寸
        canvas.style.height = 'auto';
        
        // 高质量渲染
        await page.render({
            canvasContext: context,
            viewport: scaledViewport,
            intent: 'print', // 使用打印质量
            enableWebGL: true // 启用硬件加速
        }).promise;

        container.innerHTML = '';
        container.appendChild(canvas);
        
        return {
            canvas,
            naturalWidth: viewport.width,
            naturalHeight: viewport.height,
            scaleRatio: viewport.width / scaledViewport.width
        };
    } catch (error) {
        console.error('PDF渲染失败:', error);
        container.innerHTML = '<div class="preview-error">PDF预览加载失败</div>';
        return null;
    }
}

	
	
    // 渲染预览(支持PDF和图片)
async function renderPreviews() {
    previewContainer.innerHTML = '';

    for (const [index, file] of files.entries()) {
        if (file.previewHidden) continue;

        const previewItem = document.createElement('div');
        previewItem.className = 'preview-item';
        previewItem.dataset.index = index;

        if (index === selectedPreviewIndex) {
            previewItem.classList.add('selected');
        }

        const displayName = file.customName || file.name;
        const isPDF = isPDFFile(file);
        const isImage = isImageFile(file);

        previewItem.innerHTML = `
            <div class="preview-img-container">
                ${isPDF ? '<div class="pdf-loading">加载PDF中...</div>' : 
                 isImage ? '<div class="loading-spinner"></div>' : 
                 '<i class="fas fa-file"></i>'}
            </div>
            <div class="preview-name" title="${displayName}">
                ${truncateFilename(displayName)}
            </div>
            ${(isPDF || isImage) ? '<div class="magnifier-glass"></div>' : ''}
        `;

        previewContainer.appendChild(previewItem);

        try {
            const imgContainer = previewItem.querySelector('.preview-img-container');
            
            if (isPDF) {
                // PDF渲染流程
                const result = await renderPDFPreview(file, imgContainer);
                
                if (result) {
                    setupMagnifier(previewItem, {
                        type: 'pdf',
                        source: result.canvas,
                        naturalWidth: result.naturalWidth,
                        naturalHeight: result.naturalHeight
                    });
                }

            } else if (isImage) {
                // 图片渲染流程
                const imgUrl = await readFileAsDataURL(file);
                const img = new Image();
                
                img.onload = function() {
                    // 保持原始宽高比
                    const maxWidth = 250;
                    const ratio = Math.min(maxWidth / img.naturalWidth, 1);
                    img.style.width = `${img.naturalWidth * ratio}px`;
                    img.style.height = 'auto';
                    
                    imgContainer.innerHTML = '';
                    imgContainer.appendChild(img);
                    
                    // 延迟确保图片完全渲染
                    setTimeout(() => {
                        setupMagnifier(previewItem, {
                            type: 'image',
                            source: img,
                            naturalWidth: img.naturalWidth,
                            naturalHeight: img.naturalHeight
                        });
                    }, 50);
                };
                
                img.onerror = function() {
                    imgContainer.innerHTML = `
                        <div class="preview-error">
                            <i class="fas fa-exclamation-triangle"></i>
                            <div>图片加载失败</div>
                        </div>
                    `;
                };
                
                img.src = imgUrl;
                img.className = 'preview-img';
                img.alt = displayName;
            }
        } catch (error) {
            console.error(`预览加载失败 (${file.name}):`, error);
            previewItem.querySelector('.preview-img-container').innerHTML = `
                <div class="preview-error">
                    <i class="fas fa-exclamation-triangle"></i>
                    <div>预览加载失败</div>
                </div>
            `;
        }

        // 点击事件处理
        previewItem.addEventListener('click', (e) => {
            if (e.target.closest('.magnifier-glass')) return;
            
            e.stopPropagation();
            selectedPreviewIndex = selectedPreviewIndex === index ? -1 : index;
            document.querySelectorAll('.preview-item').forEach(item => {
                item.classList.toggle('selected', parseInt(item.dataset.index) === selectedPreviewIndex);
            });
            checkPairSelection();
        });
    }
}


// 修改setupMagnifier函数,使用全局放大镜
let globalMagnifier = null;

function setupMagnifier(previewItem, options) {
    const container = previewItem.querySelector('.preview-img-container');
    
    // 创建或复用全局放大镜
    if (!globalMagnifier) {
        globalMagnifier = document.createElement('div');
        globalMagnifier.className = 'magnifier-glass';
        document.body.appendChild(globalMagnifier);
        
        // 放大镜基础样式
        Object.assign(globalMagnifier.style, {
            position: 'fixed',
            width: '300px',
            height: '300px',
            borderRadius: '50%',
            border: '2px solid #fff',
            backgroundRepeat: 'no-repeat',
            pointerEvents: 'none',
            zIndex: '9999',
            display: 'none',
            boxShadow: '0 0 10px rgba(0,0,0,0.5)',
            transform: 'translate(-50%, -50%)',
            left: '0',
            top: '0',
            opacity: '0.9',
            // 硬件加速
            transform: 'translateZ(0)',
            backfaceVisibility: 'hidden',
            perspective: '1000px',
            willChange: 'transform'
        });
    }

    const sourceUrl = sourceToDataURL(options.source);
    let lastUpdate = 0;
    const updateInterval = 16; // ~60fps

    // 节流鼠标移动处理
    const handleMouseMove = (e) => {
        const now = Date.now();
        if (now - lastUpdate < updateInterval) return;
        lastUpdate = now;

        const containerRect = container.getBoundingClientRect();
        const x = e.clientX - containerRect.left;
        const y = e.clientY - containerRect.top;
        const xRatio = x / containerRect.width;
        const yRatio = y / containerRect.height;

        if (xRatio < 0 || yRatio < 0 || xRatio > 1 || yRatio > 1) {
            globalMagnifier.style.display = 'none';
            return;
        }

        globalMagnifier.style.display = 'block';
        globalMagnifier.style.left = `${e.clientX}px`;
        globalMagnifier.style.top = `${e.clientY}px`;
        
        const bgX = xRatio * options.naturalWidth * 2 - 100;
        const bgY = yRatio * options.naturalHeight * 2 - 100;
        
        globalMagnifier.style.backgroundImage = `url("${sourceUrl}")`;
        globalMagnifier.style.backgroundPosition = `-${bgX}px -${bgY}px`;
    };

    // 事件监听
    container.addEventListener('mousemove', handleMouseMove);
    container.addEventListener('mouseleave', () => {
        globalMagnifier.style.display = 'none';
    });
    
    // 确保容器有正确的定位上下文
    container.style.position = 'relative';
}




// 添加在现有辅助函数附近
function sourceToDataURL(element) {
    if (element instanceof HTMLCanvasElement) {
        return element.toDataURL();
    } else if (element.src) {
        return element.src;
    }
    return '';
}

function isPDFFile(file) {
    return file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
}

function isImageFile(file) {
    return file.type.startsWith('image/');
}

    
    // 辅助函数:读取文件为ArrayBuffer(用于PDF)
    function readFileAsArrayBuffer(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.onerror = reject;
            reader.readAsArrayBuffer(file);
        });
    }
    
    // 辅助函数:读取文件为DataURL(用于图片)
    function readFileAsDataURL(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.onerror = reject;
            reader.readAsDataURL(file);
        });
    }
    
    // 检查配对选择
    function checkPairSelection() {
        if (selectedPreviewIndex !== -1 && selectedFilenameIndex !== -1) {
            const selectedFile = files[selectedPreviewIndex];
            const newName = generatedNames[selectedFilenameIndex];
            
            const ext = selectedFile.name.split('.').pop();
            selectedFile.customName = newName.includes('.') ? newName : `${newName}.${ext}`;
            selectedFile.isRenamed = true;
            
            selectedFile.previewHidden = true;
            files[selectedFilenameIndex].buttonHidden = true;
            
            selectedPreviewIndex = -1;
            selectedFilenameIndex = -1;
            
            renderPreviews();
            renderFilenameList();
        }
    }
    
    // 生成文件名按钮点击
    generateBtn.addEventListener('click', () => {
        const inputText = newFilenameTextarea.value.trim();
        if (!inputText) {
            alert('请输入有效的文件名');
            return;
        }
        
        generatedNames = parseFilenamesInput(inputText)
            .map((name, index) => {
                if (index >= files.length) return name;
                const ext = files[index].name.split('.').pop();
                return name.includes('.') ? name : `${name}.${ext}`;
            });
        
        renderFilenameList();
    });
    
    // 渲染文件名列表
    function renderFilenameList() {
    filenameList.innerHTML = '';
    
    generatedNames.forEach((name, index) => {
        if (files[index]?.buttonHidden) return;
        
        const btn = document.createElement('button');
        btn.className = 'filename-btn';
        btn.textContent = `${index + 1}. ${name}`;
        btn.dataset.index = index;
        btn.title = name;
        
        if (index === selectedFilenameIndex) {
            btn.classList.add('active');
        }
        
        btn.addEventListener('click', () => {
            if (selectedFilenameIndex === index) {
                selectedFilenameIndex = -1;
                btn.classList.remove('active');
            } else {
                document.querySelectorAll('.filename-btn').forEach(btn => {
                    btn.classList.remove('active');
                });
                selectedFilenameIndex = index;
                btn.classList.add('active');
            }
            checkPairSelection();
        });
        
        filenameList.appendChild(btn);
    });
    
    // 如果有搜索词,重新触发搜索以保持高亮
    if (filenameSearch.value.trim()) {
        filenameSearch.dispatchEvent(new Event('input'));
    }
}


    
    // 解析多行文件名输入
    function parseFilenamesInput(text) {
        let names = text.split('\n')
            .map(line => line.trim())
            .filter(line => line.length > 0);
        
        if (names.length === 1) {
            names = names[0].split(/[, ]+/).filter(name => name.length > 0);
        }
        
        return names;
    }
    
    // 文件名截断显示
    function truncateFilename(name) {
        return name.length > 20 ? 
            name.substring(0, 17) + '...' : 
            name;
    }
    
    // 重置按钮点击
    resetBtn.addEventListener('click', () => {
        newFilenameTextarea.value = '';
        generatedNames = [];
        selectedPreviewIndex = -1;
        selectedFilenameIndex = -1;
        
        files.forEach(file => {
            file.previewHidden = false;
            file.buttonHidden = false;
            file.customName = null;
            file.isRenamed = false;
        });
        
        renderPreviews();
        renderFilenameList();
        updateUploadAreaState();
    });
    
    // 清空所有
    clearAllBtn.addEventListener('click', () => {
        files = [];
        generatedNames = [];
        originalNames = [];
        selectedPreviewIndex = -1;
        selectedFilenameIndex = -1;
        previewContainer.innerHTML = '';
        filenameList.innerHTML = '';
        newFilenameTextarea.value = '';
        updateUploadAreaState();
    });
    
    // 确保JSZip已加载
    function ensureJSZipLoaded() {
        return new Promise((resolve, reject) => {
            if (typeof JSZip !== 'undefined') {
                resolve();
            } else {
                const script = document.createElement('script');
                script.src = 'js/jszip.min.js';
                script.onload = resolve;
                script.onerror = () => {
                    reject(new Error('无法加载JSZip库'));
                };
                document.head.appendChild(script);
            }
        });
    }
    
    // 下载全部
    downloadAllBtn.addEventListener('click', async () => {
        const filesToDownload = files.filter(file => 
            file.previewHidden && file.isRenamed
        );

        if (filesToDownload.length === 0) {
            alert('没有可下载的文件');
            return;
        }

        try {
            await ensureJSZipLoaded();
            const zip = new JSZip();
            
            filesToDownload.forEach(file => {
                zip.file(file.customName, file);
            });
            
            const content = await zip.generateAsync({ type: 'blob' });
            const url = URL.createObjectURL(content);
            
            const a = document.createElement('a');
            a.href = url;
            a.download = 'renamed_files.zip';
            document.body.appendChild(a);
            a.click();
            
            setTimeout(() => {
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }, 100);
            
        } catch (error) {
            console.error('打包下载失败:', error);
            alert(`打包下载失败: ${error.message}`);
        }
    });
});


下面是使用说明:













文件重命名.zip (979.19 KB, 下载次数: 9)


以下的我发布的一下东西,小白下载吧~老鸟勿入!

《Excel文件比较器v1.3》
https://www.52pojie.cn/thread-2020893-1-1.html

《个性计算器》
https://www.52pojie.cn/thread-2028540-1-1.html

没啥用软件 - 《Python库的批量安装》
https://www.52pojie.cn/thread-2030214-1-1.html

没啥用软件 - 《本地测试服务器》
https://www.52pojie.cn/thread-2030222-1-1.html

没啥用软件 - 拼接图像播放器
https://www.52pojie.cn/thread-2032163-1-1.html

没啥用软件 - MySQL数据库备份工具
https://www.52pojie.cn/thread-2034382-1-1.html

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
Mzhang2008 发表于 2026-3-7 07:43
实用小工具 谢谢分享
3#
a54088 发表于 2026-3-7 08:58
很有趣的小工具,感谢作者。我觉得后期可以接入多模态大模型,让AI自动识别自动提供文件名建议。
4#
laotzudao0 发表于 2026-3-7 09:13
5#
fireflying1984 发表于 2026-3-7 09:37
奇奇怪怪的功能,本人暂时好像没找到用上的地方,收藏一个先
6#
bwcloud 发表于 2026-3-7 10:36
确实是这样~
7#
gao891015 发表于 2026-3-8 08:30
先收藏,以后用的上
8#
zgch999 发表于 2026-3-23 16:12
小而巧的网页小工具,感觉教师从业者给班里同学作业图片命名的时候可以用到
9#
cloud258 发表于 2026-3-23 17:00
用的什么AI辅助呢,感觉还不错
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-11 20:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表