# 背景
需求场景:
后台管理系统:
(1)配置中支持上传视频、上传成功后封面缩略图展示,点击后自动播放视频;
(2)配置中支持上传多个文件;
前台系统:
(1)展示视频列表并点击播放;
(2)展示文件列表并点击下载;
# 说明
看需求似乎很简单,再加上本身antd-design已经封装好的Upload组件,功能强大且丰富;但是具体需求场景中还是有不少交互细节,也花了一些时间调试,为以后碰到类似场景更快速高效实现,记录和分享出来
# 上传视频且展示缩略图
- 上传视频处理:
获取视频数据,并执行上传方法;一般二进制处理,可以支持各类文件格式,本质视频也是文件的一种格式;这一步其实很简单,参考Upload组件的相关实例即可,
<Upload
multiple={true}
fileList={videoList}
listType="picture"
beforeUpload={(file) => {
const formData = new FormData();
formData.append('file', file, file.name);
request(`/upload/binary`, {
method: 'post',
body: formData,
}).then((res: any) => {
setVideoList([
...videoList,
{
name: file.name,
url: res.data,
thumbUrl: `${res?.data}`,
},
]);
});
}}
className={styles['upload-list-inline']}
>
<Button icon={<UploadOutlined />}>上传视频</Button>
<span className={styles['upload-tip']}>
仅支持 rm,rmvb, wmv,avi, mpg, mpeg,mp4等格式,单个视频最大不得超过500M。
</span>
</Upload>
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
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
上述代码listType字段设为“picture”,实例效果如下:
- 前台展示列表,demo代码如下:
<div className="introduction">
<div className="app-message-title">视频教程</div>
{videoList.map((item: FileProps, index: number) => {
return (
<div key={index} onClick={() => handleVideo(item)}>
<img
className="video-icon"
src={require("icon.png")}
/>
{/* <a href={item.url} className="file-name">
{item.name}
</a> */}
<span className="file-name">
{item.name}
</span>
</div>
);
})}
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(1)实现代码如下:被注释掉的代码:交互效果,点击直接新开页
上传的不同尺寸,播放时按原视频的宽高:
缺点:新开页打开,不利于用户操作
(2)点击后弹窗展示,实现思路是使用antd的Modal组件,承载视频播放组件:
<Modal
width={curVideo.width}
bodyStyle={{ height: curVideo.height }}
wrapClassName="video-modal"
footer={null}
visible={visible}
onCancel={() => {
setCurVideo(undefined);
setVisble(false);
}}
>
<video src={curVideo.url} controls preload="auto" autoPlay={true} />
</Modal>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 这里其实有一个问题,因为上传时不显示视频上传的像素,那么弹窗的宽高需要与视频的框高相同,所以上传的时候需要拿到视频的宽高:如何拿到视频宽高?
<Upload
multiple={true}
fileList={videoList}
listType="picture"
beforeUpload={(file) => {
console.log('fiel = ', file);
const videoUrl = URL.createObjectURL(file);
const videoObj = document.createElement("video");
videoObj.onloadedmetadata = function () {
URL.revokeObjectURL(videoUrl);
console.log("JJJJJ", videoObj.videoWidth, videoObj.videoHeight); // 拿到视频的宽高
// 执行上传的方法,获取外网路径,上传进度等
const formData = new FormData();
formData.append('file', file, file.name);
request(`/upload/binary`, {
method: 'post',
body: formData,
}).then((res: any) => {
setVideoList([
...videoList,
{
name: file.name,
url: res.data,
thumbUrl: `${res?.data}`, // 缩略图图片地址
width: videoObj.videoWidth,
height: videoObj.videoHeight,
},
]);
});
};
videoObj.src = videoUrl;
videoObj.load();
}}
className={styles['upload-list-inline']}
>
<Button icon={<UploadOutlined />}>上传视频</Button>
<span className={styles['upload-tip']}>
仅支持 rm,rmvb, wmv,avi, mpg, mpeg,mp4等格式,单个视频最大不得超过500M。
</span>
</Upload>
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
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
这样就解决了,Modal弹窗承载视频播放,Modal弹窗的宽高与视频的宽高一致;