首页 > web前端 > js教程 > 正文

JS如何实现多文件上传

畫卷琴夢
发布: 2025-08-15 13:17:01
原创
801人浏览过
JS实现多文件上传需用input的multiple属性获取FileList,通过FormData打包文件并用Fetch或XMLHttpRequest发送,结合进度监听、分片上传与Web Worker优化体验。

js如何实现多文件上传

JS实现多文件上传,核心在于利用HTML的

input type="file" multiple
登录后复制
属性获取文件列表,然后通过
FormData
登录后复制
对象将这些文件打包,最后使用
Fetch API
登录后复制
XMLHttpRequest
登录后复制
发送到服务器。这套流程既直接又高效,是前端处理文件上传的通用方案。

解决方案

说起来,这事儿真不复杂。你首先得有个HTML

登录后复制
。那个
multiple
登录后复制
属性是关键,它让用户能一次性选好几个文件。当用户选完文件后,这些文件会变成一个
FileList
登录后复制
对象,你可以通过
event.target.files
登录后复制
或者DOM元素的
files
登录后复制
属性拿到它。

拿到文件后,下一步就是打包。我们通常用

FormData
登录后复制
。这玩意儿就像一个特殊的包裹,你可以往里面塞各种数据,包括文件。它会自动帮你处理好
Content-Type
登录后复制
multipart/form-data
登录后复制
的请求头,省去了很多麻烦。

// 假设HTML中有一个 <input type="file" id="fileInput" multiple>
const fileInput = document.getElementById('fileInput');
const uploadUrl = '/api/upload-multiple-files'; // 你的后端上传接口

fileInput.addEventListener('change', (event) => {
    const files = event.target.files; // 这是一个FileList对象

    if (files.length === 0) {
        console.log('没有选择文件,或者选择了空文件。');
        return;
    }

    const formData = new FormData();
    // 遍历所有选中的文件,并添加到FormData中
    // 注意:这里使用'files[]'作为key,后端通常能自动解析成文件数组
    for (let i = 0; i < files.length; i++) {
        formData.append('files[]', files[i]);
    }

    // 如果你还有其他表单数据要一起传给后端,也可以append进去
    formData.append('description', '这是一批用户上传的文件');
    formData.append('uploaderId', 'user-123');

    // 使用Fetch API发送请求
    fetch(uploadUrl, {
        method: 'POST',
        body: formData,
        // FormData会自动设置正确的Content-Type,所以通常不需要手动设置 'Content-Type': 'multipart/form-data'
    })
    .then(response => {
        // 检查HTTP响应状态码,例如200-299表示成功
        if (!response.ok) {
            // 抛出错误,以便在catch块中统一处理
            throw new Error(`HTTP 错误!状态码: ${response.status}`);
        }
        return response.json(); // 解析JSON响应,或者根据后端返回类型选择response.text()等
    })
    .then(data => {
        console.log('文件上传成功:', data);
        // 在这里可以根据后端返回的数据更新UI,比如显示上传成功的文件列表或消息
        alert('文件已成功上传!');
    })
    .catch(error => {
        console.error('文件上传失败:', error);
        // 向用户显示错误信息
        alert(`文件上传过程中发生错误: ${error.message}`);
    });
});
登录后复制

你看,整个流程是不是挺清晰的?前端负责收集文件、打包,然后一股脑儿扔给后端。后端收到

multipart/form-data
登录后复制
请求后,就能解析出这些文件和其他字段了。

性能与体验:大文件或批量上传的挑战与优化

当我们谈到多文件上传,特别是文件数量多或者单个文件体积大的时候,‘卡顿’、‘等待’这些词就容易浮现出来。这不仅仅是后端处理能力的锅,前端也得担起一部分责任。

文件太大,一次性上传可能导致网络超时或者内存溢出。这时候,‘分片上传’(Chunked Upload)就显得尤为重要。简单来说,就是把一个大文件切成很多小块,一块一块地传。每块传完后,后端再负责把它们拼起来。JS里可以用

File.prototype.slice()
登录后复制
方法来实现文件切片。这有点像你寄一个超大的包裹,物流公司会建议你拆成几个小包裹分批寄送,既安全又高效。

webuploader-js实现多图片批量上传插件
webuploader-js实现多图片批量上传插件

webuploader-js实现多图片批量上传插件

webuploader-js实现多图片批量上传插件 101
查看详情 webuploader-js实现多图片批量上传插件
// 伪代码,展示分片上传的核心思路
async function uploadFileInChunks(file, uploadUrl, chunkSize = 1024 * 1024 * 5) { // 默认5MB一片
    let start = 0;
    let chunkIndex = 0;
    const totalChunks = Math.ceil(file.size / chunkSize);
    const fileId = `${file.name}-${file.size}-${file.lastModified}`; // 唯一标识文件,用于后端合并

    console.log(`开始上传文件: ${file.name},总大小: ${file.size}字节,共 ${totalChunks} 片。`);

    while (start < file.size) {
        const end = Math.min(start + chunkSize, file.size);
        const chunk = file.slice(start, end); // 核心:文件切片

        const formData = new FormData();
        formData.append('fileChunk', chunk);
        formData.append('fileName', file.name);
        formData.append('fileId', fileId); // 传递文件唯一ID
        formData.append('chunkIndex', chunkIndex);
        formData.append('totalChunks', totalChunks);
        // 还可以加上文件MD5等信息,用于后端校验和断点续传

        try {
            const response = await fetch(uploadUrl, { method: 'POST', body: formData });
            if (!response.ok) {
                throw new Error(`分片 ${chunkIndex} 上传失败,状态码: ${response.status}`);
            }
            const data = await response.json();
            console.log(`分片 ${chunkIndex}/${totalChunks} 上传成功`, data);
            // 这里可以更新UI上的进度条
        } catch (error) {
            console.error(`文件 ${file.name} 的分片 ${chunkIndex} 上传失败:`, error);
            // 提示用户,并可能实现重试逻辑
            return false; // 停止后续上传
        }

        start = end;
        chunkIndex++;
    }
    console.log(`文件 ${file.name} 所有分片上传完成。`);
    return true; // 表示所有分片上传成功
}
// 实际调用可能这样:
// fileInput.addEventListener('change', async (event) => {
//     const files = event.target.files;
//     for (const file of files) {
//         await uploadFileInChunks(file, '/api/upload-chunk-endpoint');
//     }
// });
登录后复制

其次,对于大量的图片或文件,在上传前做一些客户端的压缩处理也是个好主意。比如图片可以用

canvas
登录后复制
进行尺寸调整或质量压缩,能有效减少传输数据量。这虽然增加了前端的计算负担,但能显著提升整体上传体验。

最后,别忘了Web Workers。当你在前端进行文件切片、MD5计算或者图片压缩这些耗时操作时,如果直接在主线程执行,页面很可能就卡死了。把这些计算任务扔给Web Worker,让它们在后台默默工作,主线程依然可以响应用户的操作,这样用户体验就流畅多了。这就像是把厨房里切菜洗菜的活儿交给帮手,自己可以继续招呼客人。

前端交互:上传进度、取消与错误反馈

上传文件这事儿,用户最怕的就是‘没反应’。一个好的上传体验,必须让用户清楚地知道当前发生了什么。

进度条是必不可少的。对于

XMLHttpRequest
登录后复制
,你可以监听
xhr.upload.onprogress
登录后复制
事件来获取上传进度。这个事件会周期性地触发,告诉你已经上传了多少字节,总共有多少字节。有了这些数据,你就能实时更新进度条了。
Fetch API
登录后复制
虽然原生不支持
onprogress
登录后复制
,但可以通过
ReadableStream
登录后复制
来模拟,不过对于文件上传场景,
XMLHttpRequest
登录后复制
在进度追踪上确实更直接方便一些。

// 使用XMLHttpRequest实现文件上传进度显示和取消功能
function uploadFileWithProgress(file, url, onProgress, onComplete, onError, onCancel) {
    const xhr = new XMLHttpRequest();

    // 监听上传进度
    xhr.upload.onprogress = (event) => {
        if (event.lengthComputable) {
            const percentComplete = (event.loaded / event.total) * 100;
            onProgress(percentComplete.toFixed(2)); // 回调进度
        }
    };

    // 监听上传完成
    xhr.onload = () => {
        if (xhr.status >= 200 && xhr.status < 300) {
            onComplete(JSON.parse(xhr.responseText)); // 成功回调
        } else {
            onError(`上传失败: ${xhr.status} - ${xhr.statusText}`); // 错误回调
        }
    };

    // 监听上传错误(网络问题等)
    xhr.onerror = () => {
        onError('网络错误或请求失败');
    };

    // 监听上传被取消
    xhr.onabort = () => {
        onCancel('上传已取消');
    };

    xhr.open('POST', url);
    const formData = new FormData();
    formData.append('file', file); // 假设只上传一个文件,多文件类似处理

    xhr.send(formData);

    // 返回xhr对象,以便外部可以调用abort()方法取消上传
    return xhr;
}

// 示例用法:
// const uploadXHR = uploadFileWithProgress(
//     fileInput.files[0],
//     '/api/upload-single-file',
//     (progress) => { console.log(`上传进度: ${progress}%`); /* 更新UI进度条 */ },
//     (data) => { console.log('上传成功:', data); /* 提示用户 */ },
//     (error)
登录后复制

以上就是JS如何实现多文件上传的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号