首页轮播图标题自适应大小
This commit is contained in:
@@ -9,7 +9,13 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type TMDBItem,
|
type TMDBItem,
|
||||||
@@ -66,14 +72,19 @@ export default function BannerCarousel({
|
|||||||
const [isMuted, setIsMuted] = useState(true); // 视频是否静音(默认静音)
|
const [isMuted, setIsMuted] = useState(true); // 视频是否静音(默认静音)
|
||||||
const [bannerHeightScale, setBannerHeightScale] =
|
const [bannerHeightScale, setBannerHeightScale] =
|
||||||
useState<HomeBannerHeightScale>('1'); // 轮播图高度倍率
|
useState<HomeBannerHeightScale>('1'); // 轮播图高度倍率
|
||||||
|
const [isMobileView, setIsMobileView] = useState(false);
|
||||||
|
const [mobileTitleFontSize, setMobileTitleFontSize] = useState(30);
|
||||||
const videoRef = useRef<HTMLVideoElement>(null); // 视频元素引用
|
const videoRef = useRef<HTMLVideoElement>(null); // 视频元素引用
|
||||||
const videoRefs = useRef<Map<number, HTMLVideoElement>>(new Map()); // 所有视频元素的引用
|
const videoRefs = useRef<Map<number, HTMLVideoElement>>(new Map()); // 所有视频元素的引用
|
||||||
|
const titleRef = useRef<HTMLHeadingElement>(null);
|
||||||
|
const titleTextRef = useRef<HTMLSpanElement>(null);
|
||||||
const touchStartX = useRef(0);
|
const touchStartX = useRef(0);
|
||||||
const touchEndX = useRef(0);
|
const touchEndX = useRef(0);
|
||||||
const isManualChange = useRef(false); // 标记是否为手动切换
|
const isManualChange = useRef(false); // 标记是否为手动切换
|
||||||
|
|
||||||
// LocalStorage 缓存配置
|
// LocalStorage 缓存配置
|
||||||
const LOCALSTORAGE_DURATION = 24 * 60 * 60 * 1000; // 1天
|
const LOCALSTORAGE_DURATION = 24 * 60 * 60 * 1000; // 1天
|
||||||
|
const currentTitle = items[currentIndex]?.title || '';
|
||||||
|
|
||||||
// 根据数据源获取缓存key
|
// 根据数据源获取缓存key
|
||||||
const getLocalStorageKey = (source: string) => {
|
const getLocalStorageKey = (source: string) => {
|
||||||
@@ -141,6 +152,49 @@ export default function BannerCarousel({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 检测移动端视口,用于 1x 高度下的标题自适应
|
||||||
|
useEffect(() => {
|
||||||
|
const updateIsMobileView = () => {
|
||||||
|
setIsMobileView(window.innerWidth < 768);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateIsMobileView();
|
||||||
|
window.addEventListener('resize', updateIsMobileView);
|
||||||
|
return () => window.removeEventListener('resize', updateIsMobileView);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 手机界面且轮播图高度为 1x 时,仅在标题超过一行时自动缩小字号,不改变布局位置
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const titleElement = titleRef.current;
|
||||||
|
const titleTextElement = titleTextRef.current;
|
||||||
|
if (!titleElement || !titleTextElement) return;
|
||||||
|
|
||||||
|
if (bannerHeightScale !== '1' || !isMobileView) {
|
||||||
|
titleElement.style.fontSize = '';
|
||||||
|
setMobileTitleFontSize(30);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxFontSize = 30;
|
||||||
|
const minFontSize = 12;
|
||||||
|
let nextFontSize = maxFontSize;
|
||||||
|
|
||||||
|
titleElement.style.fontSize = `${nextFontSize}px`;
|
||||||
|
|
||||||
|
while (
|
||||||
|
nextFontSize > minFontSize &&
|
||||||
|
titleTextElement.getClientRects().length > 1
|
||||||
|
) {
|
||||||
|
nextFontSize -= 1;
|
||||||
|
titleElement.style.fontSize = `${nextFontSize}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
titleElement.style.fontSize = `${nextFontSize}px`;
|
||||||
|
setMobileTitleFontSize(nextFontSize);
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}, [bannerHeightScale, currentTitle, isMobileView]);
|
||||||
|
|
||||||
// 延迟加载:等待页面加载完毕后再开始加载轮播图数据
|
// 延迟加载:等待页面加载完毕后再开始加载轮播图数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!delayLoad) return;
|
if (!delayLoad) return;
|
||||||
@@ -529,8 +583,16 @@ export default function BannerCarousel({
|
|||||||
{/* 内容信息 */}
|
{/* 内容信息 */}
|
||||||
<div className='absolute inset-0 flex items-end p-8 md:p-12 pointer-events-none'>
|
<div className='absolute inset-0 flex items-end p-8 md:p-12 pointer-events-none'>
|
||||||
<div className='max-w-2xl space-y-4'>
|
<div className='max-w-2xl space-y-4'>
|
||||||
<h2 className='text-3xl md:text-5xl font-bold text-white drop-shadow-lg'>
|
<h2
|
||||||
{currentItem.title}
|
ref={titleRef}
|
||||||
|
className='text-3xl md:text-5xl font-bold text-white drop-shadow-lg'
|
||||||
|
style={
|
||||||
|
isMobileView && bannerHeightScale === '1'
|
||||||
|
? { fontSize: `${mobileTitleFontSize}px` }
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span ref={titleTextRef}>{currentItem.title}</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className='flex items-center gap-2 md:gap-3 text-sm md:text-base text-white/90 flex-wrap'>
|
<div className='flex items-center gap-2 md:gap-3 text-sm md:text-base text-white/90 flex-wrap'>
|
||||||
|
|||||||
Reference in New Issue
Block a user