uniapp 解决app端视频滚动错误、首次加载黑屏的问题(包含后续的视频播放、下载)

我的理解:出现app端视频滚动错误的原因是因为<video/> 组件在非H5端是原生组件,层级高于普通前端组件。首次加载黑屏的问题,我暂时还不知道原因

我的解决方案:获取视频第一帧转成图片展示

1、后端处理

刚开始在网上搜索解决办法都是在将video组件更换为image组件,地址仍写video的地址,在地址后面加上'?x-oss-process=video/snapshot,t_0,f_jpg'

后端给我返回的地址是预览视频地址,我加上这个是没有反应的。我试着用uniapp官网的视频地址,发现加不加这段都可以。

<image :disabled="false" :controls='false' :autoplay='false' :src="item+'?x-oss-process=video/snapshot,t_0,f_jpg'" mode=""></image>

官方视频地址跟我的视频地址的差别就是访问他的会直接下载视频,访问我的只是预览视频。所以我怀疑有这个的原因,跟后端沟通过,他说改成下载地址很麻烦。

最后的解决方法是当我访问视频的链接后面加了'?x-oss-process=video/snapshot,t_0,f_jpg',他就给我返回图片

2、前端处理:前端封装 video,结合renderjs把视频的第一帧转成图片展示

父组件页面:

<template>
    <view class="content image" @tap="showView(filePath)">
         <video-content :filePath="filePath"></video-content>
    </view>
</template>   
import VideoContent from './components/videoContent.vue';
export default {
    components: {
        VideoContent
    },
    methods: {
        showView(filePath) {
            uni.navigateTo({
                url: `/page/communication/components/videoView?filePath=${filePath}`
            })
        }
    }
}     

 

video-content组件页面

<template>
  <view class="videoContent">
    <!-- 播放按钮 -->
    <view class="video-cover">
      <image class="play-button" src="/static/communication/pc-play.png"></image>
    </view>
    <!-- 逻辑层调用视图层方法,采用监听data中变量改变的方法 -->
    <view id="canvas" class="canvas" :prop="newVal" :change:prop="canvas.create"></view>
    <!-- 逻辑层生成的图片回显 -->
    <image class="image" :src="demo" mode=""></image>
  </view>
</template>

 

<!-- 逻辑层script-->
<script>
export default {
  name: 'videoContent',
  props: {
    // 图片地址
    filePath: {
      type: String
    }
  },
  data() {
    return {
      demo: '',
    }
  },
  computed: {
    newVal() {
      return this.filePath
    }
  },
  onLoad() {

  },
  methods: {
    getDataURL(options) {
      this.demo = options.dataURL
    }
  }
}
</script>
<!-- 视图层script module对应HTML代码中view的id-->
<script module="canvas" lang="renderjs">
    export default {
        methods: {
            // 视图层创建base64图片
            create(newValue, oldValue, ownerInstance){
                // 第一次进入为空不操作
                if(newValue == null){
                    return
                }
                let video = document.createElement('video')
                video.setAttribute('crossOrigin', 'anonymous') // 处理跨域,H5需后台支持,请求的视频资源响应投标需有Access-Control-Allow-Origin
                video.setAttribute('src', newValue)
                video.setAttribute('width', 200)
                video.setAttribute('height', 200)
                video.setAttribute('preload', 'auto')
                // uni.chooseVideo选择视频,当选用手机拍摄的视频时,地址是相对地址,如 _doc/uniapp_temp_1650594368317/camera/1650594390147.mp4
                // 可播放,但是loadeddata一直不执行,会触发error事件,视频加载失败
                // 应先转换成本地地址
                video.addEventListener('loadeddata', function () {
                    console.log('视频第一帧加载完')
                    let canvas = document.createElement('canvas')
                    let width = video.width // canvas的尺寸和图片一样
                    let height = video.height
                    canvas.width = width
                    canvas.height = height
                    canvas.getContext('2d').drawImage(video, 0, 0, width, height) // 绘制canvas
                    const dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
                    // 传递数据给逻辑层
                    ownerInstance.callMethod('getDataURL',{
                        dataURL: dataURL
                   })
                    console.log('getVideoPoster-dataURL', dataURL.slice(0, 16)) 
              })
          
             video.addEventListener('error', err => {
                    console.log('视频加载失败', err)         
                })
            }
        }
    }
</script>

 

 

<style lang="scss" scoped>
.videoContent {
  position: relative;

  .video-cover {
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: rgba(1, 1, 1, .5);
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;

    .play-button {
      width: 40rpx;
      height: 40rpx;
      background-size: 50%;
      background-repeat: no-repeat;
      background-position: 50% 50%;
      cursor: pointer;
    }
  }

  .image {
    max-width: 160rpx;
    max-height: 260rpx;
  }
}
</style>

 

3、 点击,跳转页面实现视频播放、视频保存到本地相册

 

<template>
  <transition name="slide-fade">
    <view class="videoView">
      <cover-image class="cover-video" src="/static/communication/download.png" @tap="download"></cover-image>
      <video id="popupVideo" :src="videoUrl" autoplay :show-fullscreen-btn="false" :show-center-play-btn="false">
      </video>
    </view>
  </transition>
</template>

<script>
import http from '@/api/request'
import { toast } from '../../../utils'
export default {
  data() {
    return {
      videoUrl: ''
    }
  },
  onLoad({ filePath }) {
    this.videoUrl = http.config.fileUrl + filePath
  },
  methods: {
    download() {
      console.log('this.videoUrl', this.videoUrl)
      uni.downloadFile({
        url: this.videoUrl,
        success: (res) => {
          if (res.statusCode === 200) {
            uni.saveVideoToPhotosAlbum({
              filePath: res.tempFilePath,
              success: function () {
                toast("保存成功");
              },
              fail: function () {
                tToast("保存失败,请稍后重试");
              }
            });
          }
        }
      });
    }
  }
}
</script>

<style lang="scss" scoped>
.videoView {

  video {
    margin-top: 72rpx;
    height: calc(100% - 72rpx);
    width: 100%;
  }

  .close {
    padding: 12rpx;
    position: absolute;
    top: 0;
    right: 0;

    image {
      width: 48rpx;
      height: 48rpx;
    }
  }

  .cover-video {
    display: block;
    position: fixed;
    right: 15rpx;
    bottom: 15rpx;
    width: 70rpx;
    height: 70rpx;
    z-index: 999;
  }
}
</style>

 

posted @ 2023-05-19 09:00  Stitchhhhh  阅读(2332)  评论(0编辑  收藏  举报