不少时候咱们都会有图片上传的功能需求,若是咱们先将图片上传到服务器,而后在将返回结果显示在前端,这样的操做性能开销太大,若是图片一多,简直要哭,并且万一还碰到了上传错误要删除的,那简直没法想象了。因此咱们须要先将图片在前端展现后,而后由用户确认没有问题了,再统一上传,这样才是比较理想的。css
input
type=file
相信你们都知道,要在前端实现图片的上传,咱们离不开的是一个 <input>
type=file 的 input 元素,该元素能够容许用户选择一个或者多个文件。html
<input type="file">
复制代码
此时,咱们点击 input 元素,就能够浏览本地文件并选择上传。可是,此时咱们只能选择一个文件,而不能多个。这时就须要 <input>
标签的另外一个属性 multiple
前端
multiple
multipla
属性容许用户选择多个文件,他是一个不须要值的属性,也就是说,只要你的 input
标签上出现了这个属性,那么不论其值是什么,他都会支持多文件选择。一般来讲咱们使用 multiple 只会使用其属性名,而不会给他加值web
<input type='file' multiple>
复制代码
accept
若是你尝试了以上标签及属性,你会发现你的不但能选择 image 文件,还能选择其余各类各样的文件。可是通常来讲对咱们有须要的只是 image 文件,至于其余什么的,爱咋咋地吧,只要不出来妨碍我就能够了。因此这时候咱们须要 accept 的属性来进行限制。accept 属性接受逗号分隔的 MIME 类型字符串:数组
1. accept='image/png' 或者 accept='.png' --只接受 .png 格式的图片
2. accept='iamge/png,image/jpeg' 或者 accept='.png, .jpg .jpeg' 接受 .png .jpeg .jpg 格式的图片
3. accept='image/*' 接受全部类型的 image
<input type='file' multiple accetp='image/*'>
复制代码
注: 'image/*' 在部分浏览器中(Chrome和Safari等Webkit浏览器)响应比较缓慢,能够用如下方法代替浏览器
<<input type="file" multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif'>
复制代码
样式
通常来讲咱们都会将 input 设置为 display:none
, 而后经过 label 来设置其显示样式服务器
// css
input{
display:none;
}
label{
// 关于label样式
}
// html
<input type='file' multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif' id='inputFile'>
<label for="inputFile">上传图片</label>
复制代码
FileList 对象
选中文件经过 HTMLInputElement.files 属性返回了一个 FileList 对象,这个对象是一个包含了许多 file 文件的列表。每一个 file 对象包含了一下信息:app
1. name:文件名
2. lastModified:文件最后一次修改时间(时间戳形式)
3. lastModifiedDate:文件最后一次修改时间(UNIX timestamp形式)
4. size: 文件大小(byte 为单位)
5. type:文件 MIME 类型
复制代码
咱们能够经过对 input 标签监听 change 事件:异步
// js
document.getElementById('inputFile').addEventListener('change', changeHandler, false);
function changeHandler(e) {
var files = e.target.files;
console.log(files) // 这里咱们能获取到所选择的文件信息,须要注意的一点是 files 是个类数组对象。
}
复制代码
FileReader or 对象 URL
当咱们获取到文件对象信息 files 了之后,咱们要如何将他在页面上预览出来,这里提供了两种方法:FileReader 或者 对象 URL。
这两种方法该如何使用,又有何区别呢?svg
1. FileReader
FileReader 实现了一种异步的读取机制。他必须先经过 FileReader()
构造函数建立出一个 fileReader 实例。该实例实现了一下几个方法和事件(部分):
-
readerAsDataURL(file): 读取文件并以数据 URI 形式保存在 result 属性中
-
load 事件:在文件加载成功后触发 load 事件
-
error 事件:在文件加载失败后触发 error 事件
-
progress 事件:在读取文件的过程当中触发 progress 事件,该事件能够近似(间隔性触发,不是实时响应)监听文件上传进度。该方法有三个属性:lengthComputable(进度信息是否可用), loaded(已经加载了多少), total总共有多少。
usage:
files.forEach(function(item) {
var reader = new FileReader();
reader.readAsDataURL(item);
reader.onprogress = function(e) {
if (e.lengthComputable) {
// 简单把进度信息打印到控制台吧
console.log(e.loaded / e.total + '%')
}
}
reader.onload = function(e) {
var image = new Image()
image.src = e.target.result
body.appendChild(image)
}
reader.onerror = function(e) {
console.log('there is an error!')
}
})
复制代码
2. 对象 URL
对象 URL 指的是引用保存在 File 或 Blob 中的数据 URL。使用对象 URL 的时候不用像 FIleReader 同样要先把数据读取到 JavaScript 中,他能够引用 内存中 URL 地址而使用。
建立对象 URL 方法: window.URL.createObjectURL()。兼容写法:
function creatObjectURL(file) {
if (window.URL) {
return window.URL.createObjectURL(file);
} else if (window.webkitURL) {
return window.webkitURL.createObjectURL(file);
} else {
return null
}
}
复制代码
usage:
files.forEach(function(item) {
var url = createObjectURL(item)
var image = new Image()
image.src = url
body.appendChild(image)
})
复制代码
区别:
-
FileReader 是异步操做,而对象 URL 是同步操做
-
FileReader.readAsDataURL 返回的是一个包含更多字节的
base64
格式,createObejctURL 返回的是一个带 hash 的 URL。 -
因为二者返回形式不一样,FileReader.readerAsDataURL 会占用更多内存,可是当你再也不使用他的时候,他会自动释放内存,而 createObjectURL 则只有当你的页面关闭或者手动调用 revokeObejctURL 的时候才能释放内存。
-
从兼容性来讲: createObjectURL 和 FileReader.readerAsDataURL 都兼容 IE10+ 和现代全部主流浏览器
-
createObjectURL 相对 FileReader.readerAsDataURL,效率较高。可是若是图片较多,则最好手动清除内存,能够把 URL 当作参数直接传给 window.URL.revokeObjectURL()。兼容写法:
function revokeObjectURL(url) { if (widnow.URL) { return window.URL.revokeObjectURL(url) } else { return window.webkitURL.revokeObjectURL(url) } } 复制代码
简单实现:
// css input{ display:none; } label{ // 关于label样式 } // html <input type='file' multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif' id='inputFile'> <label for="inputFile">上传图片</label> // js var inputFile = document.getElementById('inputFile') var body = document.body || document.getElementsByTagName('body')[0] inputFile.addEventListener('change', changeHandler, false) function changeHandler(e) { var files = Array.from(e.target.files) files.forEach(function(item) { var image = new Image() image.src = createObjectURL(item) body.appendChild(image) image.onload = function() { revokeObjectURL(this.src) } }) } function createObjectURL(file) { if (window.URL) { return window.URL.createObjectURL(file) } else { return window.webkitURL.createObjectURL(file) } } function revokeObjectURL(file) { if (window.URL) { return window.URL.revokeObjectURL(file) } else { return window.webkitURL.revokeObjectURL(file) } } } else { 前端学习培训、视频教程、学习路线,添加威信 kaixin666haoyun 与我联系 }