图片上传是一个普通不过的功能,而图片预览就是就是上传功能中必不可少的子功能了。在这以前,我曾经经过订阅input[type=file]元素的onchange事件,一旦更改路径则将图片上传至服务器,接着就获取图片路径并赋值到img元素上。先无论文件异步提交的解决方案,就是服务端清理那些临时的预览图片已经增长很多工做量了。
偶然从MDN上找到纯前端图片预览的相关资料,通过整理后记录下来以便往后查阅。css
FileReader是HTML5的新特性,用于读取Blob和File类型的数据。具体的用法以下:
1. 构造方式var fr = new FileReader();
2. 属性readyState
:类型为unsigned short,FileReader实例的当前状态,(EMPTY——0,尚未加载任何数据;LOADING——1,数据正在加载;DONE——2,已完成所有的读取请求),只读。result
:读取到的文件内容,只读。error
:类型为DOMError,表示在读取文件时发生的错误,只读。
3. 方法abort()
:停止读取操做,并将readyState设置为DONE。当没有执行读取操做时,调用该方法会抛DOM_FILE_ABORT_ERR异常。readAsArrayBuffer(Blob blob)
:读取数据,result属性被设置为ArrayBuffer类型readAsText(Blob blob [, encoding='utf-8'])
:读取数据,result属性被设置为String类型readAsBinaryString(Blob blob)
:读取数据,result属性被设置为原始二进制数据readAsDataURL(Blob blob)
:读取数据,result属性被设置为Data URI Scheme形式
4.事件onload
:读取数据成功后触发onerror
:读取数据时抛异常时触发onloadstart
:读取数据前触发onloadend
:读取数据后触发,在onload或onerror后触发onabort
:停止读取后触发onprogress
:读取过程当中周期性触发
5. 浏览器支持
FF3.6+,Chrome7+,IE10+
html
#preview{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="dummy.png"); }
var preview = document.getElementById('preview'); preview.style.filter = preview.currentStyle.filter + ";progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src='dummy.png')"; preview.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src="dummy1.png";
enabled
:可选项,设置滤镜是否激活。值范围true(默认),falsesizingMethod
:可选项,设置滤镜做用的图片在容器边界内的显示方式,值范围crop(剪切图片以适应容器尺寸),image(默认值,增大或缩小容器尺寸以适应图片的尺寸),scale(缩放图片以适应容器尺寸)src
:必填项,使用绝对或相对URL指向背景图片。当URL为用户计算机本地地址时有效, 而img元素的src为用户计算机本地地址时会抛不容许访问本地文件系统的异常。接下来咱们就利用FileReader的readAsDataURL来获取Data URI Scheme来实现图片预览的功能,而IE5.5~9咱们就使用滤镜DXImageTransform.Microsoft.AlphaImageLoader来做降级处理。
html片段:前端
<style type="text/css"> #preview{ width: 100px; height: 100px; } </style> <!--[if lte IE 9]> <style type="text/css"> #preview{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale); } </style> <![endif]--> <input type="file" onchange="showPreview(this);"/> <div id="preview"> </div>
js片段:git
var preview = function(el){ var pv = document.getElementById("preview"); // IE5.5~9使用滤镜 if (pv.filters && typeof(pv.filters.item) === 'function'){ pv.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = el.value; } else{ // 其余浏览器和IE10+(不支持滤镜)则使用FileReader var fr = new FileReader(); fr.onload = function(evt){ var pvImg = new Image(); pvImg.style.width = pv.offsetWidth + 'px'; pvImg.style.height = pv.offsetHeight + 'px'; pvImg.src = evt.target.result; pv.removeChild(0); pv.appendChild(pvImg); }; fr.readAsDataURL(el.files[0]); } };
因为IE11做了安全方面的考虑,使得在input[type=file]元素上经过value、outerHTML和getAttribute的方式都没法获取用户所选文件的真实地址,只能获取到 C:\fakepath\文件名称 。所以假如使用IE11,但文本模式却设置为10如下,那就没木有办法实现图片预览了。
解决办法1──在head标签下加入这句: 。这样就能够告诉IE,默认使用当前IE的最高版本解析、渲染网页了。
解决办法2──采用 document.selection.createRangeColleciton() 获取真实地址,具体操做以下:github
// 假设fileEl就是[type=file]元素 fileEl.select(); var filePath = document.selection.createRangeCollection()[0].htmlText;
经过FileReader的readAsDataURL方法获取的Data URI Scheme会生成一串很长的base64字符串,若图片较大那么字符串则更长,若页面出现reflow时则会致使性能降低。解决方案以下:
1. 预览的img标签使用绝对定位,从而脱离正常文档流,那么就与文档的其余元素无关了,而reflow时则不会影响性能。
2. 采用 window.URL.createObjectURL(Blob blob) 生成数据连接。
web
var createObjectURL = function(blob){ return window[window.webkitURL ? 'webkitURL' : 'URL']['createObjectURL'](blob); };
注意: window.URL.createObjectURL 生成的数据连接是独占内存的,所以若不时用时须要调用 window.URL.revokeObjectURL(DOMString objUrl) 来释放内存。在刷新页面时,也会自动释放内容。浏览器
var resolveObjectURL = function(blob){ window[window.webkitURL ? 'webkitURL' : 'URL']['revokeObjectURL'](blob); };
好吧,如今妈妈不再担忧个人图片预览实现得太麻烦了!
若是以为上面的使用方式不方便,能够访问https://github.com/fsjohnhuang/preview/blob/master/preview.js,我已经将其封装成工具函数了。安全
若是您以为本文的内容有趣就扫一下吧!捐赠互勉!
服务器