You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,但水平滚动的有效监听对象应该是父级滚动容器,而非单个子元素。

修正步骤

  1. 在父组件中给水平滚动容器添加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>
  );
};
  1. 确保父容器有正确的水平滚动样式:
.horizontal-scroll-container {
  display: flex;
  overflow-x: auto;
  width: 100%;
  padding: 20px 0;
}
.horizontal-scroll-container li {
  flex-shrink: 0;
  margin-right: 16px;
}
  1. 调整useTransform的映射区间,根据实际滚动需求匹配透明度变化,比如你当前设置的[1, 0.8, 0] → [1, 0.5, 0]表示滚动进度从1降到0时,透明度从1渐变到0.5再到0,可根据视觉需求微调数值。

内容的提问来源于stack exchange,提问作者Emil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:58:21