效果圖:

最近自己研究了下react native里的sectionlist組件,寫了一個(gè)類似通訊錄功能的三方庫組件react-native-sectionlist-contacts,包含了點(diǎn)擊右邊的索引進(jìn)行對(duì)應(yīng)的跳轉(zhuǎn),下面就闡述下這個(gè)組件的原理和使用步驟以及當(dāng)中遇到的問題。
代碼原理
根據(jù)react native的sectionlist文檔,需要傳入一個(gè)數(shù)組類型的數(shù)據(jù)源給sectionlist,不過在此之前,需要定義下你所需要的頭部數(shù)據(jù)有哪些,我這里定下了26個(gè)字母加上一個(gè)默認(rèn)其他,具體代碼如下:
constructor(props) {
super(props);
//name字段必須,其他可有可無
let nameData=[
{name:'阿瑪尼',id:'amani',params: ''},
{name:'OK',id:'ok',params: '123'},
{name:'天津飯'},
{name:'%……&'},
{name:'周星馳'},
{name:'習(xí)大表哥'},
{name:'不要這樣'},
{name:'V字仇殺隊(duì)'},
{name:'拼車'},
{name:'他媽跌'},
{name:'淫僧'},
{name:'錢學(xué)森'},
{name:'寧采臣'},
{name:'史泰龍'},
{name:'恐龍'},
{name:'任達(dá)華'},
{name:'媽咪寶貝'},
{name:'ing'},
{name:'康麥隆'},
{name:'劉德華'},
{name:'精忠報(bào)國'},
{name:'黃藥師'},
{name:'大叔皮'},
{name:'布達(dá)拉宮'},
{name:'方世玉'},
{name:'ET外星人'},
{name:'程咬金'},
{name:'**&&&&'},
]
this.state = {
dataArray: data,
}
}
然后通過查找資料,找到一個(gè)獲取首字母的方法,傳入一個(gè)字符串,不管是中文還是英文甚至火星文,都能獲取到他的首個(gè)字母,因?yàn)榇a比較多,所以還請(qǐng)?jiān)?a target="_blank">這個(gè)鏈接里查詢方法文件(getFirstAlphabet.js),之后再render方法里進(jìn)行渲染:
<SectionList
{...this.props}
style={this.props.SectionListStyle}
ref={s=>this.sectionList=s}
keyExtractor={this._keyExtractor}
sections={delData}
renderSectionHeader={this._renderSectionHeader}
renderItem={this._renderItem}
getItemLayout={(data, index) => ( {length: this.props.sectionHeight, offset: this.props.sectionHeight * index, index} )}
/>
delData是數(shù)組數(shù)據(jù)源,getItemLayout是給出一個(gè)預(yù)計(jì)算,如果能知道每個(gè)item的高度的情況下,設(shè)置對(duì)應(yīng)的值為此高度,能夠很好的提高組件的渲染效果,同時(shí)也是后面能夠點(diǎn)擊索引定位到位置所必須的條件。這里的sectionHeight就是每個(gè)item的高度。
當(dāng)然此組件也支持自定義頭部樣式和自定義內(nèi)容item樣式,可在文檔里看到,這里不做說明。
最后就是右邊索引的功能實(shí)現(xiàn),我這里做的是給出的數(shù)據(jù)源里有對(duì)應(yīng)的索引才顯示,不然不顯示,代碼如下:
let data=_.cloneDeep(this.state.dataArray);
this.props.sectionListData.map((item,index)=>{
for (let i=0;i<data.length;i++){
if (i==data.length-1){
data[i].data.push(item)
break
}else if (data[i].key==makePy(item.name.toUpperCase())){
data[i].data.push(item)
break
}else {
continue
}
}
})
let delData = []
let letterData = []
for (var i in data){
if (data[i].data.length!=0){
delData.push(data[i])
letterData.push(data[i].key)
}
}
sectionListData是數(shù)據(jù)源數(shù)組,makePy即為獲取每個(gè)字符串的首字母方法,最后得到的letterData數(shù)據(jù)即為索引數(shù)組,然后絕對(duì)定位渲染出索引:
<View style={[styles.letterView,this.props.letterViewStyle]}>
{
letterData.map((item,index)=>{
let otherStyle=[]
if (index==letterData.length-1){
if (item==this.props.otherAlphabet){
otherStyle.push({width: 20})
}
}
return(
<TouchableWithoutFeedback key={'letter_'+index} onPress=
{()=>{
this.sectionList.scrollToLocation({animated: this.props.scrollAnimation, itemIndex: 0,sectionIndex: index,viewOffset: (this.props.sectionHeight * (index + 1)) + (this.props.sectionHeaderHeight * index)})
}}>
<View style={[styles.letterItemView,otherStyle]}>
<Text numberOfLines={0} style={[styles.letterText,this.props.letterTextStyle]}>{item}</Text>
</View>
</TouchableWithoutFeedback>
)
})
}
</View>
當(dāng)點(diǎn)擊每個(gè)索引的時(shí)候,就會(huì)觸發(fā)sectionList的scrollToLocation方法,最新版本已經(jīng)修復(fù)了點(diǎn)擊索引不準(zhǔn)確的問題。
遇到點(diǎn)擊索引不準(zhǔn)確問題,可以試著設(shè)置sectionHeight和sectionHeaderHeight
最后中間踩到的坑,做一些經(jīng)驗(yàn)總結(jié):
可能會(huì)有大量數(shù)據(jù)的時(shí)候,會(huì)有卡頓情況,所以推薦子組件繼承PureComponent,本開源組件默認(rèn)已經(jīng)做了這個(gè)功能,其次,會(huì)有遇到下滑加載緩慢,或者直接點(diǎn)擊后面的索引到最后的位置會(huì)出現(xiàn)白屏等待很久的問題,這種處理方法可以加個(gè)initialNumToRender屬性,值為數(shù)據(jù)源的個(gè)數(shù),也就是全部渲染出來initialNumToRender={this.state.dataArray.length}