最近项目有上传视频的需求,但 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 参数值进行加载展示。