上文是前段時間寫了一篇根據公司的業務需求我是如何封裝組件,也算是對那段忙碌的工做一份小小的總結吧。有時在忙碌的開發過程以後,咱們須要停下腳步去思考本身寫的代碼是否具備可讀性?是否還能夠再健壯一些?同時也要去總結業務,回過頭來看看本身在業務的需求的基礎上去設計的組件代碼是不是合理的?是否還能夠更好一些?git
我想這樣的四個問號會一直伴隨着我,由於我知道那是成長的必經之路。github
作事後臺管理系統應該都知道文件上傳這樣一個功能,說到文件上傳就想到本身曾研究的大文件上傳的案例,並總結了這樣的一篇文章。(ps:實現多個大文件拖拽上傳+大文件分片上傳+斷點續傳+文件預覽)。web
收到的業務需求並非如上的直接將文件傳送給後端的這樣的上傳功能,而是要將文件的內容進行解析成後端想要的數據格式,再將解析以後的數據送給後端,這樣來實現文件的上傳。npm
我是經過element-ui
的上傳組件和js-xlsx
庫來實現這樣的一個需求。element-ui
npm install element-ui xlsx -S
複製代碼
實現這個功能並不難,思路就是先收集文件再將文件先解析成JSON
數據,最後發送後端。但如何更好的設計組件,讓組件在整個項目複用最大化,值得去思考。json
這裏我是將這個組件拆分紅模板組件和功能組件。模板組件組是用來展現UI以及收集文件,功能組件是用來將文件內容解析成數據。由於一個項目下來文件上傳的功能可能不只僅是將文件解析成數據,也多是直接將整個文件進行上傳,那要是將文件內容解析成JSON
數據這樣的功能都放在一個組件裏,這樣組件就會顯得很臃腫。並且這樣也能夠實現對模板組件的複用,以及最大化的複用這個功能組件。後端
那如何將模板組件和功能組件鏈接在一塊兒呢?這裏的核心是利用Vue的Mixins
能夠混入另外一個組件的功能。具體可查看:Mixinsapi
我是用了el-upload
的組件做爲模板來自定義組件。開發這個功能須要自定義上傳的方法,因此我經過on-change
事件來收集文件和on-remove
屬性來移除文件。秉承着高內聚低耦合的思想,我將這兩個屬性直接在el-upload
組件上綁定,而不是經過在頁面使用自定義組件時傳入屬性再跨階級傳入到el-upload
。由於最終的目的都是爲了拿到文件數據去請求接口,那何不在那麼本身將數據進行處理好呢?因此,爲了方便我在內部整理好數據以後,經過外部傳入一個callback函數來執行拿到文件數據以後的後續操做,callback函數這是一個必傳的配置屬性,它表示將文件數據整合後的後續操做。(ps:好比調用接口等等...)數組
由於要將文件讀取成JSON
數據,因此自定義組件配置了一個屬性headerStr
,這個屬性是對象型數組,裏面承載着要傳給後端的字段key
和要從表格裏哪列讀取內容str
,以及該字段所對應的數據類型type
。那麼如何使用這個配置項,留個疑問,後續講述。以下圖:
自定義組件定義了一個multiple
屬性,值爲true
或false
,用來開啓是不是多文件上傳;組件也自配置了start
和end
屬性,用來表示表格的從哪一列到哪一列結束;組件內部也進行了文件格式的一一校驗。組件內部也對callback函數進行了一層包裝,將它包裝成一個Promise對象,這樣作的目的是爲了使多文件能夠併發上傳。
自定義組件可將文件收集成fileList以後,那麼如何對文件進行數據解析,這時須要一個功能組件。
在上面講述了使用Vue的Mixins
,因此我在自定義組件混入了功能組件UploadXlsx
,那自定義組件就能夠直接訪問功能組件的方法。
在功能組件裏,暴露了兩個方法:
handlerReaderFile
用來讀取文件內容,在這裏經過FileReader
來讀取一份文件,而且使用xlsx
將表格對象轉成JSON
對象(ps:這裏是使用xlsx
庫提供的XLSX.utils.sheet_to_json
方法。如何使用js-xlsx
這個庫,詳細可看github的js-xlsx)。該方法返回了一個Promise
對象。在編碼的過程當中一開始只考慮了一份.xlsx表格文件只有一個sheet的狀況下,但實際狀況一份xlsx表格可能有多個sheet的狀況(ps:也就是一份文件多份sheet的狀況下),因此要進行統一的處理(ps:若是是多份sheet,則對每一份sheet進行解析)。這裏是經過數組隊列保存每一份sheet解析完成的JSON
值以後再resolve
給自定義模板組件。在這個函數內部,經過自定義組件傳入的start
和end
屬性進行文件表頭的校驗,不符合要求的不給與上傳。具體的邏輯可查看源碼。來看看經過xlsx
庫生成的JSON
數據是長什麼樣的:
handlerUploadResult
用來生成真正後端想要的JSON
數據。這裏就使用到headerStr這個配置項核心,經過str
屬性和表格生成的JSON數據的key進行比對匹配,而且經過type
屬性進行數據類型的改裝,就可生成真正的JSON
數據。大體的思路:基本上功能組件已經完成了。在回頭看看自定義模板組件,在將收集到的文件LIST作處理時經過使用功能組件暴露的handlerReaderFile
方法來實現將文件解析成JSON
數據,而且調用callback函數。由於handlerReaderFile
方法返回的是數組隊列,因此我在自定義組件內部使用Promise.all
進行文件的併發上傳。我將這個返回值傳到剛剛上面所講述的包裝callback的那個函數,並將參數進行循環,而後經過使用Promsie包裝再resolve調用callback函數。最後經過調用包裝函數所返回的值做爲Promise.all
的參數。具體的實現邏輯可查看源碼。
因一開始只思考了處理一個sheet的狀況,而遺漏了多個sheet的狀況。其實只考慮了一個sheet的狀況,功能仍是可使用的,可是這個功能組件的代碼並不健壯。若是下次個人同事一份表格編寫了3份sheet呢?那麼組件就遺漏數據處理了。因此多去思考各類可能性多觀察不一樣的業務可能性,把本身的代碼變得更健壯是值得實踐的。
經過將組件拆分紅功能組件和模板組件,我以爲是有必要的。由於文件上傳實現的方案可有多種可能性。如今是將表格數據解析再上傳,那下次直接將文件上傳呢?那麼該模板就能夠被複用,並且對於所定義的函數,屬性並無什麼衝突,反而可以讓這個組件更好維護。並且作事後臺管理系統的都大概都知道好比彈框這種的功能無處不在,如何在項目當中更好的設計這類的需求,我以爲就能夠把彈框組件(UI)和是否顯示彈框(功能組件)抽離出來,這樣整個項目均可複用這個功能組件,遇到相似的彈框還能夠作個配置項去設計。
給組件定製配置項,好比headerStr
和callback
。那麼下次不同的表頭相同的上傳方式,那麼這個組件就能夠直接被複用了。並且組件儘量的高內聚低耦合
,能在內部進行處理的就必定放在內部處理,將其結果暴露給外部的使用者。
源地址可查看:源碼
開發完這個需求以後,我對Promise
和Object.assign
這些基礎的東西也有更深刻的認識。我仍是以爲動手去封裝組件是有必要的,並且隨着時間的成長,儘量的要有一套本身的組件庫。
最後,對各大掘友有幫助的話但願賞個 star ~(ps:不要吝嗇哦)