當我們在做後台管理系統時,常常會遇到非常複雜的表單:
- 表單項目非常多
- 在各種表單類型下,顯示不同的表單項目
- 在某些條件下,某些表單項目會關閉驗證
- 每個表單項目還會有其他自訂邏輯,例如輸入框可以插入範本變數、輸入字元數量顯示、圖片上傳並顯示、富文本。 。 。
- 在這種錯綜複雜的情況下,完成表單的驗證和提交
- 可以查看具體例子:範例中省略了許多瑣碎的功能,只保留整體的複雜表單框架,用於展示解決方案
vue檔中所有的表單項目顯示隱藏、驗證、資料取得、提交、自訂等邏輯放在一起
- 根據表單類型,使用
v-if/v-show處理表單項目顯示隱藏- 在
elementui自訂驗證中,根據表單類型,判斷表單項目是否有驗證- 根據表單類型,取得不同的數據,並提交到不同的接口
- 其餘所有的自訂邏輯
vue文件,輕輕鬆鬆上2000行其實很容易想到根據不同的表單類型,分離出多個對應類型的子表單。但我在實踐時還是遇到了很多問題:父子表單驗證、整體提交資料的獲取等等,並總結出一套解決方案:
所有的子元件中都需要包含兩個方法validate 、 getData供父元件呼叫。
validate方法用於驗證本身元件的表單項,並傳回一個promise對象
vaildate ( ) {
// 返回`elementUI`表单验证的结果(为`promise`对象)
return this . $refs [ "ruleForm" ] . validate ( ) ;
} ,
getData方法提供子組件中的數據
getData ( ) {
// 返回子组件的form
return this . ruleForm ;
} ,使用策略模式儲存並取得子表單的ref (用於取得子表單的方法)和提交函數。省略了大量的if-else判斷。
data: {
// type和ref名称的映射
typeRefMap : {
1 : "message" ,
2 : "mail" ,
3 : "apppush"
} ,
// type和提交函数的映射。不同类型,接口可能不同
typeSubmitMap : {
1 : data => alert ( `短信模板创建成功${ JSON . stringify ( data ) } ` ) ,
2 : data => alert ( `邮件模板创建成功${ JSON . stringify ( data ) } ` ) ,
3 : data => alert ( `push模板创建成功${ JSON . stringify ( data ) } ` )
} ,
} submit方法用於父子元件表單驗證、取得整體資料、呼叫目前類型提交函數提交數據
因為
elementUI表單驗證的validate方法可以傳回promise結果,可以利用promise的特性來處理父子表單的驗證。 例如then函數可以回傳另一個promise物件、catch可以取得它以上所有then的reject、Promise.all。
// 父表单验证通过才会验证子表单,存在先后顺序
submitForm ( ) {
const templateType = this . typeRefMap [ this . indexForm . type ] ;
this . $refs [ "indexForm" ]
. validate ( )
. then ( res => {
// 父表单验证成功后,验证子表单
return this . $refs [ templateType ] . vaildate ( ) ;
} )
. then ( res => {
// 全部验证通过
// 获取整体数据
const reqData = {
// 获取子组件数据
... this . $refs [ templateType ] . getData ( ) ,
... this . indexForm
} ;
// 获取当前表单类型的提交函数,并提交
this . typeSubmitMap [ this . indexForm . type ] ( reqData ) ;
} )
. catch ( err => {
console . log ( err ) ;
} ) ;
} , submitForm1 ( ) {
const templateType = this . typeRefMap [ this . indexForm . type ] ;
const validate1 = this . $refs [ "indexForm" ] . validate ( ) ;
const validate2 = this . $refs [ templateType ] . vaildate ( ) ;
// 父子表单一起验证
Promise . all ( [ validate1 , validate2 ] )
. then ( res => {
// 都通过时,发送请求
const reqData = {
... this . $refs [ templateType ] . getData ( ) ,
... this . indexForm
} ;
this . typeSubmitMap [ this . indexForm . type ] ( reqData ) ;
} )
. catch ( err => {
console . log ( err ) ;
} ) ;
} , 總結:很多專案我都遇到這種複雜的表單,也用了很多種解決方案,在此總結出了比較整潔簡單的方案。當然還有其他很多方案,例如可以把資料提交的方法放在每個子元件中,公共的表單項目資料透過
props傳遞給子元件用於提交。還有其他更簡潔的方案,歡迎評論,或github上提issue
題外話: 看了前端架構師親述:前端工程師成長之路的N 問及回答中的幾個回答後,對我有很大的啟發。在對自己的技術方向、前景迷茫時、或者在埋怨自己的項目太low時、或者埋怨自己每天在做重複工作時、或者每天對層出不窮的新技術焦頭爛額時,不妨認真的審視下自己的項目,
從工作流程和專案的痛點出發,你會在實踐、總結並解決實際問題中進步的更加迅速。
寫這篇文章的感受:把這些東西表達出來的難度
>>文章本身所包含的技術難度