這兩天剛好有一位同事問我怎樣作一個圖片預覽功能。做爲現代人的咱們首先想到的固然是HTML5啦,其實HTML5作圖片預覽已是一個老生常談的問題了。我在這裏就簡單說說其中相關的一些東西,固然會附上咱們的源碼。在 HTML5 以前咱們作圖片預覽主流作法有兩種,第一種是經過 Flash 插件來作預覽,第二種是 Ajax 實現的假預覽,也就是說選擇圖片文件後,圖片其實已經異步上傳到服務器,服務器處理後返回圖片路徑,前端獲得響應結果作出處理從而使圖片顯示在界面上。而有了 HTML5 以後就能夠強烈鄙視上面兩種作法了。javascript
要作圖片預覽功能,就不得不介紹一下 FileReader,顧名思義,它是用來讀取文件的。固然新東西總會有一些頑固派排斥的,咱們先來看看其兼容性如何(這不是本文討論的重點)。css
PC端兼容列表html
移動端兼容列表 前端
兼容性的話你們根據本身的需求參考一下上面的對照表,咱們接着來看看 FileReader 的幾個經常使用屬性和經常使用方法java
屬性web
方法canvas
廢話很少說,咱們經過代碼來更直觀點認識上面的屬性和方法。迴歸到需求,作一個圖片預覽功能。首先理一理咱們須要有的東西,第一要素固然是文件(文件選擇器),第二固然是預覽(容器)。瀏覽器
html 代碼 (樣式我順手加上了)ruby
<!DOCTYPE html> <html> <head> <title>Cboyce-HTML5圖片預覽</title> <style type="text/css"> /*主容器*/ .container{ width: 90%; margin-top: 20px; } /*圖片預覽容器*/ .container .img-prev-container{ width: 200px; height: 100px; margin:10px auto; border:1px solid #ccc; } /*預覽圖片樣式*/ .container .img-prev-container img{ width: 100%; height: 100%; } </style> </head> <body> <div class="container"> <div class="img-prev-container"> </div> <input type="file" value="請選擇圖片" id="fileSelecter" /> </div> </body> </html>
接下來該 FileReader 出場了服務器
window.onload = function(){ //觸發 change 事件 GetDomById('fileSelecter').onchange = function(event){ //獲取文件對象 var file = event.target.files[0]; //建立reader對象 var reader = new FileReader(); //讀取完成後觸發 reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; console.log(_img_src) //添加預覽圖片到容器框 var img = document.createElement('img'); img.setAttribute('src',_img_src); GetDomById('img-perv-div').appendChild(img); } //獲取到數據的url 圖片將轉成 base64 格式 reader.readAsDataURL(file); } } //簡化 document.getElementById() 函數 function GetDomById(id){ return document.getElementById(id); }
細節注意:這裏的圖片格式默認轉爲 base64
補充說明:
event.target 屬性,其特色在咱們的代碼中其實不忙看出來 "捕獲當前事件做用的對象",通俗點來說就是,誰觸發了該事件,我就能經過該事件的 target 拿到誰。
其實上述代碼還有一個小 bug "換圖變成多圖"。 請看下圖
修復:改造 onload
reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //預覽圖的容器 var _img_container = GetDomById('img-perv-div') //添加預覽圖片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中沒有則建立,有則修改 src 屬性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } }
解決bug
上面咱們已經把基礎功能給完成了,接下來咱們給該程序加個拓展--拖拽圖片到預覽框自動加載。 要完成該功能仍是得靠 HTML5 的 Drag 和 drop。若是你還搞不清楚咱們要作什麼,那咱們先來看下最終效果。
在代碼開始以前咱們先來了解兩個實現該功能最爲關鍵的事件。 1. dragover 拖拽一個對象到目標對象上面觸發該事件 2. drop 拖放事件結束時觸發。通俗來說就是當咱們拖拽一個對象到目標對象上後放開(鬆開鼠標左鍵)該對象的時候觸發
接下來咱們來看下代碼,這裏也對以前的代碼作出了一些改造
window.onload = function(){ //預覽圖的容器 var _img_container = getDomById('img-perv-div') //建立reader對象 var reader = new FileReader(); //觸發 change 事件 getDomById('fileSelecter').onchange = function(event){ //獲取文件對象 var file = event.target.files[0]; //讀取完成後觸發 reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //添加預覽圖片到容器框 showPrevImg(_img_container,_img_src); } //獲取到數據的url 圖片將轉成 base64 格式 reader.readAsDataURL(file); } //添加拖放支持 _img_container.addEventListener('dragover',function(ev){ ev.preventDefault();//阻止默認事件。好比說Chrome是直接將圖片用瀏覽器打開 },false) _img_container.addEventListener('drop',function(ev){ ev.preventDefault(); reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //圖片預覽處理 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false) } //簡化 document.getElementById() 函數 function getDomById(id){ return document.getElementById(id); } //圖片預覽處理函數 function showPrevImg(_img_container,_img_src){ //添加預覽圖片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中沒有則建立,有則修改 src 屬性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } }
代碼分析
addEventListener('dragover',function(ev){ ev.preventDefault(); },false)
這段代碼重點在於 ev.preventDefault();
阻止默認行爲,若是咱們不阻止其默認行爲將會產生下面的後果
接下來要作的就是拖放結束展現圖片預覽效果
_img_container.addEventListener('drop',function(ev){ ev.preventDefault(); reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //添加預覽圖片到容器框 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false)
這裏用到 event.dataTransfer 咱們補充一下,咱們先來看下他的定義
dataTransfer 拖曳數據傳遞對象,其提供了對於預約義的剪貼板格式的訪問,以便在拖曳操做中使用
通俗來說就是,咱們在拖曳操做中可使用它來操做咱們拖曳的對象。好比拖圖片,經過它能拿到咱們所拖曳的圖片對象
最後,強迫症犯了,稍微寫了點樣式美化了一下完整代碼以下
<!DOCTYPE html> <html> <head> <title>Cboyce-HTML5圖片預覽</title> <style type="text/css"> body{ font-family: '微軟雅黑'; } /*主容器*/ .container{ width: 90%; margin-top: 20px; } /*每個圖片預覽項容器*/ .img-prev-item{ width: 200px; height: 200px; display: inline-block; border:1px solid #ccc; text-align: center; border-radius: 3px; } /*圖片預覽容器*/ .container .img-prev-container{ width: 200px; height: 156px; margin: 0 auto; border-bottom: 1px solid #ccc; vertical-align: middle; display: table-cell; padding: 2px; color: #838383; text-align: center } /*預覽圖片樣式*/ .container .img-prev-container img{ width: 100%; height: auto; max-height: 100%; } /*label*/ .selfile{ background-color: #0095ff; color: white; padding: 6px 58px; border-radius: 5px; } /*工具條 div*/ .tool{ padding-top: 9px; } /*隱藏文件選擇器*/ #fileSelecter{ display: none; } </style> </head> <body> <div class="container"> <div class="img-prev-item"> <div class="img-prev-container" id="img-perv-div"> 請選擇圖片或者<br />將圖片拖拽至此 </div> <div class="tool"> <label for="fileSelecter" class="selfile">請選擇圖片</label> <input type="file" value="請選擇圖片" id="fileSelecter" /> </div> </div> </div> <script type="text/javascript"> window.onload = function(){ //預覽圖的容器 var _img_container = getDomById('img-perv-div') //建立reader對象 var reader = new FileReader(); //觸發 change 事件 getDomById('fileSelecter').onchange = function(event){ //獲取文件對象 var file = event.target.files[0]; //讀取完成後觸發 reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //添加預覽圖片到容器框 showPrevImg(_img_container,_img_src); } //獲取到數據的url 圖片將轉成 base64 格式 reader.readAsDataURL(file); } //添加拖放支持 _img_container.addEventListener('dragover',function(ev){ //ev.stopPropagation(); ev.preventDefault();//阻止默認事件。好比說Chrome是直接將圖片用瀏覽器打開 console.log('dragover') },false) // _img_container.addEventListener('dragend',function(ev){ // ev.stopPropagation(); // ev.preventDefault(); // console.log('dragend') // },false) _img_container.addEventListener('drop',function(ev){ //ev.stopPropagation(); ev.preventDefault(); console.log('drop') //console.log(ev.dataTransfer.files[0]) reader.onload = function(ev){ //獲取圖片的url var _img_src = ev.target.result; //添加預覽圖片到容器框 showPrevImg(_img_container,_img_src); } reader.readAsDataURL(ev.dataTransfer.files[0]) },false) } //簡化 document.getElementById() 函數 function getDomById(id){ return document.getElementById(id); } function showPrevImg(_img_container,_img_src){ _img_container.innerHTML=""; //添加預覽圖片到容器框 var _imgs = _img_container.getElementsByTagName('img'); //容器中沒有則建立,有則修改 src 屬性 if(!_imgs.lenght){ _imgs[0] = document.createElement('img'); _imgs[0].setAttribute('src',_img_src); _img_container.appendChild(_imgs[0]); }else{ _imgs[0].setAttribute('src',_img_src); } } //接下來要作的就是拖放結束展現圖片預覽效果 </script> </body> </html>
運行效果以下
基本上實現以及代碼的原理也就解釋到這了。其實前端作的圖片預覽功能大多數需求是用來上傳到服務器的。不得不提到的是這裏的拖拽預覽雖然看起來體驗不錯,可是要將該文件上傳就得作一些特殊處理。這個我就留到後面的博客再講了,有問題的朋友能夠直接留言。
限於筆者技術,文章觀點不免有不當之處,但願發現問題的朋友幫忙指正,筆者將會及時更新。也請轉載的朋友註明文章出處並附上原文連接,以便讀者能及時獲取到文章更新後的內容,以避免誤導讀者。筆者力求避免寫些晦澀難懂的文章(雖然也有人說這樣顯得高逼格,專業),儘可能使用簡單的用詞和例子來幫助理解。若是表達上有好的建議的話也但願朋友們在評論處指出。
本文爲做者原創,轉載請註明出處! Cboyce