真·轮播视频实现,附加缩略图功能

文章发布时间:

最后更新时间:

轮播视频的概念极其适用场景和实现方法

你真的需要轮播视频吗


图

不懂了吧 网上的轮播视频粗略看一圈下来,基本都是把轮播图的img图片位置换成了video视频,这种时间一到就直接下一张的轮播并不符合我们的需求
我们需要的是可以获取到视频播放长度,在视频彻底播放完之后才轮播到下一个视频的真轮播视频。这个时候就需要用到我们深厚且扎实的js功底,以我自己的轮播视频为例,先简单写一下基础的HTML和css布局

以下是HTML的部分

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
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>轮播视频</title>
<link rel="stylesheet" href="banner.css">
</head>
<body>
<!-- 2. banner start -->
<section id="banner">
<div class="videos-loop">
<div class="vp-area">
<video muted autoplay>
<source src="supreme.mp4" type="video/mp4">
</video>
</div>
<div class="thumbnails">
<div class="video-item playing">
<video muted>
<source src="supreme.mp4" type="video/mp4">
</video>
<div class="video-item-content">
<h3>There are birds that only land once in a lifetime.</h3>
<p>Do you want to know why? The time it landed was when it died.</p>
</div>
</div>
<div class="video-item">
<video muted>
<source src="nike.mp4" type="video/mp4">
</video>
<div class="video-item-content">
<h3>There are birds that only land once in a lifetime.</h3>
<p>Do you want to know why? The time it landed was when it died.Do you want to know why? The
time it landed was when it died.Do you want to know why? The time it landed was when it
died.Do you want to know why? The time it landed was when it died.Do you want to know why?
The time it landed was when it died.</p>
</div>
</div>
<div class="video-item">
<video muted>
<source src="adidas.mp4" type="video/mp4">
</video>
<div class="video-item-content">
<h3>There are birds that only land once in a lifetime.</h3>
<p>Do you want to know why? The time it landed was when it died.</p>
</div>
</div>
</div>
</div>
</section>
<!-- 2. banner end -->
</body>
<script src="banner.js"></script>
</html>

以下是CSS的部分

可以按需删减 ,此处的css随便写了几坨

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
/*banner start*/
#banner {
margin-top: 100px;
width: 100%;
background-color: #000;
box-sizing: border-box;
}
#banner .videos-loop {
width: 1460px;
display: flex;
justify-content: space-between;
margin: 0 auto;
}
#banner .videos-loop .vp-area {
width: 1100px;
height: calc(1100px * 9 / 16);
background-color: #161616;
}
#banner .videos-loop .vp-area video {
width: 1100px;
height: calc(1100px * 9 / 16);
}
#banner .videos-loop .thumbnails {
width: calc(100% - 1100px);
height: calc(1100px * 9 / 16);
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1e1e1e;
}
#banner .videos-loop .thumbnails .video-item {
width: 320px;
height: calc(120px);
padding: 10px;
display: flex;
transition: 0.5s ease-in-out;
border-radius: 4px;
cursor: pointer;
}
#banner .videos-loop .thumbnails .video-item video {
width: calc(320px * 0.4);
height: calc(calc(320px * 0.4) * 9 / 16);
object-fit: cover;
margin-right: 15px;
margin-top: 20px;
}
#banner .videos-loop .thumbnails .video-item .video-item-content {
flex: 1;
width: calc(calc(320px - calc(320px * 0.4)) - 15px);
}
#banner .videos-loop .thumbnails .video-item .video-item-content h3 {
width: inherit;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 16px;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 12px;
transition: 0.2s ease-in-out;
}
#banner .videos-loop .thumbnails .video-item .video-item-content p {
width: inherit;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
font-size: 16px;
color: #ccc;
transition: 0.2s ease-in-out;
}
#banner .videos-loop .thumbnails .video-item:hover {
background-color: #363636;
}
#banner .videos-loop .thumbnails .video-item:hover .video-item-content h3 {
color: #ffffff;
}
#banner .videos-loop .thumbnails .video-item:hover .video-item-content p {
color: #ccc;
}
#banner .videos-loop .thumbnails .video-item.playing {
background-color: #363636;
}
#banner .videos-loop .thumbnails .video-item.playing .video-item-content h3 {
color: #ffffff;
}
#banner .videos-loop .thumbnails .video-item.playing .video-item-content p {
color: #ccc;
}
@media (min-width: 992px) and (max-width: 1200px) {
#banner .videos-loop {
width: 1160px;
display: flex;
justify-content: space-between;
margin: 0 auto;
}
#banner .videos-loop .vp-area {
width: 800px;
height: calc(800px * 9 / 16);
background-color: #161616;
}
#banner .videos-loop .vp-area video {
width: 800px;
height: calc(800px * 9 / 16);
}
#banner .videos-loop .thumbnails {
width: calc(100% - 800px);
height: calc(800px * 9 / 16);
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1e1e1e;
}
}
@media (min-width: 700px) and (max-width: 992px) {
#banner .videos-loop {
width: 860px;
display: flex;
justify-content: space-between;
margin: 0 auto;
}
#banner .videos-loop .thumbnails {
width: calc(100% - 500px);
height: calc(650px * 9 / 16);
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1e1e1e;
}
#banner .videos-loop .vp-area {
width: 500px;
height: calc(500px * 9 / 16);
background-color: #161616;
}
#banner .videos-loop .vp-area video {
width: 500px;
height: calc(500px * 9 / 16);
margin-top: 50px;
}
}
@media (max-width: 700px) {
#banner .videos-loop {
width: 480px;
display: flex;
flex-direction: column;
justify-content: space-between;
margin: 0 auto;
}
#banner .videos-loop .vp-area {
width: 480px;
height: calc(500px * 9 / 16);
background-color: #161616;
}
#banner .videos-loop .vp-area video {
width: 480px;
height: calc(600px * 9 / 16);
}
#banner .videos-loop .thumbnails {
width: calc(100% - 500px);
height: calc(500px * 9 / 16);
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1e1e1e;
}
#banner .videos-loop .thumbnails .video-item {
width: 500px;
height: calc(120px);
padding: 10px;
display: flex;
transition: 0.5s ease-in-out;
border-radius: 4px;
cursor: pointer;
margin-bottom: 0;
}
#banner .videos-loop .thumbnails {
width: 480px;
height: calc(670px * 9 / 16);
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
background-color: #1e1e1e;
}
}
/*banner end*/

然后,把功能拆分,先实现轮播功能,这里就不细说了,直接上内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let currIndex = 0;
let playA = document.querySelector(".vp-area");
let thumb = [...document.querySelectorAll(".thumbnails > .video-item > video")];
let playTime = null;
let smWindow = undefined;

// 轮播视频的主视频播放区域
const bannerVideo = function (event) {
playA.children[0].removeEventListener("ended",bannerVideo);
document.querySelector(".playing").classList.remove("playing");
if (event.type != "click") currIndex = ++currIndex % thumb.length;
let videoDom =
`<video muted autoplay>
<source src="${thumb[currIndex].children[0].getAttribute("src")}" type="video/mp4">
</video>`;
playA.innerHTML=videoDom;
thumb[currIndex].parentElement.classList.add("playing");
playA.children[0].addEventListener("ended",bannerVideo);
}

然后就是缩略图功能,当鼠标移到缩略图范围内时,主视频区的视频暂停,开始播放缩略图视频,鼠标移开缩略图时,主视频继续播放,如果点击了指定的视频,则播放指定的视频

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
// 缩略图
const smallVideo = function () {
let videos = document.querySelectorAll(".video-item");
videos.forEach((el,index) => {

el.addEventListener("click", (event) => {
if (smWindow != undefined) {
thumb[smWindow].pause();
thumb[smWindow].currentTime = 0;
playA.children[0].play();
}
if (currIndex == index) return;
currIndex = index;
bannerVideo(event);
});

el.addEventListener("mouseover",() => {
playTime = setTimeout(() =>{
smWindow = index;
playA.children[0].pause();
thumb[index].play();
},100);
});

el.addEventListener("mouseleave", () => {
clearTimeout(playTime);
setTimeout(()=>{
smWindow = undefined;
thumb[index].pause();
thumb[index].currentTime = 0;
playA.children[0].play();
},100);
});

});
}

完整的js内容如下

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
(function () {

let currIndex = 0;//当前播放着的视频索引,默认为视频列表第一个
let smWindow = undefined;//视频列表中当前在后台播放的视频的索引
let playtime = null;//获取setTimeout返回的句柄,方便取消setTimeout
// 扩展运算符... 可以获取剩下的所有数组参数,这里的thumb相当于绑定了缩略图的三个视频,以数组的形式储存
let thumb = [...document.querySelectorAll(".thumbnails > .video-item > video")];
let playbanner = document.querySelector(".vp-area")// 轮播视频正在播放的播放区域


// 轮播视频的播放函数
const bannerVideo = function (event) {

// 触发了轮播视频的函数,就先判断视频是怎么被触发的,是视频放完了播下一个视频,还是因为缩略图被点击之后放的下一个
// 如果触发轮播函数的方式不是点击的,那就是视频放完了到下一个了,给索引先自增之后,在对视频列表的长度取余
//假设这里的索引是2,播放的是第三个视频,先自增之后就是3,3除以视频列表的长度3,3除3等于1,余数是0,
// 取余之后赋值给索引,所以索引就是0,这样播放完最后一个视频,就会重置索引到0,重新播放第一个视频
if (event.type != "click") currIndex = ++currIndex % thumb.length;
// 定义一下需要动态渲染的播放区域

let videoDom = `<video muted autoplay>
<!-- 用插值表达式动态渲染src路径 thumb这个数组里面第currIndex个参数的第一个子元素source的视频路径-->
<!-- getAttribute方法返回一个元素属性的值,这里返回的src相当于获取缩略图的的视频路径,根据缩略图的排序来划分视频播放列表-->
<source src="${thumb[currIndex].children[0].getAttribute("src")}" type="video/mp4">
</video>`

// 把这个动态渲染的html替换掉原本html里的静态内容
playbanner.innerHTML = videoDom;
// 给播放视频区域的第一个子元素,也就是主视频添加一个ended事件,当视频播放完之后,再次调用该函数
playbanner.children[0].addEventListener("ended",bannerVideo);

}
// 缩略图
const smBannerVideo = function () {
// 获取缩略图的类名
let videos = document.querySelectorAll(".video-item");
// 给缩略图循环添加三个事件
// callbackfn为数组中每个元素执行的函数,并携带两个参数
// element是数组中正在处理的当前元素 index是数组中正在处理的当前元素的索引
videos.forEach((el,index) =>{
el.addEventListener("click",(event)=>{
//如果有视频列表中有视频在后台播放,则暂停并重置它,然后恢复主视频的播放
if (smWindow != undefined) {
// pause方法暂停缩略图正在放的视频
thumb[smWindow].pause();
// currentTime使视频的播放进度归零
thumb[smWindow].currentTime = 0;
// play方法,让主视频区域的视频继续播放
playbanner.children[0].play();
}
if (currIndex == index) return;// 如果点击的是当前视频就退出
currIndex = index;//解决了pc端,鼠标移入视频列表区域中的视频时,点击该视频,播放区域主视频和视频列表中该视频同时播放的问题
bannerVideo(event);
})

el.addEventListener("mouseover",()=>{
setTimeout(() =>{
smWindow = index;
playbanner.children[0].pause();
thumb[index].play();
},100);
})

el.addEventListener("mouseleave",()=>{
setTimeout(()=>{
thumb[index].pause();
thumb[index].currentTime = 0;// 视频播放进度归0
playbanner.children[0].play();
},100);
})
});
}

const run = function () {
// 绑定第一个视频
let videoElem = playbanner.children[0];
// 给第一个视频添加事件,用ended事件,在视频播放完之后,触发轮播视频的函数
videoElem.addEventListener("ended", bannerVideo);
// 执行缩略图
smBannerVideo();
}
run();
})()

小结

那么到此为止,一套完整的轮播视频+缩略图就这么点了  
虽然细节没有说到位,但是反复看两遍源码,逻辑还是很简单的,点到为止,下播

打赏
Wechat
Alipay