手写tabs 组件
是说,会遇到一个问题,默认值play back很差,而且因为有动画,切换的时候给人体验不好
但是我仍然觉得我写的很好,所以记录这里
'use client'; import { cn } from '@/lib'; import React, { memo, ReactNode, useEffect, useState } from 'react'; import { FC } from 'react'; interface contentType { currentTabIndex: number; setCurrentTabIndex: (index: number) => void; tabsLength: number; } interface MethodClassProps { defaultTab: number; children: React.ReactNode; tabsLength: number; } const TabsContext = React.createContext<contentType | null>(null); const useTabsContext = () => { const context = React.useContext(TabsContext); if (!context) { throw new Error('useTabsContext must be used within a TabsProvider'); } return context; }; // 必须保证TabsContent和triggerList的长度一致 export const Tabs: FC<MethodClassProps> = ({ ...props }) => { const { children, defaultTab, tabsLength } = props; const [currentTabIndex, setCurrentTabIndex] = useState<number>(defaultTab); return ( <> <TabsContext.Provider value={{ currentTabIndex: currentTabIndex, setCurrentTabIndex: setCurrentTabIndex, tabsLength: tabsLength, }} > {children} </TabsContext.Provider> </> ); }; export const TabsTrigger = ({ extraContent, children, theme = 'Purple', onCurrentTabChange, }: { extraContent?: ReactNode; children: ReactNode[]; theme?: 'Orange' | 'Purple'; onCurrentTabChange?: (tab: number) => void; }) => { const { currentTabIndex, setCurrentTabIndex } = useTabsContext(); const validChildren = React.Children.toArray(children).filter( (child) => React.isValidElement(child) && child !== null, ); return ( <section className=" relative lls-flex-row bg-white border-b shadow-header text-xs px-5 w-full"> {validChildren.map((trigger, index) => ( <div key={index + 'triggerlist'} className={cn( 'lls-flex-row gap-3 py-2 pl-3 pr-7 border-b-3 justify-center items-center transition-all duration-500', { 'border-b-white': currentTabIndex !== index + 1, 'border-b-Purple-1 ': currentTabIndex === index + 1 && theme === 'Purple', 'border-b-Orange-1': currentTabIndex === index + 1 && theme === 'Orange', }, )} onClick={() => { setCurrentTabIndex(index + 1); onCurrentTabChange?.(index + 1); }} > {trigger} </div> ))} {extraContent} </section> ); }; export const TabsContent = memo(({ children }: { children: ReactNode[] }) => { const { currentTabIndex, tabsLength } = useTabsContext(); const [translateX, setTranslateX] = useState<string>(''); useEffect(() => { setTranslateX( currentTabIndex > 1 ? `translateX(-${((currentTabIndex - 1) / tabsLength) * 100}%)` : '', ); }, [currentTabIndex, tabsLength]); const validChildren = React.Children.toArray(children).filter( (child) => React.isValidElement(child) && child !== null, ); return ( <div className="flex-1 overflow-hidden w-full"> <div style={{ width: `${tabsLength * 100}%`, transform: translateX, }} className={cn(`lls-flex-row h-full transition-all duration-500`)} > {validChildren.map((content, index) => ( <section key={'content-list' + index} className={cn('w-full basis-1/1 px-5 py-3 h-full overflow-y-auto')} > {content} </section> ))} </div> </div> ); }); TabsContent.displayName = 'TabsContent';

浙公网安备 33010602011771号