背景
當我們在做后臺管理系統(tǒng)時檀头,經(jīng)常會遇到非常復(fù)雜的表單:
- 表單項非常多
- 在各種表單類型下,顯示不同的表單項
- 在某些條件下岖沛,某些表單項會關(guān)閉驗證
- 每個表單項還會有其他自定義邏輯暑始,比如輸入框可以插入模板變量、輸入字符數(shù)量顯示烫止、圖片上傳并顯示蒋荚、富文本。馆蠕。。
- 在這種錯綜復(fù)雜的情況下惊奇,完成表單的驗證和提交
- 可以查看具體例子:例子中省略了很多瑣碎的功能互躬,只保留整體的復(fù)雜表單框架,用于展示解決方案
方案1: 在一個vue
文件中
所有的表單項顯示隱藏颂郎、驗證吼渡、數(shù)據(jù)獲取、提交乓序、自定義等邏輯放在一起
- 根據(jù)表單類型寺酪,使用
v-if/v-show
處理表單項顯示隱藏- 在
elementui
自定義驗證中坎背,根據(jù)表單類型,判斷表單項是否驗證- 根據(jù)表單類型寄雀,獲取不同的數(shù)據(jù)得滤,并提交到不同的接口
- 其余所有的自定義邏輯
缺點
- 亂
- 亂
- 還是亂
- 一個
vue
文件,輕輕松松上2000
行 - 在我嘗試加入一種新的表單類型時盒犹,我發(fā)現(xiàn)我已經(jīng)無懂更。從。下急膀。手沮协。
方案2:分離組件
其實很容易想到根據(jù)不同的表單類型,分離出多個相應(yīng)類型的子表單卓嫂。但我在實踐時還是遇到了很多問題:父子表單驗證慷暂、整體提交數(shù)據(jù)的獲取等等,并總結(jié)出一套解決方案:
1. 子組件
所有的子組件中都需要包含兩個方法validate
晨雳、getData
供父組件調(diào)用呜呐。
(1) validate
方法
用于驗證本身組件的表單項,并返回一個promise
對象
vaildate() {
// 返回`elementUI`表單驗證的結(jié)果(為`promise`對象)
return this.$refs["ruleForm"].validate();
},
(2) getData
方法
提供子組件中的數(shù)據(jù)
getData() {
// 返回子組件的form
return this.ruleForm;
},
2. 父組件
(1) 策略模式
使用策略模式存儲并獲取子表單的ref
(用于獲取子表單的方法)和提交函數(shù) 悍募。省略了大量的if-else
判斷蘑辑。
data:{
// type和ref名稱的映射
typeRefMap: {
1: "message",
2: "mail",
3: "apppush"
},
// type和提交函數(shù)的映射。不同類型坠宴,接口可能不同
typeSubmitMap: {
1: data => alert(`短信模板創(chuàng)建成功${JSON.stringify(data)}`),
2: data => alert(`郵件模板創(chuàng)建成功${JSON.stringify(data)}`),
3: data => alert(`push模板創(chuàng)建成功${JSON.stringify(data)}`)
},
}
(2) submit
方法
用于父子組件表單驗證洋魂、獲取整體數(shù)據(jù)、調(diào)用當前類型提交函數(shù)提交數(shù)據(jù)
因為
elementUI
表單驗證的validate
方法可以返回promise
結(jié)果喜鼓,可以利用promise
的特性來處理父子表單的驗證副砍。
比如then
函數(shù)可以返回另一個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 => { // 全部驗證通過 // 獲取整體數(shù)據(jù) const reqData = { // 獲取子組件數(shù)據(jù) ...this.$refs[templateType].getData(), ...this.indexForm }; // 獲取當前表單類型的提交函數(shù),并提交 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 => { // 都通過時优烧,發(fā)送請求 const reqData = { ...this.$refs[templateType].getData(), ...this.indexForm }; this.typeSubmitMap[this.indexForm.type](reqData); }) .catch(err => { console.log(err); }); },
查看在線項目、項目github和組件代碼
總結(jié):很多項目我都遇到這種復(fù)雜的表單链峭,也用了很多種解決方案畦娄,在此總結(jié)出了一種比較整潔簡便的方案。當然還有其他很多方案,比如可以把數(shù)據(jù)提交的方法放在每一個子組件中熙卡,公共的表單項數(shù)據(jù)通過
props
傳遞給子組件用于提交杖刷。有其他更加簡潔的方案,歡迎評論驳癌,或者github
上提issue
題外話: 看了前端架構(gòu)師親述:前端工程師成長之路的 N 問 及 回答中的幾個回答后滑燃,對我有很大的啟發(fā)。在對自己的技術(shù)方向喂柒、前景迷茫時不瓶、或者在埋怨自己的項目太low時、或者埋怨自己每天在做重復(fù)工作時灾杰、或者每天對層出不窮的新技術(shù)焦頭爛額時蚊丐,不妨認真的審視下自己的項目,
- 每天重復(fù)的工作艳吠,是不是可以自己造輪子了麦备;
- 技術(shù)棧太low,是不是可以平滑過渡到新技術(shù)昭娩,提高開發(fā)效率凛篙;
- 學(xué)再多的新技術(shù),最終也會回歸并實踐到項目中栏渺。
從工作流程和項目的痛點出發(fā)呛梆,你會在實踐、總結(jié)并解決實際問題中進步的更加迅速磕诊。
寫這篇文章的感受:把這些東西表達出來的難度
>>
文章本身所包含的技術(shù)難度