@@ -18,6 +18,8 @@ const AnimatedBackground: React.FC = () => {
1818 const ballsRef = useRef < Ball [ ] > ( [ ] ) ;
1919 const animationRef = useRef < number > ( ) ;
2020 const lastTimeRef = useRef < number > ( 0 ) ;
21+ // 记录初始视口大小,避免输入法弹出时重新计算
22+ const initialSizeRef = useRef < { width : number ; height : number } | null > ( null ) ;
2123
2224 useEffect ( ( ) => {
2325 const canvas = canvasRef . current ;
@@ -29,12 +31,31 @@ const AnimatedBackground: React.FC = () => {
2931 const targetFPS = 30 ;
3032 const frameInterval = 1000 / targetFPS ;
3133
34+ // 获取稳定的视口大小(使用 document.documentElement 避免输入法影响)
35+ const getStableSize = ( ) => {
36+ // 优先使用初始大小,避免输入法弹出时的抖动
37+ if ( initialSizeRef . current ) {
38+ return initialSizeRef . current ;
39+ }
40+ // 使用 documentElement 的尺寸,在移动端更稳定
41+ const width = Math . max ( window . innerWidth , document . documentElement . clientWidth ) ;
42+ const height = Math . max ( window . innerHeight , document . documentElement . clientHeight ) ;
43+ return { width, height } ;
44+ } ;
45+
3246 const resizeCanvas = ( ) => {
33- canvas . width = window . innerWidth ;
34- canvas . height = window . innerHeight ;
35- ballsRef . current . forEach ( ball => {
36- ball . offscreenCanvas = createBallCanvas ( ball ) ;
37- } ) ;
47+ const size = getStableSize ( ) ;
48+ // 只在画布变大时更新,避免输入法弹出时缩小
49+ if ( ! initialSizeRef . current || size . width > canvas . width || size . height > canvas . height ) {
50+ canvas . width = size . width ;
51+ canvas . height = size . height ;
52+ if ( ! initialSizeRef . current ) {
53+ initialSizeRef . current = size ;
54+ }
55+ ballsRef . current . forEach ( ball => {
56+ ball . offscreenCanvas = createBallCanvas ( ball ) ;
57+ } ) ;
58+ }
3859 } ;
3960
4061 const colors = [
@@ -169,13 +190,21 @@ const AnimatedBackground: React.FC = () => {
169190 } ) ;
170191 } ;
171192
193+ // 防抖处理 resize,避免输入法弹出时频繁触发
194+ let resizeTimeout : ReturnType < typeof setTimeout > | null = null ;
195+ const debouncedResize = ( ) => {
196+ if ( resizeTimeout ) clearTimeout ( resizeTimeout ) ;
197+ resizeTimeout = setTimeout ( resizeCanvas , 200 ) ;
198+ } ;
199+
172200 resizeCanvas ( ) ;
173- window . addEventListener ( 'resize' , resizeCanvas ) ;
201+ window . addEventListener ( 'resize' , debouncedResize ) ;
174202 initBalls ( ) ;
175203 animationRef . current = requestAnimationFrame ( animate ) ;
176204
177205 return ( ) => {
178- window . removeEventListener ( 'resize' , resizeCanvas ) ;
206+ window . removeEventListener ( 'resize' , debouncedResize ) ;
207+ if ( resizeTimeout ) clearTimeout ( resizeTimeout ) ;
179208 if ( animationRef . current ) {
180209 cancelAnimationFrame ( animationRef . current ) ;
181210 }
0 commit comments