html5提供了原生的文件上传能力,通过给input标签添加multiple属性就可以实现文件多选,但是原生的多选功能没有内置的数量限制,需要开发者自己编写逻辑来实现同时上传数量的管控。实现这个限制需要从前端交互和后端校验两个层面共同处理,才能确保限制规则不会被绕过。

html5多选上传的基础实现
首先我们需要了解html5多选上传的基础代码结构,核心是使用带有multiple属性的<input>标签,同时配合File API来获取用户选择的文件列表。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件多选上传</title>
</head>
<body>
<!-- multiple属性开启多选 -->
<input type="file" id="fileInput" multiple accept="image/*">
<button id="uploadBtn">上传文件</button>
<div id="fileList"></div>
<script>
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const fileList = document.getElementById('fileList');
// 监听文件选择变化
fileInput.addEventListener('change', function() {
const files = this.files;
fileList.innerHTML = '';
// 遍历选中的文件
for (let i = 0; i < files.length; i++) {
const li = document.createElement('li');
li.textContent = `文件名:${files[i].name},大小:${(files[i].size / 1024).toFixed(2)}KB`;
fileList.appendChild(li);
}
});
</script>
</body>
</html>
前端限制同时上传数量的逻辑实现
前端限制是用户交互的第一层管控,核心是在用户选择文件的时候校验选中的文件数量,如果超出限制就给出提示,并且清空不符合要求的文件选择。
选择时的数量校验
我们可以在<input>的change事件中,判断选中的文件数量是否超过预设的最大值,如果超过就提示用户,并且重置input的值,避免不符合要求的文件被后续处理。
// 预设最大同时上传数量
const MAX_UPLOAD_COUNT = 3;
fileInput.addEventListener('change', function() {
const selectedFiles = this.files;
const selectedCount = selectedFiles.length;
// 判断数量是否超出限制
if (selectedCount > MAX_UPLOAD_COUNT) {
alert(`最多只能同时上传${MAX_UPLOAD_COUNT}个文件,当前选中了${selectedCount}个,请重新选择`);
// 重置input的值,清空已选文件
this.value = '';
fileList.innerHTML = '';
return;
}
// 数量符合要求,展示文件列表
fileList.innerHTML = '';
for (let i = 0; i < selectedCount; i++) {
const li = document.createElement('li');
li.textContent = `文件名:${selectedFiles[i].name},大小:${(selectedFiles[i].size / 1024).toFixed(2)}KB`;
fileList.appendChild(li);
}
});
上传时的二次校验
有些场景下用户可能会多次选择文件然后合并上传,这时候需要在点击上传按钮的时候再做一次数量校验,避免累计选择的文件超出限制。
// 存储累计选择的文件
let totalFiles = [];
fileInput.addEventListener('change', function() {
const newFiles = Array.from(this.files);
// 合并新选择的文件和之前存储的文件
const tempFiles = totalFiles.concat(newFiles);
if (tempFiles.length > MAX_UPLOAD_COUNT) {
alert(`累计最多只能上传${MAX_UPLOAD_COUNT}个文件,当前已选择${tempFiles.length}个,请移除部分文件`);
this.value = '';
return;
}
totalFiles = tempFiles;
// 展示所有已选文件
renderFileList();
this.value = '';
});
// 渲染文件列表的方法
function renderFileList() {
fileList.innerHTML = '';
totalFiles.forEach((file, index) => {
const li = document.createElement('li');
li.textContent = `文件名:${file.name},大小:${(file.size / 1024).toFixed(2)}KB`;
// 添加移除按钮
const removeBtn = document.createElement('button');
removeBtn.textContent = '移除';
removeBtn.addEventListener('click', () => {
totalFiles.splice(index, 1);
renderFileList();
});
li.appendChild(removeBtn);
fileList.appendChild(li);
});
}
// 上传按钮点击事件
uploadBtn.addEventListener('click', function() {
if (totalFiles.length === 0) {
alert('请先选择要上传的文件');
return;
}
if (totalFiles.length > MAX_UPLOAD_COUNT) {
alert(`最多只能上传${MAX_UPLOAD_COUNT}个文件,当前已选择${totalFiles.length}个`);
return;
}
// 后续上传逻辑
console.log('开始上传文件,数量:', totalFiles.length);
});
后端配合校验的必要性
前端限制只是交互层面的管控,用户可以通过修改前端代码、直接调用接口等方式绕过前端的限制,所以后端必须做同样的数量校验,才能确保限制规则生效。
后端校验的逻辑比较简单,在接收上传文件的接口中,判断请求中携带的文件数量是否超过限制值,如果超过就返回错误提示,拒绝处理请求。
<?php
// 预设最大上传数量
$maxUploadCount = 3;
// 判断是否有文件上传
if (!isset($_FILES['files'])) {
echo json_encode(['code' => 400, 'msg' => '未检测到上传文件']);
exit;
}
// 获取上传的文件数量
$fileCount = count($_FILES['files']['name']);
if ($fileCount > $maxUploadCount) {
echo json_encode(['code' => 400, 'msg' => '最多只能同时上传' . $maxUploadCount . '个文件']);
exit;
}
// 后续文件处理逻辑
echo json_encode(['code' => 200, 'msg' => '文件数量校验通过,开始处理上传']);
?>
常见注意事项
- 前端的<input>标签的multiple属性只是开启多选,不会限制数量,必须自己写逻辑校验
- 重置input的值使用
input.value = '',不要用其他清空方式,避免兼容性问题 - 如果业务需要限制单个文件大小,可以结合
file.size属性一起校验,和数量限制逻辑类似 - 后端校验是必须的,不能只依赖前端限制,否则限制规则很容易被绕过
需要注意的是,不同浏览器对文件上传的处理有细微差异,建议在主流浏览器中都测试一遍数量限制的逻辑,确保交互符合预期。