Bom动画

Bom动画

1. 动画原理

image-20230302174411603

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: brown;
}
</style>
</head>

<body>
<div></div>
<script>
// 核心原理:通过定时器 setInterval() 不断移动盒子位置。
// 实现步骤:
// 1. 获得盒子当前位置
// 2. 让盒子在当前位置加上1个移动距离
// 3. 利用定时器不断重复这个操作
// 4. 加一个结束定时器的条件
// 5. 注意此元素需要添加定位,才能使用element.style.left
document.addEventListener('DOMContentLoaded', function (e) {
var div = document.querySelector('div')
var timer = setInterval(function () {
div.style.left = div.offsetLeft + 5 + 'px'
// 停住动画,清除定时器
if (div.offsetLeft >= 400) {
clearInterval(timer)
}
}, 30)
})
</script>
</body>

</html>

2. 动画函数封装

image-20230302174558860

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: brown;
}
span {
display: block;
position: absolute;
top: 100px;
width: 100px;
height: 100px;
background-color: rgb(42, 61, 165);
}
</style>
</head>

<body>
<div></div>
<span></span>
<script>
// 核心原理:通过定时器 setInterval() 不断移动盒子位置。
// 实现步骤:
// 1. 获得盒子当前位置
// 2. 让盒子在当前位置加上1个移动距离
// 3. 利用定时器不断重复这个操作
// 4. 加一个结束定时器的条件
// 5. 注意此元素需要添加定位,才能使用element.style.left

document.addEventListener('DOMContentLoaded', function (e) {
var div = document.querySelector('div')
var span = document.querySelector('span')

// 动画函数封装
// object目标对象, target目标位置
function animate(object, target) {
var timer = setInterval(function () {
object.style.left = object.offsetLeft + 5 + 'px'
// 停住动画,清除定时器
if (object.offsetLeft == target) {
clearInterval(timer)
}
}, 30)
}
// 调用动画函数
animate(div, 300)
animate(span,200)
})

</script>
</body>

</html>

3. 动画函数给不同元素记录不同定时器

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: brown;
color: aliceblue;
text-align: center;
line-height: 100px;
}

span {
display: block;
position: absolute;
top: 200px;
width: 100px;
height: 100px;
background-color: rgb(42, 61, 165);
color: aliceblue;
text-align: center;
line-height: 100px;
}
</style>
</head>

<body>
<button>click blue</button>
<div></div>
<span></span>
<script>
// 核心原理:通过定时器 setInterval() 不断移动盒子位置。
// 实现步骤:
// 1. 获得盒子当前位置
// 2. 让盒子在当前位置加上1个移动距离
// 3. 利用定时器不断重复这个操作
// 4. 加一个结束定时器的条件
// 5. 注意此元素需要添加定位,才能使用element.style.left

document.addEventListener('DOMContentLoaded', function (e) {
var div = document.querySelector('div')
var span = document.querySelector('span')
var btn = document.querySelector('button')

// 动画函数封装
// object目标对象, target目标位置
// object.timer给不同的元素指定了不同的定时器
function animate(object, target) {
// bug解决方法:只让一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(object.timer)
object.timer = setInterval(function () {
object.style.left = object.offsetLeft + 5 + 'px'
if (object.offsetLeft == target) {
// 停住动画,清除定时器
// btn.disabled=true
clearInterval(object.timer)
}
object.innerHTML = object.offsetLeft + 'px'
}, 30)
}
// 调用动画函数
animate(div, 300)
btn.addEventListener('click', function () {
// bug:当我们不断点击按钮,这个元素的速度会越来越快,且不断调用动画函数,因为开启了太多的定时器
animate(span, 100)
})

})

</script>
</body>

</html>

4. 缓动动画

image-20230302174901579

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

div {
position: absolute;
left: 0;
margin-top: 50px;
width: 100px;
height: 100px;
background-color: blueviolet;
color: aliceblue;
text-align: center;
line-height: 100px;
}
</style>
</head>

<body>
<button class="btn1">click200</button>
<button class="btn2">click300</button>

<div></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
// 获取事件源
var btn1 = document.querySelector('.btn1')
var btn2 = document.querySelector('.btn2')
var div = document.querySelector('div')

// 封装动画函数
// var obj = {};
// obj.name = 'andy';
// object目标对象, duration目标位置或延迟
function animate(object, duration) {
// bug解决方法:只让一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(object.timer)
object.timer = setInterval(function () {
// 动画偏移量
// 把每次加10 这个步长改为一个慢慢变小的值
// object.style.left = object.offsetLeft + 10 + 'px'
//Math.ceil向上取整,Math.floor向下取整
// var step = Math.ceil((duration - object.offsetLeft) / 10)
var step = (duration - object.offsetLeft) / 10
// 当我们点击按钮时候,判断步长是正值还是负值
// 1.如果是正值,则步长往大了取整
// 2.如果是负值,则步长 向小了取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
object.style.left = object.offsetLeft + step + 'px'
if (object.offsetLeft == duration) {
// btn.disabled = true
// 停住动画,清除定时器
clearInterval(object.timer)
}
object.innerHTML = object.offsetLeft + 'px'
}, 15)
}

// 启动动画
btn1.addEventListener('click', function () {
animate(div, 100)
})
btn2.addEventListener('click', function () {
animate(div, 300)
})
})

// 匀速动画 就是 盒子是当前的位置 + 固定的值 10
// 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)

// 缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
// 思路:
// 1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
// 2. 核心算法: (目标值 - 现在的位置) / 10 做为每次移动的距离步长
// 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
// 4. 注意步长值需要取整

</script>
</body>

</html>

5. 回调函数

image-20230302175057013

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

div {
position: absolute;
left: 0;
margin-top: 50px;
width: 100px;
height: 100px;
background-color: blueviolet;
color: aliceblue;
text-align: center;
line-height: 100px;
}
</style>
</head>

<body>
<button class="btn1">click200</button>
<button class="btn2">click300</button>

<div></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
// 获取事件源
var btn1 = document.querySelector('.btn1')
var btn2 = document.querySelector('.btn2')
var div = document.querySelector('div')

// 封装动画函数
// var obj = {};
// obj.name = 'andy';
// object目标对象, duration目标位置或延迟
function animate(object, duration, callback) {
// bug解决方法:只让一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(object.timer)
object.timer = setInterval(function () {
// 动画偏移量
// 把每次加10 这个步长改为一个慢慢变小的值
// object.style.left = object.offsetLeft + 10 + 'px'
//Math.ceil向上取整,Math.floor向下取整
// var step = Math.ceil((duration - object.offsetLeft) / 10)
var step = (duration - object.offsetLeft) / 10
// 当我们点击按钮时候,判断步长是正值还是负值
// 1.如果是正值,则步长往大了取整
// 2.如果是负值,则步长 向小了取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
object.style.left = object.offsetLeft + step + 'px'
if (object.offsetLeft == duration) {
// 停住动画,清除定时器
clearInterval(object.timer)
// 回调函数写的位置:定时器结束的位置。
if (callback) { callback() }
}
object.innerHTML = object.offsetLeft + 'px'
}, 15)
}

// 启动动画
btn1.addEventListener('click', function () {
animate(div, 100)
})
btn2.addEventListener('click', function () {
animate(div, 300, color)
function color() {
div.style.backgroundColor = 'brown'
}
})
})

// 匀速动画 就是 盒子是当前的位置 + 固定的值 10
// 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)

// 缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
// 思路:
// 1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
// 2. 核心算法: (目标值 - 现在的位置) / 10 做为每次移动的距离步长
// 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
// 4. 注意步长值需要取整

// 回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执
// 行完之后,再执行传进去的这个函数,这个过程就叫做回调。
// 回调函数写的位置:定时器结束的位置。

</script>
</body>

</html>

6. 封装完整动画函数

image-20230302175145234

7. 案例

7.1 右侧滑动

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
.move {
position: fixed;
bottom: 100px;
right: 0;
width: 40px;
height: 40px;
background-color: purple;
line-height: 40px;
color: white;
width: 40px;
height: 40px;
text-align: center;
cursor: pointer;
}

.con {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 40px;
text-align: center;
background-color: purple;
text-align: center;
z-index: -1;
/* transition: all 0.5s; */
}

/* .move:hover .con{
transform: translateX(-160px);
} */
</style>
<script src="./19-animate.js"></script>
</head>

<body>
<div class="move">
<span></span>
<div class="con">问题反馈</div>
</div>
<script>
// document.addEventListener("DOMContentLoaded", function () {
move = document.querySelector('.move')
con = document.querySelector('.con')
// move.innerHTML = con.offsetLeft
move.addEventListener('mouseover', function (e) {
// animate(object, duration, callback)
var distance = -(con.offsetWidth - this.offsetWidth)// con盒子移动距离
// 回调函数
function arrow() {
move.children[0].innerHTML = '☛'
}
animate(con, distance, arrow)
})
move.addEventListener('mouseout', function (e) {
// 回调函数
function arrow() {
move.children[0].innerHTML = '☚'
}
animate(con, 0, arrow)
})
// })
</script>
</body>

</html>

7.2 原生轮播

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}

/* 轮播图容器 */
.container {
width: 550px;
height: 300px;
margin: 200px auto;
/* background-color: blueviolet; */
overflow: hidden;
position: relative;
}

/* 左右按钮 */
.btn-l,
.btn-r {
position: absolute;
width: 50px;
height: 50px;
background-color: rgba(240, 248, 255, 0.547);
text-align: center;
line-height: 50px;
border-radius: 50%;
color: white;
font-size: 30px;
font-weight: bold;
z-index: 1;
display: none;
text-decoration: none;
}

.btn-l {
left: 0;
top: 50%;
transform: translateY(-50%);
}

.btn-r {
right: 0;
top: 50%;
transform: translateY(-50%);
}

/* 轮播指示点 */
ol {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
list-style: none;
z-index: 1;
}

ol li {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid #fff;
float: left;
margin-right: 5px;
cursor: pointer;
}

ol .current {
background-color: #fff;
}

/* 轮播图 */
ul {
list-style: none;
width: 2200px;
height: 100%;
position: absolute;
top: 0;
left: 0;
}

ul li {
width: 550px;
height: 100%;
float: left;
}

ul li a img {
width: 100%;
height: 100%;
}

/* ul li:nth-child(1) {
background-color: brown;
}

ul li:nth-child(2) {
background-color: blue;
}

ul li:nth-child(3) {
background-color: greenyellow;
} */
</style>
</head>

<body>
<div class="container">

<!-- 左右按钮 -->
<a href="javascript:;" class="btn-l">&larr;</a>
<a href="javascript:;" class="btn-r">&rarr;</a>

<!-- 轮播指示点 -->
<ol></ol>

<!-- 轮播图 -->
<ul>
<li>
<a href=""><img src="./images/1001.jpg" alt="img" srcset="" class="lunboImg"></a>
</li>
<li>
<a href=""><img src="./images/1002.jpg" alt="img" srcset="" class="lunboImg"></a>
</li>
<li>
<a href=""><img src="./images/1003.jpg" alt="img" srcset="" class="lunboImg"></a>
</li>
</ul>
</div>

<!-- 引入封装好的动画函数 -->
<script src="./19-animate.js"></script>
<script>
// 轮播图也称为焦点图,是网页中比较常见的网页特效。
// 功能需求:
// 1.鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
// 2、动态生成小圆圈
// 3.点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。
// 4.图片播放的同时,下面小圆圈模块跟随一起变化。
// 5.点击小圆圈,可以播放相应图片。
// 6.鼠标不经过轮播图,轮播图也会自动播放图片。
// 7.鼠标经过,轮播图模块, 自动播放停止。

document.addEventListener("DOMContentLoaded", function (e) {

// 1.鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
// ③ 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
// ④ 显示隐藏 display 按钮。

var container = document.querySelector('.container')
var btnL = document.querySelector('.btn-l')
var btnR = document.querySelector('.btn-r')
var ul = document.querySelector('ul')

container.addEventListener('mouseover', function (e) {
btnL.style.display = 'block';
btnR.style.display = 'block';
// 问题5的解决
clearInterval(timer)
timer = null
})
container.addEventListener('mouseout', function (e) {
btnL.style.display = 'none';
btnR.style.display = 'none';
// 问题5的解决
timer = setInterval(function () {
// tips:手动调用
btnR.click()
}, 2000)
})

// 2、小圆圈问题
// 2.1 动态生成小圆圈
// ① 动态生成小圆圈
// ② 核心思路:小圆圈的个数要跟图片张数一致
// ③ 所以首先先得到ul里面图片的张数(图片放入li里面,所以就是li的个数)
// ④ 利用循环动态生成小圆圈(这个小圆圈要放入ol里面)
// ⑤ 创建节点 createElement(‘li’)
// ⑥ 插入节点 ol. appendChild(li)
var ol = document.querySelector('ol')
var ulLis = ul.children

for (var i = 0; i < ulLis.length; i++) {
var dot = document.createElement('li')
ol.appendChild(dot)
}
// 2.2第一个小圆圈需要添加 current 类
// ⑦ 第一个小圆圈需要添加 current 类
ol.children[0].className = 'current'

// 2.3 点击小圆圈变色(排他思想)
// ① 小圆圈的排他思想
// ② 点击当前小圆圈,就添加current类
// ③ 其余的小圆圈就移除这个current类
// ④ 注意: 我们在刚才生成小圆圈的同时,就可以直接绑定这个点击事件了。
// ol.children,ol的所有li,即为所谓的所有小圆圈dot
for (var i = 0; i < ol.children.length; i++) {
// 我们可以在生成小圆圈的时候,给它设置一个自定义属性
ol.children[i].setAttribute('index', i);

// 小圆圈点击事件
ol.children[i].addEventListener('click', function () {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
this.className = 'current'

// 2.4点击小圆圈滚动图片
// ① 点击小圆圈滚动图片
// ② 此时用到animate动画函数,将js文件引入(注意,因为index.js 依赖 animate.js 所以,animate.js 要写到 index.js 上面)
// ③ 使用动画函数的前提,该元素必须有定位
// ④ 注意是ul 移动 而不是小li
// ⑤ 滚动图片的核心算法: 点击某个小圆圈 , 就让图片滚动 小圆圈的索引号乘以图片的宽度做为ul移动距离
// ⑥ 此时需要知道小圆圈的索引号, 我们可以在生成小圆圈的时候,给它设置一个自定义属性,点击的时候获取这个自定义属性即可。

// 点击的时候获取这个自定义属性即可
var indexes = this.getAttribute('index')
// 问题4的bug解决
num = indexes
circle = indexes
// ⑤ 滚动图片的核心算法: 点击某个小圆圈 , 就让图片滚动 小圆圈的索引号乘以图片的宽度做为ul移动距离
var lunboImg = document.querySelector('.lunboImg');
var moveDistance = indexes * lunboImg.offsetWidth
// ④ 注意是ul 移动 而不是小li
animate(ul, -moveDistance)
})
}

// 3、左右按钮点击滑动
// ① 点击右侧按钮一次,就让图片滚动一张。
// ② 声明一个变量num, 点击一次,自增1, 让这个变量乘以图片宽度,就是 ul 的滚动距离。
// ③ 图片无缝滚动原理
// ④ 把ul 第一个li 复制一份,放到ul 的最后面
// ⑤ 当图片滚动到克隆的最后一张图片时, 让ul 快速的、不做动画的跳到最左侧: left 为0
// ⑥ 同时num 赋值为0,可以从新开始滚动图片了

// 在事件点击发生之前把ul 第一个li 复制一份,放到ul 的最后面
var firstLi = ul.children[0].cloneNode(true);
ul.appendChild(firstLi)
var num = 0
var circle = 0
// 防止轮播图按钮连续点击造成播放过快。
// 节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
// 核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
// 开始设置一个变量var flag= true;
// If(flag){flag = false; do something} 关闭水龙头
// 利用回调函数动画执行完毕, flag = true 打开水龙头
var flag = true
btnR.addEventListener("click", function () {
if (flag) {
flag = !flag //关闭节流阀
if (num == ul.children.length - 1) {
ul.style.left = 0 + 'px'
num = 0
}
num++
var lunboImg = document.querySelector('.lunboImg');
var nextDistance = num * lunboImg.offsetWidth
animate(ul, -nextDistance, function () {
flag = true
})

// 4、点击右侧按钮, 小圆圈跟随变化
// ① 点击右侧按钮, 小圆圈跟随变化
// ② 最简单的做法是再声明一个变量circle,每次点击自增1,注意,左侧按钮也需要这个变量,因此要声明全局变量。
// ③ 但是图片有5张,我们小圆圈只有4个少一个,必须加一个判断条件
// ④ 如果circle == 4 就 从新复原为 0
circle++
// if (circle == ol.children.length) {
// circle = 0
// }
circle = circle == ol.children.length ? 0 : circle

// 调用circleMove()
circleMove()
}
})

function circleMove() {
// 先清除其余小圆圈的current
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = ''
}
// 留下当前的小圆圈的current
ol.children[circle].className = 'current'
}

btnL.addEventListener("click", function () {
if (flag) {
flag = !flag
if (num == 0) {
num = ul.children.length - 1
ul.style.left = -num * container.offsetWidth + 'px'
}
num--
var lunboImg = document.querySelector('.lunboImg');
var nextDistance = num * lunboImg.offsetWidth
animate(ul, -nextDistance,function () {
flag=true
})

// 4、点击右侧按钮, 小圆圈跟随变化
// ① 点击右侧按钮, 小圆圈跟随变化
// ② 最简单的做法是再声明一个变量circle,每次点击自增1,注意,左侧按钮也需要这个变量,因此要声明全局变量。
// ③ 但是图片有5张,我们小圆圈只有4个少一个,必须加一个判断条件
// ④ 如果circle < 0 就 小圆圈改为第最后小圆圈
circle--
// if (circle < 0) {
// circle = ol.children.length - 1
// }
circle = circle < 0 ? ol.children.length - 1 : circle

// 调用circleMove()
circleMove()
}

})

// 5、自动播放功能
var timer = setInterval(function () {
// tips:手动调用
btnR.click()
}, 2000)
})
</script>
</body>

</html>

7.3 返回顶部

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.slider-bar {
position: absolute;
right: 7%;
top: 300px;
width: 45px;
height: 130px;
background-color: pink;
}

.w {
width: 80%;
margin: 10px auto;
}

.header {
height: 150px;
background-color: purple;
}

.banner {
height: 250px;
background-color: skyblue;
}

.main {
height: 1000px;
background-color: yellowgreen;
}

span {
display: none;
position: absolute;
bottom: 0;
background-color: brown;
text-align: center;
color: aliceblue;
cursor: pointer;
}
</style>
</head>

<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
var header = document.querySelector('.header');

// banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
var bannerTop = banner.offsetTop
// 当我们侧边栏固定定位之后应该变化的数值
var sliderbarTop = sliderbar.offsetTop - bannerTop
// 获取main 主体元素
var main = document.querySelector('.main')
var goBack = document.querySelector('.goBack')
var mainTop = main.offsetTop

// 2. 页面滚动事件 scroll
document.addEventListener('scroll', function () {
// console.log(11);
// window.pageYOffset 页面被卷去的头部
// console.log(window.pageYOffset);
// 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
// 或者大于等于header.offsetHeight
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed'
sliderbar.style.top = sliderbarTop + 'px'
} else {
sliderbar.style.position = 'absolute'
sliderbar.style.top = ''
}
// 4. 当我们页面滚动到main盒子,就显示 goback模块
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block'
} else {
goBack.style.display = ''
}
})

// 案例:仿淘宝固定右侧侧边栏
// 1.原先侧边栏是绝对定位
// 2. 当页面滚动到一定位置,侧边栏改为固定定位
// 3. 页面继续滚动,会让 返回顶部显示出来

// 案例分析
// ① 需要用到页面滚动事件 scroll 因为是页面滚动,所以事件源是 document
// ② 滚动到某个位置,就是判断页面被卷去的上部值。
// ③ 页面被卷去的头部:可以通过window.pageYOffset 获得 如果是被卷去的左侧 window.pageXOffset
// ④ 注意,元素被卷去的头部是 element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset
// ⑤ 其实这个值 可以通过盒子的 offsetTop 可以得到,如果大于等于这个值,就可以让盒子固定定位了

// 5、当我们点击了返回顶部,就让窗口滚动到页面的最上方
// 1. 带有动画的返回顶部
// 2. 此时可以继续使用我们封装的动画函数
// 3. 只需要把所有的left 相关的值改为 跟 页面垂直滚动距离相关就可以了
// 4. 页面滚动了多少,可以通过 window.pageYOffset 得到
// 5. 最后是页面滚动,使用 window.scroll(x,y)

goBack.addEventListener('click', function () {
// 里面的坐标不加px
// window.scroll(0, 0)
animate(window, 0)

function animate(object, duration, callback) {
// bug解决方法:只让一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(object.timer)
object.timer = setInterval(function () {
// 动画偏移量
// object.style.left = object.offsetLeft + 10 + 'px'
// 把每次加10 这个步长改为一个慢慢变小的值
var step = (duration - window.pageYOffset) / 10
// 当我们点击按钮时候,判断步长是正值还是负值
// 1.如果是正值,则步长往大了取整
// 2.如果是负值,则步长 向小了取整
//Math.ceil向上取整,Math.floor向下取整
// var step = Math.ceil((duration - object.offsetLeft) / 10)
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// object.style.left = window.pageYOffset + step + 'px'
// 里面的坐标不加px
window.scroll(0, window.pageYOffset + step)

if (window.pageYOffset == duration) {
// 停住动画,清除定时器
clearInterval(object.timer)
// 回调函数写的位置:定时器结束的位置。
// if (callback) { callback() }
callback && callback()
}
// object.innerHTML = object.offsetLeft + 'px'
}, 15)
}
})
</script>
</body>

</html>

7.4 筋斗云

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
<!DOCTYPE html>
<html lang="en">

<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>Document</title>
<style>
* {
margin: 0;
padding: 0
}

ul {
list-style: none;
}

body {
background-color: black;
}

.c-nav {
width: 900px;
height: 42px;
background: #fff url(images/rss.png) no-repeat right center;
margin: 100px auto;
border-radius: 5px;
position: relative;
}

.c-nav ul {
position: absolute;
}

.c-nav li {
float: left;
width: 83px;
text-align: center;
line-height: 42px;
}

.c-nav li a {
color: #333;
text-decoration: none;
display: inline-block;
height: 42px;
}

.c-nav li a:hover {
color: rgb(238, 13, 13);
}

.cloud {
position: absolute;
left: 0;
top: 0;
width: 83px;
height: 42px;
background: url(images/cloud.gif) no-repeat;
}
</style>
</head>

<body>
<div class="c-nav" id="c-nav">
<span class="cloud"></span>
<ul>
<li class="current"><a href="javascript:;">首页新闻</a></li>
<li><a href="javascript:;">师资力量</a></li>
<li><a href="javascript:;">活动策划</a></li>
<li><a href="javascript:;">企业文化</a></li>
<li><a href="javascript:;">招聘信息</a></li>
<li><a href="javascript:;">公司简介</a></li>
<li><a href="javascript:;">我是佩奇</a></li>
<li><a href="javascript:;">啥是佩奇</a></li>
</ul>
</div>
<script src="19-animate.js"></script>
<script>
// 1. 利用动画函数做动画效果
// 2. 原先筋斗云的起始位置是0
// 3. 鼠标经过某个小li,把当前小li的offsetLeft 位置做为目标值即可
// 4. 鼠标离开某个小li,就把目标值设为 0
// 5. 如果点击了某个小li, 就把li当前的位置存储起来,做为筋斗云的起始位置
window.addEventListener('load', function () {
// 1、获取元素
var cloud = document.querySelector('.cloud');
var c_nav = document.querySelector('.c-nav');
var li = c_nav.querySelectorAll('li');

// 2、给所有的li绑定事件
// 这个current 做为筋斗云的起始位置
var current = 0;
for (var i = 0; i < li.length; i++) {
// (1) 鼠标经过把当前小li 的位置做为目标值
li[i].addEventListener('mouseenter', function () {
animate(cloud, this.offsetLeft)
})
// (2) 鼠标离开就回到起始的位置
li[i].addEventListener('mouseleave', function () {
animate(cloud, current)
})
// (3) 当我们鼠标点击,就把当前位置做为目标值
li[i].addEventListener('click', function () {
current = this.offsetLeft;
});
}
})
</script>
</body>

</html>