本文已经过原作者 Tapas Adhikary 授权翻译
上传文件功能可以说是项目经常出现的需求。从在社交媒体上上传照片到在求职网站上发布简历,文件上传无处不在。在本文中,我们将讨论 HTML文件上传支持的10种用法,希望对你有用。
我们可以将input 类型指定为file,以在Web应用程序中使用文件上传功能。
<input type="file" id="file-uploader">
input filte 提供按钮上传一个或多个文件。默认情况下,它使用操作系统的本机文件浏览器上传单个文件。成功上传后,File API 使得可以使用简单的 JS 代码读取File对象。要读取File对象,我们需要监听 change事件。
首先,通过id获取文件上传的实例:
const fileUploader = document.getElementById('file-uploader');
然后添加一个change 事件侦听器,以在上传完成后读取文件对象, 我们从event.target.files属性获取上传的文件信息:
fileUploader.addEventListener('change', (event) => {
const files = event.target.files;
console.log('files', files);
});
在控制台中观察输出结果,这里关注一下FileList数组和File对象,该对象具有有关上传文件的所有元数据信息。
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/rNLOyRm
如果我们想上传多个文件,需要在标签上添加 multiple 属性:
<input type="file" id="file-uploader" multiple />
现在,我们可以上传多个文件了,以前面事例为基础,选择多个文件上传后,观察一下控制台的变化:
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/MWeamYp
每当我们上传文件时,File对象都有元数据信息,例如file name,size,last update time,type 等等。这些信息对于进一步的验证和特殊处理很有用。
const fileUploader = document.getElementById('file-uploader');
// 听更 change 件并读取元数据
fileUploader.addEventListener('change', (event) => {
// 获取文件列表数组
const files = event.target.files;
// 遍历并获取元数据
for (const file of files) {
const name = file.name;
const type = file.type ? file.type: 'NA';
const size = file.size;
const lastModified = file.lastModified;
console.log({ file, name, type, size, lastModified });
}
});
下面是单个文件上传的输出结果:
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/gOMaRJv
我们可以使用accept属性来限制要上载的文件的类型,如果只想上传的文件格式是 .jpg,.png 时,可以这么做:
<input type="file" id="file-uploader" accept=".jpg, .png" multiple>
在上面的代码中,只能选择后缀是.jpg和.png的文件。
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/OJXymRP
成功上传文件后显示文件内容,站在用户的角度上,如果上传之后,没有一个预览的,就很奇怪也不体贴。
我们可以使用FileReader对象将文件转换为二进制字符串。然后添加load 事件侦听器,以在成功上传文件时获取二进制字符串。
// FileReader 实例
const reader = new FileReader();
fileUploader.addEventListener('change', (event) => {
const files = event.target.files;
const file = files[0];
reader.readAsDataURL(file);
reader.addEventListener('load', (event) => {
const img = document.createElement('img');
imageGrid.appendChild(img);
img.src = event.target.result;
img.alt = file.name;
});
});
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/zYBvdjZ
如果用户上传图片过大,为了不让服务器有压力,我们需要限制图片的大小,下面是允许用户上传小于 1M 的图片,如果大于 1M 将上传失败。
fileUploader.addEventListener('change', (event) => {
// Read the file size
const file = event.target.files[0];
const size = file.size;
let msg = '';
// 检查文件大小是否大于1MB
if (size > 1024 * 1024) {
msg = `<span style="color:red;">The allowed file size is 1MB. The file you are trying to upload is of ${returnFileSize(size)}</span>`;
} else {
msg = `<span style="color:green;"> A ${returnFileSize(size)} file has been uploaded successfully. </span>`;
}
feedback.innerHTML = msg;
});
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/pobjMKv
更好的用户体验是让用户知道文件上传进度,前面我们用过了FileReader以及读取和加载文件的事件。
const reader = new FileReader();
FileReader还有一个progress 事件,表示当前上传进度,配合HTML5的progress标签,我们来模拟一下文件的上传进度。
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
// 计算完成百分比
const percent = (event.loaded / event.total) * 100;
// 将值绑定到 `progress`标签
progress.value = percent;
}
});
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/eYzpwYj
我们可以上传整个目录吗?嗯,这是可能的,但有一些限制。有一个叫做webkitdirectory的非标准属性(目前只有谷歌浏览器还有Microsoft Edge支持按照文件夹进行上传),它允许我们上传整个目录。
目前只有谷歌浏览器还有Microsoft Edge支持按照文件夹进行上传,具体可以看下百度云盘的网页版的上传按钮,在火狐下就支持按照文件进行上传,而在谷歌和Edge下,就会给用户提供一个下拉,让用户选择是根据文件进行上传还是根据文件夹进行上传。
<input type="file" id="file-uploader" webkitdirectory />
用户必须需要确认才能上传目录
用户单击“上传”按钮后,就会进行上传。这里要注意的重要一点。FileList数组将以平面结构的形式包含有关上载目录中所有文件的信息。对于每个File对象,webkitRelativePath属性表示目录路径。
例如,上传一个主目录及其下的其他文件夹和文件:
现在,File 对象将将webkitRelativePath填充为:
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/dyXYRKp
不支持文件上传的拖拽就有点 low 了,不是吗?我们来看看如何通过几个简单的步骤实现这一点。
首先,创建一个拖放区域和一个可选的区域来显示上传的文件内容。
<div id="container">
<h1>Drag & Drop an Image</h1>
<div id="drop-zone">
DROP HERE
</div>
<div id="content">
Your image to appear here..
</div>
</div>
通过它们各自的ID获取dropzone和content 区域。
const dropZone = document.getElementById('drop-zone');
const content = document.getElementById('content');
添加一个dragover 事件处理程序,以显示将要复制的内容的效果:
dropZone.addEventListener('dragover', event => {
event.stopPropagation();
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
});
接下来,我们需要一个drop事件监听器来处理。
dropZone.addEventListener('drop', event => {
// Get the files
const files = event.dataTransfer.files;
});
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/ExyVoXN
有一个特殊的方法叫做URL.createobjecturl(),用于从文件中创建唯一的URL。还可以使用URL.revokeObjectURL()方法来释放它。
URL.revokeObjectURL() 静态方法用来释放一个之前已经存在的、通过调用 URL.createObjectURL() 创建的 URL 对象。当你结束使用某个 URL 对象之后,应该通过调用这个方法来让浏览器知道不用在内存中继续保留对这个文件的引用了。
fileUploader.addEventListener('change', (event) => {
const files = event.target.files;
const file = files[0];
const img = document.createElement('img');
imageGrid.appendChild(img);
img.src = URL.createObjectURL(file);
img.alt = file.name;
});
如果大家看到这里,有点激动,想手贱一下,可以 CodePen 玩玩,地址:https://codepen.io/atapas/pen/BazzaoN
无论何时,如果你还想学习本文涉及的一些知识,你可以在这里尝试。
https://html-file-upload.netlify.app/
天我们要来谈谈一个前端面试中经常出现的问题:如何实现上传图片并存储到服务器?这个问题听起来好像很复杂,但其实只要掌握了基本的HTML、JavaScript和一点后端知识,就能轻松搞定!
首先,我们需要一个HTML表单来让用户选择并上传图片。这个表单需要包含一个<input type="file">元素,让用户可以选择文件。然后,我们还需要一个提交按钮,让用户可以提交表单。
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" id="imageUpload" name="image">
<button type="submit">上传图片</button>
</form>
接下来,我们需要用JavaScript来监听表单的提交事件,并阻止表单的默认提交行为。然后,我们可以获取用户选择的文件,并创建一个FormData对象来存储这个文件。最后,我们用fetch API或者axios等库来发送一个POST请求到服务器,把文件传给服务器。
document.getElementById('uploadForm').addEventListener('submit', function(event) {
event.preventDefault();
const formData = new FormData();
const imageFile = document.getElementById('imageUpload').files[0];
formData.append('image', imageFile);
fetch('/api/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
});
在上面的代码中,我们假设服务器的API路径是/api/upload,你需要根据实际情况来修改这个路径。另外,我们还假设服务器会返回一个JSON响应,包含了上传结果的信息。当然,这也取决于你的后端实现。
好了,前端的工作我们就完成了。接下来,我们来看看服务器是怎么处理这个上传的图片的。
一般来说,服务器会接收到一个包含文件的POST请求,然后把这个文件保存到服务器的某个地方,比如一个文件系统或者一个云存储服务。这个过程的具体实现会依赖于你使用的后端框架和存储服务。
不过,有一点需要注意的是,为了安全起见,你应该在服务器端对上传的文件进行一些验证和过滤,比如检查文件的类型、大小等,防止恶意文件或者过大的文件上传到服务器。
总的来说,上传图片并存储到服务器这个功能虽然听起来很复杂,但其实只要掌握了基本的HTML、JavaScript和一点后端知识,就能轻松搞定。当然,这个过程还有很多细节和优化点可以探讨,比如如何显示上传进度、如何处理上传失败等等。但无论如何,只要你敢于尝试和挑战,就一定能成为一名优秀的前端工程师!
.表单上传
最传统的图片上传方式是form表单上传,使用form表单的input[type=”file”]控件,打开系统的文件选择对话框,从而达到选择文件并上传的目的。
form表单上传
表单上传需要注意以下几点:
(1).提供form表单,method必须是post。
(2).form表单的enctype必须是multipart/form-data。
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码。HTML表单如何打包数据文件是由enctype这个属性决定的。enctype有以下几种取值:
application/x-www-form-urlencoded:在发送前编码所有字符(默认)(空格被编码为’+’,特殊字符被编码为ASCII十六进制字符)。
multipart/form-data:不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain:空格转换为 “+” 加号,但不对特殊字符编码。
默认enctype=application/x-www-form-urlencoded,所以表单的内容会按URL规则编码,然后根据表单的提交方法:
method=’get’ 编码后的表单内容附加在请求连接后,
method=’post’ 编码后的表单内容作为post请求的正文内容。
(3).提供input type="file"上传输入域。
浏览器请求体如下:
请求体
2.ajax上传
ajax和FormData可实现页面无刷新的文件上传效果,主要用到了jQuery的ajax()方法和XMLHttpRequest Level 2的
FormData接口。通过FormData对象可以更灵活方便的发送表单数据,因为可以独立于表单使用。如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit()方法传输的数据格式相同。
ajax无刷新上传
Ajax无刷新上传的方式,本质上与表单上传无异,只是把表单里的内容提出来采用ajax提交,并且由前端决定请求结果回传后的展示结果。
3.各类插件上传
当上传的需求要求可预览、显示上传进度、中断上传过程、大文件分片上传等等,这时传统的表单上传很难实现这些功能,我们可以借助现有插件完成。
如百度上传插件Web Uploader、jQuery图片预览插件imgPreview 、拖拽上传与图像预览插件Dropzone.js等等,大家可根据项目实际需求选择适合的插件。
*请认真填写需求信息,我们会在24小时内与您取得联系。