要实现 input type=file
上传除图片和视频外的所有文件,你可以通过 accept
属性来指定允许的文件类型。
核心思想:accept
属性允许你指定一个逗号分隔的列表,其中包含:
* MIME 类型: 例如 text/plain
, application/pdf
, application/zip
等。
* 文件扩展名: 例如 .doc
, .xls
, .txt
等。
* 通配符: 例如 */*
表示所有文件,audio/*
表示所有音频文件。
为了排除图片和视频,我们可以采取两种策略:
策略一:明确列出所有允许的类型(推荐,更安全)
这是最安全和最精确的方法。你需要了解你期望用户上传的“除图片和视频外”的文件类型,然后将它们一一列出。
示例:
假设你想允许上传文本文件(.txt)、PDF 文档(.pdf)、ZIP 压缩包(.zip)、Word 文档(.doc/.docx)和 Excel 表格(.xls/.xlsx)。html
<input type="file" accept=".txt,application/pdf,application/zip,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
说明:
* .txt
: 允许 .txt 文件。
* application/pdf
: 允许 PDF 文件。
* application/zip
: 允许 ZIP 文件。
* application/msword
: 允许旧版 Word 文档 (.doc)。
* application/vnd.openxmlformats-officedocument.wordprocessingml.document
: 允许新版 Word 文档 (.docx)。
* application/vnd.ms-excel
: 允许旧版 Excel 表格 (.xls)。
* application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
: 允许新版 Excel 表格 (.xlsx)。
优点:
* 精确控制: 只有指定的文件类型才能被选择。
* 安全性: 避免用户上传不期望的文件类型。
缺点:
* 维护成本: 如果需要支持的文件类型很多,列表会很长。
* 不全面: 如果你不知道所有可能的“非图片/视频”文件类型,可能会遗漏。
策略二:使用通配符并排除(不太推荐,可能存在安全隐患)
理论上,你可以尝试使用 */*
来允许所有文件,然后在服务器端进行过滤。然而,accept
属性在前端主要是一个用户体验的辅助,它不能完全阻止用户选择不希望的文件类型。用户仍然可以绕过浏览器限制,选择任何文件。
更实际的“排除”思路(尽管 accept
本身没有直接的“排除”语法):
如果你真的想用 accept
属性来尝试“排除”,一个更可行的方向是:
1. 允许所有文件(不写 accept
属性,或者写 accept="*/*"
)。
2. 在前端 JavaScript 中验证文件类型:在用户选择了文件后,通过 FileList
对象检查每个文件的 type
属性或文件扩展名。
3. 在后端服务器端验证文件类型:这是最重要的,也是唯一真正安全的方法。服务器端必须验证上传文件的类型,以防止恶意文件被上传。
示例(前端 JavaScript 验证):html
<input type="file" id="fileInput">
<script>
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', (event) => {
const files = event.target.files;
const allowedTypes = ['txt', 'pdf', 'zip', 'doc', 'docx', 'xls', 'xlsx']; // 允许的文件扩展名
const imageVideoTypes = ['image/', 'video/']; // 包含图片和视频的 MIME 类型前缀
for (const file of files) {
const fileName = file.name.toLowerCase();
const fileExtension = fileName.slice((fileName.lastIndexOf(".") - 1 >>> 0) + 2);
const fileType = file.type.toLowerCase();
let isAllowed = false;
// 检查是否是允许的文件扩展名
if (allowedTypes.includes(fileExtension)) {
isAllowed = true;
}
// 额外检查,确保上传的文件不是图片或视频 (更严谨的做法)
if (isAllowed) {
for (const prefix of imageVideoTypes) {
if (fileType.startsWith(prefix)) {
alert(`文件 "${file.name}" 是图片或视频,不允许上传。`);
isAllowed = false; // 标记为不允许
break; // 找到匹配就退出内层循环
}
}
}
if (!isAllowed) {
alert(`文件 "${file.name}" 的类型不允许上传。`);
// 这里可以清除文件选择,或者提示用户
event.target.value = ''; // 清除当前选择
return; // 停止处理其他文件
}
}
});
</script>
为什么不推荐直接用 accept
来“排除”?
* accept
属性的语法没有提供明确的“排除”选项。你无法写出 accept="*/*,-image/*,-video/*"
这样的语法。
* 即使你尝试使用非常通用的 MIME 类型,也很难精确地排除所有图片和视频,并且可能会无意中排除其他你想要的文件类型。
* 安全性是关键: accept
属性只是前端的提示,无法替代服务器端的严格文件类型验证。
总结:
最推荐的解决方案是:
1. 在 input type="file"
标签中使用 accept
属性,明确列出所有允许的文件类型(策略一)。
2. 在前端 JavaScript 中进行一次额外的验证,以提供更好的用户体验和更及时的反馈(可选,但推荐)。
3. 在后端服务器端进行最严格的文件类型验证,这是绝对必要的安全措施。
选择哪种策略取决于你的具体需求和对安全性的重视程度。对于大多数情况,策略一(明确列出允许的类型)是最佳实践。