JS34 文件上传前实时预览
上传图片前在本地预览的方法。
概述
上传图片前在本地预览
当使用<input type="file">上传图片文件时,如何在上传到服务器之前,在本地进行预览?
FileReader对象
FileReader对象允许Web应用程序异步读取用户计算机上的文件。使用new创建一个FileReader实例对象:
1 | const fileReader = new FileReader(); |
属性
error:在读取时发生的错误readyState:fileReader当前状态result:读取到的文件内容,只有在读取操作完成后有效
方法
abort():终止读取操作readAsDateURL():读取文件中的内容,读取完成后调用onloadend方法,结果result中包含一个data:URL格式的字符串表示文件内容(针对图片就是base64格式的字符串)
事件处理程序
onabort:读取被终止时被调用onerror:读取错误时调用onload:读取成功时调用onloadend:读取完成时调用,无论成功失败, 在onload或onerror后调用onloadstart:读取开始前调用onprogress:读取过程中周期调用、
兼容性
可以看出除了IE系列支持不太好之外,包括Edge在内兼容性还是不错的。
使用FileReader对象预览图片
- 在
<input>的onchange事件中获取上传的图片对象 - 使用
<input>的event.target.files获取上传对象的类数组对象,每一项的name属性对应文件名 <input>中增加multiple属性,上传多个文件- 创建
FileReader对象,并通过readAsDateURL()方法,传入要预览的文件对象,在onload回调函数中对FileReader对象的result进行处理
预览多张图片的Demo:
1 | <body> |
由于FileReader读取的过程是一个异步函数,我们可以封装为一个Promise形式进行更方便的调用:
1 | function asyncPreview(file) { |
拖拽预览
不通过点击事件而是通过将图片拖拽到指定区域实现预览。
在拖放过程中会触发的事件:
- 在源元素上触发的事件(需要设置
draggable属性)ondragstart:开始拖动时触发ondrag:拖动时触发ondragend:拖动完成时触发
- 释放时触发的事件
ondragenter:进入容器范围时触发ondragover:拖动时触发(触发间隔350毫秒)ondragleave:离开容器范围时触发ondrop:拖动过程中,释放鼠标按键时触发
显然这里需要使用的是ondrop事件,但是需要注意,使用ondrop事件需要阻止浏览器dragenter、dragleave、dragover和drop事件的默认行为,否则不会触发
1 | // 释放 |
在ondrop事件中触发上面的函数preview就可以实现图片预览了。注意,input 的onchange事件获取文件对象是e.target.files,而drop事件则是e.dataTransfer.files
如果报错event.js:501 Uncaught TypeError: this._drop is not a function是因为事件冒泡的原因,所以要增加e.stopPropagation()
window.URL.createObjectURL()
也可以通过这个方法来实现图片的预览
它对IE的支持比fileReader稍好一些
window.URL属性返回一个对象,它提供了用于创建和管理对象URLs的静态方法。它也可以作为一个构造函数被调用来构造URL对象。
URL.createObjectURL() 静态方法会创建一个 DOMString,这个新的URL 对象表示指定的File对象或Blob对象。
在每次调用createObjectURL()方法时,都会创建一个新的URL对象,即使已经用相同的对象作为参数创建过。当不再需要这些URL对象时,每个对象必须通过调用URL.revokeObjectURL()方法来释放。浏览器会在文档退出的时候自动释放它们,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。
1 | // 使用 createObjectURL |
fileReader和URL.createObjectURL的区别
(1)兼容性
URL.createObjectURL()对IE10和IE11的支持更好一些,但是总体上来说,二者兼容性是差多不的
(2)异步
fileReader是异步读取的过程,而URL.createObjectURL()是同步读取的,所以如果是读取比较大的图片会对性能有一定影响。为了解决这个问题可以再Web Woker中完成读取的操作。
(3)释放
上面提到了,使用URL.createObjectURL()时,从性能角度出发,可以通过手动调用URL.revokeObjectURL()来释放URL对象