动画效果
思路
-
我们做复杂需求的时候通常都是这样的思路,从简单到复杂,由点到面,然后再优化,完善边界情况,这个动画也是,如果想直接copy代码,可以直接看最后的代码
-
思考如何炸,从简单到复杂:
- 第一步,让一个图片动,从一个位置动到另外一个位置,并且渐渐消失,也就是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;
}
};
- 第二步,爆炸不只一个方向,需要向四面八方扩散,并且初始位置也是随机的,不全是从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);
齐活
- 第三步,抽离成单独函数,动态创建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);