HTML 5應(yīng)用實(shí)戰(zhàn):靈活拖拉文件
這篇文章將分如下幾個(gè)方面進(jìn)行初步的分析和探討:
◆ 如何將文件拖放到web頁面中
◆ 在Javascript中分析拖拽文件
◆ 在客戶端裝載和解析文件
◆ 使用 XMLHttpRequest2異步上傳文件到服務(wù)端
◆ 上傳時(shí)顯示一個(gè)進(jìn)度條
◆ 改進(jìn)上傳文件的表單,甚至支持IE 6,以讓在各瀏覽器中可以兼容運(yùn)行。
◆ 并介紹如何單單只用Javascript實(shí)現(xiàn),不用任何框架。
目前瀏覽器對文件拖拉的支持
在我們開始講解前,我們先要說明下,由于HTML5的標(biāo)準(zhǔn)最終版本還沒完全發(fā)布,各瀏覽器也不是完全都對所有功能進(jìn)行支持,所以本文的程序有可能在今后的各瀏覽器中不能完全運(yùn)行成功,但至少在本文發(fā)表時(shí),會對以下瀏覽器在如下各方面進(jìn)行支持。
1) 目前程序能在所有的Firefox和Chrome的瀏覽器中很好的運(yùn)行。
2) Opera瀏覽器能解通過Javascript去解析文件,但不支持文件的拖拉到瀏覽器中及使用XMLHttpRequest2去上傳文件。
3) IE和Safari不支持任何本文提到的API和新特性。
4) Apple不允許在iOS系統(tǒng)中使用HTML表單上傳文件。
下面,就讓我們開始學(xué)習(xí)之旅吧。
HTML和CSS
我們先來看下上傳文件的表單,代碼如下:
- <form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
- <fieldset>
- <legend>HTML File Upload</legend>
- <input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
- <div>
- <label for="fileselect">Files to upload:</label>
- <input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
- <div id="filedrag">or drop files here</div>
- </div>
- <div id="submitbutton">
- <button type="submit">Upload Files</button>
- </div>
- </fieldset>
- </form>
- <div id="messages">
- <p>Status Messages</p>
- </div>
可以看到,在這個(gè)表單中,放置了一個(gè)文件選擇框,唯一跟HTML4不同的時(shí),這個(gè)框采用的是HTML5中的一個(gè)新增的文件上傳框?qū)傩詍ultiple,允許選擇多個(gè)不同的文件。此外,在id為 filedrag的div中,這個(gè)區(qū)域是用來將文件拖拉放置的區(qū)域,下文中會用到。
接下來會看下CSS,代碼如下:
- #filedrag
- {
- display: none;
- font-weight: bold;
- text-align: center;
- padding: 1em 0;
- margin: 1em 0;
- color: #555;
- border: 2px dashed #555;
- border-radius: 7px;
- cursor: default;
- }
- #filedrag.hover
- {
- color: #f00;
- border-color: #f00;
- border-style: solid;
- box-shadow: inset 0 3px 4px #888;
- }
在這段CSS中,設(shè)置了當(dāng)文件拖放到頁面的指定區(qū)域時(shí)的樣式,這個(gè)樣式是當(dāng)文件被拖動到指定區(qū)域時(shí),才起到作用的,是通過Javascript擊發(fā)其起作用的,下文會提到。
HTML5中的文件API
在HTML5中,對文件的API有如下幾點(diǎn)的新的改進(jìn),其標(biāo)準(zhǔn)可以參考(http://www.w3.org/TR/file-upload/)。
FileList: 表示已選擇的文件,以數(shù)組的形式表示。
File: 代表一個(gè)單獨(dú)的文件
FileReader: FileReader是一個(gè)接口,它允許我們在客戶端讀取文件的數(shù)據(jù),并且可以在Javascript中去使用。
開始動手寫Javascript
下面,我們開始動手編寫Javascript,首先我們編寫一些工具javascript,比如:
- // getElementById
- function $id(id) {
- return document.getElementById(id);
- }
- //
- // 輸出信息
- function Output(msg) {
- var m = $id("messages");
- m.innerHTML = msg + m.innerHTML;
- }
接者,我們編寫init方法,去判斷文件API的可用性,代碼如下:
- // 判斷當(dāng)前瀏覽器中文件API是否可用
- if (window.File && window.FileList && window.FileReader) {
- Init();
- }
- //
- // 初始化程序
- function Init() {
- var fileselect = $id("fileselect"),
- filedrag = $id("filedrag"),
- submitbutton = $id("submitbutton");
- // 添加文件選擇的事件監(jiān)聽
- fileselect.addEventListener("change", FileSelectHandler, false);
- // 判斷xmlhttprequest 2是否可用
- var xhr = new XMLHttpRequest();
- if (xhr.upload) {
- // file drop
- filedrag.addEventListener("dragover", FileDragHover, false);
- filedrag.addEventListener("dragleave", FileDragHover, false);
- filedrag.addEventListener("drop", FileSelectHandler, false);
- filedrag.style.display = "block";
- // remove submit button
- submitbutton.style.display = "none";
- }
- }
程序中,首先判斷當(dāng)前瀏覽器中文件API是否可用,如果可用的話則調(diào)用init的初始方法。在init方法中,做了如下幾件事情:
為文件的選擇框增加了上傳的監(jiān)聽事件。
顯示#filedrag區(qū)域
設(shè)置了拖動文件經(jīng)過放置區(qū)域時(shí)和文件離開放置區(qū)域時(shí)的事件以及樣式。
設(shè)置了當(dāng)用戶將文件拖動到放置區(qū)域***松開鼠標(biāo),以決定文件放置時(shí)的事件。
這里還隱藏了提交按鈕,因?yàn)檫@里并不需要它了。
當(dāng)然,這里還可以連傳統(tǒng)的文件上傳瀏覽框也去掉,但這并不是十分友好,所以這里采用的是兩者并存的方式。
而用到了XMLHttpRequest的upload方法,主要是防止在一些瀏覽器中如果當(dāng)文件上傳API不可用時(shí),則用舊的方法,不顯示文件拖拉框,取而代之的是顯示傳統(tǒng)的上傳提交按鈕。
考慮到很少用戶很熟悉文件的這種拖拉上傳用法,因此,我們在事件中對文件放置區(qū)域的樣式進(jìn)行設(shè)置,當(dāng)文件被拖拉到區(qū)域中時(shí),區(qū)域的邊框會變成紅色,以提醒用戶,代碼如下:
- function FileDragHover(e) {
- e.stopPropagation();
- e.preventDefault();
- e.target.className = (e.type == "dragover" ? "hover" : "");
- }
這里判斷是否文件拖拉到區(qū)域上方,如果是的話,則采用樣式中的hover樣式。
接下來,我們會在另外的一個(gè)div區(qū)域中,顯示文件上傳的小結(jié)信息,代碼如下:
- function FileSelectHandler(e) {
- FileDragHover(e);
- // 獲得所有的文件列表
- var files = e.target.files || e.dataTransfer.files;
- // 循環(huán)處理每個(gè)文件
- for (var i = 0, f; f = files[i]; i++) {
- ParseFile(f);
- }
- }
在FileSelectHandler事件中,實(shí)現(xiàn)了如下的功能:
1 調(diào)用FileDragHover()方法移除了hover的樣式,并且取消瀏覽器的響應(yīng)事件,否則的話瀏覽器會嘗試顯示文件的內(nèi)容。
2 將上傳的文件放置到FileList對象數(shù)組中去,包括用傳統(tǒng)文件上傳框上傳的及用拖拉方法上傳的。
3 單獨(dú)使用一個(gè)方法ParseFile輸出上傳每個(gè)文件的具體屬性信息,代碼如下;
- function ParseFile(file) {
- Output(
- "
- File information: " + file.name +
- " type: " + file.type +
- " size: " + file.size +
- " bytes
- "
- );
- }
#p#
使用Javascript打開客戶端文件
現(xiàn)在,我們已經(jīng)把客戶端機(jī)器上的文件成功拖拉到瀏覽器中了,也就是說,我們用新的拖拉的方法,完成了以往要使用傳統(tǒng)的文件上傳選擇框才能完成的工作!接下來,我們嘗試通過Javascript,去判斷用戶上傳的文件類型,并學(xué)習(xí)如何使用Javascript去操作客戶端的文件。
首先,為什么要通過Javascript去分析操作客戶端的文件呢?假如要求用戶上傳很多文件,或者上傳指定格式的圖片,假如用戶選好上傳文件到服務(wù)端后,服務(wù)端才判斷發(fā)現(xiàn)文件不符合要求,再要求用戶重新上傳的話,給用戶的體驗(yàn)則不大友好,所以,希望能在用戶在客戶端選擇完文件后就馬上能判斷出文件的大小和類型,如果是圖片的話,甚至可以實(shí)現(xiàn)客戶端圖片預(yù)覽的效果。
在HTML5的起草標(biāo)準(zhǔn)中,提供了FileReader接口去處理客戶端的文件,有如下幾個(gè)重要API:
readAsText(File f, [encoding]):將一個(gè)文件讀入到字符串中去,其中可以選用文件的編碼,默認(rèn)的是UTF-8
.readAsDataURL(File f): 將文件以data URL編碼的方式讀入文件內(nèi)容,dat Url方式是一種以BASE64編碼在頁面中展示文件的方法,詳細(xì)見:http://en.wikipedia.org/wiki/Data_URI_scheme
.readAsBinaryString(File f): 將文件以二進(jìn)制方式讀取。.readAsArrayBuffer(File f):.將文件作為ArrayBuffer對象的方式讀取。ArrayBuffer詳見http://www.khronos.org/registry/typedarray/specs/latest/
接下來,我們看下如何在Javascript中異步打開讀取文件。
Javascript中異步打開文件
先來復(fù)習(xí)下之前我們用到的parseFile方法,代碼如下:
- function ParseFile(file) {
- Output(
- "
- File information: " + file.name +
- " type: " + file.type +
- " size: " + file.size +
- " bytes
- "
- );
- }
這里只是簡單顯示了文件的文件名和文件大小,而接下來我們要判斷是這個(gè)文件是否屬于文件類型的文件(即text/plain,text/html,text/css等),可以使用FileReader.readAsText()方法讀取并且去掉其中的<,>符號,代碼如下;
- if (file.type.indexOf("text") == 0) {
- var reader = new FileReader();
- reader.onload = function(e) {
- Output(
- "
- " + file.name + ":
- " +
- e.target.result.replace(//g, ">") +
- "
- "
- );
- }
- reader.readAsText(file);
- }
同樣,我們希望將一張圖片從用戶的資源管理器中,拖拉到頁面的放置區(qū)域后,能馬上顯示這張圖片的實(shí)際內(nèi)容以及大小,可以用如下代碼實(shí)現(xiàn):
- 0.// display an image
- 0.if (file.type.indexOf("image") == 0) {
- 0. var reader = new FileReader();
- 0. reader.onload = function(e) {
- 0. Output(
- 0. "<p><strong>" + file.name + ":</strong><br />" +
- 0. '<img src="' + e.target.result + '" /></p>'
- 0. );
- 0. }
- 0. reader.readAsDataURL(file);
- 0.}
這里,直接將圖片的內(nèi)容以FileReader的readAsDataURL方法讀取入并顯示。
***,我們可以通過http://blogs.sitepointstatic.com/examples/tech/filedrag/2/index.html觀看我們的
DEMO演示,請讀者嘗試從自己電腦上的windows資源管理器中,拖放圖片或其他類型文
件到頁面的指定區(qū)域中,則會發(fā)現(xiàn)瀏覽器能自動識別用戶拖放的文件,當(dāng)然,請使用Chrome
或Firefox瀏覽器才能看到效果。
小結(jié)
在本文中,為讀者介紹了HTML5中新的文件處理API,利用文件處理API,可以實(shí)現(xiàn)讓瀏覽器識別從用戶端拖放到頁面的文件,在下一講中,將重點(diǎn)介紹如何上傳這些已經(jīng)拖放了的文件。
原文:http://tech.it168.com/a2011/1207/1285/000001285230.shtml
【編輯推薦】