目录
I. 总述
II. 匀速动画的封装原理与编码
III. 减速动画的封装原理与编码
高质量前端博主,点个关注不迷路!
写在最前:
这篇文章是来填坑的,填上一次给大家讲轮播图的一个坑:关于封装动画函数的详细介绍,以及匀速和减速动画各自的封装原理,废话不多说,大家请阅读文章!
首先我们要明白封装动画函数是要干什么?
考虑这样一件事,例如我想要一个div元素,从一个位置,通过运动到达另一个位置。并且是左右移动,应该怎么做?
这个时候大家第一个想到的应该是用css的动画样式,动画样式固然可以实现,但是我们今天采用另一种思路:用JavaScript实现这个移动的效果,那么它实现动画效果的原理是什么呢?我们仍然以左右移动为例:
通过提前判定目标位置的坐标,而后计算出距离目标坐标需要给div设置的left值,最后,通过函数setInterval()函数连续的执行移动(间隔时间非常短,通常设置30ms,越短越好),但是每一次移动,仅仅移动一小段,由于间隔的时间很短,于是我们人眼的错觉会认为是在缓缓移动。
这就是实现的原理了,而常用的两类动画函数封装有匀速运动的封装和减速运动的封装,下面我们就一一给予原理的讲解与编码。
首先,我们进行匀速运动动画函数的封装:
我们一步一步来,首先,我们新建一个js文件,名字比如起一个animate.js,并把函数的框架写出来:
function animate(obj, target, callback) {
}
从框架中,我们看到有三个参数:obj、target 和 callback,我们逐一解释它们的作用:
1️⃣ obj:obj是需要执行动画的元素,例如我们前面举的例子,那么div就是我们的obj,传入div对应的dom对象即可。(jquery对象也可以)
2️⃣ target:这是目标位置的left值,当然了如果后面大家需要向别的方向做动画,例如上下方向,那这个target就是目标的top值或者bottom值。
3️⃣ callback:这是完成了本次动画后执行的回调函数,我们要理解"完成"二字:完成指的是已经完成了从一个地方到目的地,而不是我刚才说的setInterval()函数的每一次执行,简单的说,这里的完成就是指的是已经到达目的地了,然后会执行的函数。
于是,接下来就像我刚才提到的那样,我们先在里面写一个setInterval()函数,并设置一个很短的调用间隔时间,比如30ms调用一次:
function animate(obj, target, callback) {
obj.timer = setInterval(function () {
},30);
}
这里obj.timer指的就是obj的setInterval()函数,我们知道每一个dom元素或者jQuery元素对象都有一个timer属性,这个timer属性就是指它绑定的定时器,这个定时器其实就是setInterval(),通俗的讲就是这一步就给obj加了一个定时器timer,加的方式是setInterval()函数。
那看到这里,大家应该会有一个想法:那就是会不会出现多个定时器的混叠,比如每次调用了这个函数,传入一个obj,这个obj就会被安装一个定时器,这样就会引起混叠和混乱,于是我们需要在安装定时器前加一句代码:
function animate(obj, target, callback) {
clearInterval(obj);
obj.timer = setInterval(function () {
},30);
}
没错,就是用经典的clearInterval()(不了解的朋友可以回看我之前关于setInterval()函数的博客)。
这之后,我们开始分析div的移动过程,请看下图:
首先,我们拿到了div这个元素的dom对象obj后,我们理所应当的可以拿到它当前的left样式值,拿到样式值的代码大家都会写,应该是这样的:
var current_left = obj.css("left")
之后,我们每一次调用setInterval()要走的距离,由于时间只有30ms,因此不能走的太远,否则就没有动画的感觉了,而是有很突兀的瞬移感,因此我推荐每次移动5像素,但由于传入的目标值可以大于当前的left值,也可以小于当前的left值,因此我们加一个判断:
var step;
if(parseInt(current_left) > target){
step = -5;
}
else{
step = 5
}
有了每一次移动的距离step(也叫步长,后面我们都叫它步长),我们也有目标left值target,于是很自然的,我们可以写出这样的逻辑判断进行匀速移动,于是完整的匀速代码也就完成了:
function animate(obj, target, callback) {
clearInterval(obj);
obj.timer = setInterval(function () {
var current_left = obj.css("left");
var step;
if(parseInt(current_left) > target){
step = -5;
}
else{
step = 5
}
if (parseInt(current_left) == target) {
clearInterval(obj.timer);
if (callback) {
callback();
}
}
obj.css("left", parseInt(current_left) + step + "px");
}, 30)
}
可以看到,当完成了运动,也即满足:
parseInt(current_left) == target
则会先把定时器解除,防止再运动;与此同时,执行回调函数callback()。
那说到这里,匀速运动的封装我们就完成了,为了使讲解更加生动有趣,我们用一个小例子测试一下动画函数好不好用:
animation
点击运动