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

如何让react-confetti在Next.js+MUI表单的当前视口生效?

问题描述

我开发了一个基于Next.js和MUI的类Typeform表单应用,每个问题页面占满整个视口。完成最后一题时,我希望渲染react-confetti特效,但目前特效显示在页面起始位置,而非当前的最后一题区域。

页面截图

  • 欢迎页:欢迎页
  • 最后一题页面:最后一题页面

问题现象

特效显示在第一题区域而非最后一题:特效位置错误

安装依赖命令

yarn add @mui react-use react-confetti

我的index.tsx代码

import Button from '@mui/material/Button'
import Grid from '@mui/material/Grid'
import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import type { NextPage } from 'next'
import dynamic from 'next/dynamic'
import { useState } from 'react'
import useWindowSize from 'react-use/lib/useWindowSize'
const Confetti = dynamic(() => import('react-confetti'), {
  ssr: false,
})

const Home: NextPage = () => {
  const { width, height } = useWindowSize()
  const [run, setRun] = useState(false)

  return (
    <div>
      <Grid
        id="welcome"
        container
        spacing={0}
        direction="column"
        alignItems="center"
        justifyContent="center"
        style={{ minHeight: '100vh', textAlign: 'center' }}
      >
        <Grid item xs={3}>
          <Typography variant="h6" gutterBottom>
            Hello User!
          </Typography>
          <Typography variant="body2" gutterBottom>
            Tell more about your experience with us
          </Typography>
          <Button variant="contained" color="primary" sx={{ marginBottom: '1em' }} size="large">
            Start
          </Button>
          <Typography variant="caption" display="block" gutterBottom>
            It takes less than 1 minute
          </Typography>
        </Grid>
      </Grid>
      {run && (
        <Confetti
          height={height}
          width={width}
          recycle={false}
          numberOfPieces={1000}
          onConfettiComplete={() => setRun(false)}
        />
      )}
      <Grid
        id="suggestion"
        container
        spacing={0}
        direction="column"
        alignItems="center"
        justifyContent="center"
        style={{ minHeight: '100vh', textAlign: 'center' }}
      >
        <Grid item xs={3}>
          <Typography variant="h5" gutterBottom>
            Any suggestions to improve our space?
          </Typography>
          <TextField
            variant="standard"
            size="medium"
            label="Leave your suggestion"
            fullWidth
            color="primary"
            margin="dense"
          />
          <Button
            variant="contained"
            color="primary"
            sx={{ marginTop: '20px' }}
            size="large"
            disabled={run}
            onClick={() => setRun(true)}
          >
            Finish
          </Button>
        </Grid>
      </Grid>
    </div>
  )
}

export default Home

解决方案

问题根源是react-confetti默认采用固定定位(position: fixed),会相对于浏览器视口顶部渲染。你的页面是多屏滚动结构,用户滚动到最后一题时,视口对应的页面顶部是第一题位置,所以特效会显示在最上方。

下面两种方法都能解决问题,选其一即可:

方法一:将Confetti嵌套到最后一题容器内

把Confetti组件放到最后一题的Grid容器里,给容器添加position: relative,再给Confetti设置position: absolute,让它相对于最后一题的视口区域渲染:

修改后的关键代码:

<Grid
  id="suggestion"
  container
  spacing={0}
  direction="column"
  alignItems="center"
  justifyContent="center"
  style={{ minHeight: '100vh', textAlign: 'center', position: 'relative' }} // 新增相对定位
>
  <Grid item xs={3}>
    {/* 原有表单内容不变 */}
  </Grid>
  {run && (
    <Confetti
      height={height}
      width={width}
      recycle={false}
      numberOfPieces={1000}
      onConfettiComplete={() => setRun(false)}
      style={{ position: 'absolute', top: 0, left: 0 }} // 新增绝对定位
    />
  )}
</Grid>

方法二:根据滚动位置动态调整Confetti的top值

用react-use的useScroll钩子获取当前滚动距离,给Confetti设置对应的top偏移,让它跟着当前视口走:

首先导入钩子:

import useScroll from 'react-use/lib/useScroll'

然后在组件中使用:

const { y: scrollY } = useScroll()

修改Confetti的渲染代码:

{run && (
  <Confetti
    height={height}
    width={width}
    recycle={false}
    numberOfPieces={1000}
    onConfettiComplete={() => setRun(false)}
    style={{ top: scrollY }} // 同步滚动偏移
  />
)}

这样Confetti就会显示在当前用户看到的最后一题区域了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:39:20