uniapp 开发全屏切换视频(仿抖音)

方案一


    此方案能解决swiper数量过多时黑屏的问题

<template>
	<view>
		<!--swiper实现整屏划动播放视频-->
		<swiper circular vertical duration="200" @change="changed" :style="{height: screenHeight-navBarHeight +'px'}">
			<block v-for="(item,index) in displaySwiperList" :key="index">
				<swiper-item>
					<!-- v-if="index==changeIndex" 只渲染当前页的视频,能够有效解决数组不断追加后引起黑屏的问题 -->
					<video v-if="index==changeIndex" :src="item.src" autoplay="true" controls="true"
						custom-cache="false" loop="false" enable-play-gesture="true" enable-progress-gesture="true"
						show-center-play-btn="true">
					</video>
					<!-- 文本标题 -->
					<view class="video-text">
						<view class="tips"> {{item.title}} </view>
					</view>
				</swiper-item>
			</block>
		</swiper>
		
	</view>
</template>

<script>
	export default {
		data() {
			return {
				screenHeight: 0,
				statusBarHeight: 0,
				navBarHeight: 0,
				originList: [], // 源数据
				displaySwiperList: [], // swiper需要的数据
				displayIndex: 0, // 用于显示swiper的真正的下标数值只有:0,1,2。
				originIndex: 0, // 记录源数据的下标
				changeIndex: 0, //控制video是否渲染
				page: 0, // 视频分页
				num:0,
				flag:true
			}
		},

		onLoad() {
			/* 获取系统信息 */
			wx.getSystemInfo({
				success: (res) => {
					// 获取屏幕高度
					this.screenHeight = res.screenHeight
					// 获取状态栏高度
					this.statusBarHeight = res.statusBarHeight
					// 通过操作系统 确定自定义导航栏高度  
					if (res.system.substring(0, 3) == "iOS") {
						this.navBarHeight = 42
					} else {
						this.navBarHeight = 40
					}
				}
			})

			// 调用函数
			this.getPageID()
			
		},

		methods: {
			/* 生成随机的 pageID */
			getPageID() {
				let pageID = parseInt(Math.random() * (0 - 100 + 1) + 100) //生成 [min,max] 的随机数
				console.log(pageID)
				this.getVideoList(pageID) //调用函数请求数据
			},

			/* 获取视频数据 */
			getVideoList(pageID) {
				//this.page++ //累加				
				uni.request({					
					url:'https://api.apiopen.top/api/getMiniVideo?page='+pageID+'&size=10',  // 请求数据接口
					data: {
						page: pageID,
						pageSize: 10,
					},
					success: (res) => {												
						if (res.data.code == 200) {
							console.log(res.data)							
							res.data.result.list.forEach(item =>{
								//取源数据的部分属性组合成新的数组
								let obj = {}								
								obj.src = item.playurl
								obj.title = item.title
								
								this.originList.push(obj)	//数据量大的追加到这个数组	,再经过下面的initSwiperData方法分批加载到displaySwiperList数组
								//this.displaySwiperList.push(obj)	//数据量小的直接使用这个数组								
							})
						}
						console.log(this.originList)					
						
						//解决首次加载页面的时候没有画面的问题
						if(this.flag){
							this.flag = false
							this.initSwiperData(0)
						}
						
					}
				})

			},

			/* 滑动切换 ,数据量小的时候可以直接使用这个方法 */
			/*changed(e) {
				let current = e.detail.current  //当前滑块的索引	
				this.changeIndex = current 	 
				//滑到最后一个视频的时候开始请求新数据
				if(this.displaySwiperList.length == current + 1) {  
					this.getPageID()					
				}
			},*/
			

			/**
			 * swiper滑动事件,数据量大的时候与initSwiperData方法一起使用,分批加载源数据到 swiper数组
			 */
			changed(event) {
				let {current} = event.detail;
				let originListLength = this.originList.length; // 源数据长度
				this.changeIndex = current; //同步下标
				
				// ==========如果两者的差为2或者-1则是向后滑动=======
				if (this.displayIndex - current == 2 || this.displayIndex - current == -1) {
					this.originIndex = this.originIndex + 1 == originListLength ? 0 : this.originIndex + 1;
					this.displayIndex = this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1;
					this.initSwiperData(this.originIndex);
					//如果滑到最后一条,请求新数据
					this.num++
					if(this.num+5 >= this.originList.length){
						this.getPageID()
					}
				}
				// ======如果两者的差为-2或者1则是向前滑动============
				else if (this.displayIndex - current == -2 || this.displayIndex - current == 1) {
					this.originIndex = this.originIndex - 1 == -1 ? originListLength - 1 : this.originIndex - 1;
					this.displayIndex = this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1;
					this.initSwiperData(this.originIndex);
					
					if(this.num > 0){
						this.num--
					}
				}
			},
			
			/**
			 * 初始一个swiper数组,包含三个元素 [{...},{...},{...}]
			 * originIndex 从源数据的哪个开始显示默认0,如从其他页面跳转进来,要显示第n个,这个参数就是他的下标
			 */
			initSwiperData(originIndex = this.originIndex) {
				let originListLength = this.originList.length; //源数据长度
				let displayList = [];
				displayList[this.displayIndex] = this.originList[originIndex];
				displayList[this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1] = this.originList[originIndex - 1 == -1 ? originListLength - 1 : originIndex - 1];
				displayList[this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1] = this.originList[originIndex + 1 == originListLength ? 0 : originIndex + 1];
				this.displaySwiperList = displayList; //刷新数据
			},
		}
	}
</script>

<style>
	swiper {
		width: 100%;
		background: #000
	}

	swiper-item {
		height: 100%;
		width: 100%
	}

	video {
		height: 96%;
		width: 100%
	}

	.video-text {
		position: absolute;
		margin-left: 32rpx;
		width: 580rpx;
		bottom: 200rpx;
		z-index: 9999;
	}

	.tips {
		width: 560rpx;
		font-size: 26rpx;
		color: #ffffff;
	}
</style>

 

 

方案二

        此方案在看的视频越来越多的时候,会引起黑屏现象。原因是数据不断追加到数组,导致swiper-item数量过多从而渲染变慢。

<template>
	<view class="index">
		<view class="videoItem">
			<swiper class="swiper" 
				:current="current_index" 
				:vertical="true" 
				@change="changeSwiper">
				<swiper-item class="swiper-item" v-for="(item,index) in videoList" :key="index">
					<video 
						class="video" 
						loop="true" 
						@click="videoPlay" 
						:id="`video_${item.video_id}`" 
						:src="item.src"
						:autoplay="false" 
						:controls="false" 
						:show-center-play-btn="false" 
						:show-fullscreen-btn="false"
						:show-play-btn="false">
					</video>

					<!-- 播放按钮,默认第一次进来是暂停,浏览器需要用户手动和video交互 -->
					<image class="play" v-if="stop_play" @tap="videoPlay" src="../../static/mp4/1.png"></image>

					<!-- 视频内容简介 -->
					<view class="username">						
						<view class="tips">
							{{item.title}}
						</view>
					</view>
				</swiper-item>
			</swiper>
		</view>

	</view>
</template>
<script>
	var pageID = 110001
	
	export default {		
		data() {
			return {
				videoList: [], // 视频列表
				videoCtx: null,
				current_index: 0, // swiper滑动位置
				play_state: true, // 播放状态(true播放,暂停false)
				page: 0, // 视频分页
				totalVideo: '', // 视频总条数
			}
		},
		
		onLoad() {
			this.getPageID()
			this.getVideoList();// 接口请求获取视频列表
		},
				
		methods: {
			// 视频播放
			videoPlay() {
				let video_id = this.videoList[this.current_index].video_id; // 当前播放视频的video_id
				if (this.play_state) {
					// 播放
					this.videoCtx = uni.createVideoContext(`video_${video_id}`, this); // 创建并返回 video 上下文 videoContext 对象
					this.videoCtx.play(); // 播放
					this.play_state = false; 
				} else {
					// 暂停
					this.videoCtx = uni.createVideoContext(`video_${video_id}`, this);
					this.videoCtx.pause(); // 暂停
					this.play_state = true; 
				}
			},
			
			// 暂停之前的视频
			videoPause() {
				let video_id = this.videoList[this.current_index].video_id;
				this.videoCtx = uni.createVideoContext(`video_${video_id}`, this);
				this.videoCtx.pause(); // 暂停
				this.play_state = true;
			},
			
			// swiper切换
			changeSwiper(e) {
				this.videoPause(); // 先暂停正在播放的视频
				this.current_index = e.detail.current; // 更换current_index
				this.videoPlay(); // 播放当前current_index位置的视频
			
				// 判断是否第一条
				if (e.detail.current == 0) {
					return false;
				}
				
				// 判断是否最后一条
				if (e.detail.current == this.videoList.length - 1) {
					this.getPageID()
					this.getVideoList();//最后一条视频,获取新的数据					
					return false;
				}
			},

			// 获取视频列表
			getVideoList() {
				// 分页,总条数 == videoList.length:暂无更多数据 return
				if (this.totalVideo === this.videoList.length) {
					return;
				} else {                    
					this.page++; //累加
					uni.showLoading({
						title: '加载中'
					});
					// 示例接口:
					uni.request({
						url: 'https://api.apiopen.top/videoRecommend?id=' + pageID,
						data:{
							page: this.page,
							pageSize: 10,
						},
						success: (res) => {
                            uni.hideLoading()
							if (res.data.code == 200) {
								this.totalVideo = res.data.count;
								res.data.result.forEach(item => {
									if (item.type == 'videoSmallCard') {
										let obj = {}
										obj.video_id = item.data.id;
										obj.src = item.data.playUrl;;
										obj.title = item.data.title;
										this.videoList.push(obj)
									}
								})

							}
						}
					})
				}
			},
			
			getPageID(){
				pageID = parseInt(Math.random()*(219999-110000+1)+110000,10); //生成 [min,max] 的随机数
				console.log(pageID)
			}
		}
	}
</script>
<style scoped lang="scss">
	.index {
		position: absolute;
		width: 100%;
		height: 100%;
		background: #000;

		.videoItem {
			position: absolute;
			width: 100%;
			height: 100%;
			background: #000;

			/deep/.swiper {
				position: fixed;
				width: 100%;
				top: 0;
				bottom: var(--window-bottom);
				height: auto;

				.video {
					width: 750rpx;
					height: 100%;
				}
			}

			.play {
				position: absolute;
				width: 20vw;
				height: 20vw;
				left: 40vw;
				top: 45vh;
				opacity: 0.5;
			}

			.username {
				position: absolute;
				margin-left: 32rpx;
				width: 580rpx;
				bottom: 200rpx;
				z-index: 9999;

				.name {
					width: 500rpx;
					font-size: 32rpx;
					color: #ffffff;
					margin-bottom: 18rpx;
				}

				.tips {
					width: 500rpx;
					font-size: 26rpx;
					color: #ffffff;
				}
			}

		}
	}
</style>

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值