vue项目获取网络视频/图片九宫格列表展示预览组件

今天有点时间,总结下前段时间在vue项目中做的移动端视频/图片上传查看组件遇到的一些问(大)题(坑),组件全部实现过程就不讲了,主要说其中遇到的问题以及解决方法,有不足之处请大神们拍砖指教

问题1:将获取尺寸不一的图片/视频在方格内展示

由于无法确定图片的尺寸大小,就决定使用js来控制样式(不拉伸图片,截取方格展示)

解决思路:将图片相对于父盒子上下左右居中显示,方法很多,选一个自己中意的就好了。js获取图片视频尺寸,若宽比高长,就以设置高为100%,反之就设置宽为100%,父盒子设置溢出隐藏。简单粗暴,就这样。

css实现https://vip.kingdee.com/article/7600

问题2:在mounted生命周期内获取图片/视频尺寸问题

理想没毛病,现实总是会挖很多坑等你。美美的想着,dom在mounted生命周期内已经挂在完了,这时候我去获取图片尺寸应该没毛病可以吧,得,是获取到,宽高全都是0!原因就是Dom已经加载了没错,可因为网络请求原因,图片/视频资源还没加载回来,以致数据都是0。图样图森破,尝试了很多方法,$nextTick也不管用。setTimeout设置一段时间后请求可以解决这个问题,但是对于请求时间的不确定性,以及强迫症晚期不允许我这么粗暴处理,继续想想方法,那就等图片/视频资源加载后再去获取宽高啊,聪明如我,哈哈哈

calcImgStyle(){ 
  //设置图片在方格内展示
  let imgArr = document.querySelectorAll(".img")
  for(let i=0;i<imgArr.length;i++){
    imgArr[i].onload = ()=>{          
      if(imgArr[i].width>imgArr[i].height){
        imgArr[i].style.height = '100%'          
      }else {
        imgArr[i].style.width = '100%'
      }
    }        
  }
}
问题3:如何获取视频图片作为预览封面

拿到的数据就是视频的url地址,并没有缩略图,怎么破,自己创造呗,网上找了很多资源,大家都差不多,将video隐藏,使用canvas来绘制一张video一帧,使用toDataURL将地址给创建的img图片的src就好。

几个注意点:

  1. 获取视频尺寸问题,我是选择在 loadeddata 事件后获取,目前没啥毛病
  2. 虽然你设置了autoplay在Safari视频也不会自动播放(我的是有音频的文件,不能静音),但是一定要设置autoplay才能自动触发video的loadeddata事件,所以需要设置autoplay,曾经被坑哭了
    可以了解更多video加载过程事件:http://www.w3school.com.cn/tags/av_event_loadeddata.asp
  3. 在mounted内干这事

代码:

captureVideoImage() {
  let videoArr = document.querySelectorAll(".video")    
  for(let i=0;i<videoArr.length;i++){
    //loadeddata当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时,会发生 loadeddata 事件。
    //浏览器支持:所有主流浏览器都支持 loadeddata 事件。注释:Internet Explorer 8 或更早的浏览器不支持该事件。
    let video = videoArr[i]
    video.addEventListener('loadeddata', function () {         
      let canvas = document.createElement('canvas')
      canvas.width = video.videoWidth //loadeddata事件后,获取视频宽高妥妥的
      canvas.height = video.videoHeight      
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
      let dataUrl = canvas.toDataURL('image/png')
      let pareantNode = video.parentNode
      let imgNode =  document.createElement('img')
      imgNode.src = dataUrl 
      if( video.videoWidth > video.videoHeight ){
        imgNode.style.height = '100%'          
      }else {
        imgNode.style.width = '100%'
      }                 
      pareantNode.appendChild(imgNode)       
      video.pause()          
    }, false)  
  } 
}
问题4:canvas绘制视频封面时,若视频非本地地址而是网络请求回来的地址,使用toDataURL会报安全问题错误

https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror

解决:设置video的标签属性crossorigin为anonymous,然后在视频加载后处理canvas。其中还需要后端配合设置CORS为所有*

 video.setAttribute('crossorigin', 'anonymous')
问题5:ios设备上video标签不自动加载

由于浏览器的限制,用户未点击之前呈现的是黑屏,即使设置了preload="auto"也无效,体验很糟糕。需要配合设置video的poster属性,手动设置视频封面。

video.setAttribute('poster', dataUrl);

解决思路:canvas获取视频的第一帧,赋值给poster属性
过程中遇到一个很坑很坑的事情:虽然你设置了autoplay在Safari视频也不会自动播放,但是一定要设置autoplay才能触发video的loadeddata事件,就是这里被坑哭的,呜呜呜。。。

问题6:video标签在ios设备上自动全屏播放问题

到此,似乎已经很满意很开心了,可是在ios设备上查看视频时,鸡肋的将视频自动全屏播放,不是我想要的样子,打死都不开心,找找找,人家是可以设置的,Down there:

https://stackoverflow.com/questions/22697311/webkit-playsinline-on-iphone

<video :src="item" class="swipe-video" v-else controls="controls" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow"></video>

终于相对满意了,开心,撒花花

最后附一下关键代码

data:
feedbackImages:['../static/images/test/img_1.jpg','../static/images/test/img_2.jpg','../static/images/test/img_3.png','../static/images/test/img_4.png','../static/images/test/video_1.mp4','http://www.source.com/video_2.mp4']
html:
<span v-for="(item,index) in feedbackImages" :key="item" @click.stop.prevent="view(index)" >
  <img :src="item" v-if="isImg(item)" class="img"/>
  <div class="video-con" v-else > 
    <video :src="item" class="swipe-video" x-webkit-airplay="allow" autoplay preload="auto" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow"></video>   
  </div>
</span>
获取视频封面作为缩略图:
captureVideoImage() {
  let videoArr = document.querySelectorAll(".video")    
  for(let i=0;i<videoArr.length;i++){
    //loadeddata当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时,会发生 loadeddata 事件。
    //浏览器支持:所有主流浏览器都支持 loadeddata 事件。注释:Internet Explorer 8 或更早的浏览器不支持该事件。
    let video = videoArr[i]
    video.addEventListener('loadeddata', function () {         
      let canvas = document.createElement('canvas')
      canvas.width = video.videoWidth 
      canvas.height = video.videoHeight 
      video.setAttribute('crossorigin', 'anonymous')//跨域设置,后端也需要设置CORS为*
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
      let dataUrl = canvas.toDataURL('image/png')
      let pareantNode = video.parentNode
      let imgNode =  document.createElement('img')
      imgNode.src = dataUrl 
      if( video.videoWidth > video.videoHeight ){
        imgNode.style.height = '100%'          
      }else {
        imgNode.style.width = '100%'
      }             
      pareantNode.appendChild(imgNode)       
      video.pause()          
    }, false)  
  } 
}
设置video封面海报poster:
setPoster() {
  let videoArr = document.querySelectorAll(".swipe-video")   
  for(let i=0;i<videoArr.length;i++){        
    let video = videoArr[i]
    video.setAttribute('crossorigin', 'anonymous')
    let canvas = document.createElement('canvas')
    canvas.width =video.videoWidth 
    canvas.height =video.videoHeight 
    video.addEventListener('loadeddata', function () {   
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
      let dataUrl = canvas.toDataURL('image/png')  
      video.setAttribute('poster', dataUrl);
      video.pause()
    }, false)  
  }
} 
Logo

前往低代码交流专区

更多推荐