首先尊搬,根據業(yè)務和交互UI設計瓤湘,本文實現的自定義的輸入框組件InputItem需要用到React-native的View泊脐、Text、TextInput课蔬、TouchableOpacity四個原生組件和自定義的一個Icon組件闪檬。
組件基本結構如下,簡略版购笆,樣式就不詳細舉出了
<View style={styles.container}>
/*label 文字*/
<View>
<Text>{labelText}</Text>
<View>
{isTips && (<TouchableOpacity>
<Text><Icon name=‘tips’></Text>
</TouchableOpacity>
)}
/*輸入框*/
<TextInput
style={styles.textInput}
onBlur={this.onBlurTest}
onChangeText={this.onInputChange}
autoCorrect={false}
/>
</View>
/*文字錯誤提示*/
{(this.state.isError && (
<View style={styles.errorMsgContainer}>
<Text style={styles.errorMsg}>{this.props.errorMsg}</Text>
</View>
)}
接下來就是本人在結合需求開發(fā)的這個輸入框組件時粗悯,遇到的幾個比較關鍵點(坑)
1、輸入的值的保存
2同欠、校驗的結果顯示方式(邊輸入邊校驗還是輸入框失去焦點以后再校驗)
3样傍、校驗的觸發(fā)時機
4、父組件如何記錄铺遂、計算所有InputItem的校驗結果
5衫哥、鍵盤彈出,輸入框會被遮罩的問題
第一點:輸入值的保存
(1)一開始使用的react-native 版本是0.56襟锐,在ios上是輸入不了中文的(巨坑這個點)撤逢。目前項目升級到0.57版本可以解決。之前不升級項目版本粮坞,用了一套暴力的解決方案蚊荣,訪問鏈接:https://github.com/facebook/react-native/issues/18403 ( withHandleHandWritingTextInput)。問題基本可以解決莫杈,但是沒有滿足項目的需求互例,所以被迫升級版本。
(2)假如輸入的內容需要限定位數筝闹,且要輸入中文媳叨,位數要注意長度:用戶每打一個拼音字母,其實就占了輸入框的一位數关顷。舉個例子:假設設定輸入框位數為4糊秆,那用戶想打個 ‘想’,拼音是xiang议双,拼音位數是5痘番,這時候用戶只能打出前四位 ‘xian’,無法打出第五位 ‘g’聋伦,因為位數不夠了夫偶。
(3)由于TextInput是受控組件,并不提倡在TextInput中使用value綁定state的寫法來保存輸入的值觉增,事實也是兵拢,在react-native中使用這種寫法也會出現bug。所以逾礁,此項目中使用的是说铃,父組件props傳遞一個saveValue函數給InputItem访惜,然后在InputItem中的onChangeText中調用this.props.saveValue(value),將value傳遞給父組件腻扇,讓父組件保存對應的輸入值债热。
第二點:校驗的結果顯示方式
(1)一開始項目的需求是用戶一點輸入一邊實時校驗。這種方式其實比較簡單幼苛,只需要在onChangeText的監(jiān)聽函數中窒篱,加上自己的校驗函數regTest并且在regTest中設置自身的校驗結果state,控制errorMsg顯示與否就可以了舶沿。
(2)順便提一句墙杯,校驗所使用的正則表達式其實也是從父組件props傳遞過來的,感覺這樣可以盡量讓InputItem組件pure一點點括荡。
(3)現在項目的需求想改成高镐,輸入內容不實時檢驗,當輸入框失焦的時候才去校驗畸冲。這時候嫉髓,就可以把之前的onChangeText函數中的regTest函數抽離出來,放到onBlur函數中去邑闲。
第三點:校驗的觸發(fā)時機
這個點一看其實好像不是一個問題算行,因為觸發(fā)的時機看第二點問題,就已經很明顯了监憎,要不就是邊輸入邊觸發(fā)纱意,要不就失焦的時候觸發(fā)婶溯,很好理解鲸阔。
(1)需要考慮到一個需求情況是,輸入框的值迄委,理應是可以設置默認的值褐筛。例如,進入用戶的信息編輯頁叙身,要把InputItem的value設置成默認用戶信息渔扎。我們從開始的添加信息的時候,就已經校驗了輸入內容的合法性信轿,因此晃痴,在理想的情況下,獲取到的用戶信息和設定的默認值财忽,應該是不需要再校驗倘核。但是為了程序更加健壯,還是得假設獲取的數據是不可靠即彪,所以在獲取到數據并且設置默認值的時候紧唱,依然需要加上校驗的處理。
(2)接下來就是如何觸發(fā)設置完默認值以后進行校驗的問題了。首先漏益,能想到的是設置默認值蛹锰,其實就是數據從無到有,因此可以在InputItem 中的componentWillReceiveProps函數設置
/* 設置默認值時绰疤,初始數據為null*/
if (nextProps.value && !this.props.value) {
this.regTest(nextProps.value);
}
這樣基本能滿足頁面加載后同時設置了默認值铜犬,然后對默認值進行校驗的需求轻庆。
(3)然后翎苫,項目有個特別的需求,就是輸入內容可以通過掃描照片來自動填入榨了。假若煎谍,用戶一開始沒有自己輸入過信息,直接通過掃描來填入信息龙屉,其實情況與上面所說的情況是一致的呐粘,數據都是從無到有,可以觸發(fā)校驗转捕。需要考慮的情況其實是作岖,用戶掃描之前填入過內容,再去掃描結果覆蓋之前填入的信息五芝,這時候要觸發(fā)對覆蓋的掃描結果信息的校驗痘儡。
(4)這種情況還得結合第2大點--校驗的結果顯示方式來討論。
假如顯示方式是邊輸入邊校驗枢步,則可以在InputItem 中的componentWillReceiveProps函數設置
/*新輸入的(掃描結果設置)value和之前的value不同沉删,就校驗新的value,符合邊輸入邊校驗的規(guī)則*/
else if (nextProps.value !== this.props.value) {
this.regTest(nextProps.value ? nextProps.value : '');
}
假如顯示方式是失焦以后再校驗醉途,則會相對比較復雜一點矾瑰。我們需要考慮,什么時候去觸發(fā)校驗隘擎。(新需求殴穴,目前還在研究解決方案)
第四點:父組件如何記錄、計算所有InputItem的校驗結果
之前的實現背景是:父組件有多個輸入框货葬,輸入框值保存在父組件的state中采幌,同時,輸入框的校驗結果也需要同步到父組件震桶,在父組件記錄下來休傍,并且計算所有輸入框的狀態(tài),以便決定用戶是否可以成功點擊完成按鈕尼夺。
目前的解決方案是尊残,在父組件中設置一個變量炒瘸,對象allStatus。在用戶輸入信息寝衫,InputItem調用父組件的saveValue函數將信息set進父組件state進行保存的后顷扩,將輸入信息的校驗后的狀態(tài)也設置到變量對象allStatus中,相當于每一個輸入框慰毅,在allStatus對象中會有一個對應的輸入框檢驗屬性隘截,類型是Boolean值,記錄輸入框當前的信息的狀態(tài)是否合法汹胃。然后再用戶點擊完成按鈕的時候婶芭,遍歷allStatus對象的屬性,遇到一個屬性為true(就是有輸入框內容是錯誤的)就阻止完成按鈕的后臺請求操作着饥。
這個方案可能不是最優(yōu)解犀农,目前在考慮使用二進制數記錄計算,還在研究中宰掉。
第五點:鍵盤彈出呵哨,輸入框會被遮罩的問題
使用的是react-native-keyboard-aware-scroll-view依賴的KeyboardAwareScrollView解決項目的問題,iso和Android平臺使用方法不一樣轨奄,不一定適用你們的項目孟害,谷歌很多解決方案,多嘗試挪拟。以下是代碼:
if (Platform.OS === 'ios') {
return (
<KeyboardAwareScrollView style={{ flex: 1 }} showsVerticalScrollIndicator={false}>
{this.props.children}
</KeyboardAwareScrollView>
);
}
return (
<KeyboardAvoidingView style={{ flex: 1 }} behavior="padding">
<ScrollView showsVerticalScrollIndicator={false}>
{this.props.children}
</ScrollView>
</KeyboardAvoidingView>
);
}