积分球领取补位动画实现

案例动画: 支付宝-会员-积分球列表领取

动画演示

积分球与列表UI结构,以及动画轨迹/样式变化路径:

CSS实现

核心都是基于css的transition属性,来实现各种属性的动画效果:

1、球领取中,触发单球飞起的动画,手动计算单球与终点的位移transform,然后设置transform中属性的动画效果:

js 复制代码
 // 计算动画偏移量
ballEl.style.transition = 'transform 0.7s cubic-bezier(.52,.2,.13,.97), opacity 0.7s';
ballEl.style.transform = `translate3d(${dx}px, ${dy}px, 0) scale(0.2)`;
ballEl.style.opacity = '0';

2、列表中,球飞起同时,其占位元素的宽度、边距等属性变化,触发flex布局的列表中其他球的位移(transform):

关键动画属性:

  • 在flex布局中,每一个球的位置自适应: flex: 0 0 auto;
  • 下一个球的补位动画实现,主要由消失球的width等变化,和下一个球的位移(transform)变化组合实现
js 复制代码
.ball-item {
  width: 118px;
  /* 关键1、在flex布局中,每一个球的位置和尺寸自适应 */
  flex: 0 0 auto;
  /* 关键2、球补位动画的实现变化,主要由消失球的width等UI变化,和下一个球的transform变化组合实现 */
  transition: width 0.7s, margin-left 0.7s, opacity 0.7s, transform 0.7s;
  z-index: 1;

   /* 消失球的UI变化 */
  &.removing,
  &.batch-removing {
    // 平滑变小,飞出动画
    width: 0 !important;
    margin-left: 0 !important;
    opacity: 0;

    .ball-content {
      opacity: 0;
    }
  }
}

完整代码

js 复制代码
import { delay } from 'lodash';
import { useAsyncEffect } from 'ahooks';
import React, { useRef, useMemo } from 'react';
import cn from 'classnames';
import './index.less';
import { IPointCertInfoItemProps } from '../../../store/initialState';

type BallItemProps = {
  ball: IPointCertInfoItemProps;
  onClick?: () => void;
  targetId: string;
  children: React.ReactNode;
  id: string;
};

export const BallItem = ({ ball, targetId, id, children, onClick }: BallItemProps) => {
  const ballRef = useRef<HTMLDivElement>(null);

  const animationDuration = useMemo(() => {
    return `${3 + Math.random()}s`;
  }, []);

  const animationDelay = useMemo(() => {
    return `${Math.random()}s`;
  }, []);

  useAsyncEffect(async () => {
    const ballEl = ballRef.current;
    const targetEl = document.getElementById(targetId);
    // "领取"或"批量领取"状态响应动画
    if ((ball.state === 'removing' || ball.state === 'batch-removing') && ballEl && targetEl) {
      const ballRect = ballEl.getBoundingClientRect();
      const targetRect = targetEl.getBoundingClientRect();
      const dx = targetRect.left - ballRect.left;
      const dy = targetRect.top - ballRect.top;
      // 计算动画偏移量
      ballEl.style.transition = 'transform 0.7s cubic-bezier(.52,.2,.13,.97), opacity 0.7s';
      ballEl.style.transform = `translate3d(${dx}px, ${dy}px, 0) scale(0.2)`;
      ballEl.style.opacity = '0';
      // 清理动画,方便下一次复用
      await delay(700);
      if (ballEl) {
        ballEl.style.transition = '';
        ballEl.style.transform = '';
        ballEl.style.opacity = '';
      }
    }
  }, [ball.state]);

  return (
    <div
      id={id}
      className={cn('ball-item', {
        removing: ball.state === 'removing',
        'batch-removing': ball.state === 'batch-removing',
      })}
      onClick={onClick}
    >
      <div
        className={cn('ball-content', {
          float: !ball.state,
        })}
        style={{
          animationDuration,
          animationDelay,
        }}
        ref={ballRef}
      >
        {children}
      </div>
    </div>
  );
};
less 复制代码
.ball-item {
  width: 118px;
  flex: 0 0 auto;
  transition: width 0.7s, margin-left 0.7s, opacity 0.7s, transform 0.7s;
  z-index: 1;

  .ball-content {
    width: 118px;
    height: 118px;
    transition: opacity 0.7s, transform 0.7s;

    &.float {
      animation: upDown 0.8s ease-in-out infinite;
    }
  }

  &.removing,
  &.batch-removing {
    // 平滑变小,飞出动画
    width: 0 !important;
    margin-left: 0 !important;
    opacity: 0;

    .ball-content {
      opacity: 0;
    }
  }
}

@keyframes upDown {
  0% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-6px);
  }

  100% {
    transform: translateY(0);
  }
}
相关推荐
前端开发爱好者2 小时前
v5.0 版本发布!Vue3 生态最强大的 3D 开发框架!
前端·javascript·vue.js
Sosse2 小时前
window.close()失效 + Chrome浏览器调试线上代码
前端·浏览器
干就完事了2 小时前
Edge 浏览器安装selenium
前端·selenium·edge
IT_陈寒3 小时前
Vue3性能优化实战:这5个技巧让我的应用加载速度提升70%
前端·人工智能·后端
mumu1307梦3 小时前
html 占位符
前端·javascript·html
WY3 小时前
前端项目部署:Nginx 从入门到实战
前端
Apifox3 小时前
Apifox 9 月更新| AI 生成接口测试用例、在线文档调试能力全面升级、内置更多 HTTP 状态码、支持将目录转换为模块
前端·后端·测试
用户458203153173 小时前
CSS性能优化全攻略:提升页面加载与渲染速度
前端·css
90后的晨仔4 小时前
Vue 组件事件完全指南:子父组件通信的艺术
前端·vue.js