需求:
从API上请求下来的用户数据,做成一个类似通讯录的模式
请求下来的数据格式:
//获取数据的方法
CustomerList().then(res => {
let data = res.data
var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#".split("");
var segs = []; // 存放数据
var res = {};
let curr;
var re = /[^\u4e00-\u9fa5]/;//中文正则
letters.filter((items, i) => {
curr = {
title: '', //字母
data: [], //数据
};
data.map((v, index) => {
//将首字母相同的放到一起,如果涉及到用户名是中文的,可以先解析成英文,可以自行查一下
if (v.name[0].toUpperCase() == items) {
curr.data.push(v);
}
//将首字母是中文的以及数字的放到#下
if (!re.test(v.name[0]) || !isNaN(v.name[0])) {
if (items === "#") {
curr.data.push(v);
}
}
//将数据集中到一块
if (curr.data.length) {
curr.title = letters[i]
segs.push(curr);
}
})
res.segs = Array.from(new Set(segs)) //去重
return res
})
//console.log(res.segs)
//传入数据计算高度,下文有方法
this._setItemLayout(res.segs);
})
整理后数据格式
现在数据格式很符合需求了,那么就开始套数据
我们使用SectionList来做这件事
<SectionList
//这里是做点击右侧字母定位用的
ref={(ref) => { this.sectionList = ref }}
showsVerticalScrollIndicator={false}
//getItemLayout很关键,下面说
getItemLayout={this._getItemLayout.bind(this)}
keyExtractor={this._keyExtractor}
//这里的data就是上面返回的data
sections={data}
renderItem={({ item }) => {
//以下是页面的展示代码
return (
<View style={styles.sectionItem}>
<TouchableOpacity onPress={() => {
//这里做页面跳转
}}>
<View style={{ flexDirection: "row", width: width - 90 }}>
<View style={{ width: 46, height: 46, borderRadius: 25, backgroundColor: "#C7D7E4", justifyContent: "center", alignItems: "center" }}>
<Text style={{ fontSize: 16, color: "#fff", fontWeight: "700" }}>{item.name[0].toUpperCase()}</Text>
</View>
<View style={{ marginLeft: 15 }}>
<Text style={{ fontSize: 14, color: "#393939", fontWeight: "700", marginBottom: 5 }}>{item.name}</Text>
<Text style={{ fontSize: 12, color: "#828282", marginBottom: 5 }}>{item.phone}</Text>
<Text style={{ fontSize: 12, color: "#828282", marginBottom: 5 }}>{item.email}</Text>
</View>
</View>
</TouchableOpacity>
</View>
)
}}
//这里是每组数据的title,即A,B,C这些
renderSectionHeader={({ section }) => <View style={styles.sectionHeader}><Text style={styles.sectionHeaderTxt}>{section.title}</Text></View>}
/>
这里是右侧字母的列表
<View style={styles.sectionTitleList}>
{
list.map((v, k) => {
return (
<Text style={styles.titleText} key={k} onPress={() => { this._onSectionselect(k) }}>{v.title}</Text>
)
})
}
</View>
在获取到API数据并且转换之后要对每一条数据的高度进行计算,为点击字母页面滚动到对应位置滚动做准备
//计算每个index的length和offset
_setItemLayout(list) {
let [itemHeight, headerHeight] = [ITEM_HEIGHT, HEADER_HEIGHT];
let layoutList = [];
let layoutIndex = 0;
let layoutOffset = 0;
list.forEach(section => {
layoutList.push({
index: layoutIndex,
length: headerHeight,
offset: layoutOffset,
});
layoutIndex += 1;
layoutOffset += headerHeight;
section.data.forEach(() => {
layoutList.push({
index: layoutIndex,
length: itemHeight,
offset: layoutOffset,
});
layoutIndex += 1;
layoutOffset += itemHeight;
});
layoutList.push({
index: layoutIndex,
length: 0,
offset: layoutOffset,
});
layoutIndex += 1;
});
this.layoutList = layoutList;
}
将计算出来的数据传给getItemLayout使用(上面把数据全都放在了this.layoutLis中,下面的data没用了,不用管)
_getItemLayout(data, index) {
let layout = this.layoutList.filter(n => n.index == index)[0];
return layout;
}
点击右侧字母定位
_onSectionselect = (k) => {
this.sectionList.scrollToLocation(
{
sectionIndex: k,
itemIndex: 0,
viewOffset: HEADER_HEIGHT,
}
);
}
效果图: