提示:React-native类商城分类联动
效果展示
提示:以下是本篇文章正文内容,下面案例可供参考
具体案例地址
组件主要代码
renderRootCate() {//左边分类列表
const { rootCateData, bgColor } = this.state
const { rootEndReached } = this.props
return (
<View style={{ backgroundColor: bgColor }}>
<FlatList
ref={flatList => this.flatList = flatList}
data={rootCateData}
ListHeaderComponent={() => (<View />)}
ListFooterComponent={() => (<View />)}
// ItemSeparatorComponent={() => <View style={{ height: 1, backgroundColor: '#F5F5F5' }} />}
renderItem={(e) => this.renderRootItem(e.item, e.index)}
onEndReachedThreshold={20}
showsVerticalScrollIndicator={false}
onEndReached={() => rootEndReached()}
/>
</View>
)
}
renderRootItem = (item, index) => {//左边菜单节点
const { rootCateData, selectedRootCate, mainColor, bgColor } = this.state
const { needScrollTo } = this.props
return (
<View style={{ position: 'relative' }}>
{
selectedRootCate !== index && <View style={{ width: ROOT_WIDTH, height: ROOT_HEIGHT, backgroundColor: mainColor, position: 'absolute', zIndex: -1 }} />
}
<TouchableOpacity
key={index}
style={[{ alignItems: 'center', justifyContent: 'center', width: ROOT_WIDTH, height: ROOT_HEIGHT },
index === selectedRootCate + 1 ? { borderTopRightRadius: ROOT_RADIUS } : {},
index === selectedRootCate - 1 ? { borderBottomRightRadius: ROOT_RADIUS } : {},
index === selectedRootCate ?
{ backgroundColor: mainColor, borderTopLeftRadius: ROOT_RADIUS, borderBottomLeftRadius: ROOT_RADIUS }
: { backgroundColor: bgColor }
]}
onPress={() => {
setTimeout(() => {
(rootCateData.length - index) * ROOT_HEIGHT > screenH - HEADER_HEIGHT - ROOT_HEIGHT ? this.flatList.scrollToOffset({ animated: true, offset: index * ROOT_HEIGHT }) : null
this.sectionList.scrollToLocation({ itemIndex: 0, sectionIndex: needScrollTo ? index : 0, animated: true, viewOffset: 0 })
}, 100)
this.setState({ selectedRootCate: index, rootSelItem: item, isScroll: false })
}}
>
<Text
style={{ fontSize: 14, color: '#808080' }}
numberOfLines={1}
ellipsizeMode='tail'
>
{item.firstCateName}
</Text>
</TouchableOpacity>
</View>
)
}
renderItemCate() {//右边菜单
const { cateData, selectedRootCate, rootSelItem } = this.state
const { renderSectionHeader, renderItem, needScrollTo, onCateEndReached, onCateRefresh } = this.props
return (
<View style={{ flex: 1 }}>
<SectionList
ref={(ref) => this.sectionList = ref}
renderSectionHeader={(item) => renderSectionHeader ? renderSectionHeader(item) : this.sectionComp(item)}
renderItem={(data) => renderItem ? renderItem(data) : this.renderItem(data)}
sections={cateData}
// ListEmptyComponent={<DefaultPage style={{ height: 200 }} />}
ItemSeparatorComponent={() => <View />}
ListHeaderComponent={() => <View />}
showsVerticalScrollIndicator={false}
keyExtractor={(item, index) => 'key' + index + item}
onEndReached={() => onCateEndReached && onCateEndReached()}
onViewableItemsChanged={(e) => { needScrollTo && this.scrollRootSel(e) }}
onScrollBeginDrag={(e) => { this.setState({ isScroll: true }) }}
onScrollAnimationEnd={() => { this.setState({ isScroll: false }) }}
/>
</View>
)
}
renderItem(item) {//右边菜单二级分类
const { cateData, } = this.state
const { renderCell, needScrollTo } = this.props
let sectionIndex = item.section.rootIndex
let data = item?.section?.data
return item.index === 0 ?
<>
<View key={item.index}
style={{
paddingLeft: 24,
flexDirection: 'row',
alignItems: 'center',
flexWrap: 'wrap'
}}
>
{
data.map((cell, index) => renderCell ? renderCell(cell, sectionIndex, index) : this.renderCell(cell, sectionIndex, index))
}
</View>
{
needScrollTo && <>
{
item?.section?.rootIndex !== cateData?.length - 1 ?
<View style={{ height: 1, backgroundColor: '#efefef' }} />
: <View style={{ height: screenH - (Math.ceil(item?.section?.data?.length / SECTION_COLUMS) * CELL_HIGHT + SECTION_HEADER) - HEADER_HEIGHT }} />//最后一个菜单的空白占位
}
</>
}
</>
: null
}
scrollRootSel = (e) => {//右边菜单滚动时左边菜单跳到相应选项
const { cateData, isScroll, rootCateData } = this.state
let currentIndex = e?.viewableItems[0]?.section?.rootIndex
if (isScroll) {
this.setState((preveState, preveProps) => ({
selectedRootCate: currentIndex,
rootSelItem: cateData[currentIndex]
}), () => {
(rootCateData.length - currentIndex) * ROOT_HEIGHT > screenH - HEADER_HEIGHT ? this.flatList.scrollToOffset({ animated: true, offset: currentIndex * ROOT_HEIGHT }) : null
})
}
}
使用
render() {//左右联动菜单
return (
<View style={[{ flex: 1, paddingTop: 10 }]}>
<CategoryList
rootCateData={data.rootCateData}
cateData={data.cateData}
rootEndReached={() => { }}
itemOnPress={(item, sectionIndex, index) => alert(`点击了第${sectionIndex}组中的第${index}个商品`)}
needScrollTo
// onCateEndReached={() => {}}
/>
</View>
)
}
render() {//自定义非联动菜单
const { selectedRootCate } = this.state
return (
<View style={{ flex: 1, paddingTop: 10, backgroundColor: '#fff' }}>
<CategoryList
bgColor='#fff'
mainColor='#f5f5f5'
rootCateData={data.rootCateData}
rootEndReached={() => { }}
cateData={[data.cateData[selectedRootCate]]}
renderCell={(item, sectionIndex, index) => this.renderCell(item, sectionIndex, index)}
renderSectionHeader={(item) => this.sectionComp(item)}
selRootCateChange={(index, item) => { this.setState({ selectedRootCate: index }) }}
/>
</View >
)
}
数据格式
提示:一般右边菜单都是根据左边选中的再进行请求,因此左右菜单的数据是分开传的
{
"rootCateData":[
{
"firstCateName":"香蕉",
"firstCateId":0
}
,{
"firstCateName":"苹果",
"firstCateId":1
}
,{
"firstCateName":"车厘子",
"firstCateId":2
}
],
"cateData":[
{
"rootIndex":0,
"secondCateName":"香蕉",
"data":[
{
"id":100010,
"img":"",
"name":"本地蕉",
"sectionId":0
}
,{
"id":100011,
"img":"",
"name":"国产蕉",
"sectionId":0
}
]
}
,{
"rootIndex":1,
"secondCateName":"苹果",
"data":[
{
"id":100020,
"img":"",
"name":"红苹果",
"sectionId":1
}
,{
"id":100021,
"img":"",
"name":"青苹果",
"sectionId":1
}
]
}
,{
"rootIndex":2,
"secondCateName":"车厘子",
"data":[
{
"id":100030,
"img":"",
"name":"车厘子A",
"sectionId":2
}
,{
"id":100031,
"img":"",
"name":"车厘子JJ",
"sectionId":2
}
]
}
]
}