/* eslint-disable react-hooks/exhaustive-deps */ 'use client'; import React, { useEffect, useRef, useState } from 'react'; import MultiLevelSelector from './MultiLevelSelector'; import WeekdaySelector from './WeekdaySelector'; interface SelectorOption { label: string; value: string; } interface DoubanSelectorProps { type: 'movie' | 'tv' | 'show' | 'anime'; primarySelection?: string; secondarySelection?: string; onPrimaryChange: (value: string) => void; onSecondaryChange: (value: string) => void; onMultiLevelChange?: (values: Record) => void; onWeekdayChange: (weekday: string) => void; } const DoubanSelector: React.FC = ({ type, primarySelection, secondarySelection, onPrimaryChange, onSecondaryChange, onMultiLevelChange, onWeekdayChange, }) => { // 为不同的选择器创建独立的refs和状态 const primaryContainerRef = useRef(null); const primaryButtonRefs = useRef<(HTMLButtonElement | null)[]>([]); const [primaryIndicatorStyle, setPrimaryIndicatorStyle] = useState<{ left: number; width: number; }>({ left: 0, width: 0 }); const secondaryContainerRef = useRef(null); const secondaryButtonRefs = useRef<(HTMLButtonElement | null)[]>([]); const [secondaryIndicatorStyle, setSecondaryIndicatorStyle] = useState<{ left: number; width: number; }>({ left: 0, width: 0 }); // 电影的一级选择器选项 const moviePrimaryOptions: SelectorOption[] = [ { label: '全部', value: '全部' }, { label: '热门电影', value: '热门' }, { label: '最新电影', value: '最新' }, { label: '豆瓣高分', value: '豆瓣高分' }, { label: '冷门佳片', value: '冷门佳片' }, ]; // 电影的二级选择器选项 const movieSecondaryOptions: SelectorOption[] = [ { label: '全部', value: '全部' }, { label: '华语', value: '华语' }, { label: '欧美', value: '欧美' }, { label: '韩国', value: '韩国' }, { label: '日本', value: '日本' }, ]; // 电视剧一级选择器选项 const tvPrimaryOptions: SelectorOption[] = [ { label: '全部', value: '全部' }, { label: '最近热门', value: '最近热门' }, ]; // 电视剧二级选择器选项 const tvSecondaryOptions: SelectorOption[] = [ { label: '全部', value: 'tv' }, { label: '国产', value: 'tv_domestic' }, { label: '欧美', value: 'tv_american' }, { label: '日本', value: 'tv_japanese' }, { label: '韩国', value: 'tv_korean' }, { label: '动漫', value: 'tv_animation' }, { label: '纪录片', value: 'tv_documentary' }, ]; // 综艺一级选择器选项 const showPrimaryOptions: SelectorOption[] = [ { label: '全部', value: '全部' }, { label: '最近热门', value: '最近热门' }, ]; // 综艺二级选择器选项 const showSecondaryOptions: SelectorOption[] = [ { label: '全部', value: 'show' }, { label: '国内', value: 'show_domestic' }, { label: '国外', value: 'show_foreign' }, ]; // 动漫一级选择器选项 const animePrimaryOptions: SelectorOption[] = [ { label: '每日放送', value: '每日放送' }, { label: '番剧', value: '番剧' }, { label: '剧场版', value: '剧场版' }, ]; // 处理多级选择器变化 const handleMultiLevelChange = (values: Record) => { onMultiLevelChange?.(values); }; // 更新指示器位置的通用函数 const updateIndicatorPosition = ( activeIndex: number, containerRef: React.RefObject, buttonRefs: React.MutableRefObject<(HTMLButtonElement | null)[]>, setIndicatorStyle: React.Dispatch< React.SetStateAction<{ left: number; width: number }> > ) => { if ( activeIndex >= 0 && buttonRefs.current[activeIndex] && containerRef.current ) { const timeoutId = setTimeout(() => { const button = buttonRefs.current[activeIndex]; const container = containerRef.current; if (button && container) { const buttonRect = button.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); if (buttonRect.width > 0) { setIndicatorStyle({ left: buttonRect.left - containerRect.left, width: buttonRect.width, }); } } }, 0); return () => clearTimeout(timeoutId); } }; // 组件挂载时立即计算初始位置 useEffect(() => { // 主选择器初始位置 if (type === 'movie') { const activeIndex = moviePrimaryOptions.findIndex( (opt) => opt.value === (primarySelection || moviePrimaryOptions[0].value) ); updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); } else if (type === 'tv') { const activeIndex = tvPrimaryOptions.findIndex( (opt) => opt.value === (primarySelection || tvPrimaryOptions[1].value) ); updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); } else if (type === 'anime') { const activeIndex = animePrimaryOptions.findIndex( (opt) => opt.value === (primarySelection || animePrimaryOptions[0].value) ); updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); } else if (type === 'show') { const activeIndex = showPrimaryOptions.findIndex( (opt) => opt.value === (primarySelection || showPrimaryOptions[1].value) ); updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); } // 副选择器初始位置 let secondaryActiveIndex = -1; if (type === 'movie') { secondaryActiveIndex = movieSecondaryOptions.findIndex( (opt) => opt.value === (secondarySelection || movieSecondaryOptions[0].value) ); } else if (type === 'tv') { secondaryActiveIndex = tvSecondaryOptions.findIndex( (opt) => opt.value === (secondarySelection || tvSecondaryOptions[0].value) ); } else if (type === 'show') { secondaryActiveIndex = showSecondaryOptions.findIndex( (opt) => opt.value === (secondarySelection || showSecondaryOptions[0].value) ); } if (secondaryActiveIndex >= 0) { updateIndicatorPosition( secondaryActiveIndex, secondaryContainerRef, secondaryButtonRefs, setSecondaryIndicatorStyle ); } }, [type]); // 只在type变化时重新计算 // 监听主选择器变化 useEffect(() => { if (type === 'movie') { const activeIndex = moviePrimaryOptions.findIndex( (opt) => opt.value === primarySelection ); const cleanup = updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); return cleanup; } else if (type === 'tv') { const activeIndex = tvPrimaryOptions.findIndex( (opt) => opt.value === primarySelection ); const cleanup = updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); return cleanup; } else if (type === 'anime') { const activeIndex = animePrimaryOptions.findIndex( (opt) => opt.value === primarySelection ); const cleanup = updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); return cleanup; } else if (type === 'show') { const activeIndex = showPrimaryOptions.findIndex( (opt) => opt.value === primarySelection ); const cleanup = updateIndicatorPosition( activeIndex, primaryContainerRef, primaryButtonRefs, setPrimaryIndicatorStyle ); return cleanup; } }, [primarySelection]); // 监听副选择器变化 useEffect(() => { let activeIndex = -1; let options: SelectorOption[] = []; if (type === 'movie') { activeIndex = movieSecondaryOptions.findIndex( (opt) => opt.value === secondarySelection ); options = movieSecondaryOptions; } else if (type === 'tv') { activeIndex = tvSecondaryOptions.findIndex( (opt) => opt.value === secondarySelection ); options = tvSecondaryOptions; } else if (type === 'show') { activeIndex = showSecondaryOptions.findIndex( (opt) => opt.value === secondarySelection ); options = showSecondaryOptions; } if (options.length > 0) { const cleanup = updateIndicatorPosition( activeIndex, secondaryContainerRef, secondaryButtonRefs, setSecondaryIndicatorStyle ); return cleanup; } }, [secondarySelection]); // 渲染胶囊式选择器 const renderCapsuleSelector = ( options: SelectorOption[], activeValue: string | undefined, onChange: (value: string) => void, isPrimary = false ) => { const containerRef = isPrimary ? primaryContainerRef : secondaryContainerRef; const buttonRefs = isPrimary ? primaryButtonRefs : secondaryButtonRefs; const indicatorStyle = isPrimary ? primaryIndicatorStyle : secondaryIndicatorStyle; return (
{/* 滑动的白色背景指示器 */} {indicatorStyle.width > 0 && (
)} {options.map((option, index) => { const isActive = activeValue === option.value; return ( ); })}
); }; return (
{/* 电影类型 - 显示两级选择器 */} {type === 'movie' && (
{/* 一级选择器 */}
分类
{renderCapsuleSelector( moviePrimaryOptions, primarySelection || moviePrimaryOptions[0].value, onPrimaryChange, true )}
{/* 二级选择器 - 只在非"全部"时显示 */} {primarySelection !== '全部' ? (
地区
{renderCapsuleSelector( movieSecondaryOptions, secondarySelection || movieSecondaryOptions[0].value, onSecondaryChange, false )}
) : ( /* 多级选择器 - 只在选中"全部"时显示 */
筛选
)}
)} {/* 电视剧类型 - 显示两级选择器 */} {type === 'tv' && (
{/* 一级选择器 */}
分类
{renderCapsuleSelector( tvPrimaryOptions, primarySelection || tvPrimaryOptions[1].value, onPrimaryChange, true )}
{/* 二级选择器 - 只在选中"最近热门"时显示,选中"全部"时显示多级选择器 */} {(primarySelection || tvPrimaryOptions[1].value) === '最近热门' ? (
类型
{renderCapsuleSelector( tvSecondaryOptions, secondarySelection || tvSecondaryOptions[0].value, onSecondaryChange, false )}
) : (primarySelection || tvPrimaryOptions[1].value) === '全部' ? ( /* 多级选择器 - 只在选中"全部"时显示 */
筛选
) : null}
)} {/* 动漫类型 - 显示一级选择器和多级选择器 */} {type === 'anime' && (
分类
{renderCapsuleSelector( animePrimaryOptions, primarySelection || animePrimaryOptions[0].value, onPrimaryChange, true )}
{/* 筛选部分 - 根据一级选择器显示不同内容 */} {(primarySelection || animePrimaryOptions[0].value) === '每日放送' ? ( // 每日放送分类下显示星期选择器
星期
) : ( // 其他分类下显示原有的筛选功能
筛选
{(primarySelection || animePrimaryOptions[0].value) === '番剧' ? ( ) : ( )}
)}
)} {/* 综艺类型 - 显示两级选择器 */} {type === 'show' && (
{/* 一级选择器 */}
分类
{renderCapsuleSelector( showPrimaryOptions, primarySelection || showPrimaryOptions[1].value, onPrimaryChange, true )}
{/* 二级选择器 - 只在选中"最近热门"时显示,选中"全部"时显示多级选择器 */} {(primarySelection || showPrimaryOptions[1].value) === '最近热门' ? (
类型
{renderCapsuleSelector( showSecondaryOptions, secondarySelection || showSecondaryOptions[0].value, onSecondaryChange, false )}
) : (primarySelection || showPrimaryOptions[1].value) === '全部' ? ( /* 多级选择器 - 只在选中"全部"时显示 */
筛选
) : null}
)}
); }; export default DoubanSelector;