tags: 圖片上傳, multipart, 截圖上傳, file對象, FormData, 拖拽上傳圖片, dataTransfer, readAsDataURLjavascript
一個以下所示的發佈框,常常會出如今各類微博、社區、論壇站點上,這類發佈形式雖然沒有高級編輯器那樣能夠任意排版加工,但也知足了常見的表述觀點意見的要求,它一般搭配一些表情、文件上傳、分享網頁視頻等方式,來知足上述需求。最近我從事的一個項目中,就完成了以下圖示的發佈內容的需求,今天主要講一下其中圖片和附件的上傳發布方式。html
其實上傳的方式有不少種,本文將列舉需求中用到的幾種上傳方式。前端
也就是用傳統的form表單來上傳,使用form表單的input[type=」file」]控件,能夠打開系統的文件選擇對話框,從而達到選擇文件並上傳的目的,它的好處是多瀏覽器兼容,可是在多圖上傳、分段上傳上等高級特性上就顯得力不從心。java
表單的格式以下:git
我列出表單上傳所需的關鍵幾點:github
method=」post」: 採用post方式提交數據ajax
enctype=」multipart/form-data」:採用multipart格式上傳文件,此時request頭會顯示 Content-Type:multipart/form-data; boundary=——WebKitFormBoundaryzr34cwJ67R95KQC9windows
action:標明上傳的服務端處理地址api
type=」file」:使用input的file控件上傳瀏覽器
accept屬性是HTML5的新屬性,它規定了可經過文件上傳提交的文件類型
上傳的觸發事件能夠是:input[type=」file」]的onChange觸發,也能夠由一個獨立的按鈕的onClick使整個表單提交,此時還能夠用input[type=」hidden」]帶一些其它的參數,好比Token來源驗證等等。
ajax無刷新上傳的方式,本質上與表單上傳無異,只是把表單裏的內容提出來採用ajax提交,而且由前端決定請求結果回傳後的展現結果,不用像直接表單上傳那樣刷新和跳轉頁面。在這裏,咱們採用jQuery來做爲操做DOM和建立ajax提交的js基礎庫。
html代碼片斷以下:
javascript代碼片斷以下:
咱們使用了file控件的change來觸發上傳事件,固然你也可使用某個按鈕來觸發表單提交。提交數據時,我用到了FormData對象來發送二進制文件,FormData構造函數提供的append()方法,除了直接添加二進制文件還能夠附帶一些其它的參數,做爲XMLHttpRequest實例的參數提交給服務端。
以下是Firefox MDN對FormData的解釋。
XMLHttpRequest Level 2添加了一個新的接口FormData.利用FormData對象,咱們能夠經過JavaScript用一些鍵值對來模擬一系列表單控件,咱們還可使用XMLHttpRequest的send()方法來異步的提交這個」表單」.比起普通的ajax,使用FormData的最大優勢就是咱們能夠異步上傳一個二進制文件.
https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
BTW: 使用jQuery提供的ajax方法來發送二進制文件,還須要附加兩個參數:
processData: false // 不要對data參數進行序列化處理,默認爲true
contentType: false // 不要設置Content-Type請求頭,由於文件數據是以 multipart/form-data 來編碼
不少時候上傳的需求都不是隻侷限於單圖上傳,並且須要顯示上傳進度、中斷上傳過程、大文件分段上傳等等,這時傳統的表單上傳沒法實現這些功能,因而產生了使用Flash上傳的方式,它採用Flash做爲一箇中間代理層,代替客戶端跟服務端通訊,此外,它也對客戶端的文件選擇方面擁有更多的控制權,比input[type=」file」]要大得多。
在這裏我使用了jQuery封裝好的uploadify插件來進行演示,通常這類插件都自帶了上傳用的Flash文件,由於跟服務端回傳的數據和展現跟客戶端的交互,都是Flash文件的接口跟插件來對接的。
<div id="file_upload">
html部分很簡單,預留一個hook後,插件會在這個節點內部建立Flash的object,而且還附帶建立了上傳進度、取消控件和多文件隊列展現等界面。
選擇一個文件後,html代碼以下所示:
更多的API和配置請參考jQuery.uploadify 官網APIs ( http://www.uploadify.com/documentation/ )
美中不足的是,mac下會對Flash有各類各樣的限制,甚至不支持,因此使用的時候也要慎重考慮。
目前只有較大的幾家SNS和微博類型的站點發布框實現了這個功能,本着業界良心和用戶至上的原則,咱們也在內外站點開發的早期上線了此功能,這次只是對上傳接口的改造,在這裏簡單的把上傳過程和用到的內容介紹一下。
首先,截圖粘貼上傳的核心思想是,監聽粘貼事件,而後獲取剪切板中的數據,若是是一張圖片,則觸發上傳事件。
代碼片斷以下:
從上面代碼能夠看出,上傳的過程都是同樣的,主要是獲取文件的方式。
當進行粘貼(右鍵paste/ctrl+v)操做時,觸發剪貼板事件’paste’,從系統剪切板獲取內容,而系統剪切板的數據在不一樣瀏覽器保存在不一樣的位置:
IE內核:windows.clipboardData
其它:e.originalEvent.clipboardData
https://www.w3.org/TR/clipboard-apis/
拖拽上傳的方式,支持的瀏覽器比較少,由於它用到了HTML5的兩個新的屬性(API)一個是Drag and Drop ( http://caniuse.com/#search=drag ),一個是File API ( http://caniuse.com/#search=file )
上傳域監聽拖拽的三個事件:dragEnter、dragOver和drop,分別對應拖拽至、拖拽時和釋放三個操做的處理機制,固然你也能夠監聽dragLeave事件。
HTML5的File API提供了一個FileList的接口,它能夠經過拖拽事件的e.dataTransfer.files來傳遞的文件信息,獲取本地文件列表信息。
File API在HTML5規範中只是草案,在 W3C 草案中,File 對象只包含文件名、文件類型和文件大小等只讀屬性。但部分瀏覽器在草案以外提供了一個名爲 FileReader 的對象,用以讀取文件內容,而且能夠監控讀取狀態,它提供的方法有: 「readAsBinaryString」 ,」readAsDataURL」 ,」readAsText」 ,」abort」 等。
參考MDN https://developer.mozilla.org/en-US/docs/Web/API/File
代碼片斷以下:
拖拽上傳過程當中的幾個關鍵點:
在drop事件觸發後經過e.dataTransfer.files獲取拖拽文件列表,在jQuery中是e.originalEvent.dataTransfer.files
拖拽上傳僅支持圖片,文件對象中file.type標識了文件類型
因爲多是多圖拖拽,因此能夠遍歷圖片上傳,這裏用了Underscore的each方法
這裏用readAsDataURL讀取文件內容爲二進制文件,你還能夠將其轉換爲Base64方式上傳,只是http協議裏面存在對非二進制數據的上傳大小限制爲2M。
上傳的過程跟前面的方式相同,即:建立FormData對象併發起Ajax請求
以上各類方式分別試用不一樣的場景,並沒有高下之分。
後面集中方式只有高級瀏覽器才支持,因此僅算是體驗上的加強。
上面的代碼僅是核心代碼片斷,如需運行還需補充參數,好比上傳地址,固然,也須要服務器的支持。代碼地址 ( https://github.com/moxiaohe/moxiaohe.github.io/issues/7 )
對於這些方式,阿里巴巴信息平臺的uxcore框架已經封裝了成型的組件且用在了咱們平常的項目中,歡迎使用。傳送門 uxcore-uploader ( http://uxco.re/components/uploader/ )