基于html5的多圖片上傳
本文是建立在張鑫旭大神的多文圖片傳的基礎之上.
首先先放出來大神多圖片上傳的博客地址:http://www.zhangxinxu.com/wordpress/2011/09/%E5%9F%BA%E4%BA%8Ehtml5%E7%9A%84%E5%8F%AF%E9%A2%84%E8%A7%88%E5%A4%9A%E5%9B%BE%E7%89%87ajax%E4%B8%8A%E4%BC%A0/
代碼思路
因為html5開放了multiple, 可以讓用戶一次上傳多個文件.
所以,最開始,我們需要建立這樣的html.
<input type="file" name="fuck" multiple="" id="js-file">//上傳文件區域
<div id="js-pre"></div>//圖片預覽區域
<button id="js-button" type="button">提交</button>//提交按鈕
這個時候,我們就可以直接通過獲得input里面的files(不明白的同學可以百度一下),然后循環.提交給服務器.但是,我們會遇到另外一個問題.如果,用戶提交了一個圖片,但是用戶忽然覺得,我不想提交這個.我這個不要了,我要提交其他幾個. 這種情況就非常的尷尬了.(用戶真特么事逼┑( ̄Д  ̄)┍).
所以,我們需要一個數組,臨時存儲這些上傳的數據.當用戶刪除之前上傳的圖片的時候,我們可以在那個臨時的數組中,刪除相應的數據.
打一個比方.用戶通過input選擇了ABC三個圖片.
然后,我們循環input的files,然后依次把ABC加入到我們的臨時數組x中.
這個時候,用戶不想上傳A圖片了,他想刪除A. 于是,貼心的我們,從臨時數組刪除A.
接下來,我們的圖片預覽以及上傳圖片都來自臨時數組x的內容.這樣,無論用戶怎么折騰,貼心無比的我們,都可以滿足用戶的需求.
帶著這樣的思路.我們開始扯淡.
如果有懶惰黨,可以直接下載代碼使用.但是代碼的地址在最下面哦~
完成這個多文件上傳.我們要做到以下幾點要求(所以是幾點?)
- 可以復用(這段代碼可以在一個頁面多次使用,不會相互沖突)
- 我們要根據用戶選擇上傳圖片->完成文件的預覽和刪除
- 用戶選擇提交代碼的時候,進行文件傳輸,傳輸成功的時候,提供success(response){},提供完成相應的回調,同時也提供Failure(response){},進行提交失敗的處理.以及Complete(){},提交完成的處理.
所以,我們從以上幾點,一點一點的開始.
可以復用.
可以復用的意思是,使用者(不想造輪子的程序猿),可以在使用的時候,傳遞一個obj,里面帶有以下參數
- 用來上傳文件的input的id
- 觸發提交的button的id
- 預覽圖片的div的id
- 后端的url
- 唯一的文件名稱,為了在html中與其他的多圖片上傳進行劃分
- 上傳成功的函數
- 上傳失敗的函數
- 上傳完成的函數
- 對上傳圖片過濾的函數(可選) 可供使用者設置處理圖片
所以,我們可以設置一個obj.
obj = {
name: obj.name? obj.name:null, //唯一名,用來與其他文件區分
fileInput: obj.fileInput?obj.fileInput: null, //html file控件
upButton: obj.upButton? obj.upButton:null, //提交按鈕
pre: obj.pre?obj.pre:null, //預覽地址
url: obj.url? obj.url:null, //ajax地址
fileFilter: [], //過濾后的文件數組
filter: obj.filter?obj.filter:function(files){
var arrFiles = [];
for (var i = 0, file; file = files[i]; i++) {
if (file.type.indexOf("image") == 0) {
arrFiles.push(file);
} else {
alert('文件"' + file.name + '"不是圖片。');
}
}
return arrFiles;
}, //過濾的文件,默認判斷如果是圖片可以加入臨時數組
onSuccess: obj.onSuccess?obj.onSuccess:function(data){
console.log('success');
}, //文件上傳成功時
onFailure: obj.onFailure?obj.onFailure:function(data){
console.log('error');
}, //文件上傳失敗時,
onComplete: obj.onComplete?obj.onComplete:function(){
console.log('complete');
}, //文件全部上傳完畢時
}
然后我們需要一個函數,這個函數里面包含了我們生成多圖片預覽,刪除,上傳等功能.將obj傳入到函數FFile().
這樣,我們就可以通過 var fuck = new FFile(obj) 創建一個可以復用的多文件上傳.
外部構造基本結束,接下來,就可以進行 FFile(){}的內部處理.
function FFile(obj) {
this.FileSet = {
name: obj.name? obj.name:null, //唯一名,用來與其他文件區分
fileInput: obj.fileInput?obj.fileInput: null, //html file控件
upButton: obj.upButton? obj.upButton:null, //提交按鈕
pre: obj.pre?obj.pre:null, //預覽地址
url: obj.url? obj.url:null, //ajax地址
fileFilter: [], //過濾后的文件數組
filter: obj.filter?obj.filter:function(files){
var arrFiles = [];
for (var i = 0, file; file = files[i]; i++) {
if (file.type.indexOf("image") == 0) {
arrFiles.push(file);
} else {
alert('文件"' + file.name + '"不是圖片。');
}
}
return arrFiles;
}, //過濾的文件,默認判斷如果是圖片可以加入臨時數組
onSuccess: obj.onSuccess?obj.onSuccess:function(data){
console.log('success');
}, //文件上傳成功時
onFailure: obj.onFailure?obj.onFailure:function(data){
console.log('error');
}, //文件上傳失敗時,
onComplete: obj.onComplete?obj.onComplete:function(){
console.log('complete');
},
}
this.init();//一會再給你們說這個是干嘛的(笑)
}
接下來我們要處理的事情有兩個.
- 我們要根據用戶選擇上傳圖片->完成文件的預覽和刪除
- 用戶選擇提交代碼的時候,進行文件傳輸,傳輸成功的時候,提供success(response){},提供完成相應的回調,同時也提供Failure,complate.
首先是第一個
當用戶上傳文件后,會觸發change事件.
然后,我們根據change事件,可以調用一個函數,這個函數把過濾后的圖片(不符合圖片要求),加入到臨時數組fileFilter中.
funGetFiles: function(e) {
// 獲取文件列表對象
var files = e.target.files || e.dataTransfer.files;
//繼續添加文件
this.FileSet.fileFilter = this.FileSet.fileFilter.concat(this.FileSet.filter(files));
this.funDealFiles();//下面講解這個是啥(┑( ̄Д  ̄)┍)
return this; //方便進行鏈式操作,類似jq的$().xx().xx().xx();
},
因為,用戶可能對上傳的圖片,進行刪除.這樣,我們要知道用戶刪除了哪個圖片,我們才能在數組fileFilter中刪除相應的圖片.于是乎,我們就增加了一個索引值.
//選中文件的處理與回調
funDealFiles: function() {
for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
//增加唯一索引值
file.index = i;
}
//執行選擇回調
this.onSelect(this.FileSet.fileFilter);
return this;
},
然后就要在預覽區域顯示圖片,同時為預覽的圖片增加刪除選項,如何獲得上傳圖片的地址.我采用了FileReader,本文不討論這個.想知道關于FileReader,請自行百度.
/*
* 對保存在fileFilter的圖片,生成預覽
* @param file {array} 傳遞進來的含有所有file的數組
*/
onSelect: function(files) {
var html = '',
self = this,
i = 0;
$(this.FileSet.pre).html();//清空預覽地址
var funAppendImage = function() { //因為調用FileReader(),在FileReader.onload里面,進行的數值的修改,無法帶到外面來,就像是,一個只允許進不允許出的盒子(原諒我不恰當的比喻),所以,可以通過遞歸的放置,來保存對var html的修改.
file = files[i];
if (file) {
var reader = new FileReader()
reader.onload = function(e) { //生成的圖片
html += '<div id="js-uploadList_'+self.FileSet.name+i+'" class="img-box">';
html += '<div class="img-border">';
html += '<span class="js-upload_delete icon-delete_fill red" data-index="'+ i +'"></span>';
html += '</img>';
html += '</div>';
html += '</div>';
i++;
funAppendImage();
}
reader.readAsDataURL(file);
} else {
$(self.FileSet.pre).html(html);
if (html) {
//刪除方法
$(".js-upload_delete").click(function() {
self.funDeleteFile(files[parseInt($(this).attr("data-index"))]);
return false;
});
}
}
};
funAppendImage();
},
接下來是刪除的方法,這里分為兩個步驟.一個是刪除臨時數組中的圖片,另一個是刪除html中的圖片(在這里,利用了FileSet.name劃分多個多圖片上傳.)
//刪除對應的文件
funDeleteFile: function(fileDelete) {
var arrFile = [];
for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
if (file != fileDelete) {
arrFile.push(file);
} else {
this.onDelete(fileDelete);
}
}
this.FileSet.fileFilter = arrFile;
return this;
},
/*
*刪除函數
*@param fileDelete {str} 傳遞過來要刪除的File
*/
onDelete: function(file){//清除圖片
let self = this;
$("#js-uploadList_" + self.FileSet.name+ file.index).empty();
},
然后是第二個
第二個使用了FormData來傳輸多文件的數據.不明白的小伙伴可以繼續百度FormData.代碼簡單,直接閱讀即可.
//文件上傳
funUploadFile: function() {
var self = this;
if (location.host.indexOf("sitepointstatic") >= 0) {
//非站點服務器上運行
return;
}
for (var i = 0, file; file = this.FileSet.fileFilter[i]; i++) {
(function(file) {
var formData = new FormData();
formData.append(self.FileSet.name,file);
$.ajax({
url: self.FileSet.url,
type: 'post',
data: formData,
contentType: false,
processData: false,
success: function(data) {
self.FileSet.onSuccess(data);
self.funDeleteFile(file);
},
error: function(data) {
self.FileSet.onFailure(data);
}
})
if(!self.FileSet.fileFilter.length){
//執行完成
self.FileSet.onComplete();
}
})(file);
}
},
最后就是一開始提到的init()
就是初始化一些東西啦~~~
init: function() {
var self = this;
//判斷必須參數是否為空
if(self.FileSet.fileInput == null || self.FileSet.pre == null || self.FileSet.upButton == null) {
console.log('必須提供 input的id 預覽區的id 以及 button的id');
return false;
}
//文件選擇控件選擇
if (self.FileSet.fileInput) {
// self.FileSet.fileInput.addEventListener("change", function(e) { self.funGetFiles(e); }, false);
$(self.FileSet.fileInput).on('change',function(e){
self.funGetFiles(e);
})
}
//上傳按鈕提交
if (self.FileSet.upButton) {
// self.FileSet.upButton.addEventListener("click", function(e) { self.funUploadFile(e); }, false);
$(self.FileSet.upButton).on('click', function(e) {
self.funUploadFile(e);
})
}
基本上,一個多圖片上傳的思路就是這樣的~
以上.
另外這里是源代碼地址.https://github.com/fankof29/duotupianshangchuan