使用原生JS实现动画-缓动动画

    缓动动画跟前面的匀速动画相比肯定会更加细腻,在现实中还是缓动应用的较多,
下面的同样列出实现主要有几个点:

  • 效果是实现一个对象(obj)移动到目标位置(target)
  • 用之前先清一下定时器,防止导致出现存在多个定时器,无法停下来,导致出现bug;
  • 定时器间隔设为25ms是因为现在主流的大多是25ms效果比较好一点,具体你也可以根据需要改变;
  • step是指的步长,在这里的step是实现缓动效果的关键,step是通过目标点和当前位置的距离差来决定的,这样就会有随着距离减小会慢慢变小,也就是会有慢慢减速,先快后慢的效果
  • 清除定时器的时间点判断-这次就不用向匀速动画中那样通过手动在快接近目标点的时候将其赋值为目标点,因为这里上面的step都是除以10,并且也对step在0位置做了判断,所以可以达到当前位置等于目标位置,也就是可以顺利清除定时器;
    下面是具体代码实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function animate(obj, target) { //缓动动画  事实证明还是缓动效果比较细腻
    clearInterval(obj.timer); //防止重复调用,用前先清定时器
    obj.timer = setInterval(function() {
    var leader = obj.offsetLeft; //读取的时候用offsetTop确保也能读取到不是行内的样式
    var step = (target - leader) / 10;
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    //通过下面这个方法能够在控制台中体会到数据的渐变
    console.log("target:" + target + "---leader:" + leader + "---step:" + step);
    if (leader != target) {
    obj.style.left = leader + step + "px"; //赋值的时候就用top设置行间样式
    } else {
    clearInterval(obj.timer);
    }
    }, 25)
    }

下面是使用这个封装的animate实现的缓动动画效果
另外这个案例当中还穿插了一下无缝滚动的效果,能够实现最后一张平滑的切换到第一张,下面附上代码:

下面的代码并不是特别规范,只是站在初学者的角度通俗的将几个重要的点展示出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<body>
<div id='box'>
<div class="screen">
<ul>
<li><img src="images/1.jpg"></li>
<li><img src="images/2.jpg"></li>
<li><img src="images/3.jpg"></li>
<li><img src="images/4.jpg"></li>
<li><img src="images/5.jpg"></li>
</ul>
<ol>
</ol>
</div>
<div id="arr"><span id="left">&lt;</span><span id="right">&gt;</span></div>
</div>
</body>
</html>
<script>
var box = document.getElementById("box"),
screen = box.children[0],
ul = screen.children[0],
ullis = ul.children,
ol = screen.children[1],
imgWidth = screen.offsetWidth,
arr = document.getElementById("arr"),
arrLeft = document.getElementById("left"),
arrRight = document.getElementById("right"),
pic = 0,
square = 0,
timer = null,
ollis = ol.children;

<!-- 根据图片的数量生成小按钮 -->
for (var i = 0; i < ullis.length; i++) {
var li = document.createElement("li");
ol.appendChild(li);
li.innerHTML = i + 1;
}
ollis[0].className = "current";

var firstImg = ullis[0].cloneNode(true); //如果不加上.cloneNode(true),只是单纯的把li移动了,而不是重新复制一个
ul.appendChild(firstImg); //这样能够很好地实现无缝衔接;

// 根据按钮来让图片滚动
for (var j = 0; j < ollis.length; j++) {
ollis[j].index = j;
ollis[j].onmouseover = function() {
for (var k = 0; k < ollis.length; k++) {
ollis[k].className = "";
}
this.className = "current";
var target = -this.index * imgWidth;
animate(ul, target);
square = pic = this.index;
}
}
// 鼠标放到盒子上面清除定时器,并显示箭头
box.onmouseover = function() {
arr.style.display = "block";
clearInterval(timer);
}
// 鼠标离开盒子重新设置定时器,并隐藏箭头
box.onmouseout = function() {
arr.style.display = "none";
timer = setInterval(playnextR, 2000);
}

arrRight.onclick = function() {
playnextR();
}
arrLeft.onclick = function() {
playnextL();
}

//封装向右切换的动画函数
function playnextR() {
if (pic == ullis.length - 1) { //注意这里是pic == ullis.length-1,先前写成了pic == ollis.length-1,导致出现bug
ul.style.left = 0;
pic = 0;
}
pic++;
var target = -imgWidth * pic;
animate(ul, target);
if (square < ollis.length - 1) {
square++;
} else {
square = 0;
}
for (var i = 0; i < ollis.length; i++) {
ollis[i].className = "";
}
ollis[square].className = "current";
}

//封装向左切换的动画函数
function playnextL() {
if (pic == 0) {
ul.style.left = -imgWidth * (ullis.length - 1) + "px"; //后面的这个px一定要注意加上去;
pic = ullis.length - 1;
}
pic--;
var target = -imgWidth * pic;
animate(ul, target);
if (square > 0) {
square--;
} else {
square = ollis.length - 1;
}
for (var i = 0; i < ollis.length; i++) {
ollis[i].className = "";
}
ollis[square].className = "current";

}

//4.添加自动滚动
//相当于每秒钟按下一次右箭头
timer = setInterval(playnextR, 2000);