Files
workspace/code/allapp/allapp-rn/src/components/common/ao/Tab.tsx
T
2026-02-02 22:42:58 +08:00

115 lines
2.7 KiB
TypeScript

import React, { useMemo, useRef, useState } from 'react'
import { Pressable, ScrollView, Text, View } from 'react-native'
import PagerView from 'react-native-pager-view'
interface TabItem {
label: string
key: string | number
content?: React.ReactNode
}
interface TabProps {
data?: TabItem[]
defaultKey?: TabItem['key']
onChange?: (key: TabItem['key']) => void
}
export default function Tab({
data,
defaultKey,
onChange,
}: TabProps) {
if (!data || data.length === 0)
return null
// 默认选中 key(没传就用第一个)
const initialKey = defaultKey ?? data[0].key
const [selectedKey, setSelectedKey] = useState(initialKey)
const pagerRef = useRef<PagerView>(null)
// 是否有 content
const hasContent = useMemo(
() => data.some(item => item.content),
[data],
)
// key -> index
const getIndexByKey = (key: TabItem['key']) =>
data.findIndex(item => item.key === key)
// index -> key
const getKeyByIndex = (index: number) =>
data[index]?.key
const handlePress = (key: TabItem['key']) => {
setSelectedKey(key)
onChange?.(key)
if (hasContent) {
const index = getIndexByKey(key)
if (index !== -1)
pagerRef.current?.setPage(index)
}
}
const onPageSelected = (e: any) => {
const index = e.nativeEvent.position
const key = getKeyByIndex(index)
if (key !== undefined) {
setSelectedKey(key)
onChange?.(key)
}
}
return (
<View className="flex-1">
{/* tab bar */}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
flexDirection: 'row',
gap: 8,
}}
>
{data.map((item) => {
const isActive = item.key === selectedKey
return (
<Pressable
key={item.key}
onPress={() => handlePress(item.key)}
className={
isActive
? 'items-center justify-center rounded-md px-4 py-2 bg-gray-800'
: 'items-center justify-center rounded-md px-4 py-2 bg-gray-200'
}
>
<Text className={isActive ? 'text-white' : 'text-gray-700'}>
{item.label}
</Text>
</Pressable>
)
})}
</ScrollView>
{hasContent && (
<PagerView
ref={pagerRef}
style={{ flex: 1, marginTop: 16 }}
initialPage={getIndexByKey(initialKey)}
onPageSelected={onPageSelected}
>
{data.map(item => (
<View key={item.key} style={{ flex: 1 }}>
{item.content}
</View>
))}
</PagerView>
)}
</View>
)
}