tsParticles 更改选项而无需突然刷新

问题描述 投票:0回答:1

在我的 typescript next js 项目中,我有这个粒子组件:

"use client"

import { Container, ISourceOptions, MoveDirection, OutMode } from "@tsparticles/engine";
import Particles, { initParticlesEngine } from "@tsparticles/react";
import { loadSlim } from "@tsparticles/slim";


import React, { useEffect, useMemo, useState } from "react";


const ParticlesComponent: React.FC = ({}) => {
  
  const [init, setInit] = useState(false)

  useEffect(() => {
    initParticlesEngine(async (engine) => {
      await loadSlim(engine)
    }).then(() => {
      setInit(true)
    })
  }, [])

  const particlesLoaded = async (container?: Container): Promise<void> => {
    console.log(container);
  };

  const options: ISourceOptions = useMemo(
    () => (
      {
      background: {
        color: {
          value: "#0F0F11",
        },
      },
      fpsLimit: 60,
      particles: {
        color: {
          value: ["#ffffff"],
        },
        move: {
          direction: MoveDirection.none,
          enable: true,
          outModes: {
            default: OutMode.out,
          },
          random: false,
          speed: 0.1,
          straight: false,
        },
        number: {
          density: {
            enable: true,
          },
          value: 1800,
        },
        opacity: {
          value: { min: 0.1, max: 0.5 },
        },
        shape: {
          type: "circle",
        },
        size: {
          value: { min: 0.1, max: 1 },
        },
      },
    }
  ),
    [],
  );
  
  return (
    <Particles options={options} particlesLoaded={particlesLoaded} className="-z-20 absolute"></Particles>
  )
}

export default ParticlesComponent

我想通过单击按钮以编程方式更改各种选项参数,例如速度和颜色。

我可以将速度设置为状态变量:

const [speed, setSpeed] = useState(0.1)

并在选项中实现它,同时将其提供给

useMemo
依赖项。这可行,但问题是它会导致粒子“突然”刷新。有没有办法在不突然改变的情况下更改选项参数?

next.js tsparticles
1个回答
0
投票

我个人使用编程 API 而不是框架组件(在我的例子中是 Vue)实现了它,如此处所述 https://github.com/tsarticles/tsarticles/issues/180#issuecomment-604711173

stopConfetti()
功能中,我在动画停止之前淡化五彩纸屑

let confettiContainer: ReturnType<typeof tsParticles.domItem>
export async function startConfetti(options: Record<string, unknown> = {}) {
  if (confettiContainer) {
    console.info(`Confetti already started`)
    return
  }
  confettiContainer = await tsParticles.load({
    id: `tsparticles`,
    options: {
      particles: {
        "number": {
          "value": 0,
        },
        "shape": {
          "type": [
            // `circle`,
            // `square`,
            `emoji`,
          ],
          "options": {
            "emoji": {
              "particles": {
                "size": {
                  "value": 8,
                },
              },
              "value": [
                `⭐️`,
              ],
            },
          },
        },
        "size": {
          "value": {
            "min": 2,
            "max": 4,
          },
        },
        "links": {
          "enable": false,
        },
        "life": {
          "duration": {
            "sync": true,
            "value": 5,
          },
          "count": 1,
        },
        "move": {
          "enable": true,
          "gravity": {
            "enable": true,
            "acceleration": 10,
          },
          "speed": {
            "min": 10,
            "max": 20,
          },
          "decay": 0.1,
          "direction": `none`,
          "straight": false,
          "outModes": {
            "default": `destroy`,
            "top": `none`,
          },
        },
        "rotate": {
          "value": {
            "min": 0,
            "max": 360,
          },
          "direction": `random`,
          "move": true,
          "animation": {
            "enable": true,
            "speed": 60,
          },
        },
        "roll": {
          "darken": {
            "enable": true,
            "value": 25,
          },
          "enable": true,
          "speed": {
            "min": 15,
            "max": 25,
          },
        },
      },
      "emitters": {
        "life": {
          "count": 0,
          "duration": 0.1,
          "delay": 0.4,
        },
        "rate": {
          "delay": 0.1,
          "quantity": 100,
        },
        "size": {
          "width": 0,
          "height": 0,
        },
      },
      ...options,
    },
  })
}

let stopConfettiTimeout: ReturnType<typeof setTimeout> | undefined
export function stopConfetti(duration: number = 2) {
  if (! confettiContainer) {
    console.info(`No confetti started`)
    return
  }

  if (stopConfettiTimeout) {
    console.info(`Confetti already stopping`)
    return
  }

  confettiContainer.options.duration = duration
  confettiContainer.options.emitters.rate.delay = duration
  confettiContainer.options.particles.opacity = {
    value: {
      min: 0,
      max: 1,
    },
    animation: {
      enable: true,
      // delay: 8,
      speed: duration,
      sync: true,
      startValue: `max`,
      count: 1,
      destroy: `min`,
    },
  }
  confettiContainer.refresh()


  stopConfettiTimeout = setTimeout(() => {
    if (! confettiContainer) {
      return
    }

    confettiContainer.stop()
    confettiContainer.destroy()
    confettiContainer = undefined
    stopConfettiTimeout = undefined
  }, duration * 1000)
}
© www.soinside.com 2019 - 2024. All rights reserved.