React实现类Instagram直播飞心动画:如何让追加Div平滑消失
实现Instagram直播式飞心动画:让生成的爱心平滑消失
我想实现如图所示的飞心动画:用户点击按钮时,在随机X、Y位置生成爱心,爱心能自动平滑消失,效果类似Instagram直播。现有React及CSS代码如下,请教如何让追加的div无缝平滑消失。

现有代码:
import React, { useState } from "react"; const MyComponent = () => { const [divs, setDivs] = useState([]); const addDiv = () => { const x = Math.floor(Math.random() * window.innerWidth); const y = Math.floor(Math.random() * window.innerHeight); const newDiv = ( <div className="animated-div" style={{ position: "absolute", left: x, top: y }} > <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="heart" className="svg-inline--fa fa-heart fa-w-16" width="100%" height="100%" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" preserveAspectRatio="none" > <path fill="#f67280" d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z" /> </svg> </div> ); setDivs([...divs, newDiv]); }; return ( <div> <button onClick={addDiv}>Add Div</button> <div className="container">{divs}</div> </div> ); }; export default MyComponent;
.animated-div { height: 50px; width: 50px; animation: fly-in 0.3s ease-out forwards; color: white; font-size: 1em; padding: 10px; } @keyframes fly-in { from { transform: translateY(100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
解决方案
1. 扩展CSS动画,加入淡出阶段
把原来的仅飞入动画改成飞入→停留→上移淡出的完整生命周期动画,让爱心自动完成消失过程:
.animated-div { height: 50px; width: 50px; position: absolute; /* 把定位属性统一移到类中 */ animation: heart-fly 2s ease-out forwards; /* 总时长和动画关键帧对应 */ pointer-events: none; /* 避免爱心遮挡按钮点击 */ } @keyframes heart-fly { 0% { transform: translateY(100%) scale(0.5); opacity: 0; } 20% { transform: translateY(0) scale(1); opacity: 1; } 80% { transform: translateY(-50px) scale(1); /* 中间停留并缓慢上移 */ opacity: 1; } 100% { transform: translateY(-100px) scale(0.8); opacity: 0; } }
2. 优化React状态管理,存储数据而非元素
直接存React元素无法跟踪生命周期,改为存储爱心的唯一ID和位置数据,渲染时动态生成元素,并自动移除已完成动画的爱心:
import React, { useState, useEffect } from "react"; const MyComponent = () => { const [hearts, setHearts] = useState([]); const addHeart = () => { // 减去爱心宽高,避免生成的爱心超出屏幕 const x = Math.floor(Math.random() * (window.innerWidth - 70)); const y = Math.floor(Math.random() * (window.innerHeight - 70)); const newHeart = { id: Date.now() + Math.random(), // 生成唯一ID x, y }; setHearts(prev => [...prev, newHeart]); }; // 动画结束后自动移除爱心,定时器时长和动画总时长一致 useEffect(() => { if (hearts.length === 0) return; const timer = setTimeout(() => { setHearts(prev => prev.slice(1)); }, 2000); return () => clearTimeout(timer); }, [hearts]); return ( <div style={{ position: "relative", minHeight: "100vh" }}> <button onClick={addHeart}>点击生成爱心</button> <div className="container"> {hearts.map(heart => ( <div key={heart.id} className="animated-div" style={{ left: `${heart.x}px`, top: `${heart.y}px` }} > <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="heart" className="svg-inline--fa fa-heart fa-w-16" width="100%" height="100%" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" preserveAspectRatio="none" > <path fill="#f67280" d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z" /> </svg> </div> ))} </div> </div> ); }; export default MyComponent;
3. 调整容器样式
给容器添加定位,确保爱心的绝对定位基于容器,同时不干扰下层元素点击:
.container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }
修改后,爱心会自动完成飞入→停留→上移淡出的完整动画,动画结束后React会移除对应的DOM元素,实现无缝平滑消失的效果。
内容的提问来源于stack exchange,提问作者FeelRightz
相关产品推荐
相关产品推荐

