javascript和HTML5上傳圖片之前實現預覽效果

龍恩0707發表於2015-06-28

一:FileList物件與file物件

     FileList物件表示使用者選擇的檔案列表,在HTML4中,file控制元件內只允許放置一個檔案,但是到了HTML5中,通過新增multiple屬性,file控制元件內允許一次放置多個檔案,控制元件內的每一個使用者選擇的檔案都是一個file物件,而FileList物件是file物件的列表;

比如如下程式碼:

選擇檔案<input type="file" id="file" multiple size="80"/>
<input type="button" onclick="ShowFileName();" value="檔案上傳"/>

我們可以按住ctrl鍵選擇多個檔案;

JS程式碼如下:

function ShowFileName() {
    var files = document.getElementById("file").files;
    for(var i = 0; i < files.length; i+=1) {
        var file = files[i];
        console.log(file);
        console.log(file.name);
     }
}

我們先列印下file物件有哪些屬性,在safari截圖如下:

如上圖可以看到有檔名(name)屬性,檔案大小(size)屬性,最後修改時間,還有type屬性等;

二:Blob物件

在HTML5中,新增一個Blob物件,代表原始二進位制資料,我們上面提到的file物件也繼承了這個Blob物件;

Blob物件有2個屬性,size屬性表示一個Blob物件的位元組長度,type屬性表示Blob的MIME型別,如果是未知型別,則返回一個空字串。

如下程式碼:

選擇檔案<input type="file" id="file" multiple size="80" accept="image/*"/>
<input type="button" onclick="ShowFileType();" value="顯示檔案資訊"/>
檔案位元組長度:<span id="size"></span><br/>
檔案型別:<span id="type"></span>

JS程式碼如下:

function ShowFileType() {
    var file = document.getElementById("file").files[0];
    var size = document.getElementById("size");
    var type = document.getElementById("type");
    // 顯示檔案位元組長度
    size.innerHTML = file.size;
    // 顯示檔案型別
    type.innerHTML = file.type;
    console.log(file);
}

我們列印出file,如下圖所示:

三:FileReader物件

    FileReader物件有5種方法,其中四種用於讀取檔案,另一種用來讀取過程中斷,需要注意的是:無論讀取成功與失敗,方法並不會返回讀取結果,而是將結果儲存在result屬性中。此物件也是非同步的。

FileReader物件的方法如下:

    readAsBinaryString(file): 這個方法將blob物件或檔案中的資料讀取為二進位制字串,通常我們將它傳送到伺服器端,伺服器端可以通過這段字串儲存檔案。

    readAsText(file,encoding): 以純文字形式讀取檔案,將讀取到的文字儲存在result屬性中,第二個引數用於指定編碼型別,可選的。

    readAsDataURL(file): 讀取檔案並將檔案以資料URL的形式儲存在result屬性中。

    readAsArrayBuffer(file): 讀取檔案並將一個包含檔案內容的ArrayBuffer儲存在result屬性中。

FileReader物件的事件如下:

    onabort:  資料讀取中斷時觸發

    onerror: 資料讀取出錯時觸發

    onloadstart: 資料讀取開始時觸發

    onprogress: 資料讀取中

    onload: 資料讀取成功完成時觸發

    onloadend: 資料讀取完成時觸發,無論成功或失敗。

我們可以先看看demo,如何使用FileReader物件中前面三個方法;注意:fileReader物件讀取的資料都儲存在result中,如下程式碼:

<p>
    <label>請選擇一個檔案:</label>
    <input type="file" id="file" />
    <input type="button" value="讀取影象" onclick = "readAsDataURL()"/>
    <input type="button" value="讀取二進位制資料" onclick = "readAsBinaryString()"/>
    <input type="button" value="讀取文字檔案" onclick = "readAsText()"/>
</p>
<div id="result"></div>

JS程式碼如下:

<script>
    var result = document.getElementById("result");
    if(typeof FileReader == 'undefined') {
        result.innerHTML = "抱歉,你的瀏覽器不支援FileReader";
    }
    // 將檔案以Data URL形式進行讀入頁面
    function readAsDataURL(){
        // 檢查是否為影象型別
        var simpleFile = document.getElementById("file").files[0];
        if(!/image\/\w+/.test(simpleFile.type)) {
            alert("請確保檔案型別為影象型別");
            return false;
        }
        var reader = new FileReader();
        // 將檔案以Data URL形式進行讀入頁面
        reader.readAsDataURL(simpleFile);
        reader.onload = function(e){
            console.log(this.result);
            result.innerHTML = '<img src="'+this.result+'" alt=""/>';
        }
    }
    // 將檔案以二進位制形式讀入頁面
    function readAsBinaryString(){
        // 檢查是否為影象型別
        var simpleFile = document.getElementById("file").files[0];
        if(!/image\/\w+/.test(simpleFile.type)) {
            alert("請確保檔案型別為影象型別");
            return false;
        }
        var reader = new FileReader();
        // 將檔案以二進位制形式進行讀入頁面
        reader.readAsBinaryString(simpleFile);
        reader.onload = function(e){
            // 在頁面上顯示二進位制資料
            result.innerHTML = this.result;
        }
    }
    // 將檔案以文字形式讀入頁面中
    function readAsText(){
        var simpleFile = document.getElementById("file").files[0];
        var reader = new FileReader();
        // 將檔案以文字形式讀入頁面中
        reader.readAsText(simpleFile);
        reader.onload = function(e){
            result.innerHTML = this.result;
        }
    }
</script>

如上程式碼,如果需要演示的話,可以複製程式碼到文字編輯器去,預覽下即可,這裡就不截圖了;但是如上程式碼,在safari瀏覽器就不支援了~   截圖如下:

四:btoa方法與atob方法

在HTML5中,btoa方法與atob方法來支援base64編碼,b可以被理解為一串二進位制資料,a可以被理解為一個ASCLL碼字串,btoa的使用方法如下:

    var result = window.btoa(data);

該方法用於將一串字串進行base64編碼處理,該方法使用一個引數,引數值由一串二進位制資料組成的Unicode字串,該方法返回編碼後的base64格式的字串。

atob方法使用如下所示:

    var result = window.atob(data);

該方法用於將一串經過base64編碼後的base64格式的字串進行解碼處理,該方法使用一個引數,引數值為一串經過base64編碼後的字串,方法返回經過解碼後的一串由二進位制資料組成的Unicode字串;

瀏覽器支援:firefox,chrome,opera10.5+及IE10+

什麼時候使用btoa方法呢?

當伺服器端資料庫中直接儲存了是圖片的二進位制資料及圖片檔案的格式時,當我們需要根據此二進位制資料來渲染圖片的時候非常有用;如下程式碼:

<p>
    <label>請選擇一個檔案:</label>
    <input type="file" id="file"/>
    <input type="button" value="讀取影象" onclick = "readPicture()" id="btnReadPicture"/>
</p>
<div id="result"></div>

JS程式碼如下:

if(typeof FileReader == 'undefined') {
    result.innerHTML = "抱歉,你的瀏覽器不支援FileReader";
}
function readPicture(){
    // 檢查是否為影象型別
    var simpleFile = document.getElementById("file").files[0];
    if(!/image\/\w+/.test(simpleFile.type)) {
        alert("請確保檔案型別為影象型別");
        return false;
    }
    var reader = new FileReader();
    // 將檔案以二進位制檔案讀入頁面中
    reader.readAsBinaryString(simpleFile);
    reader.onload = function(f){
        var result = document.getElementById("result");
        var src = "data:" + simpleFile.type + ";base64," + window.btoa(this.result);
        result.innerHTML = '<img src ="'+src+'"/>';
    }
}

當我們選擇一張影象的時候,點選讀取影象按鈕即可生成一張圖片,雖然此方法我們還可以使用我們上面介紹的readAsDataURL的方法也可以直接讀取影象,但是當伺服器中直接是儲存的是二進位制檔案的話,我們可以直接使用btoa此方法生成圖片即可;

下面我們可以看看atob的demo如下:

我們可以使用canvas來繪製一張圖片後,點選上傳圖片按鈕後,首先通過canvas元素的toDataURL()方法獲取該圖片的url地址,最後獲取該URL地址中的base64格式的字串,最後使用atob方法將其解碼為一串二進位制資料,並將該二進位制資料提交到伺服器端;如下程式碼:

<input type="button" value="上傳圖片" onclick="imgSave()"/><br/>
<canvas id="canvas" width="400" height="300"></canvas>

JS程式碼如下:

<script>
    var canvas;
    function draw(id) {
         canvas = document.getElementById(id);
        var context = canvas.getContext('2d');
        context.fillStyle = 'rgb(0,0,255)';
        context.fillRect(0,0,canvas.width,canvas.height);
        context.fillStyle = 'rgb(255,255,0)';
        context.fillRect(10,20,50,50);
    }
    draw('canvas');
    function imgSave(){
        var data = canvas.toDataURL("image/png");
        data = data.replace("data:image/png;base64,","");
        var xhr = new XMLHttpRequest();
        xhr.open("POST","uploadImg.php");
        xhr.send(window.atob(data));
    }
</script>

uploadImg.php自己寫;

下面我們來做一個本地圖片上傳前預覽效果,但是safari不支援,所以在做移動端的同學可能不好了,特別是在IOS6下就不支援哦,應該還有其他辦法可以解決的,我們可以看看百度的外掛,網址如下:

http://fex.baidu.com/webuploader/demo.html

之前我是做了一個上傳本地圖片之前預覽效果,如下連結:

http://www.cnblogs.com/tugenhua0707/p/3568134.html

今天為了學習FileReader,我們可以再來學習下;之前的本地上傳圖片預覽的話,不支援IE10+, 且把頁面放在伺服器端在IE下會有bug,如下所示:

如上所示,在IE下 這個方法  document.selection.createRange() 不支援,因此為了修復這個bug和在IE10+以上的話,今天又特意研究了下, 在file控制元件下獲取焦點情況下 document.selection.createRange() 將會拒絕訪問,所以我們要失去下焦點。我們可以再加一句程式碼就可以支援了 file.blur();

IE10+的bug的話,我們可以使用html5的上面介紹的檔案API來解決,先判斷是不是IE,如果是的話,且小於10的話,使用濾鏡的方法解決圖片上傳的問題,如果是其他瀏覽器的話,就使用html5的檔案上傳方法;但是safari沒有處理好,原因是safari不支援html5的fileReader的API,所以如果在移動端開發的圖片,如果需要相容IOS6和6+的話,請注意一下,並不支援~ 當然如果大家有更好的方案來支援IOS6的話,請留言,可以一起總結,一起學習~

五:上傳圖片之前預覽效果demo(Safari不相容)

 1. 在標準瀏覽器下(IE10+)使用HTML5中檔案API即可解決上傳圖片前預覽效果;在這裡有2中方案可以解決,第一種是使用檔案API,如下程式碼:

function html5Reader(file) {
    var file = file.files[0];
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function(e){
        var pic = document.getElementById("img");
        pic.src=this.result;
    }
}

2. 第二種方案是使用 URL.createObjectURL(fileObj) 這個方法和canvas技術,  我們先來看看 支援這個 URL.createObjectURL(fileObj) 的瀏覽器有哪些,我們可以點選下面的連線檢視:

http://caniuse.com/#search=createObjectURL/ 

 實現程式碼如下:

function html5Reader(file) {         
    var fileObj = file.files[0],
        img = document.getElementById("img");   
        // URL.createObjectURL  safari不支援
    img.src = URL.createObjectURL(fileObj);
    img.onload =function() {
        var data = getBase64Image(img);
        console.log(data);  // 列印出base64編碼
    }
}
function getBase64Image(img) {
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, img.width, img.height);
    var ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();
    var dataURL = canvas.toDataURL("image/"+ext);
    return dataURL;
}

HTML程式碼如下:

<input type="file" id="logo" name="logo" accept="image/*">
<img src= '' id="img"/>
<div id="btn" style="margin-top:50px;font-size:40px;">btn</div>
<canvas id="myCanvas"></canvas>

所有的JS程式碼如下:

<script>
        var EventUtil = {
            addHandler: function(element,type,handler) {
                if(element.addEventListener) {
                    element.addEventListener(type,handler,false);
                }else if(element.attachEvent) {
                    element.attachEvent("on"+type,handler);
                }else {
                    element["on" +type] = handler;
                }
            }
        };
         var btn = document.getElementById("btn");
         var pic = document.getElementById("img");
         function getBase64Image(img) {
              var canvas = document.createElement("canvas");
              canvas.width = img.width;
              canvas.height = img.height;

              var ctx = canvas.getContext("2d");
              ctx.drawImage(img, 0, 0, img.width, img.height);
              var ext = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();
              var dataURL = canvas.toDataURL("image/"+ext);
              return dataURL;
         }
         var ua = navigator.userAgent.toLowerCase();
         EventUtil.addHandler(btn,'click',function(){
            var file = document.getElementById("logo");
            
            var ext=file.value.substring(file.value.lastIndexOf(".")+1).toLowerCase();
            
             // gif在IE瀏覽器暫時無法顯示
             if(ext!='png'&&ext!='jpg'&&ext!='jpeg'){
                 alert("圖片的格式必須為png或者jpg或者jpeg格式!"); 
                 return;
             }
             if(/msie ([^;]+)/.test(ua)) {
                  var lowIE10 = RegExp["$1"]*1;
                  if(lowIE10 == 6){
                        // IE6瀏覽器設定img的src為本地路徑可以直接顯示圖片
                        file.select();
                        // 在file控制元件下獲取焦點情況下 document.selection.createRange() 將會拒絕訪問,所以我們要失去下焦點。
                        file.blur();

                        var reallocalpath = document.selection.createRange().text;
                        pic.src = reallocalpath;
                  }else if(lowIE10 > 6 && lowIE10 < 10){
                      // IE7~9 IE10+按照html5的標準去處理
                      file.select();
                      // 在file控制元件下獲取焦點情況下 document.selection.createRange() 將會拒絕訪問,所以我們要失去下焦點。
                      file.blur();

                      var reallocalpath = document.selection.createRange().text;
                      // 非IE6版本的IE由於安全問題直接設定img的src無法顯示本地圖片,但是可以通過濾鏡來實現
                      pic.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + reallocalpath + "\")";
                      // 設定img的src為base64編碼的透明圖片 取消顯示瀏覽器預設圖片
                      pic.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
                  }else if(lowIE10 >= 10) {
                      html5Reader(file);
                  } 
             }else {
                html5Reader(file);
             }
         });
         
         function html5Reader(file) {
             var fileObj = file.files[0],
                img = document.getElementById("img");
              // URL.createObjectURL  safari不支援
              img.src = URL.createObjectURL(fileObj);
              img.onload =function() {
                  var data = getBase64Image(img);
                  console.log(data);  // 列印出base64編碼
              }
              /*
              var file = file.files[0];
              var reader = new FileReader();
              reader.readAsDataURL(file);
              reader.onload = function(e){
                 var pic = document.getElementById("img");
                 pic.src=this.result;
              }*/
         }
    </script>

上傳圖片demo下載

相關文章