这篇文章主要介绍了 js 实现纯前端的图片预览的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
图片上传是一个普通不过的功能,而图片预览就是就是上传功能中必不可少的子功能了。在这之前,我曾经通过订阅 input[type=file] 元素的 onchange 事件,一旦更改路径则将图片上传至服务器,接着就获取图片路径并赋值到 img 元素上。先不管文件异步提交的解决方案,就是服务端清理那些临时的预览图片已经增加不少工作量了。
偶然从 MDN 上找到纯前端图片预览的相关资料,经过整理后记录下来以便日后查阅。
一、准备功夫 1──FileReader
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 形式(具体请浏览《JS 魔法堂:Data URI Scheme 介绍》)
(4). 事件
onload:读取数据成功后触发
onerror:读取数据时抛异常时触发
onloadstart:读取数据前触发
onloadend:读取数据后触发,在 onload 或 onerror 后触发
onabort:中止读取后触发
onprogress:读取过程中周期性触发
(5). 浏览器支持
FF3.6+,Chrome7+,IE10+
二、准备功夫 2──DXImageTransform.Microsoft.AlphaImageLoader 滤镜
(1). 作用:主要作用是对图片进行透明处理(IE5.5~6 并不支持透明的 png)
(2). 样式中的使用方式
- #preview{
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale,src="dummy.png");
- }
(3). JS 中的使用方式
- 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";
(4). 属性
enabled:可选项,设置滤镜是否激活。值范围 true(默认),false
sizingMethod:可选项,设置滤镜作用的图片在容器边界内的显示方式,值范围 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 片断:
- 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 以下,那就没木有办法实现图片预览了。
解决办法 2──采用 document.selection.createRangeColleciton() 获取真实地址,具体操作如下:
- // 假设fileEl就是[type=file]元素
- fileEl.select();
- var filePath = document.selection.createRangeCollection()[0].htmlText;
五、补充:使用 window.URL.createObjectURL 代替 FileReader
通过 FileReader 的 readAsDataURL 方法获取的 Data URI Scheme 会生成一串很长的 base64 字符串,若图片较大那么字符串则更长,若页面出现 reflow 时则会导致性能下降。解决方案如下:
1. 预览的 img 标签使用绝对定位,从而脱离正常文档流,那么就与文档的其他元素无关了,而 reflow 时则不会影响性能。
2. 采用 window.URL.createObjectURL(Blob blob) 生成数据链接。
- 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);
- };
来源: http://www.phperz.com/article/17/0223/266123.html