最近有幾個問題一直被提及,就是圖片上傳這一塊,雖然之前也說過,今天對這部分內(nèi)容進(jìn)行一個歸納和整理.
1.自定義input file樣式
input file有自己默認(rèn)的樣式,而且這個樣式一般是不能進(jìn)行修改的,所以想自定義樣式,思路是在input標(biāo)簽外套一層父級,a標(biāo)簽和div都可以,然后把input的透明度設(shè)置成0,把想要的樣式都加到父級上,這樣就能修改了
首先是CSS部分代碼:
<style>
a {
display: inline-block;
width: 200px;
height: 100px;
background: red;
line-height: 100px;
text-align: center;
color: black;
text-decoration: none;
position: relative;
font-size: 25px;
}
a:hover {
background: green;
}
input {
position: absolute;
right: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
}
</style>
然后是body對應(yīng)內(nèi)容
<a/ href="#"> // 把/去掉就好了,要不總不顯示
圖片上傳
<input type="file" value="瀏覽" />
</a>
跟file類似的還有radio,想使用自定義的點(diǎn)或者圖片,可以參照上面的寫法.

如果已經(jīng)確定了上傳文件的類型,可以直接指定接受的類型,這樣能避免因類型不正確而帶來的錯誤,使用屬性accept指定文件類型,順便把多文件上傳的代碼也放進(jìn)去
<input type="file" value="瀏覽" name="up[]" id="up" multiple="multiple" accept="image/jpeg, image/gif"/>
2.上傳預(yù)覽
這部分就需要找到對應(yīng)的上傳圖片,并且顯示在屏幕上.可以上傳之后顯示返回的網(wǎng)絡(luò)圖片,也能顯示本地的圖片,網(wǎng)絡(luò)圖片依賴后臺返回?cái)?shù)據(jù),這里只說一下怎么顯示本地的圖片,做預(yù)覽
當(dāng)圖片上傳成功之后,可以給input加一個onchange事件,這個事件會在上傳之后觸發(fā)
var up = document.getElementById("up");
up.onchange = function(){
console.log(this.files);
}
我打印了一下this.files,它包含了上傳的所有的文件,用法跟數(shù)組類似,也是下標(biāo)取值,取出來的值包含了上傳文件所有的信息,包括尺寸,文件類型,文件名等.多文件也一樣,按上傳順序用下標(biāo)取值.files還有l(wèi)ength,能獲取長度
接下來是獲取本地圖片的路徑,然后給img標(biāo)簽賦值
var img = document.getElementById("im");
var up = document.getElementById("up");
up.onchange = function(){
console.log(this.files.length);
var blob2 = URL.createObjectURL(this.files[0]);
img.src = blob2;
}
用了一個URL對象,根據(jù)對應(yīng)上傳文件創(chuàng)建了一個路徑,然后給圖片src賦值,就實(shí)現(xiàn)了上傳圖片預(yù)覽的功能
3.FileReader 文件讀取
FileReader提供了讀取文件的方法和讀取結(jié)果的事件類型,能幫助獲取文件內(nèi)容,也能對上傳過程進(jìn)行監(jiān)聽.它的使用有兼容問題,主要是還是IE兼容

FileReader的使用需要通過構(gòu)造函數(shù)創(chuàng)建一個對象,然后對這個對象進(jìn)行方法調(diào)用,它有幾個方法,能把文件異步讀到內(nèi)存里:
1.readAsText(file,encoding):以純文本形式讀取文件,將讀取到的文本保存在result屬性中,第二個參數(shù)用于指定編碼類型,可選。
2.readAsDataURL(file):讀取文件以數(shù)據(jù)URL的形式保存在result屬性中。
3.readAsBinaryString(file):讀取文件并將一個二進(jìn)制字符串保存在result屬性中。
4.readAsArrayBuffer(file):讀取文件并將一個包含文件人容的ArrayBuffer保存在result屬性中.
FileReader也有對應(yīng)的狀態(tài)監(jiān)聽
事件 描述
onabort 中斷時觸發(fā)
onerror 出錯時觸發(fā)
onload 文件讀取成功完成時觸發(fā)
onloadend 讀取完成觸發(fā),無論成功或失敗
onloadstart 讀取開始時觸發(fā)
onprogress 讀取中
接下來,就用FileReader也實(shí)現(xiàn)一遍圖片預(yù)覽
var img = document.getElementById("im");
var up = document.getElementById("up");
up.onchange = function() {
var fr = new FileReader();
fr.onloadend = function(ev) {
img.src = ev.target.result;
}
fr.readAsDataURL(this.files[0]);
}
給FileReader對象一個讀取完成的方法,使用readAsDataURL會返回一個url,這個值就保存在事件對象的result里,img通過加載這個地址,完成圖片的加載
4.本地上傳進(jìn)度
不能上傳比較大的文件,如果太小的圖片,直接就是100%了,我測試使用的是視頻.用法跟之前差不多,只不過上傳過程使用onprogress方法去監(jiān)聽過程
var img = document.getElementById("im");
var up = document.getElementById("up");
up.onchange = function() {
var fr = new FileReader();
fr.readAsDataURL(this.files[0]);
var total = this.files[0].size;
fr.onprogress = function(ev) {
console.log(ev.loaded / total);
}
}
ev.loaded是當(dāng)前上傳的大小,total是上傳的時候獲取的文件總大小.就能計(jì)算本地上傳的進(jìn)度,進(jìn)度條的話可以用<label>把結(jié)果顯示就可以了,這個效果可以參照QQ郵箱上傳大文件時候那個進(jìn)度條來做.
5.服務(wù)器上傳進(jìn)度
這部分需要顯示的是上傳后臺的進(jìn)度,跟之前本地的有點(diǎn)區(qū)別,這部分主要還是使用ajax進(jìn)行上傳狀態(tài)的監(jiān)控,先看JQ版
var img = document.getElementById("im");
var up = document.getElementById("up");
up.onchange = function() {
var formD = new FormData();
formD.append("file", this.files[0]);
$.ajax({
type: "POST",
url: "up.php",
data: formD,
processData: false,
//必須false才會自動加上正確的Content-Type
contentType: false,
xhr: function() {
var xhr = $.ajaxSettings.xhr();
if(onprogress && xhr.upload) {
xhr.upload.addEventListener("progress", onprogress, false);
return xhr;
}
}
});
}
function onprogress(evt) {
var loaded = evt.loaded; //已經(jīng)上傳大小情況
var tot = evt.total; //附件總大小
var per = Math.floor(100 * loaded / tot); //已經(jīng)上傳的百分比
console.log(loaded, tot);
}
首先是formData,它可以模擬表單,使用formData能上傳文件,在使用ajax上傳的時候,先把圖片加到formData對象里,通過對象傳輸圖片
在ajax里,使用了好幾個之前沒用過的屬性,第一個是processData,默認(rèn)值是true,當(dāng)data傳來數(shù)據(jù)的時候,如果是一個對象,會處理轉(zhuǎn)換成字符串,在這里,如果還使用true的話,會報(bào)錯,所以設(shè)置成false.還有一個xhr,這個是需要返回一個XMLHttpRequest,jq的ajax沒有progress,xhr能指定對應(yīng)的XMLHttpRequest對象,所以需要給XMLHttpRequest加上progress方法,這樣能監(jiān)聽進(jìn)度,這樣就能通過JQ完成上傳的進(jìn)度加載