圖片上傳是一個普通不過的功能,而圖片預覽就是就是上傳功能中必不可少的子功能了。在這以前,我曾經經過訂閱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,我已經將其封裝成工具函數了。安全
若是您以爲本文的內容有趣就掃一下吧!捐贈互勉!
服務器