最近项目有上传视频的需求,但 Element 的 el-upload上传视频后,回显异常,不会显示视频内容(如下图)
通过在网上查找截取视频第一帧的方法,自己稍加修改,得以正常显示封面,如下图:
本方法采用前端动态获取第一帧画面,后端不保存当前视频第一帧信息。这样做,好处是:修改及删除视频时,不用做额外的关联封面处理,减少交互以及省去服务器保存封面资源,不好的地方就是:如果视频过大,获取第一帧封面的时间会比较长,本人亲测,40几M的视频,差不多2-3秒左右加载封面出来,但针对此问题,可以先默认加载系统预设默认封面,待视频处理完后,再加载第一帧画面。
1. JS 中获取视频第一帧方法
- /**
- * 获取视频第一帧作为回显封面
- * @param file 至少应包含url信息,即 {url: ""}
- */
- getVideoCover(file) {
- let _self = this;
- _self.$set(file, 'videoUrl', _self.$utils.deepClone(file.url)); //备份视频源路径,用于后续预览展示
-
- const video = document.createElement("video") // 也可以自己创建video
- video.src = file.url // url地址 url跟 视频流是一样的
- file.url = videoDefCover; //设置默认封面,videoDefCover 为预制的默认封面,不需要可去除或替换成自己的
- let canvas = document.createElement('canvas') // 获取 canvas 对象
- const ctx = canvas.getContext('2d'); // 绘制2d
- video.crossOrigin = 'anonymous' // 解决跨域问题,也就是提示污染资源无法转换视频
- video.currentTime = 1 // 第一帧
-
- video.oncanplay = () => {
- console.log(video.clientWidth, video.clientHeight);
- canvas.width = video.clientWidth ? video.clientWidth : 320; // 获取视频宽度
- canvas.height = video.clientHeight ? video.clientHeight : 320; //获取视频高度
- // 利用canvas对象方法绘图
- ctx.drawImage(video, 0, 0, canvas.width,canvas.height)
- // 转换成base64形式
- let _videoFirstimgsrc = canvas.toDataURL ("image/png"); // 截取后的视频封面
- _self.$set(file, 'url', _videoFirstimgsrc); //重置文件的url为当前截取的封面,用于 el-upload展示
- video.remove();
- canvas.remove();
- }
- },
2. el-upload 设置
2.1 上传成功后回显调用
- handleUploadSuccess(response, file, fileList) { //为 el-upload on-success 方法实现
- let _self = this;
- _self.fileList = fileList;
- if (response.code != 0) {
- _self.$message({
- message: '附件上传失败',
- type: 'error'
- })
- _self.fileList.splice(_self.fileList.indexOf(file, 1))
- } else {
- let _fileName = file.name;
- if (_self.$utils.getFileIsVideo(_fileName)) { //getFileIsVideo 为我本地自定义判断是否是视频方法,可自己修改
- //视频附件,获取第一帧画面作为 封面展示
- _self.getVideoCover(file);
- }
- }
- },
2.2 页面编辑、数据回显
- /**
- * 查看详情时附件回显
- **/
- setFileList(_fileList) {
- let _self = this;
- if (_self.$utils.isNotEmpty(_fileList)) {
- for (let obj of _fileList) {
- //视频附件,获取第一帧画面作为 封面展示
- let _fileName = obj.name;
- if (_self.$utils.getFileIsVideo(_fileName)) { //getFileIsVideo为我自定义的判断是否是视频的方法,可以自己修改
- //视频附件,获取第一帧画面作为 封面展示
- _self.getVideoCover(obj);
- }
- }
- }
- _self.fileList = _fileList; //fileList 为 Element file-list 参数值
- },
至此处理完成。
预览时,在预览弹窗中判断是否是视频,如果是视频的话,直接取文件的 videoUrl 参数值进行加载展示。