记录一下在uni-app我的项目中遇到的一些问题。

一、抉择视频并上传,播放

展现:

全屏播放:

1、<video>在非H5端图层太高的问题

安卓APP中,因为<video>是原生组件,层级高于一般前端组件,笼罩其须要应用<cover-view>、<cover-image>,但要在<video>开始完结标签之间。
自定义播放按钮,删除按钮都能够应用这些标签实现。
但展现抉择的视频时,弹出抉择框(如picker),就无奈用这些标签实现层级高于<video>。
实现形式:展现时用view,播放时用<video>全屏播放。

html局部

<!-- 展现视频 --><!-- #ifdef APP-PLUS || H5 --><view :id="`${item.id}`" class="video">  <image class="video-poster" :src="item.posterUrl"/>  <image v-if="clearable" class="video-clear-btn" src="/static/clear.png" @click="deleteFile(item, index)"/>  <image class="video-play-btn" src="/static/play.png" @click="toPlayVideo(item.url)"/></view><!-- #endif --><!-- 全屏播放视频 --><video  class="full-play-video"  id="fullScreenVideo"  v-if="videoUrl"  :src="videoUrl"  object-fit="contain"  @fullscreenchange="fullscreenchange"  @error="onVideoError"/>

js局部

   mounted() {        // #ifdef APP-PLUS || H5     this.videoContext = uni.createVideoContext('fullScreenVideo')     // #endif     // #ifdef MP-WEIXIN     this.videoContext = uni.createVideoContext('fullScreenVideo', this)     // #endif    },    beforeDestroy() {      clearTimeout(this.timer)      this.timer = null   },     methods: {     toPlayVideo(url) {        this.videoUrl = url //.split('?')[0]        this.timer = setTimeout(() =>{          // #ifdef APP-PLUS || H5          this.videoContext = uni.createVideoContext('fullScreenVideo')          // #endif          // #ifdef MP-WEIXIN          this.videoContext = uni.createVideoContext('fullScreenVideo', this)          // #endif         // 微信开发工具不失效,要真机测试          this.videoContext.requestFullScreen({            direction: 0          })                    this.videoContext.play()        }, 100)      },      fullscreenchange(e) {        if(!e.detail.fullScreen) {          this.videoContext.stop()          this.videoUrl = false        }      },      onVideoError(err) {        console.log('播放视频失败:', err)      },      deleteFile(file, index) {        uni.showModal({            title: '提醒',            content: '您确定要删除此项吗?',            success: res => {                if (res.confirm) {              this.$emit('delete-item', { file, index })            }          }        })      },    }

2、获取视频的封面

展现视频的view外面,要用一个图片作为视频的封面,能够用视频的首帧。
获取视频的封面,用到renderjs,通过canvas实现。

html局部

<!-- #ifdef APP-VUE || H5 --><view :prop="videos" :change:prop="rdVideo.getAllPoster" style="opacity: 0;"></view><!-- #endif -->

js局部

<!-- #ifdef APP-VUE || H5 --><script module="rdVideo" lang="renderjs">  import mixinVideo from './video-poster.js'  // 监听videos, 有更改调用rdVideo.getAllPoster办法获取视频封面  export default {    mixins: [mixinVideo]  }  </script><script>export default {  data() {    return {      videos: []    }   }  methods: {    // 获取视频封面后,调用此办法更新视频数据    updateVideos(newVal) {      this.videos = newVal    },  }}</script><!-- #endif -->

video-poster.js

const mixinVideo = {  methods: {    getVideoPoster(url) {      return new Promise(function (resolve, reject) {        let video = document.createElement('video')        video.setAttribute('crossOrigin', 'anonymous') // 解决跨域,H5需后盾反对,申请的视频资源响应招标需有Access-Control-Allow-Origin        video.setAttribute('src', url)        video.setAttribute('width', 400)        video.setAttribute('height', 400)        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          console.log('getVideoPoster-dataURL', dataURL.slice(0, 16))           resolve(dataURL)        })                video.addEventListener('error', err => {          console.log('视频加载失败', err)                   reject(err)        })      })    },    async getAllPoster(newVal, oldVal, owner, instance) {      console.log('执行getAllPoster')      // renderjs中,监听的属性videos是一个数组,寄存的是选取的视频信息           // 删除,或updateVideos更新后(长度一样)      if(newVal.length <= oldVal.length) return      // 有默认值或增加时      const newList = []      for(const item of newVal) {        // 已获取视频封面的不再反复获取        if(item.posterUrl !== undefined) {          newList.push({ ...item })          continue        }          try {          let url = item.url          // 拍摄视频:_doc/uniapp_temp_1650594368317/camera/1650594390147.mp4          // 网络视频:https://          // 本地视频:file://          if(!item.url.includes('file://') && !item.url.includes('https://')) {            // 将本地URL门路转换成平台绝对路径            // 如输出url为“_doc/a.png”:            // Android平台转换后的门路为“/storage/sdcard0/Android/data/io.dcloud.HBuilder/.HBuilder/apps/HBuilder/doc/a.png”;            // #ifdef APP-VUE            url =  'file://' + plus.io.convertLocalFileSystemURL(item.url)            // #endif             }          const dataUrl = await this.getVideoPoster(url)          newList.push({ ...item, posterUrl: dataUrl })        } catch (err) {          newList.push({ ...item })        }      }      this.$ownerInstance.callMethod('updateVideos', newList)    }  }}  export default mixinVideo