終於抽出時間來繼續更新本身的博客,最近忙得夠嗆...
對於該系列博客不知道你們有沒有這樣的見解,對於React常見的基礎東西並無過多或者詳細列出,感受有點不符合系列標題。的確,筆者一開始也想把React基礎從頭至尾列一邊,可是想一想看沒這個必要,由於這種基礎教程在網上多如牛毛,再寫豈不是重複造輪子,因此筆者就挑一些相對「偏僻」可是確定會用到的東西拿出來分享。react
本期的主題是在React中如何實現文件上傳
。文件上傳這個功能在實際開發過程當中用的地方相對較多,固然還有不少花裏胡哨的解決方案,不過萬變不離其宗再複雜的解決方案也離不開最基礎的技術,因此筆者將文件上傳這一塊詳細整理了一下而且作了demo供你們參考學習。ios
目前比較主流的解決方案就是form表單
、fetch(或者axios)
和form表單+fetch
來實現。對於第二位而言,筆者本着能用原生就用原生
的原則就沒有使用axios模塊。那麼下面就一一開始分享。git
利用表單組件進行文件上傳是遠古時期就一直在用的方法並且還真經久不衰,厲害了。利用form表單的enctype
屬性能夠把表單提交的對象設置爲多媒體資源,而後經過inuput:file
就能夠實現文件上傳的功能,例子以下:github
import React, {Component} from 'react' class FormUploadOnly extends Component { render() { return ( <div> <form action="http://127.0.0.1:3001/file/upload" method="post" enctype="multipart/form-data"> <input type="file" name='file'/> <input type="submit" value="上傳"/> </form> </div> ) } } export default FormUploadOnly;
這個solution相對便捷有效並且還不用考慮跨域的問題
,畢竟咱們上傳的文件終究仍是要訪問API接口;不過這種方法還有一個不方便的地方,就是form表單會默認跳轉也就是會在瀏覽器訪問你所提交文件的那個接口,這個行爲處理起來很麻煩。這個問題筆者推薦經過一個iframe來解決。ajax
Fetch是瀏覽器的原生API,能夠像Ajax那樣請求後臺接口。不過由於它是基於Promise的,因此不支持Promise的瀏覽器則沒法使用該方法。閒話不說,如何經過fetch來實現上傳?express
import React, {Component} from 'react'; class FetchUpload extends Component { constructor(props) { super(props); this.fileInput = React.createRef(); } upload = () => { const data = new FormData(); data.append('file', this.fileInput.current.files[0]); //至關於 input:file 中的name屬性 fetch('http://127.0.0.1:3001/file/upload', { method: 'POST', body: data }).then(response => console.log(response)) }; render() { return ( <div> <input type="file" name='file' ref={this.fileInput}/> <input type="button" value="上傳" onClick={this.upload}/> </div> ) } } export default FetchUpload;
這個方法比較投機取巧,就是將input:type
中的數據append到FormData中,FormData會將數據編譯成鍵值對,這樣能夠被fetch發送至後臺(不只僅限於fetch,也能夠是ajax或者axios等等)。不過這種方法有個致命的問題,那就是會有跨域問題。對於這個問題,筆者會在博客末尾提供相關解決方案。axios
這個方案看小標題和前面的內容,相信你們都能猜到是什麼樣子了。下面直接上代碼:跨域
import React, {Component} from 'react' class FormUpload extends Component { submit = (e) => { e.preventDefault(); let formData = new FormData(e.target); fetch('http://127.0.0.1:3001/file/upload', { method: 'POST', body: formData //自動將input:file的name屬性與文件對象組合成鍵值對 }).then(response => console.log(response)) }; render() { return ( <div> <form onSubmit={this.submit}> <input type="file" name='file'/> <input type="submit" value="上傳"/> </form> </div> ) } } export default FormUpload;
總的來講,這個方法和第二中方法在原理上是相同的,只是獲取的文件數據不是直接從input:type
中獲取的,而是從form的提交事件中獲取的,其餘的沒什麼變化,因此也會遇到跨域的問題。瀏覽器
該博客的demo後臺是express寫的,因此不論是跨域管理
仍是接收並保存文件
都是基於Node模塊。app
筆者經常使用的Node服務跨域解決方案是第三方庫cors。固然cors除了是這個第三方庫的名字,也有比較重要的W3C標準,它對解決瀏覽器跨域問題起到重要的做用,不過該博文的重點不在這因此不做贅述,相關的使用方法都在文末的demo裏,有興趣的朋友能夠嘗試用用,真的很high!
由於express自身的request對象不包含上傳過來的文件對象,因此必需要用到第三方庫multer。負責處理multipart/form-data 類型的表單數據
和保存相關資源的做用。
小提示
利用multer初始化一個upload中間件對象時候須要指定一個「標誌符」,好比:
let upload = multer({storage: storage}).single('file');
這裏的標識符是file
,對應前面代碼中的:
<input type="file
" name=' file'/>
和
data.append('file
', this.fileInput.current.files[0])
這是一個不算大的坑,因此你們使用時候多多關注。
最後筆者奉上準備好的demo,有興趣的話能夠download下來耍耍。固然裏面還包含了下一篇文件下載的代碼,你們能夠也順帶看看。