JavaScript:匀速和减速动画函数的封装原理和编码
目录
高质量前端博主,点个关注不迷路🌸🌸🌸!
写在最前:
这篇文章是来填坑的,填上一次给大家讲轮播图的一个坑:关于封装动画函数的详细介绍,以及匀速和减速动画各自的封装原理,废话不多说,大家请阅读文章!
I. 总述
首先我们要明白封装动画函数是要干什么?
考虑这样一件事,例如我想要一个div元素,从一个位置,通过运动到达另一个位置。并且是左右移动,应该怎么做?
这个时候大家第一个想到的应该是用css的动画样式,动画样式固然可以实现,但是我们今天采用另一种思路:用JavaScript实现这个移动的效果,那么它实现动画效果的原理是什么呢?我们仍然以左右移动为例:
通过提前判定目标位置的坐标,而后计算出距离目标坐标需要给div设置的left值,最后,通过函数setInterval()函数连续的执行移动(间隔时间非常短,通常设置30ms,越短越好),但是每一次移动,仅仅移动一小段,由于间隔的时间很短,于是我们人眼的错觉会认为是在缓缓移动。
这就是实现的原理了,而常用的两类动画函数封装有匀速运动的封装和减速运动的封装,下面我们就一个一个地给予原理的讲解与编码。
II. 匀速动画的封装原理与编码
首先,我们进行匀速运动动画函数的封装:
我们一步一步来,首先,我们新建一个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()。
那说到这里,匀速运动的封装我们就完成了,为了使讲解更加生动有趣,我们用一个小例子测试一下动画函数好不好用:
-
-
-
<head>
-
<meta charset="UTF-8">
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>animation</title>
-
<style>
-
#father {
-
position: relative;
-
height: 200px;
-
}
-
-
#son {
-
position: absolute;
-
width: 200px;
-
height: 200px;
-
border: 1px solid black;
-
background-color: aqua;
-
}
-
-
#btn {
-
width: 120px;
-
height: 30px;
-
line-height: 30px;
-
margin: 0 auto;
-
margin-top: 100px;
-
border: 1px solid black;
-
text-align: center;
-
}
-
</style>
-
</head>
-
-
<body>
-
<div id="father">
-
<div id="son"></div>
-
</div>
-
<div id="btn">点击运动</div>
-
<script type="text/javascript" src="../匀速动画/animate.js"></script>
-
<script type="text/javascript" src="../匀速动画/jquery.min.js"></script>
-
<script type="text/javascript">
-
var btn = $("#btn");
-
var div_obj = $("#son");
-
btn.bind("click", function () {
-
animate(div_obj, 400, function () {
-
alert("完成运动!")
-
})
-
})
-
</script>
-
-
</body>
-
-
</html>
其中,我们用这句话引入写好的动画函数的js文件:
<script type="text/javascript" src="https://blog.csdn.net/qq_52736131/article/匀速动画/animate.js"></script>
下面我还引入了jQuery,目的是简化代码,大家也可以用原生的DOM,都可以。
运行后,效果如下图所示:
III. 减速动画的封装原理与编码
最后,我们谈一谈减速动画要怎么封装,原理是什么。
所谓的减速,其实和我们中学物理学的减速运动很类似,也就是在运动的过程中,速度越走越慢,那么我们看一个式子:
v = s / t
这个公式不知道的,可以面壁思过了哈哈,中学物理的速度定义式子,从这个式子中,我们知道想要让速度越走越慢,有两个可行角度:
增加 s 或者减小 t
但是事实上,减小t并不现实,原因其实刚才已经说过了,30ms的每次执行移动时间间隔已经是一个极限的时间了,小于这个时间的移动,会变得很假,就不像是动画了,更像瞬移。于是结论就有了:
要实现减速运动 = = = 减小每一次移动的距离 s
那么我们要怎么减小每一次移动的距离s呢,一个很简单的想法就是每一次让移动的步长减小一个固定的常数,但如果每一次减小的都是一个固定的常数,那等于没有实现减速,而是速度变小的匀速,于是我们应该是每一次的s都能比前一次的小,于是我们可以用下面的这个式子:
var step = (target - parseInt(obj.css("left"))) / 10;
其中,step是当次移动的步长,target仍然是目标的left值,parseInt(obj.css)是当前的left值,那么每一次的step有没有减小呢?我们来计算一下:
例如当前的left值是100,目标是0,那么我们的步长应该是这样的:
第一次:step = (100 - 0) / 10 = 10 px
第二次:step = (100 - 10) / 10 = 9 px
第三次:step = (100 - 19) / 10 = 8.1 px
...
好了,于是计算了一下发现的确能使得步长step不断减小,也即我们上面式子中的s不断减小,因此这个式子貌似可行。
但是善于思考的朋友可能要质疑我了:如果按照这样的计算方式,那么理论上应该是永远也到不了目的地,因为每一次总会与目的地有一个细微的差值,其实这样的理解是对的,于是我们需要加这样一行代码:
step = step > 0 ? Math.ceil(step) : Math.floor(step);
这句代码涉及了两个函数Math.ceil()和Math.floor(),避免大家之前没见过,我们做一个简述:
Math.ceil()方法执行的是向上取整计算,它返回的是大于或等于函数参数,并且与之最接近的整数。
Math.floor() 方法执行的是向下取整计算,它返回的是小于或等于函数参数,并且与之最接近的整数。
于是加了这句话,会出现什么神奇的事情呢?我们看一下:
当前的left是91,目标是100,那么有:
step = (100 - 99) / 10 = 0.1
按理说,它应该走0.1,然后再留下0.9,但有了这个函数,它直接就走了1,也就是走到了目的地。这是对ceil()函数的解释,那对于floor()则逻辑是完全一样的,不做赘述了。
于是我们拿出刚才封装好的匀速函数,把step的公式换成上面的公式,就得到了减速运动的封装函数:
-
function animate(obj, target, callback) {
-
clearInterval(obj);
-
obj.timer = setInterval(function () {
-
var current_left = parseInt(obj.css("left"));
-
var step;
-
step = (target - current_left) / 10;
-
step = step > 0 ? Math.ceil(step) : Math.floor(step);
-
if (current_left == target) {
-
clearInterval(obj.timer);
-
if (callback) {
-
callback();
-
}
-
}
-
obj.css("left", current_left step "px");
-
}, 30)
-
}
继续用前面那个小例子,我们测试一下减速函数好不好用:
-
-
-
<head>
-
<meta charset="UTF-8">
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>animation</title>
-
<style>
-
#father1,
-
#father2 {
-
position: relative;
-
height: 150px;
-
margin-top: 50px;
-
}
-
-
#son1,
-
#son2 {
-
text-align: center;
-
font-size: 30px;
-
line-height: 150px;
-
position: absolute;
-
width: 150px;
-
height: 150px;
-
border: 1px solid black;
-
background-color: aqua;
-
}
-
-
#btn {
-
width: 120px;
-
height: 30px;
-
line-height: 30px;
-
margin: 0 auto;
-
margin-top: 100px;
-
border: 1px solid black;
-
text-align: center;
-
}
-
</style>
-
</head>
-
-
<body>
-
<div id="father1">
-
<div id="son1">匀速</div>
-
</div>
-
<div id="father2">
-
<div id="son2">减速</div>
-
</div>
-
<div id="btn">点击运动</div>
-
<script type="text/javascript" src="../减速动画/animate2.js"></script>
-
<script type="text/javascript" src="../减速动画/animate.js"></script>
-
<script type="text/javascript" src="../减速动画/jquery.min.js"></script>
-
<script type="text/javascript">
-
var btn = $("#btn");
-
var div_obj1 = $("#son1");
-
var div_obj2 = $("#son2");
-
btn.bind("click", function () {
-
animate(div_obj1, 400, function () {
-
})
-
animate2(div_obj2, 400, function () {
-
})
-
})
-
</script>
-
-
</body>
-
-
</html>
为了方便大家对比,我这次把两个动画函数都引了进来,并且把匀速动画函数命名为animate,把减速动画函数命名为animate2,并复制了一个二号盒子,下面是效果展示:
好了,那到这里减速动画的封装原理和编码也讲解完毕,感谢大家的阅读!(评论区制定有本次讲解的两个动画函数的资源,大家可以自行下载js资源文件)
以上是本期的全部内容,喜欢的小伙伴们可以三连支持一下!💓💓💓!
另外本期博客参与了【新星计划】,还请大家支持一下🌟🌟🌟!
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkfehb
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13