1. 程式人生 > >移動端HTML5 檔案預覽及上傳

移動端HTML5 檔案預覽及上傳

本文主要介紹使用HTML5 圖片上傳及上傳前的預覽。本人是做PHP後端的,由於前端有時也需要自己寫,有空就研究了下圖片上傳預覽,寫的都是原生程式碼,廢話不多說,直接上程式碼。

前端程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>
Document</title> <style> *{ margin:0; padding:0; } ul,ol{ list-style-type:none; } .clearfix:after,.clearfix:before{ display:table; content:' '; } .clearfix:after{ clear
:both
} .tc{ text-align:center; } .select,.select_video{ height:2rem; line-height:2rem; background:#fff; border:1px solid #4285F4; margin:0.5rem 1rem; position:relative; } .select
label,.select_video label{ width:100%; position:absolute; top:0; left:0; font-size:14px; color:#333; } #upload,#upload_video{ display:none; } .preview,.video_preview{ margin:0.5rem 1rem; border:1px solid #bbb; padding:4px; display:none; } .preview_img_list li{ float:left; width:25%; padding:2px 0; } .preview_img_list li img{ vertical-align:top; max-width:98%; } .btn{ background: #4285F4; color:#fff; height:2.5rem; line-height:2.5rem; margin:2rem 1rem; border-radius:0.5rem; }
</style> <script> window.onload = function(){ var uploadBtn = document.querySelector('#upload'); var previewImgList = document.querySelector('.preview_img_list'); var uploadVideo = document.querySelector('#upload_video'); var submitBtn = document.querySelector('.submit'); imgArr = new Array(); uploadBtn.addEventListener('change',function(){ var imgLen = this.files.length; var liLen = previewImgList.getElementsByTagName('li').length; var ImgLen = imgLen + liLen ; if(ImgLen > 9){ alert("上傳最大數量不能大於9"); return false; } document.querySelector(".preview").style.display = 'block'; for(var i = 0; i < imgLen;i++){ var file = this.files[i]; var imgType = /^image\//; if(!imgType.test(file.type)){ continue; } var li = document.createElement('li'); var img = document.createElement("img"); li.appendChild(img); previewImgList.appendChild(li); var reader = new FileReader(); reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; initHW(); imgArr.push(e.target.result);}; })(img); reader.readAsDataURL(file); // var objectUrl = window.URL.createObjectURL(file); // img.src = objectUrl; } },false); uploadVideo.addEventListener('change',function(){ var file = this.files[0]; var videoType = /^video\//; if(!videoType.test(file.type)){ alert("所選檔案不是合法的視訊檔案"); return false; } var pv = document.querySelector('.video_preview'); var video = document.createElement('video'); video.setAttribute('controls','controls'); video.style.width = "100%"; pv.appendChild(video); pv.style.display = "block"; // var objectUrl = window.URL.createObjectURL(file); // video.src = objectUrl; // var reader = new FileReader(); reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(video); reader.readAsDataURL(file); video.play(); },false); submitBtn.addEventListener('click',function(){ if(!imgArr.length){ alert('請選擇要上傳的圖片'); return false; } var form = document.querySelector('form'); var fd = new FormData(form); for(var i = 0;i < imgArr.length;i++){ fd.append('file[]',imgArr[i]); } var request = new XMLHttpRequest(); var url = "./file_preview.php"; request.open('post',url); request.send(fd); },false); } // 初始化圖片寬度 // 使得圖片高度一致 function initHW(){ var previewImgList = document.querySelector('.preview_img_list'); var Lis = previewImgList.getElementsByTagName('li'); var LisLen = Lis.length; if(LisLen > 1){ var img = Lis[0].getElementsByTagName('img')[0]; var imgW = img.width; var imgH = img.height; for(var i = 1; i < LisLen; i++){ var img = Lis[i].getElementsByTagName('img')[0]; img.style.width = imgW + 'px'; img.style.height = imgH + 'px'; } } } </script> </head> <body> <h2 class = "tc">圖片上傳及預覽</h2> <form action="" > <div class="select tc" > <label for="upload">圖片上傳及預覽</label> <input type="file" id = "upload" multiple="multiple" accpet = "image/*" capture = "camera" > </div> <div class="preview"> <ul class = "preview_img_list clearfix"> </ul> </div> <div class="select_video tc"> <label for="upload_video">視訊上傳及預覽</label> <input type="file" id = "upload_video" accpet = "video/*" capture = "camcorder"> </div> <div class="video_preview"> </div> <div class="submit btn tc">上傳</div> </form> </body> </html>

看效果:

在google chrome 瀏覽器開啟效果

這裡寫圖片描述

手機uc瀏覽器開啟

這裡寫圖片描述

這裡寫圖片描述

在手機瀏覽器開啟會呼叫手機攝像頭進行拍攝。

拋開美觀不說,暫且討論下相容性,除了蘋果safari沒測試外,在現在主流瀏覽器上(ie8以上級別),展示效果差不多。

下面開始講解程式碼(關鍵部分程式碼)
檔案預覽主要是用到了這個webApi :FileReader

var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; initHW(); imgArr.push(e.target.result);}; })(img);
reader.readAsDataURL(file);
// var objectUrl = window.URL.createObjectURL(file);
// img.src = objectUrl;
// imgArr.push(e.target.result);
}

首先是新建了一個FileReader 物件,然後是readAsDataURL(file),該方法會讀取指定的 Blob 或 File 物件。讀取操作完成的時候,readyState 會變成已完成(DONE),並觸發 loadend 事件,同時 result 屬性將包含一個data:URL格式的字串(base64編碼)以表示所讀取檔案的內容。 在讀取操作完成時觸發reader.onload事件,在該事件出來處理中,將讀取的圖片內容賦值給生成的img dom的src 屬性。然後初始化預覽圖片高度(inintHW()),將base64編碼內容push 到陣列中。

上面註釋掉的程式碼跟沒註釋的程式碼功能是一樣的,只不過該api 有相容性問題,我看到也有網友使用該api實現了圖片預覽功能,但我個人看法跟官方給的提示一樣,暫時不建議使用!!!

這裡寫圖片描述

再看一下視訊預覽:
這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

視訊預覽是跟圖片預覽原理是一樣的。

不過在移動端即便這樣子寫<input type="file" id = "upload_video" accpet = "video/*" capture = "camcorder"> 也不會調起手機攝像,至於為什麼要這樣子寫,我也不是很懂,在網上查資料,看到有人這樣子做,就嘗試了下,果然不行,不過讀取檔案預覽是沒問題的,這裡暫不考慮這個問題。

下面來看上傳功能程式碼(只討論圖片上傳):

submitBtn.addEventListener('click',function(){
       if(!imgArr.length){
          alert('請選擇要上傳的圖片');
          return false;
       }
       var form = document.querySelector('form');
       var fd = new FormData(form);
       for(var i = 0;i < imgArr.length;i++){
           fd.append('file[]',imgArr[i]);
        }

       var request = new XMLHttpRequest();
       var url = "./file_preview.php";
       request.open('post',url);
       request.send(fd);
},false);

關鍵程式碼fd.append('file[]',imgArr[i]); 在for迴圈中,寫成file[]是為了後臺PHP 處理方便,寫成這個樣子,PHP後臺可以把它當做陣列來處理。

file_preview.php 程式碼

<?php
$imgCount = count($_POST['file']);
for($i = 0;$i < $imgCount;$i++){
    if(preg_match('/^(data:\s*image\/(\w+);base64,)/',$_POST['file'][$i],$result)){

        $ImageType = $result[2];
        $res = str_replace($result[0],'',$_POST['file'][$i]);
        $filePath = './';
        $fileName = mt_rand().'.'.$ImageType;
        file_put_contents($filePath.$fileName,base64_decode($res));
    }else{
        return false;
    }
}

講解:首先判斷上傳的檔案的數量,$imgCount = count($_POST['file']); 然後迴圈處理,正則匹配檔名字尾,preg_match('/^(data:\s*image\/(\w+);base64,)/',$_POST['file'][$i],$result),獲取檔名字尾:$ImageType = $result[2];,然後將類似data:image/png;base64,頭給處理掉:$res = str_replace($result[0],'',$_POST['file'][$i]);,然後儲存圖片到伺服器:file_put_contents($filePath.$fileName,base64_decode($res));

為什麼要將base64編碼:data:image/png;base64 給處理掉呢?因為如果直接放到php裡用base64_decode函式解碼會導致最終儲存的圖片檔案格式損壞,而解決方法就是先去掉這一base64識別部分。

整體效果圖:
這裡寫圖片描述

這裡寫圖片描述