Next.js中使用Framer Motion报错window未定义且滚动动效失效
问题解决方案
1. 修复「window is not defined」错误
Next.js服务端渲染阶段不存在window对象,而Framer Motion的useScroll依赖浏览器环境,必须让组件仅在客户端执行相关逻辑:
方案一:用Next.js动态导入禁用SSR
在父组件中修改ProjectItem的导入方式:
import dynamic from 'next/dynamic'; const ProjectItem = dynamic(() => import('@/components/ProjectItem'), { ssr: false, });
方案二:组件内判断客户端环境
在ProjectItem组件中加入客户端环境判断,避免服务端执行浏览器相关逻辑:
import Poster from '@/components/poster'; import { motion, useScroll, useTransform } from 'framer-motion'; import { StaticImageData } from 'next/image'; import React, { useRef, useEffect, useState } from 'react'; type ProjectItemProps = { item: { id: string | number }; posterHeight: number; posterWidth: number; ImagePoster: string | StaticImageData; scrollContainerRef: React.RefObject<HTMLElement>; }; const ProjectItem = ({ posterHeight, posterWidth, ImagePoster, scrollContainerRef }: ProjectItemProps) => { const ref = useRef(null); const MotionPoster = motion.create(Poster); const [isClient, setIsClient] = useState(false); let opacity = 1; useEffect(() => { setIsClient(true); }, []); if (isClient) { const { scrollXProgress } = useScroll({ target: scrollContainerRef, offset: ['0 1', '1.33 1'], axis: 'x', }); opacity = useTransform(scrollXProgress, [1, 0.8, 0], [1, 0.5, 0]); } return ( <li ref={ref}> <MotionPoster style={{ opacity }} height={posterHeight} width={posterWidth} src={ImagePoster} alt='poster' /> </li> ); }; export default ProjectItem;
2. 修复滚动时透明度无动态变化的问题
问题根源
你把useScroll的监听目标设为每个子项li的ref,但水平滚动的有效监听对象应该是父级滚动容器,而非单个子元素。
修正步骤
- 在父组件中给水平滚动容器添加ref,并传递给子组件:
import { useRef } from 'react'; import ProjectItem from '@/components/ProjectItem'; const ParentComponent = () => { const scrollContainerRef = useRef(null); const items = [...]; // 你的项目数据 return ( <ul ref={scrollContainerRef} className="horizontal-scroll-container"> {items.map(item => ( <ProjectItem key={item.id} item={item} posterHeight={300} posterWidth={200} ImagePoster={item.poster} scrollContainerRef={scrollContainerRef} /> ))} </ul> ); };
- 确保父容器有正确的水平滚动样式:
.horizontal-scroll-container { display: flex; overflow-x: auto; width: 100%; padding: 20px 0; } .horizontal-scroll-container li { flex-shrink: 0; margin-right: 16px; }
- 调整
useTransform的映射区间,根据实际滚动需求匹配透明度变化,比如你当前设置的[1, 0.8, 0] → [1, 0.5, 0]表示滚动进度从1降到0时,透明度从1渐变到0.5再到0,可根据视觉需求微调数值。
内容的提问来源于stack exchange,提问作者Emil
相关产品推荐
相关产品推荐

