动画效果

/* eslint-disable semi */
let animationId = 0;
let fnAnimation = null;
let Container = null;
let Balls = [];

export function clearBallScreen () {
  setTimeout(() => {
    for (let i = 0; i < Balls.length; i++) {
      Container.removeChild(Balls[i]);
    }
    Balls = [];
  }, 1000);
}

export function ballCrash (el, classArr, ballNum, diameters) {
  let getFlag = function (id) {
    return document.getElementById(id);
  };
  let extend = function (des, src) {
    for (let p in src) {
      des[p] = src[p];
    }
    return des;
  };

  // 球的屏幕初始化配置类
  let Screen = function (cid, config) {
    let self = this;
    if (!(self instanceof Screen)) {
      return new Screen(cid, config);
    }

    config = extend(Screen.Config, config);

    self.container = getFlag(cid);

    if (!self.container) return;

    self.ballsnum = config.ballsnum;

    self.spring = config.spring;
    self.bounce = config.bounce;

    self.gravity = config.gravity;

    self.balls = [];
    self.timer = null;

    self.L_bound = 0;
    self.R_bound = self.container && self.container.clientWidth;
    self.T_bound = 0;

    self.B_bound = self.container && self.container.clientHeight;
  };

  Screen.Config = {
    ballsnum: 10,
    spring: 0.8,
    bounce: -1,
    gravity: 0.05
  };

  function Ball (classn) {
    let ball = document.createElement('div');
    ball.className = classn;

    ball.style.position = 'absolute';
    ball.style.zIndex = '10';
    return ball;
  }

  Screen.prototype = {
    initialize: function () {
      if (!this.container) return;
      let self = this;
      self.createBalls();

      function animation () {
        animationId = requestAnimationFrame(animation);

        self.hitBalls();
      }

      fnAnimation = animation;

      if (window.requestAnimationFrame) {
        animation();
      } else {
        self.timer = setInterval(function () {
          self.hitBalls();
        }, 30);
      }
    },
    prefix: 'wave_',
    createBalls: function () {
      let self = this;
      let num = self.ballsnum;
      let frag = document.createDocumentFragment();
      for (let i = 0; i < num; i++) {
        let ball = Ball(`${this.prefix}${classArr[i]} wave_ball`);

        ball.diameter = diameters[i];
        ball.radius = ball.diameter / 2;

        ball.style.left = Math.random() * self.R_bound + 'px';
        ball.style.top = Math.random() * self.B_bound + 'px';

        // [定义 每次刷新, 移动多少距离]
        ball.moveX = Math.random() * 6 - 3;
        ball.moveY = Math.random() * 6 - 3;
        frag.appendChild(ball);
        self.balls[i] = ball;
        Balls.push(ball);
      }

      Container = self.container;
      self.container.appendChild(frag);
    },
    hitBalls: function () {
      let self = this;
      let num = self.ballsnum;
      let balls = self.balls;
      for (let i = 0; i < num - 1; i++) {
        let ball1 = self.balls[i];
        // [获取圆点位置]
        ball1.x = ball1.offsetLeft + ball1.radius;
        ball1.y = ball1.offsetTop + ball1.radius;

        // [循环计算后面的球, 是否碰撞]
        for (let j = i + 1; j < num; j++) {
          let ball2 = self.balls[j];

          // [获取下一个球的圆点位置]
          ball2.x = ball2.offsetLeft + ball2.radius;
          ball2.y = ball2.offsetTop + ball2.radius;

          // [圆心之间 X  Y]
          let dx = ball2.x - ball1.x;
          let dy = ball2.y - ball1.y;

          // [圆心之间的距离]
          let dist = Math.sqrt(dx * dx + dy * dy);

          // [圆心之间最小距离]
          let misDist = ball1.radius + ball2.radius;

          if (dist < misDist) {
            let angle = Math.atan2(dy, dx);

            let tx = ball1.x + Math.cos(angle) * misDist;
            let ty = ball1.y + Math.sin(angle) * misDist;

            // 这次渲染移动的距离
            let ax = (tx - ball2.x) * self.spring;
            let ay = (ty - ball2.y) * self.spring;

            /** [反弹运动] **/
            ball1.moveX -= ax;
            ball1.moveY -= ay;
            ball2.moveX += ax;
            ball2.moveY += ay;
          }
        }
      }
      for (let i = 0; i < num; i++) {
        self.moveBalls(balls[i]);
      }
    },
    moveBalls: function (ball) {
      let self = this;
      // [重力 0.01]
      ball.moveY += self.gravity;

      ball.style.left = ball.offsetLeft + ball.moveX + 'px';
      ball.style.top = ball.offsetTop + ball.moveY + 'px';
      let L = self.L_bound;
      let R = self.R_bound;
      let T = self.T_bound;
      let B = self.B_bound;
      let BC = self.bounce;

      // BC是负值, 所以每次碰到边后, moveX moveY 会设置成相反的值, 后续都用这个, 球就会持续反方向运动
      if (ball.offsetLeft < L) {
        ball.style.left = L;
        ball.moveX *= BC;
      } else if (ball.offsetLeft + ball.diameter > R) {
        ball.style.left = R - ball.diameter + 'px';
        ball.moveX *= BC;
      } else if (ball.offsetTop < T) {
        ball.style.top = T;
        ball.moveY *= BC;
      }
      // top 不能大于可视区的高度
      if (ball.offsetTop + ball.diameter > B) {
        ball.style.top = B - ball.diameter + 'px';
        ball.moveY *= BC;
      }
    }
  };

  let sc = new Screen(el, {
    ballsnum: ballNum,
    spring: 0.8,
    bounce: -0.9,
    gravity: 0.01
  });
  sc.initialize();
}

export function stopAnimation () {
  animationId && window.cancelAnimationFrame(animationId);
  animationId = 0;
}

export function goAnimation () {
  fnAnimation && window.requestAnimationFrame(fnAnimation);
}

//使用
import { ballCrash, clearBallScreen } from '../../../util/effect.js'

createBallScreen () {
      ballCrash('lottery-crash', ['one', 'two', 'three', 'four', 'five', 'six', 'seven'], 7, [25, 18, 14, 18, 11, 17, 10])
    }

  

原文地址:https://www.cnblogs.com/dhsz/p/11624520.html