H5 爆炸动画 效果的实现

803 阅读3分钟

动画效果

思路

  • 我们做复杂需求的时候通常都是这样的思路,从简单到复杂,由点到面,然后再优化,完善边界情况,这个动画也是,如果想直接copy代码,可以直接看最后的代码

  • 思考如何炸,从简单到复杂:

  1. 第一步,让一个图片动,从一个位置动到另外一个位置,并且渐渐消失,也就是startX,startY变化到endX,endY,我们给img标签加一个动画即可
第一步我们用transform和opacity就可以实现
      @keyframes move {
          0% {
              -webkit-transform: translate(0px, 0px);
              transform: translate(0px, 0px);
              opacity: 1;
          }
          100% {
              -webkit-transform: translate(10px, 10px);
              transform: translate(10px, 10px);
              opacity: 0;
          }
      };
  1. 第二步,爆炸不只一个方向,需要向四面八方扩散,并且初始位置也是随机的,不全是从0,0开始,所以,这就是个坐标系,原点是点击的地方,也就是点击的div所在的位置,那么向四面八方扩散如何实现呢
这里用判断两个随机数的范围来实现随机象限
  const isY = random(0, 10) > 5; 
  const isX = random(0, 10) > 5; // isY 和 isX 两个变量构成四个象限

然后生成随机起始位置、生成随机距离distance
  // 生成随机起始位置
  const randomA = random(10, 50);
  const randomB = random(10, 50);
  const x = isY ? randomA : -randomA;
  const y = isX ? randomB : -randomB;
  const distance = random(60, 100); // 随机运动距离

然后根据起始位置的x,y值,计算出弧度,根据弧度计算出斜边长度,然后加上运动距离distance,根据终点位置的斜边长度和弧度,计算出终点位置的x,y值
  // 根据起始坐标求出弧度,根据弧度求出终点坐标
  const z = parseInt(Math.sqrt(x * x + y * y), 10) + distance;
  const rad = Math.atan2(x, y);

  const endx = Math.round(Math.sin(rad) * z);
  const endy = Math.round(Math.cos(rad) * z);

齐活
  1. 第三步,抽离成单独函数,动态创建img标签,动态生成动画,根据点击的元素位置,设置动画位置,传入dom即可

代码实现

  • copy即用
superThumb.js

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

function setKeyFrames(name) {
  const isY = random(0, 10) > 5; // 正反
  const isX = random(0, 10) > 5; // x y 两个变量构成四个象限

  // 生成随机起始位置
  const randomA = random(10, 50);
  const randomB = random(10, 50);
  const x = isY ? randomA : -randomA;
  const y = isX ? randomB : -randomB;
  const distance = random(60, 100); // 随机运动距离
  
  // 根据起始坐标求出弧度,根据弧度求出终点坐标
  const z = parseInt(Math.sqrt(x * x + y * y), 10) + distance;
  const rad = Math.atan2(x, y);

  const endx = Math.round(Math.sin(rad) * z);
  const endy = Math.round(Math.cos(rad) * z);

  const animation = `\
      @-webkit-keyframes move${name} {\
          0% {\
              -webkit-transform: translate(${x}px, ${y}px);\
              transform: translate(${x}px, ${y}px);\
              opacity: 1;
          }\
          100% {\
              -webkit-transform: translate(${endx}px, ${endy}px);\
              transform: translate(${endx}px, ${endy}px);\
              opacity: 0;
          }\
      }\
      @keyframes move${name} {\
          0% {\
              -webkit-transform: translate(${x}px, ${y}px);\
              transform: translate(${x}px, ${y}px);\
              opacity: 1;
          }\
          100% {\
              -webkit-transform: translate(${endx}px, ${endy}px);\
              transform: translate(${endx}px, ${endy}px);\
              opacity: 0;
          }\
      }`;
  const styles = document.getElementsByTagName('style');
  let style = null;
  if (styles.length > 0) {
    style = styles[styles.length - 1];
  } else {
    style = document.createElement('style');
    style.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(style);
  }
  style.innerHTML += animation;
}
const imgList = [
  require('./resource/emoji_1.png'),
  require('./resource/emoji_2.png'),
  require('./resource/emoji_3.png'),
  require('./resource/emoji_4.png'),
  require('./resource/emoji_5.png'),
  require('./resource/emoji_6.png'),
  require('./resource/emoji_7.png'),
];

function createImg(dom) {
  for (let i = 0; i < imgList.length; i++) {
    const src = imgList[i];
    const img = document.createElement('img');
    img.src = src;
    const style = {
      animation: `move${i + 1} 0.8s`,
      position: 'absolute',
      width: '100%',
    };
    Object.assign(img.style, style);
    setKeyFrames(i + 1);
    dom.appendChild(img);
    img.addEventListener('animationend', () => {
      img.remove();
    });
    img.addEventListener('webkitAnimationEnd', () => {
      img.remove();
    });
  }
}
function superThumb(dom) {
  const { top, left } = dom.getBoundingClientRect();
  const pDiv = document.createElement('div');
  const style = {
    position: 'fixed',
    top: `${top}px`,
    left: `${left}px`,
    zIndex: '1001',
    width: '24px',
    height: '24px',
  };
  createImg(pDiv);
  Object.assign(pDiv.style, style);
  document.documentElement.appendChild(pDiv);
  setTimeout(() => {
    pDiv.remove();
  }, 1000);
}


export default superThumb;

引用
App.vue
<template>
    <div ref="thumb">copy留赞,谢谢</div>
</template>

import superThumb from './superThumb';

触发动画
superThumb(this.$refs.thumb.$el);