文章目錄
- Netscape 4的問題
- IE4的問題
- Netscape 3的問題
- 解決辦法-JavaScript
- 解釋
- 點擊事件的路徑
在所有的表單項裡面,檔案上傳部分是最難添加樣式的。IE支援一些(不是很多)樣式屬性,Mozilla很少,其他瀏覽器幾乎沒有。“瀏覽”按鈕在CSS操作裡面也很難訪問。
問題
在一個網站中可能我的輸入框式下面這樣的:
設計者可能想讓上傳部分也像這樣然後再添加一個select按鈕。但是當我想把普通的輸入框改為上傳框時就根本不能工作。瀏覽器之間有很大的不同,給預設按鈕添加樣式也幾乎不可能。
這很難成為設計的很好的上傳框,但是也是我們能做的最多的了。
注意到Safari的設計有些不同。Safari小組想關閉手動輸入檔案的功能,可能擔心這樣的溢出。這樣設計有個缺點就是使用者在選擇了一個檔案之後不能取消上傳檔案。
解決辦法
讀者Michael McGrady發明了一個不錯的小技巧來解決給上傳按鈕添加樣式的問題。這個頁面上的所有解決辦法都是他發明的,我只是添加了position:relative,一些注釋和測試,然後轉為JavaScript。
沒有使用這個技巧的時候:
使用了之後我想成為這樣:
現在看起來好多了不是嗎?
McGrady的方法很簡單且優雅:
1、設定一個普通的<input type="file">
,然後放置在包含postion:relative屬性的元素中。
2、同樣在父元素中,添加一個普通的<input>和一個圖片,給他們設定樣式。給他設定絕對位置讓這個普通的input能夠和<input type="file">重疊。
3、然後把<input type="file">的z-index設定為2,這樣他就能在普通的input上面顯示。
4、最後將<input type="file">的opacity設定為0。這樣<input type="file">就看不見了,下面的input/image就能顯現出來,但是你還能點擊“瀏覽”按鈕。如果這個按鈕的位置在圖片上面,那麼看起來好像點擊的就是圖片一樣。
注意你不能使用visibility:hidden,因為一個真正的隱藏元素是不能點擊的,我們需要一個能點擊的隱藏元素。
至此,這個效果可以通過純CSS顯示了,但是還差一點
5、當使用者選擇了一個檔案之後,那個可見的假的輸入框應該顯示選擇檔案的路徑,就像正常的<input type="file">一樣。雖然只需要簡單的把<input type="file">的內容複寫過來,但是還是需要JavaScript的。
所以這個技術如果沒有JavaScript可能不能完全實現。我一會會解釋原因。我決定把整個這個想法寫成JavaScript的。如果你想使用沒有檔案名稱顯示的上傳框的話也可以使用純CSS方式,雖然這不是一個好辦法。
HTML/CSS結構
我打算用下面的HTML/CSS結構:
div.fileinputs {position: relative;}div.fakefile {position: absolute;top: 0px;left: 0px;z-index: 1;}input.file {position: relative;text-align: right;-moz-opacity:0 ;filter:alpha(opacity: 0);opacity: 0;z-index: 2;}<div class="fileinputs"><input type="file" class="file" /><div class="fakefile"><input /><img src="search.gif" /></div></div>
<div class="fileinputs">的位置是relative,這樣我們就能在裡面放置一個絕對位置的層:假的輸入框。
<div class="fakefile">
包含一個假的輸入框和一個按鈕,他的位置是絕對的,z-index值是1,這樣他就能在真正的上傳框下面顯示。
真正的上傳框也有位置屬性relavtive,這樣就能設定他的z-index值了。總之需要上傳框在假的輸入框之上顯示。然後我們設定他的透明度為0,讓他不可見。
還需要注意text-align:right:因為Mozilla不能設定上傳框的寬度,所以我們要保證瀏覽按鈕在DIV的右邊緣,假的按鈕也要在右邊,而且應該在真的下面。
你還需要一些css代碼來設定寬度高度邊框等等,在這個例子中我沒有寫。
為什麼是JavaScript?使用JavaScript的第一個原因就是要把檔案路徑複製到假的文字框裡。
第二,JavaScript會忽略掉沒有意義的HTML代碼:<div class="fakefile">
,讓代碼保持乾淨。
最後,對於一些舊的瀏覽器不能處理CSS,在Netscape和IE4裡面檔案輸入就不可訪問。對於那些沒有CSS的瀏覽器,使用者會看到兩個輸入框,而且不能理解第二個是幹嘛的。
Netscape 4的問題在Netscape 4裡面使用者只能看見按鈕。可能是因為position:absolute的原因。
IE4的問題在IE4裡面會有一個詭異的原來的“瀏覽”按鈕的影子,而且不能點擊。沒有解決辦法
Netscape 3的問題對於那些沒有CSS功能的瀏覽器。雖然可以使用,但是兩個輸入框會讓使用者鬱悶。
解決辦法-JavaScript這些問題的解決辦法就是JavaScript:通過JavaScript產生輸入框和按鈕。現在最壞的情況就是JavaScript不能執行,即使如此,使用者也能上傳檔案。雖然不那麼好看,但是還是能工作的。
所以原來複雜的HTML變成了:
<div class="fileinputs"><input type="file" class="file"></div>
我們通過JavaScript來添加其他元素。
代碼var W3CDOM = (document.createElement && document.getElementsByTagName);function initFileUploads() {if (!W3CDOM) return;var fakeFileUpload = document.createElement('div');fakeFileUpload.className = 'fakefile';fakeFileUpload.appendChild(document.createElement('input'));var image = document.createElement('img');image.src='pix/button_select.gif';fakeFileUpload.appendChild(image);var x = document.getElementsByTagName('input');for (var i=0;i<x.length;i++) {if (x[i].type != 'file') continue;if (x[i].parentNode.className != 'fileinputs') continue;x[i].className = 'file hidden';var clone = fakeFileUpload.cloneNode(true);x[i].parentNode.appendChild(clone);x[i].relatedElement = clone.getElementsByTagName('input')[0];x[i].onchange = x[i].onmouseout = function () {this.relatedElement.value = this.value;}}}
解釋如果瀏覽器不支援W3C DOM,那麼什麼也不做。
var W3CDOM = (document.createElement && document.getElementsByTagName);function initFileUploads() {if (!W3CDOM) return;
建立<div class="fakefile">和他的內容。需要的時候我們會複製它。
var fakeFileUpload = document.createElement('div');fakeFileUpload.className = 'fakefile';fakeFileUpload.appendChild(document.createElement('input'));var image = document.createElement('img');image.src='pix/button_select.gif';fakeFileUpload.appendChild(image);
然後遍曆頁面上的所有input,如果不是<input type="file">則忽略。
var x = document.getElementsByTagName('input');for (var i=0;i<x.length;i++) {if (x[i].type != 'file') continue;
再做一次檢測:如果<input type="file">的父元素沒有fileinputs的class,則忽略。
if (x[i].parentNode.className != 'fileinputs') continue;
現在我們就找到了需要添加樣式的上傳框。首先我們添加一個hidden的類名。
x[i].className = 'file hidden';
複製假的輸入框然後添加在<input type="file">的父元素上。
var clone = fakeFileUpload.cloneNode(true);x[i].parentNode.appendChild(clone);
現在我們就成功的添加了樣式。但是還沒有結束,我們希望使用者在輸入框內看到檔案路徑。
首先我們給<input type="file">建立一個屬性,指向假的輸入框:
x[i].relatedElement = clone.getElementsByTagName('input')[0];
這樣當使用者改變了上傳檔案的時候我們就能很輕鬆及時的訪問到假的輸入框,然後複製路徑。
在這有個問題,我們使用什麼event呢?通常使用change事件,當上傳檔案改變的時候,假的輸入框的值也隨之改變。
但是Mozilla 1.6在上傳框上不支援這個事件(Firefox支援)。所以我在這裡添加一個onmouseout的事件。(IE下同樣可以運行,Safari不行)
x[i].onchange = x[i].onmouseout = function () {this.relatedElement.value = this.value;}
問題和擴充還有一個問題,使用者在選擇了一個檔案之後就不能取消了。
假設使用者選擇了一個檔案之後,突然不想上傳了。通常只需要刪除檔案路徑就可以了。但是在我們的例子裡卻很難,試一試,可以刪除但是通常與感覺相反。
所以我們希望使用者通過修改假的輸入框也能修改真正的上傳路徑。
允許選擇是可能的。當使用者選擇了上傳檔案的任何部分,我們就選擇整個假輸入框的全部內容。
x[i].onselect = function () {this.relatedElement.select();}
但是JavaScript的安全性不允許程式修改上傳路徑,所以我們不能通過讓使用者修改輸入框的內容來修改真正的上傳路徑。所以我決定放棄onselect事件。
一種可行的辦法是:給假的輸入框添加一個清楚按鈕,當使用者點擊之後就刪除掉原來的上傳框然後重新建立一個。這雖然笨重,但是能確實刪除使用者不想上傳的檔案路徑。我不覺得這個一定可以工作,我也沒有寫這部分代碼。
點擊事件的路徑有讀者建議,去掉那些繁雜的CSS,徹底隱藏上傳框,然後把假的輸入框的click事件綁定在真正的上傳框上。非常棒的想法,而且比上面的簡單的多。
fakeField.onclick = function () {realField.click()}
這個click()方法允許你模擬一個表單項。複選框的點擊,單選框被選中等等。然而Mozilla和Opera不支援。我想知道為什麼,因為添加這個方法最大的不安全性就在於彈出一個選擇檔案的對話方塊而已。
所以我們也不能用這個簡單的辦法。
翻譯地址:http://www.quirksmode.org/dom/inputfile.html