修复弹幕选集分组无法鼠标滑轮滚动
This commit is contained in:
@@ -63,3 +63,6 @@ public/workbox-*.js.map
|
|||||||
*.db
|
*.db
|
||||||
*.db-shm
|
*.db-shm
|
||||||
*.db-wal
|
*.db-wal
|
||||||
|
|
||||||
|
# local scripts
|
||||||
|
scripts/tvbox/
|
||||||
|
|||||||
@@ -35,9 +35,12 @@ export default function DanmakuPanel({
|
|||||||
const [searchError, setSearchError] = useState<string | null>(null);
|
const [searchError, setSearchError] = useState<string | null>(null);
|
||||||
const initializedRef = useRef(false); // 标记是否已初始化过
|
const initializedRef = useRef(false); // 标记是否已初始化过
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const episodeGroupContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const episodeGroupButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);
|
||||||
const [episodeGroupIndex, setEpisodeGroupIndex] = useState(0);
|
const [episodeGroupIndex, setEpisodeGroupIndex] = useState(0);
|
||||||
const [episodeDescending, setEpisodeDescending] = useState(false);
|
const [episodeDescending, setEpisodeDescending] = useState(false);
|
||||||
const [episodeViewMode, setEpisodeViewMode] = useState<'list' | 'grid'>('list');
|
const [episodeViewMode, setEpisodeViewMode] = useState<'list' | 'grid'>('list');
|
||||||
|
const [isEpisodeGroupHovered, setIsEpisodeGroupHovered] = useState(false);
|
||||||
const episodesPerGroup = 50;
|
const episodesPerGroup = 50;
|
||||||
|
|
||||||
// 搜索弹幕
|
// 搜索弹幕
|
||||||
@@ -230,6 +233,62 @@ export default function DanmakuPanel({
|
|||||||
return String(episodeNumber);
|
return String(episodeNumber);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const preventPageScroll = useCallback((e: WheelEvent) => {
|
||||||
|
if (isEpisodeGroupHovered) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}, [isEpisodeGroupHovered]);
|
||||||
|
|
||||||
|
const handleEpisodeGroupWheel = useCallback((e: WheelEvent) => {
|
||||||
|
if (!isEpisodeGroupHovered || !episodeGroupContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = episodeGroupContainerRef.current;
|
||||||
|
if (container.scrollWidth <= container.clientWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
container.scrollBy({
|
||||||
|
left: e.deltaY * 2,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}, [isEpisodeGroupHovered]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEpisodeGroupHovered) {
|
||||||
|
document.addEventListener('wheel', preventPageScroll, { passive: false });
|
||||||
|
document.addEventListener('wheel', handleEpisodeGroupWheel, { passive: false });
|
||||||
|
} else {
|
||||||
|
document.removeEventListener('wheel', preventPageScroll);
|
||||||
|
document.removeEventListener('wheel', handleEpisodeGroupWheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('wheel', preventPageScroll);
|
||||||
|
document.removeEventListener('wheel', handleEpisodeGroupWheel);
|
||||||
|
};
|
||||||
|
}, [handleEpisodeGroupWheel, isEpisodeGroupHovered, preventPageScroll]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const btn = episodeGroupButtonRefs.current[displayEpisodeGroupIndex];
|
||||||
|
const container = episodeGroupContainerRef.current;
|
||||||
|
if (!btn || !container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const btnRect = btn.getBoundingClientRect();
|
||||||
|
const btnLeft = btnRect.left - containerRect.left + container.scrollLeft;
|
||||||
|
const targetScrollLeft = btnLeft - (containerRect.width - btnRect.width) / 2;
|
||||||
|
|
||||||
|
container.scrollTo({
|
||||||
|
left: targetScrollLeft,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}, [displayEpisodeGroupIndex]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex h-full flex-col overflow-hidden'>
|
<div className='flex h-full flex-col overflow-hidden'>
|
||||||
{/* 搜索区域 - 固定在顶部 */}
|
{/* 搜索区域 - 固定在顶部 */}
|
||||||
@@ -348,12 +407,20 @@ export default function DanmakuPanel({
|
|||||||
{!isLoadingEpisodes && episodes.length > 0 && (
|
{!isLoadingEpisodes && episodes.length > 0 && (
|
||||||
<div className='pb-4'>
|
<div className='pb-4'>
|
||||||
<div className='mb-4 border-b border-gray-300 dark:border-gray-700'>
|
<div className='mb-4 border-b border-gray-300 dark:border-gray-700'>
|
||||||
<div className='flex items-center gap-4 overflow-x-auto pb-3'>
|
<div
|
||||||
|
ref={episodeGroupContainerRef}
|
||||||
|
className='flex items-center gap-4 overflow-x-auto pb-3'
|
||||||
|
onMouseEnter={() => setIsEpisodeGroupHovered(true)}
|
||||||
|
onMouseLeave={() => setIsEpisodeGroupHovered(false)}
|
||||||
|
>
|
||||||
{episodeGroups.map((label, idx) => {
|
{episodeGroups.map((label, idx) => {
|
||||||
const isActive = idx === displayEpisodeGroupIndex;
|
const isActive = idx === displayEpisodeGroupIndex;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={label}
|
key={label}
|
||||||
|
ref={(el) => {
|
||||||
|
episodeGroupButtonRefs.current[idx] = el;
|
||||||
|
}}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setEpisodeGroupIndex(
|
setEpisodeGroupIndex(
|
||||||
episodeDescending ? episodeGroupCount - 1 - idx : idx
|
episodeDescending ? episodeGroupCount - 1 - idx : idx
|
||||||
|
|||||||
Reference in New Issue
Block a user