最近使用了elementUI提供的upload組件上傳文件,總結下使用過程當中的一些心得。本文不會介紹如何使用elementUI中的upload組件,由於官網自己就已經介紹的很詳細了。vue
本文主要包括如下幾個問題:git
/packages/upload
文件夾下面;upload組件提供了兩種上傳文件的方式:github
針對上述兩種方式,upload組件提供了屬性accept
來限制和校驗文件格式。這裏,我使用了兩個詞:瀏覽器
校驗:從結果層面上校驗,也就是在最後一步才能發現選擇不了,同時適用於上述兩種方式,其中校驗又包括兩種:dom
接下來咱們結合upload組件源碼來分析下實現原理。ide
限制形式的主要原理就是原生input元素的accept屬性(源碼/packages/upload/src/upload.vue文件第206行):函數
<input class="el-upload__input" type="file" ref="input" name={name} on-change={handleChange} multiple={multiple} accept={accept}></input>
當沒有添加accept屬性的時候,系統的文件選擇框中的文件都是可選的:this
<input type="file" />
當添加了accept以後,好比.png
,系統的文件選擇框中只有符合格式的文件纔是可選的:spa
<input type="file" accept=".png" />
如何支持多種文件格式上傳呢?看下原生input元素accept屬性的文檔,會發現accept是支持逗號分割的多種文件格式的:操作系統
<input type="file" accept=".png,.jpg,.jpeg" />
開發的時候發現一個有意思的問題,就是若是accept裏面.jpg和.jpeg只寫一個,另一種格式也是能夠選擇的:
<input type="file" accept=".png,.jpeg" /> // 或者 <input type="file" accept=".png,.jpg" />
因此,jpg和jpeg有啥關係?查找了下資料,發現這兩種格式並無任何區別,至於爲何會有兩個名字,說是先有了jpeg,而後Windows的早期版本規定文件的擴展名只能是三個字符,因此就變成了jpg。感興趣的能夠參考這篇文章。
因此,
這個時候就只能依賴下面的校驗方式了。
當使用拖拽方式上傳文件的時候,是能夠拖拽任何文件的,因此只能在拖拽完成的時候去校驗文件格式。那麼,應該去校驗哪些格式呢?從upload組件使用者的角度來講,不管是input元素方式仍是拖拽方式,都應該是保持統一的。也就是,原生input的accept屬性支持的格式,在使用拖拽方式的時候,也都得支持。
因此,先看下input的accept屬性支持的格式類型:
.
開頭;upload組件源碼針對上述三種類型作的相應處理(/packages/upload/src/upload-dragger.vue
文件onDrop方法)以下:
this.$emit('file', [].slice.call(e.dataTransfer.files).filter(file => { const { type, name } = file; const extension = name.indexOf('.') > -1 ? `.${ name.split('.').pop() }` : ''; const baseType = type.replace(/\/.*$/, ''); return accept.split(',') .map(type => type.trim()) .filter(type => type) .some(acceptedType => { if (/\..+$/.test(acceptedType)) { // 1. 擴展名形式 return extension === acceptedType; } if (/\/\*$/.test(acceptedType)) { // 3. "audio/*" "video/*" "image/*" return baseType === acceptedType.replace(/\/\*$/, ''); } if (/^[^\/]+\/[^\/]+$/.test(acceptedType)) { // 2. MIME類型 return type === acceptedType; } return false; }); }));
upload組件提供了自定義校驗的鉤子函數:before-upload。根據該函數的返回值決定是繼續仍是終止(/packages/upload/src/upload.vue
文件第91行):
const before = this.beforeUpload(rawFile);
結論:不能
dragEvent有一個dataTransfer屬性,這個屬性有一個setDragImage方法,該方法看似能夠用來自定義拖拽樣式。可是,這個方法有一個使用限制:只能在dragstart事件中調用。
可是當從操做系統拖拽文件到瀏覽器中的時候,dragstart事件是不會觸發的,因此setDragImage方法不能實現咱們的目的。
upload組件dom中包含一個不顯示的input元素,當點擊組件的時候觸發input元素的click事件(/packages/upload/src/upload.vue):
handleClick() { if (!this.disabled) { this.$refs.input.value = null; this.$refs.input.click(); } }
若有錯誤,歡迎留言討論。