微信小程序之多视频暂停播放,超出可视区域停止播放视频在自定义组件中实现案例

项目页面存在多个视频时,只播放视频可见范围内单个视频播放的解决方案

QQ录屏20240326175303

在自定义组件中无onPageScroll(e)监听页面滚动的函数所以在自定义组件中用<scroll-view>标签包裹所有组件(以下为WXML页面源码)

html 复制代码
<scroll-view scroll-y bindscroll="getScrollLength" style="height:{{scrollHeight*2+'rpx'}}">
<view class="content-box" wx:for="{{articleList}}" wx:key="i">
	<view class="userInfo-box">
		<!-- 用户头像 -->
		<image src="{{item.UserHeadImg}}" mode="" class="head-imag" class="user-image" />
		<view class="name-lab-box">
			<!-- 用户昵称 -->
			<view class="user-name">{{item.UserNickName}}</view>
			<!-- 用户标签 -->
			<view class="user-lab">标签</view>
		</view>
		<!-- 关注标签 -->
		<view class="follow-btn">
			+关注
		</view>
		<!-- 删除当前微博文章 -->
		<view class="user-del">
			<view>x</view>
		</view>
	</view>
	<!-- 内容区域 -->
	<view class="weibo-content">
		<view class="text-contrnt" catch:tap="navGo">{{item.WeiBoContent}}</view>
		<!-- 视频或图片区域 -->
		<view class="weibo-content-img-video">
			<block wx:if="{{item.WeiBoImg}}">
				<image wx:for="{{item.WeiBoImg}}" bind:tap="preview" data-urls="{{item.WeiBoImg}}" data-index="{{number}}" wx:key="i" wx:for-item="imgUrl" wx:for-index="number" class="weibo-content-img" src="{{imgUrl}}" mode="aspectFill" />
			</block>
			<block wx:if="{{item.WeiBoVideo}}">
				<video controls id="{{'video'+item.Id}}" autoplay="{{false}}" show-mute-btn controls="false" custom-cache='true' direction="0" class="weibo-content-video" src="{{item.WeiBoVideo}}" />
			</block>

		</view>
	</view>
	<!-- 点赞转发评论区域 -->
	<view class="woo-box">
		<view class="woo-img-box" bind:tap="launch">
			<image src="../../img/weibocontent/3.1转发.png" mode="" class="icon" />
			转发
		</view>
		<view class="woo-img-box">
			<image src="../../img/weibocontent/pinglun.png" mode="" class="icon" />
			评论
		</view>
		<view class="woo-img-box">
			<image src="../../img/weibocontent/dianzan.png" mode="" class="icon" />
			点赞
		</view>
	</view>
</view>
</scroll-view>

给每个存在<video>组件赋值唯一的id属性,且不能为纯数字id属性(不知道为啥不行,我刚开始用的纯数字,就是获取不到video的上下文)

定义组件属性列表用于接收自定义组件的父组件传过来的数据遍历

javascript 复制代码
 /**
   * 组件的属性列表
   */
  properties: {
    articleList: Array, //文章集合
  },

在自定义组件的初始数据中定义几个数据

javascript 复制代码
/**
   * 组件的初始数据
   */
  data: {
    videoList: [], // 用于存储视频集合
    scrollHeight: 0, //滚动视图(<scroll-view>组件的高度)高度
    scrollLength: 0, //滚动距离
  },

在自定义组件的生命周期声明对象(在组件视图布局完成后获得手机设备的屏幕可用高度,此代码中减去的83为在我本次项目中自定义组件的父组件导航的高度,所以自定义组件在父组件中可用高度为屏幕可用高度减去父组件中导航的高度)

javascript 复制代码
/* 组件生命周期声明对象 */

  lifetimes: {
    //组件在视图层布局完成后执行
    attached: async function () {
      var {
        windowHeight
      } = await wx.getSystemInfoSync();
      this.setData({
        scrollHeight: windowHeight - 83
      })
    }
  },

定义<scroll-view>组件的滚动事件监听,监听滚动的距离长度(if中的判断移动的距离长度大于200时才给赋值,可根据实际需要调整)

javascript 复制代码
//获得滚动长度
    getScrollLength(e) {
      if (e.detail.scrollTop - this.data.scrollLength > 200 || e.detail.scrollTop - this.data.scrollLength < -200) {
        this.setData({
          scrollLength: e.detail.scrollTop, //获得滚动距离
        })
        //控制视频播放和暂停
        this.getVideo();
      }
    },

函数getVideo()控制自定义组件中可见范围内的视频的播放和暂停

javascript 复制代码
//控制视频播放和暂停
    getVideo() {
      this.setData({
        videoList: []
      })//父组件在给自定义组件传值时都是传输的完整的新值,所以在每次执行函数时清空初始数据的值
      this.data.articleList.forEach(item => {
        if (item.WeiBoVideo) {
          this.setData({
            videoList: [...this.data.videoList, item]
          })
        }
      })//将父组件传输给自定义组件的的数据中找出存在item.WeiBoVideo的数据
      //将所有存在<video>组件的数据遍历并创建上下文  
      this.data.videoList.forEach(video => {
        var id = video.Id;
        const query = this.createSelectorQuery();//创建组件上下文
        //依据视频组件的id通过boundingClientRect()方法获得当前视频组件的相对位置(此方法为异步方法)
        query.select('#video' + id).boundingClientRect(rect => {
          //校验视频是否跑出范围(rect.top)意为距离滚轮组件顶部的距离,每次滚轮滚动后,此值都会发生变化
          if (rect.top <300&&rect.bottom>100) {
            // 视频在可视范围内,暂停它  
            this.playVideo(id);
          } else {
            // 视频在可视范围内,暂停它  
            this.pauseVideo(id);
          }
        }).exec();
      })
    },

此段代码中需要留意的就是boundingClientRect()此函数为异步函数,rect.top 、rect.bottom意为距离滚轮组件顶部的距离,每次滚轮滚动后,此值都会发生变化

视频播放函数及暂停函数(在自定义组件中需要添加this参数,不然无法控制自定义组件内部的播放和暂停)

javascript 复制代码
    //视频播放
    playVideo(id) {
      const video = wx.createVideoContext('video' + id,this);
      video.play();
    },
    //视频暂停
    pauseVideo(id) {
      const video = wx.createVideoContext('video' + id,this);
      video.pause();
    },
相关推荐
木易士心19 小时前
一文读懂:微信小程序云数据库直连原理与使用指南
微信小程序·serverless
明月_清风1 天前
小程序云函数:从入门到全栈的“降维打击”指南
前端·微信小程序·小程序·云开发
拉不动的猪2 天前
移动端调试工具VConsole初始化时的加载阻塞问题
前端·javascript·微信小程序
WangHappy4 天前
不写 Canvas 也能搞定!小程序图片导出的 WebView 通信方案
前端·微信小程序
小时前端4 天前
微信小程序选不了本地文件?用 web-view + H5 一招搞定
前端·微信小程序·uni-app
icebreaker5 天前
Weapp-vite:原生模式之外,多一种 Vue SFC 选择
前端·vue.js·微信小程序
icebreaker5 天前
重走 Vue 长征路 Weapp-vite:编译链路与 Wevu 运行时原理拆解
前端·vue.js·微信小程序
大米饭消灭者8 天前
Taro是怎么实现一码多端的【底层原理】
微信小程序·taro
REDcker9 天前
WebCodecs VideoDecoder 的 hardwareAcceleration 使用
前端·音视频·实时音视频·直播·webcodecs·videodecoder
gihigo19989 天前
基于TCP协议实现视频采集与通信
网络协议·tcp/ip·音视频