字節(jié)封裝React組件手機號自動校驗格式FormItem
更新時間:2022年08月16日 14:43:27 作者:一袋米要扛幾樓
這篇文章主要為大家介紹了字節(jié)封裝React組件手機號自動校驗格式FormItem,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
Situation 背景
- 多人開發(fā)的老項目里面,很多地方都寫了驗證手機格式的需求,代碼各有千秋、百花齊放
- 實現(xiàn):有的寫在公共組件庫里,有的是單獨開發(fā)局部組件支持,有的直接手寫不復(fù)用,有的抽離正則到utils再引入
- 正則:正則校驗也各有千秋,比如/^\d{11}/、/1\d10/、/1[2−9]\d9/、/^1\d{10}/、/^1[2-9]\d{9}/、/1\d10/、/1[2−9]\d9/、/^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/等等。
- 長度限制:有的地方限制maxLength=11,而有的地方?jīng)]限制
- 輸入格式:有的地方滿足334格式(181 2222 3333)手機號碼輸入, 而有的地方只允許輸入純數(shù)字
Target 目標(biāo)
- 實現(xiàn)一個易用的手機號碼公共組件
- 使用較為寬松的正則校驗并與后端達成一致
- 不再限制輸入長度但會報錯提示
- 支持334的格式輸入,并自動去除所有空格
- 寫好參數(shù)說明,方便開發(fā)使用
- 盡可能的保持靈活,適用更多場景
Action 行動
import type { FormItemProps, InputProps, RulesProps, } from '@arco-design/web-react'; import { Form, Input } from '@arco-design/web-react'; import { usePersistCallback } from '@byted/hooks'; import type { ReactNode } from 'react'; import { useMemo } from 'react'; export type VerifyInputProps = { /** ?? 綁定屬性 */ field: string; /** ?? 顯示標(biāo)簽文字 */ label: string; /** 標(biāo)簽前面是否顯示必填*號 */ labelRequired?: boolean; /** ?? rules是否加入必填校驗(為true時無需再設(shè)置labelRequired=true) */ phoneRequired?: boolean; /** 除檢驗手機號格式外其他規(guī)則,默認添加正則檢驗/^1[2-9]\d{9}$/ */ rules?: RulesProps<any>[]; /** 顯示提示文字 */ placeholder?: string; /** 是否禁用input */ disabled?: boolean; /** phone輸入框onChange事件 */ onChange?: InputProps['onChange']; /** FormItem其他屬性 */ formItemProps?: FormItemProps; /** Input其他屬性 */ inputProps?: InputProps; }; /** 手機號表單(帶有 Form.Item) */ export const VerifyPhoneInput = (props: VerifyInputProps) => { const { field, label, placeholder, rules = [], labelRequired = false, phoneRequired = false, disabled, onChange, formItemProps, inputProps, } = props; const resultRules = useMemo(() => { const arr = [ { validator(val: string | undefined, cb: (error?: ReactNode) => void) { const realVal = (`${val}` as any).replaceAll(' ', ''); if (!val || /^1[2-9]\d{9}$/.test(realVal)) { cb(); } else { cb(`請輸入正確的${label}`); } }, }, ...rules, ]; if (phoneRequired) { arr.unshift({ validator(val: string | undefined, cb: (error?: ReactNode) => void) { if (!val) { cb(`請輸入${label}`); } else { cb(); } }, }); } return arr; }, [rules, phoneRequired, label]); const normalize = usePersistCallback((val: string | undefined) => { if (val) { const realVal = (`${val}` as any).replaceAll(' ', ''); if (val !== realVal) { return realVal; } } return val; }); const resultInputProps = { disabled, onChange, allowClear: true, placeholder: placeholder || `請輸入${label}`, ...inputProps, }; return ( <Form.Item required={labelRequired || phoneRequired} field={field} label={label} formatter={normalize} rules={resultRules} {...formItemProps} > <Input {...resultInputProps} /> </Form.Item> ); };
- 定義入?yún)㈩愋蚔erifyInputProps,并按使用頻率對屬性排序并加以說明
- 將是否必填從rules中移出變成phoneRequired參數(shù),錯誤提示也根據(jù)label自動拼接請輸入正確的${label},封裝復(fù)雜、暴露簡單
- placeholder默認根據(jù)label自動拼接成(請輸入${label}),提高易用性
- 將FormItem其他屬性收斂到formItemProps中,方便開發(fā)同學(xué)擴展,提高通用性
- 默認allowClear=true,可以通過inputProps進行覆蓋
- 通過formatter自動去掉所有空格,支持334格式
- 將Input其他屬性收斂到inputProps中,方便開發(fā)同學(xué)擴展,提高通用性
- 暴露rules,支持自定義遠程驗證等規(guī)則
- 暴露常用的disabled、onChange在最外層方便使用
Result 結(jié)果
- 已經(jīng)投入使用,測試符合預(yù)期,提供給其他同事使用,后續(xù)繼續(xù)完善
Review 復(fù)盤
- 問題1:使用normalize去空格后,input下面的錯誤驗證并沒有重新觸發(fā)導(dǎo)致輸入框數(shù)據(jù)已經(jīng)是對的,而錯誤提示還存在的現(xiàn)象。
- 解決:第一種方案將form傳入,在formatter之后通過form?.validate(field)來重新觸發(fā)驗證;第二種方案將rules改為validator的實現(xiàn)方式手動去空格。不希望引入更多參數(shù),最終采用第二種。
- 問題2:正則格式到底怎么定義才能平衡正確性和普適性
- 解決:和后端協(xié)商使用適用目前所有可見場景下的最嚴格的驗證格式/^1[2-9]\d{9}$/
- 問題3:老代碼治理
- 解決:一次性將所有手機號碼相關(guān)的代碼全部改掉,需要測試介入帶來大量的回歸測試時間,而收益很小。所以新需求使用此組件,老需求改動的時候再改成此組件的方案代價更小。
- 問題4:還能再豐富一哈嗎?
- 支持151****2222的顯示與編輯時未修改不校驗,保證手機號私密性
- 問題5:VerifyPhoneInput實際是個FormItem組件,且api與FormItem原本的有很大區(qū)別,會不會給使用者帶來心智負擔(dān)?
- 解決:
import type { FormItemProps, InputProps } from '@arco-design/web-react'; import { Form, Input } from '@arco-design/web-react'; import { usePersistCallback } from '@byted/hooks'; import type { ReactNode } from 'react'; import { useMemo } from 'react'; const defaultLabel = '手機號碼'; export type PhoneFormItemProps = { /** ?? rules是否加入必填校驗(為true時無需再設(shè)置labelRequired=true) */ phoneRequired?: boolean; /** ?? rules是否加入正則校驗(/^1[2-9]\d{9}$/),默認true */ phoneFormatCheck?: boolean; /** Input其他屬性 */ inputProps?: InputProps; } & FormItemProps; /** 手機號表單(帶有 Form.Item) */ export const PhoneFormItem = (props: PhoneFormItemProps) => { const { phoneRequired = false, phoneFormatCheck = true, inputProps, ...formItemProps } = props; const resultRules = useMemo(() => { const arr = [...(formItemProps.rules || [])]; if (phoneFormatCheck) { arr.unshift({ validator(val: string | undefined, cb: (error?: ReactNode) => void) { const realVal = (`${val}` as any).replaceAll(' ', ''); if (!val || /^1[2-9]\d{9}$/.test(realVal)) { cb(); } else { cb(`請輸入正確的${formItemProps?.label || defaultLabel}`); } }, }); } if (phoneRequired) { arr.unshift({ validator(val: string | undefined, cb: (error?: ReactNode) => void) { if (!val) { cb(`請輸入${formItemProps.label || defaultLabel}`); } else { cb(); } }, }); } return arr; }, [ formItemProps.rules, formItemProps.label, phoneFormatCheck, phoneRequired, ]); const normalize = usePersistCallback((val: string | undefined) => { if (val) { const realVal = (`${val}` as any).replaceAll(' ', ''); if (val !== realVal) { return realVal; } } return val; }); const resultInputProps = { allowClear: true, ...inputProps, placeholder: inputProps?.placeholder || `請輸入${formItemProps.label || defaultLabel}`, }; return ( <Form.Item normalize={normalize} rules={resultRules} {...formItemProps} required={formItemProps.required || phoneRequired} > <Input {...resultInputProps} /> </Form.Item> ); };
以前都是用vue,來字節(jié)之后天天react,感覺自己變菜了好多,又或許我原本就菜的離譜。
以上就是字節(jié)封裝React組件手機號自動校驗格式FormItem的詳細內(nèi)容,更多關(guān)于React封裝手機號校驗格式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React Native實現(xiàn)進度條彈框的示例代碼
本篇文章主要介紹了React Native實現(xiàn)進度條彈框的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07