如何无突兀刷新修改tsParticles配置?Next.js+TypeScript场景
如何在tsParticles中无突兀修改粒子配置参数
在TypeScript+Next.js项目中使用tsParticles组件时,想通过按钮点击程序化修改粒子速度、颜色等配置,但将speed设为状态变量并加入useMemo依赖的方式,会导致粒子系统突兀刷新。以下是实现无突兀配置修改的方案:
核心思路
不要通过更新options对象触发组件重新渲染(这会重启粒子系统),而是直接获取tsParticles的容器实例,在现有粒子系统上动态修改参数,实现平滑过渡。
具体实现步骤
- 保存粒子容器实例:使用
useRef存储tsParticles的Container实例,在particlesLoaded回调中完成赋值。 - 定义可修改的状态变量:比如粒子速度、颜色等需要动态调整的参数。
- 编写动态修改函数:通过容器实例直接修改粒子配置,无需更新整个
options对象。
修改后的完整组件代码
"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, useRef } from "react"; const ParticlesComponent: React.FC = ({}) => { const [init, setInit] = useState(false); // 保存粒子容器实例 const particlesContainerRef = useRef<Container | null>(null); // 定义可修改的状态变量 const [speed, setSpeed] = useState(0.1); const [particleColor, setParticleColor] = useState("#ffffff"); useEffect(() => { initParticlesEngine(async (engine) => { await loadSlim(engine); }).then(() => { setInit(true); }); }, []); const particlesLoaded = async (container?: Container): Promise<void> => { // 赋值容器实例 if (container) { particlesContainerRef.current = container; } }; // 动态修改速度的函数 const handleSpeedChange = (newSpeed: number) => { setSpeed(newSpeed); if (particlesContainerRef.current) { // 直接修改容器内粒子的移动速度 particlesContainerRef.current.options.particles.move.speed = newSpeed; // 通知粒子系统更新配置 particlesContainerRef.current.refresh(); } }; // 动态修改颜色的函数 const handleColorChange = (newColor: string) => { setParticleColor(newColor); if (particlesContainerRef.current) { // 直接修改粒子颜色配置 particlesContainerRef.current.options.particles.color.value = [newColor]; // 遍历现有粒子,即时更新颜色 particlesContainerRef.current.particles.forEach(particle => { particle.color.value = newColor; }); } }; const options: ISourceOptions = useMemo( () => ({ background: { color: { value: "#0F0F11", }, }, fpsLimit: 60, particles: { color: { value: [particleColor], }, move: { direction: MoveDirection.none, enable: true, outModes: { default: OutMode.out, }, random: false, speed: speed, 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 ( <> <div className="fixed top-4 left-4 z-10"> <button onClick={() => handleSpeedChange(0.5)} className="mr-2 px-4 py-2 bg-blue-500 text-white rounded" > 加快速度 </button> <button onClick={() => handleSpeedChange(0.1)} className="mr-2 px-4 py-2 bg-blue-500 text-white rounded" > 减慢速度 </button> <button onClick={() => handleColorChange("#ff0000")} className="px-4 py-2 bg-red-500 text-white rounded" > 变红 </button> </div> <Particles options={options} particlesLoaded={particlesLoaded} className="-z-20 absolute"></Particles> </> ); }; export default ParticlesComponent;
关键说明
- 容器实例操作:通过
particlesContainerRef.current直接访问粒子系统的配置和粒子实例,修改后调用refresh()让全局配置生效;针对颜色这类需要即时更新的属性,直接遍历粒子修改单个实例的属性。 - 避免options依赖状态:
useMemo的依赖数组保持为空,防止状态变化时重新生成options导致粒子系统重启,彻底解决突兀刷新问题。
内容的提问来源于stack exchange,提问作者Riccardo Perego
相关产品推荐
相关产品推荐

