html5 文件拖曳上傳是個老話題了,網路上有很多例子,我一開始的程式碼也是網路找來改的,只是踩了幾個坑之後就想把過程記錄下來。
以下主要介紹從瀏覽器外拖曳檔案到瀏覽器進行上傳的實作。 首先會介紹一些必須的基礎。
拖曳事件有以下這些:
dragstart
:當使用者開始拖曳物件時觸發。
dragenter
: 當滑鼠第一次經過目標元素,且有拖曳發生時觸發。此事件的監聽者應指明在這個位置上是否允許drop,或監聽者不執行任何操作,那麼drop預設是不允許的。
dragover
:當滑鼠經過一個元素時,且有拖曳發生時觸發 。
dragleave
:當滑鼠離開一個元素,且有拖曳在發生時觸發。
drag
: 當物件被拖曳,每次移動滑鼠時觸發。
drop
:在drag操作的最後發生drop時,在元素上觸發此事件。監聽者應該負責檢索拖曳的數據,並插入drop的位置。
dragend
: 拖曳物件時放開滑鼠按鍵時觸發。
從瀏覽器外拖曳檔案到瀏覽器時,必須綁定的事件有 dragover
#和 drop
,其他的都可以不綁定。 dragover
和drop
事件的處理函數內部必須呼叫事件的 <a href="//m.sbmmt.com/wiki/1074.html" target="_blank"></a>
dataTransfer.dropEffect [ = value ]
:傳回目前選擇的操作類型,可以設定新的值來修改已選擇的操作。可選的值有: none, <a href="//m.sbmmt.com/wiki/1297.html" target="_blank">copy</a>, link, move
。
dataTransfer.effectAllowed [ = value ]
:傳回允許的操作類型,可修改。可選的值有:none, copy, copyLink, copyMove, link, linkMove, move, all, uninitialized
#。
dataTransfer.types
:傳回一個DOMString,列出在dragstart事件裡設定的所有格式。另外,如果有檔案被拖曳,那麼其中一個類型的字串將是「Files」。
dataTransfer.clearData( [ format ] )
:移除指定格式的資料。如果忽略參數則移除所有資料。
dataTransfer.setData(format, data)
:新增指定的資料。
data = dataTransfer.getData(format)
:傳回指定的資料。如果沒有這樣的數據,則傳回空字串。
dataTransfer.files
:傳回被拖曳的FileList,如果有。
dataTransfer.setDragImage(element, x, y)
:用指定的元素來更新drag回饋,取代先前指定的回饋( feedback)。
dataTransfer.addElement(element)
:新增指定元素到用於渲染drag回饋的元素清單。
在這個用例裡,最重要的就是 #dataTransfer.files
屬性#它是使用者拖曳進瀏覽器的檔案列表,是個 FileList
對象,有 length
#屬性,可以透過下標存取。
FormData
代表表單,可以透過 append('fieldName', value)
函數在表單裡新增參數,參數的只不僅可以是字串,還可以是File對象,甚至是二進位資料。
新版本的XMLHttpRequest對象,這裡說的XMLHttpRequest都是指新版的。
XMLHttpRequest可以向不同網域的伺服器發出HTTP請求。這叫做 「跨域資源共享」(Cross-origin resource sharing,簡稱CORS)。
瀏覽器有個著名的同源策略,這裡瀏覽器安全的基礎,CORS 除了需要瀏覽器支援外,還要伺服器同意。
XMLHttpRequest 支援直接傳送FormData,就像瀏覽器進行表單提交一樣。
XMLHttpRequest 也支援進度資訊(progress
事件),進度分為上傳進度和下載進度,上傳進度的事件是在XMLHttpRequest.upload
物件上,下載進度的事件是在 XMLHttpRequest
#」物件。每個進度事件都有三個屬性:
lengthComputable
:可計算的已上傳位元組數
total
:總的位元組數
loaded
:到目前為止上傳的位元組數
除了進度事件,也支援以下五個事件:
load
事件:傳輸成功完成。
abort
事件:傳輸被使用者取消。
error
事件:傳輸中出現錯誤。
loadstart
事件:傳輸開始。
loadend
事件:傳輸結束,但不知道成功還是失敗。
同 progress
事件一樣,屬於上傳作業的事件處理函數綁定在XMLHttpRequest.upload
物件上,屬性下載的直接綁定在 XMLHttpRequest
物件。
本機測試時要注意把下面程式碼裡的路徑改為自己本機的。
伺服器端需要寫個Servlet來接收上傳的表單。 /html5/FileUploadServlet
用servlet3的 @MultipartConfig 註解就可以很快實現。
<html> <head> <title> drag drop upload demo <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> </head> <body> <p id= "progressBarZone">请将文件拖拽进浏览器内! <br/></ p> </body> <script> var progressBarZone = document.getElementById('progressBarZone'); function sendFile(files) { if (!files || files.length < 1) { return; } var percent = document.createElement('p' ); progressBarZone.appendChild(percent); var formData = new FormData(); // 创建一个表单对象FormData formData.append( 'submit', '中文' ); // 往表单对象添加文本字段 var fileNames = '' ; for ( var i = 0; i < files.length; i++) { var file = files[i]; // file 对象有 name, size 属性 formData.append( 'file[' + i + ']' , file); // 往FormData对象添加File对象 fileNames += '《' + file.name + '》, ' ; } var xhr = new XMLHttpRequest(); xhr.upload.addEventListener( 'progress', function uploadProgress(evt) { // evt 有三个属性: // lengthComputable – 可计算的已上传字节数 // total – 总的字节数 // loaded – 到目前为止上传的字节数 if (evt.lengthComputable) { percent.innerHTML = fileNames + ' upload percent :' + Math.round((evt.loaded / evt.total) * 100) + '% ' ; } }, false); // false表示在事件冒泡阶段处理 xhr.upload.onload = function() { percent.innerHTML = fileNames + '上传完成。 ' ; }; xhr.upload.onerror = function(e) { percent.innerHTML = fileNames + ' 上传失败。 ' ; }; xhr.open( 'post', 'http://cross.site.com:8080/html5/FileUploadServlet' , true); xhr.send(formData); // 发送表单对象。 } document.addEventListener("dragover", function(e) { e.stopPropagation(); e.preventDefault(); // 必须调用。否则浏览器会进行默认处理,比如文本类型的文件直接打开,非文本的可能弹出一个下载文件框。 }, false); document.addEventListener("drop", function(e) { e.stopPropagation(); e.preventDefault(); // 必须调用。否则浏览器会进行默认处理,比如文本类型的文件直接打开,非文本的可能弹出一个下载文件框。 sendFile(e.dataTransfer.files); }, false); </script> </html>
如果上面的程式碼都部署在同一個網站下,那是沒有問題的。可是我要做的上傳操作是要把文件傳到另一個網站上,坑也就產生了。
以上是html5檔案拖曳上傳的範例程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!