图片轮播实现,按钮点播实现
1. 互斥代码抽取
1 | // 导航栏互斥-只能有一个元素有active类 |
2. 图片轮播
2.1. 思路
图片轮播实际是
- 图片列表中所有图片水平排布,每个图片宽度都是100%
- 而可视区宽度只有100%,除了第一张图片,其余图片只能被隐藏
- 图片列表每向左移动100% translateX(-100%),可视区显示的图片就变下一张
- 再加上移动过渡,实现图片轮播
⚠️但是,等到最后一张图片,图片列表应该移动回第一张图片 translateX(0)
- 这里还是用移动过渡的话,从最后一张图片移动到第一张图片的过渡像是视频的倒带
- 为了显示的连贯,复制第一张图片放到最后一张图片后
- 移动到复制的第一张图片后,
无动画的移动回到真正的第一张,再进行图片列表下一轮的前移
设置静止
- 当鼠标在图片列表上时,定时器关闭,不再进行图片的轮播
- 鼠标离开图片列表,定时器重启
2.2. html骨架原型
2.3. 轮播
count变量全程控制列表的移动
为什么移动到复制的最后一张图片后要定时500ms后移动到真正的第一张,而不是立即移动?
- 是使用定时器每2s执行一次move函数
- 等到photos移动至-500%时,说明到达复制的第一张图片,此时视觉上完成了“最后一张到第一张的移动”
- 如果立即执行移动至translateX(0),那可视区显示的还是第一张图片,要再等2s,移动至第二张图片。视觉上就是“第一张图片”出现了4s,重复显示,而不是连贯的轮播
- 将第一张的移动加到定时器中,就变为在等待移动到第二张的2s中,使用了0.5s先无过渡移动到第一张,1.5s后移动过渡到第二张,视觉上就是“最后一张 - 第一张 - 第二张”
1 | // main-top 部分 图片列表 |
2.4. 静止
1 | // 鼠标在图片上时定时器停止 |
3. 图片轮播下的按钮点播
3.1. 思路
按钮的不同选中状态
每个按钮的选中状态
互斥随图片轮播而不停被选中
当鼠标选中第几个按钮,可视区显示第几张图
3.2. html骨架原型
3.3. js代码
- count依然控制图片列表的移动,按钮指向第几张图,下一个2s后就应该播下一张
1 | // 按钮数组 |
4. 绝对定位下的图片轮播
4.1. 改变样式
将所有图片设置为绝对定位。第一张图片left:0,其余图片left:100%,都在第一张图片右边
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15.main-top .photos {
position: relative;
display: flex;
height: 298px;
}
.main-top .photos .item {
position: absolute;
left: 100%;
width: 100%;
/* 禁止缩放 */
flex-shrink: 0;
}
.main-top .photos .item:first-child {
left: 0;
}
4.2. 实现思路
比显示图片索引小的在左边,比显示图片索引大的在右边
- 让需要展示第二张图片时,第一张图片left:-100%,第二张位置left变为0,其余的还是left:100%
- 让需要展示第三张图片时,第一,二张图片left:-100%,第三张位置left变为0,其余的还是left:100%
- …
- 让需要展示最后一张(len-1)图片时,第一,二,…,(len-2)张图片left:-100%,最后一张位置left变为0,复制的第一张图片的left:100%
需要设置 previousIndex,记录原来的展示图片,实现移动效果
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
47let count = 0;
let previousIndex = 0;
let activeBtnEl = btns[0];
function move(){
photos.children[previousIndex].style.transition = "left 0.5s linear";
if(count == len){
activeButton(0);
}
else {
activeButton(count);
}
for (let j = 0; j <= len; j++) {
var nowItem = photos.children[j];
// 选中的索引图片
if(j === count){
nowItem.style.left = 0;
nowItem.style.transition = "left 0.5s linear";
}
else if( j < count){
nowItem.style.left = "-100%";
if(previousIndex !== j) {
nowItem.style.transition = "none";
}
}
else {
nowItem.style.left = "100%";
if(previousIndex !== j) {
nowItem.style.transition = "none";
}
}
}
// 到达最后一张后无动画回到第一张
if(count == len){
count = 0;
setTimeout(()=>{
// 取消过渡 500毫秒之后切换第一张
for (let i = 0; i < len; i++) {
photos.children[i].style.left = "100%";
photos.children[i].style.transition = "none";
}
photos.children[0].style.left = "0";
photos.children[0].style.transition = "none";
},500);
}
previousIndex = count;
}
4.3. 导航点播
1 | function activeButton(index) { |
5. 导航点播列表-左移
5.1. 思路
导航中每项的不同选中状态
每项的选中状态
互斥当鼠标选中第几项,可视区显示第几个列表
5.2. html骨架原型
王者荣耀CSS实现hero-skin的hero-content部分
5.3. js代码
1 | // 导航栏鼠标悬停-内容转变-向左 |
- 得到导航中的项数组
- 得到包裹多个列表的元素,每个项绑定该元素的前移距离
- true 表示添加移动过渡
1 | // 中间部分 - 导航栏 |
6. 导航点播列表-上移
6.1. 思路
导航中每项的不同选中状态
每项的选中状态
互斥当鼠标选中第几项,可视区显示第几个列表
6.2. html骨架原型
王者荣耀CSS实现content-center的dropdown部分
6.3. js代码
1 | function changeTranslateY(navs, len, list, flag){ |
- 得到导航中的项数组 A
- 得到包裹多个列表的元素 B
- A中每个项绑定B的上移距离,不添加移动过渡
1 | const contentHeroSubNavs = contentList.querySelectorAll(".hero-part .hero-type .item"); |
7. 导航点播列表-透明度
7.1. 思路
导航中每项的不同选中状态
每项的选中状态
互斥当鼠标选中第几项,可视区是逐渐显示第几个列表
7.2. html骨架原型
王者荣耀CSS实现content-center的content-list部分
王者荣耀CSS实现match-center的match-content部分
7.3. js代码
- 透明度的变换要先去除移动过渡,添加上自身的透明度过渡
- 不然会变为空白->内容显示的过渡
1 | function setOpacity(navs, len, num) { |
- 得到导航中的项数组 A
- 得到包裹多个列表的元素 B
- A中每个项绑定B的前移距离,不添加移动过渡
- A中每个项绑定B中每个项的透明度,对应项透明度为1,其余为0,添加透明度过渡
1 | // 内容中心导航栏 |
7.4. 消除元素
点击该元素使父元素不可见
原html骨架
1
2
3<div class="down-flow">
<a href="#" class="close">x</a>
</div>
1 | const closeBtn = document.querySelector(".down-flow .close"); |