一、良生- input type=file與檔案上傳
本文所說的input type=file
指的是type
型別是file
的input
元素,最簡HTML程式碼如下:
1 |
<input type=file> |
但是,為了習慣,我們多寫成:
1 |
<input type="file"> |
在HTML5出現之前(XHTML),我們的閉合規則則有些出入:
1 |
<input type="file" /> |
顧名思義,選擇檔案,並上傳檔案。
在萬惡的舊時代,HTML5還沒有出現之前,原生的file
input
表單元素只能讓我們一次上傳一張圖片。無法滿足一次上傳多圖的互動需求,所以,很多場景,就被swfupload.js給取代了,有點逐漸淡出人們視野的感覺。
然,技術發展,日新月異,三十年河東,三十年河西。隨著原生HTML5表單對多圖(multiple
屬性)、上傳前預覽,二進位制上傳等支援越來越廣泛,原生的file
input
表單元素又迎來了新的升級,flash為背景的swfupload.js註定要落寞。
但是,對於PC專案,IE8-IE9瀏覽器還是不能忽略的。所以,現在,很流行的一種處理方式,就是HTML5 file上傳和flash swfupload上傳一起整合的模式,優先使用原生HTML5上傳,不支援的,使用flash上傳。我之前有篇關於HTML5上傳的文章,每天訪問量很高的:“基於HTML5的可預覽多圖片Ajax上傳”,大家有興趣可以看看。
二、蓮安-原生input上傳與表單form元素
如果想使用瀏覽器原生特性實現檔案上傳(如圖片)效果,父級的form
元素有個東西不能丟,就是:
1 |
enctype="multipart/form-data" |
enctype
屬性規定在傳送到伺服器之前應該如何對錶單資料進行編碼,預設的編碼是:”application/x-www-form-urlencoded
“。對於普通資料是挺適用的,但是,對於檔案,科科,就不能亂編碼了,該什麼就是什麼,只能使用multipart/form-data
作為enctype
屬性值。
無論是舊時代的單圖上傳,還是HTML5中的多圖上傳,均是如此。
三、沿見-原生file input圖片上傳前預覽與Ajax上傳
檔案,尤其圖片,上場前能夠預覽,是很棒的互動體驗。不走伺服器,不耗費流量,多棒!
理想雖好,實現起來……
在HTML5還沒出現的舊時代,只有低版本的IE瀏覽器貌似有方法,使用私有的濾鏡,超越安全的限制(其實是利用了不好的東西),實現圖片直接預覽;但是呢,那個時候,Chrome, FireFox沒有這一出,於是,想要使用原生file input實現圖片的上傳前預覽,相容性坎很難跨過去。
但是,後來,HTML5來了,我們出現了轉機,IE10+以及其他現代瀏覽器,可以讓我們直接讀取圖片的資料,然後在頁面上呈現,實現了上傳前預覽;加上之前老IE的濾鏡策略,貌似,可行。但是呢但是,老的IE瀏覽器只能最多一次選擇一個檔案,因此,只有單圖上傳的時候,大家可以考慮考慮。
傳統的form提交,是要改變頁面流的,也就是重新整理後跳轉。好的體驗應該是走Ajax互動的。HTML5裡面支援二進位制formData資料提交,因此,可以從容Ajax提交上傳的檔案資料;那老舊的IE瀏覽器怎麼辦?
一般方法如下:
- form元素新增
target
屬性,其值指向頁面內隱藏的一個<iframe>
元素的id
, 如下示意:12<form action="" method="post" enctype="multipart/form-data" target="uploadIframe"><<iframe id="uploadIframe"></iframe> - 處理
<iframe>
元素的onload
事件,獲得返回內容(如下程式碼示意),具體細節非本文重點,不表。12var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;var response = doc.body && doc.body.innerHTML;
OK, 當然,你也可以不用像上面這麼麻煩,直接使用jquery.form.js. 原理呢,就是上面這樣,但是,不需要這麼麻煩。
四、恩和-原生file input大小、按鈕文字等UI自定義
原生的file input不收待見的另外一個原因是:長的醜還不好控制。
舉個例子,下圖這個“選擇檔案”這幾個文字,我們就不好對file控制元件動刀子實現自定義:
怎麼辦呢?
有一種方法是這樣的:
讓file型別的元素透明度0
,覆蓋在我們好看的按鈕上。然後我們去點選好看的按鈕,實際上點選是是file
元素。
然而,此方法有一些不足:
- 尺寸控制不靈活。CSS
width
屬性有些瀏覽器不管用,需要使用size
,然後高度控制也不精準,我們很難正好覆蓋在好看的自定義按鈕上。 - 樣式不好控制,按鈕的
hover
態以及active
態不好處理。 - HTML結構限制以及定位成本。
更好的方法是,使用label
元素與file
控制元件關聯,好處在於:
- 點選自定義的漂亮按鈕就是點選我們file控制元件;
- 沒有尺寸控制不精確的問題;
- 沒有不能響應hover態active態的問題;
- 我們的漂亮按鈕甚至可以在form表單元素的外面,例如:
12<label for="xFile">上傳檔案</label><form><input type="file" id="xFile" style="position:absolute;clip:rect(0 0 0 0);"></form>
效果如下(真實實時效果):
五、盈年-file型別控制元件的accept屬性
input file型別控制元件有一個屬性,名為accept
, 可能有些小夥伴不太瞭解。可以用來指定瀏覽器接受的檔案型別,也就是的那個我們開啟系統的選擇檔案彈框的時候,預設介面中呈現的檔案型別。例如:accept="image/jpeg"
,則介面中只有jpg圖片,如下截圖,同時,窗體右下方是“自定義檔案”按鈕:
實際開發的時候,很少只允許傳jpg圖片,應該都是隻能傳圖片型別,此時,可以使用:
1 |
accept="image/*" |
於是乎,“自定義檔案”按鈕變成了語義更明確的“圖片檔案”:
accept
屬性值其實是MIME型別, 例如下面幾個可能常用的:
1 2 3 4 |
accept="application/pdf" accept="audio/x-mpeg" accept="text/html" .accept="video/x-mpeg2" |
然後,多個屬性值使用逗號分隔,例如:
1 |
<input accept="audio/*,video/*,image/*"> |
六、又及-input file值的清除
現代瀏覽器直接value = ""
, 有些IE瀏覽器貌似不行,好像使用file.outerHTML = file.outerHTML
,我自己沒測試。
不過我覺得比較麻煩,還要判斷瀏覽器什麼的。像本文的Ajax單圖上傳,直接form.reset()
就可以了。
以上~