积分球领取补位动画实现

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

动画演示

积分球与列表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);
  }
}
相关推荐
爱吃甜品的糯米团子21 小时前
JavaScript 正则表达式:选择、分组与引用深度解析
前端·javascript·正则表达式
excel21 小时前
Vue SSR 编译器源码深析:ssrTransformShow 的实现原理与设计哲学
前端
excel21 小时前
深入解析 Vue 3 SSR 编译管线:ssrCodegenTransform 源码全解
前端
excel21 小时前
深入解析 Vue SSR 编译器的核心函数:compile
前端
IT_陈寒21 小时前
Vue 3性能优化实战:7个关键技巧让我的应用加载速度提升50%
前端·人工智能·后端
excel21 小时前
Vue SSR 错误系统源码解析:createSSRCompilerError 与 SSRErrorCodes 的设计原理
前端
excel21 小时前
Vue SSR 源码解析:ssrTransformModel 深度剖析
前端
excel21 小时前
Vue SSR 运行时辅助工具注册机制源码详解
前端
excel21 小时前
Vue SSR 源码解析:ssrProcessIf 条件渲染的服务端转换逻辑
前端
excel21 小时前
深度解析:Vue 3 中 ssrTransformTransitionGroup 的实现原理与机制
前端