uniapp开发小程序时遇到多个视频无法自动只播放一个的问题解决

作者刚开始接触Uniapp开发,在开发小程序时遇到多个视频无法自动只播放一个的问题。作者所需布局是两个连续的video,三个视频组件也能实现只播放一个。还提到使用uni.createVideoContext时的注意点,以及将video保存在数组中实现单播放的方法。

笔者也是刚开始接触uniapp开发,如有错漏,欢迎讨论

笔者需要的布局是两个连续的video,不过我试了一下三个视频组件也可以做到只播放其中一个视频,代码如下:


				<video src="txt1.mp4" 
					id="myVideo1"
					autoplay 
					muted
					loop
					controls
					show-mute-btn
					auto-pause-if-open-native
					poster="txt1.png"
					auto-pause-if-navigate
					style="width: 100%; height: 250rpx;"
					@play="videoPlayHandle('myVideo1')">
				</video>
				
				<div class="video-gap"></div>
				
				<video src="txt2.mp4"
					id="myVideo2"
					muted
					loop
					controls
					show-mute-btn
					auto-pause-if-open-native
					auto-pause-if-navigate
					poster="txt2.png"
					style="width: 100%; height: 250rpx;"
					@play="videoPlayHandle('myVideo2')">
				</video>
				

videoPlayHandle方法代码如下:

methods{
			videoPlayHandle(id){
				let newVideo = uni.createVideoContext(id,this);
				console.log("newvideo:"+JSON.stringify(newVideo));
				newVideo.id = id;
				if (!this.video) {
					this.video = newVideo;
					this.video.play();
					console.log(JSON.stringify(this.video)+"播放");
					return;
				}
				if (this.video.id !== newVideo.id) {
					console.log("this.video.id = "+this.video.id + "  newVideo.id = " + newVideo.id);
					console.log("切换视频主体");
					newVideo.play();
					console.log("目前视频主体播放");
					this.video.pause();
					console.log("之前视频主体暂停");
					this.video = newVideo;
					console.log("播放主体切换");
				}
			},
}

一开始uni.createVideoContext()中只写了id,没有后面的this,所以明明下面的log输出都是对的,但是.pause一直无法实现,以后使用的时候uni.createVideoContext需要注意。


补充一个代码中看到的将video保存在数组中的只同时播放一个video的方法:

<!--视频-->
			<view v-else-if="n.name=='video'">
				<view v-if="(!loadVideo||n.lazyLoad)&&!(controls[n.attrs.id]&&controls[n.attrs.id].play)" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
				 :style="n.attrs.style" @tap="_loadVideo" />
				<video v-else :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||(controls[n.attrs.id]&&controls[n.attrs.id].play)"
				 :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[(controls[n.attrs.id]&&controls[n.attrs.id].index)||0]"
				 :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" data-from="video" data-source="source" @error="error" @play="play" />
			</view>



/*play方法*/

method{
    // #ifndef MP-ALIPAY
			play(e) {
				if (this.top.videoContexts.length > 1 && this.top.autopause)
					for (var i = this.top.videoContexts.length; i--;)
						if (this.top.videoContexts[i].id != e.currentTarget.dataset.id)
							this.top.videoContexts[i].pause();
			},
			// #endif
}

在使用 UniApp 开发小程序,若要实现类似抖音的上下滑动切换视频功能(即全屏竖向视频流,滑动切换),需要结合 `swiper` 组件和视频组件 `video` 来实现。由于小程序平台对 `video` 组件有层级限制和性能优化要求,必须特别注意组件嵌套、预加载、自动播放等细节。 以下是完整的实现方案: ```vue <template> <view class="video-swiper-container"> <swiper :current="currentIndex" @change="onSwiperChange" class="swiper" :style="{ height: windowHeight + 'px' }" :duration="300" @animationfinish="onAnimationFinish" > <swiper-item v-for="(item, index) in videoList" :key="index"> <view class="video-item"> <!-- 视频组件 --> <video :id="'video_' + index" :ref="'video_' + index" :src="item.src" :autoplay="index === currentIndex" :initial-time="0" object-fit="cover" :controls="false" :show-center-play-btn="false" loop class="video-player" @play="onVideoPlay(index)" @pause="onVideoPause(index)" @ended="onVideoEnded(index)" ></video> <!-- 视频右侧信息栏(如点赞、评论、分享) --> <view class="video-right-bar"> <view class="action-item" @click="likeVideo(index)"> <text class="icon">👍</text> <text class="count">{{ item.likes }}</text> </view> <view class="action-item" @click="openComment(index)"> <text class="icon">💬</text> <text class="count">{{ item.comments }}</text> </view> <view class="action-item" @click="shareVideo(index)"> <text class="icon">📤</text> <text class="count">{{ item.shares }}</text> </view> </view> <!-- 视频底部信息 --> <view class="video-bottom-info"> <text class="title">{{ item.title }}</text> <view class="user-info"> <text class="username">@{{ item.author }}</text> </view> </view> </view> </swiper-item> </swiper> </view> </template> <script> export default { data() { return { currentIndex: 0, windowHeight: uni.getSystemInfoSync().windowHeight, videoList: [ { src: 'https://example.com/video1.mp4', title: '这是第一个视频', author: '用户A', likes: 1230, comments: 45, shares: 67 }, { src: 'https://example.com/video2.mp4', title: '这是第二个视频', author: '用户B', likes: 890, comments: 32, shares: 54 }, { src: 'https://example.com/video3.mp4', title: '这是第三个视频', author: '用户C', likes: 2100, comments: 78, shares: 91 } ], videoContexts: [] }; }, mounted() { this.initVideoContexts(); }, methods: { initVideoContexts() { this.$nextTick(() => { this.videoList.forEach((_, index) => { this.$set(this.videoContexts, index, uni.createVideoContext('video_' + index, this)); }); }); }, onSwiperChange(e) { const { current } = e.detail; this.currentIndex = current; }, onAnimationFinish(e) { const { current } = e.detail; // 停止上一个视频 if (this.videoContexts[this.currentIndex]) { this.videoContexts[this.currentIndex].pause(); } // 播放当前视频 this.$nextTick(() => { if (this.videoContexts[current]) { this.videoContexts[current].play(); } }); this.currentIndex = current; }, onVideoPlay(index) { console.log(`视频 ${index} 开始播放`); }, onVideoPause(index) { console.log(`视频 ${index} 暂停`); }, onVideoEnded(index) { console.log(`视频 ${index} 播放结束`); }, likeVideo(index) { const item = this.videoList[index]; item.likes += 1; }, openComment(index) { uni.showToast({ title: '打开评论', icon: 'none' }); }, shareVideo(index) { uni.share({ provider: 'weixin', scene: 'WXSenceTimeline', type: 0, success: () => uni.showToast({ title: '分享成功', icon: 'success' }), fail: () => uni.showToast({ title: '分享失败', icon: 'error' }) }); } }, onPageScroll() { // 防止页面滚动影响 swiper return false; } }; </script> <style scoped> .video-swiper-container { width: 100%; overflow: hidden; } .swiper { width: 100%; } .video-item { position: relative; width: 100%; height: 100%; background-color: #000; } .video-player { width: 100%; height: 100%; } .video-right-bar { position: absolute; right: 20rpx; bottom: 200rpx; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 40rpx; } .action-item { display: flex; flex-direction: column; align-items: center; color: #fff; font-size: 24rpx; } .action-item .icon { font-size: 48rpx; } .action-item .count { margin-top: 8rpx; } .video-bottom-info { position: absolute; left: 20rpx; bottom: 100rpx; color: #fff; max-width: 70%; } .video-bottom-info .title { font-size: 32rpx; line-height: 48rpx; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); } .user-info { margin-top: 10rpx; } .username { font-size: 28rpx; color: #ffd700; } </style> ``` --- ### 解释: 1. **`swiper` 组件**: - 使用 `swiper` 实现垂直滑动切换视频- 设置 `:style="{ height: windowHeight + 'px' }"` 保证全屏显示。 - `@animationfinish` 是关键生命周期钩子,在滑动动画结束后触发,用于精确控制视频播放。 2. **`video` 组件**: - 每个 `swiper-item` 中包含一个 `video`。 - `autoplay` 只在当前页启用,避免多个视频加载。 - 使用 `uni.createVideoContext` 创建每个视频的上下文实例,以便手动控制播放/暂停。 3. **性能优化**: - 滑动后通过 `animationfinish` 切换播放状态,防止滑动过程中误触发。 - 使用 `loop` 属性让视频循环播放- 控制 `controls="false"` 隐藏原生控件,保持 UI 美观。 4. **交互设计**: - 添加右侧点赞、评论、分享按钮。 - 底部显示标题和作者信息。 5. **注意事项**: - 小程序中 `video` 是原生组件,层级最高,不能被普通 view 覆盖,需用 `cover-view` 在某些情况下处理,但本例未使用是因为兼容性复杂。 - 若需更复杂的弹幕或封面层,请使用 `cover-view` 替代部分 UI。 --- ### 可能遇到的问题解决方案: - **问题1:视频自动播放** - 原因:小程序策略限制自动播放,需用户主动触发首次播放- 解决:可在进入页面添加“点击播放”按钮,首次播放后后续可自动播放- **问题2:滑动卡顿或视频加载慢** - 建议:对视频进行压缩、使用 CDN 加速、懒加载前几个视频- **问题3:`videoContext` 获取不到** - 必须使用 `uni.createVideoContext(id, this)`,且 `id` 要与模板中一致,并确保 DOM 已渲染(使用 `$nextTick`)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值