帧动画插件

Posted lijianming180

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了帧动画插件相关的知识,希望对你有一定的参考价值。

动画插件封装

最近这段时间一直都在研究关于动画方法的知识,说实话确实不容易,主要还是动画算法这方面比较难,毕竟没学过。当然也有所收获,明白了基本动画的原理是什么,所以自己也封装了一个简单的动画插件来巩固自己所学。

动画插件的实现方式

对于前端来说,主要实现动画的方式就是css(transition , animation),js(setTimeout , setInterval , requestAnimationFrame),canvas,svg等方式,在这里我主要是通过requestAnimationFrame来实现动画效果的。

插件说明

该插件接受5个参数:

  1. 第一个参数是需要动画的目标元素。
  2. 第二个参数是需要动画的属性,是一个对象。
  3. 第三个参数是动画的总时长。
  4. 第四个参数是动画的效果。目前支持三种动画效果,linear,easeIn,easeOut。
  5. 第五个参数是动画结束之后的回调函数。

该插件可以实现多个属性一起动画效果,也可以实现单个属性动画效果,也可以实现一个属性接着一个属性动画效果。由于使用的是回调函数,所以当一个接着一个属性来实现动画效果的时候,会产生回调函数嵌套。

插件代码

function (element , props , duration , easing , callback) {
if (typeof element !== 'object' && element.nodeType !== 1) {
return;
};
if (typeof props !== 'object' && props.toString() !== '[object Object]') {
return;
};
var noop = function () {};
this.element = element;
this.props = props;
this.duration = duration || 600;
this.easing = easing || 'linear';
this.callback = callback || noop;
this.tickID = 0;
this.styles = this.getStyle();
this.animate();
};
Animator.prototype = {
getStyle : function () {
return window.getComputedStyle ? window.getComputedStyle(this.element) : this.element.currentStyle();
},
animate : function () {
for (var prop in this.props) {
this.step.call(this , prop);
}
},
step : function (prop) {
var self = this;
var initialValue = 0;
var beginTime = new Date();
var endValue = parseFloat(this.props[prop]);
var beginValue = parseFloat(this.styles[prop]);
var changeValue = parseFloat(endValue - beginValue);
var distance = 0;
var move = function () {
var p = (new Date() - beginTime) / self.duration;
if (p > 1) {
self.element.style[prop] = (prop === 'opacity') ? endValue : endValue + 'px';
cancelAnimationFrame(self.tickID);
self.tickID = null;
self.callback.call(self);
} else {
if (self.easing === 'linear') {
distance = changeValue * p;
} else if (self.easing === 'easeIn') {
distance = changeValue * p * p;
} else if (self.easing === 'easeOut') {
distance = changeValue * (2 * p - p * p);
};
self.element.style[prop] = (prop === 'opacity') ? (beginValue + distance) : (beginValue + distance + 'px');
this.tickID = requestAnimationFrame(move);
}
};
move();
}
};

实例代码

<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.box{
width:100px;
height:100px;
background:#f60;
position:absolute;
top:50;
left:0;
border: 1px solid #000;大专栏  帧动画插件iv>
}
</style>
</head>
<body>
<button id="btn">click</button>
<div id="box" class="box"></div>
<script>
function (element , props , duration , easing , callback) {
if (typeof element !== 'object' && element.nodeType !== 1) {
return;
};
if (typeof props !== 'object' && props.toString() !== '[object Object]') {
return;
};
var noop = function () {};
this.element = element;
this.props = props;
this.duration = duration || 600;
this.easing = easing || 'linear';
this.callback = callback || noop;
this.tickID = 0;
this.styles = this.getStyle();
this.animate();
};
Animator.prototype = {
getStyle : function () {
return window.getComputedStyle ? window.getComputedStyle(this.element) : this.element.currentStyle();
},
animate : function () {
for (var prop in this.props) {
this.step.call(this , prop);
}
},
step : function (prop) {
var self = this;
var initialValue = 0;
var beginTime = new Date();
var endValue = parseFloat(this.props[prop]);
var beginValue = parseFloat(this.styles[prop]);
var changeValue = parseFloat(endValue - beginValue);
var distance = 0;
var move = function () {
var p = (new Date() - beginTime) / self.duration;
if (p > 1) {
self.element.style[prop] = (prop === 'opacity') ? endValue : endValue + 'px';
cancelAnimationFrame(self.tickID);
self.tickID = null;
self.callback.call(self);
} else {
if (self.easing === 'linear') {
distance = changeValue * p;
} else if (self.easing === 'easeIn') {
distance = changeValue * p * p;
} else if (self.easing === 'easeOut') {
distance = changeValue * (2 * p - p * p);
};
self.element.style[prop] = (prop === 'opacity') ? (beginValue + distance) : (beginValue + distance + 'px');
this.tickID = requestAnimationFrame(move);
}
};
move();
}
};
var box = document.querySelector('#box');
var btn = document.querySelector('#btn');
btn.addEventListener('click' , function () {
new Animator(box , {
width : 300,
height : 300,
top : 200,
left : 100,
opacity : 0.5,
borderWidth : 20
});
});
//效果二
btn.addEventListener('click' , function () {
new Animator(box , {
width : 500
} , 1000 , 'easeOut' , function () {
new Animator(box , {
height : 300,
left : 100,
borderWidth : 50
} , 1000 , 'easeIn' , function () {
new Animator(box , {
opacity : 0.6
})
});
});
});
</script>

以上是关于帧动画插件的主要内容,如果未能解决你的问题,请参考以下文章

最简单的序列帧动画canvas插件

寻找画布关键帧暂停关键帧动画示例

UGUI Image快速创建帧动画

background-position和animation制作逐帧动画

VSCode自定义代码片段——CSS动画

VSCode自定义代码片段7——CSS动画