uniapp实现视频上下滑动功能

该博客主要讨论了在uniapp中使用swiper组件和video组件时遇到的自动播放问题。作者指出,当设置autoplay属性时,切换swiper项会导致声音重叠。为了解决这个问题,作者通过监听swiper的change和animationfinish事件,实现了在切换视频时正确暂停上一个视频并播放当前视频的功能,确保了声音的正确切换。此外,还展示了详细的代码实现和数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路

主要是用到uniapp官网的swiper组件 然后再嵌套一个video组件,下面是我的实现效果:
在这里插入图片描述

问题

当我使用官方的autoplay属性实现自动播放,会导致我切换下一个视频的时候出现声音播放还停留在上一个视频,或者多个视频的声音同时播放。在这里插入图片描述

实现

一开始是拿到所有视频的数据,根据点击的当前视频对象中的id获得swiper需要的current(就是当前下标),正确定位到当前点击的视频,然后自己去控制自动播放视频
在这里插入图片描述
注意这个地方是没有手动关闭的,所以就肯定会导致我上面所说的那种画面变了但是声音还停留在上一个视频的问题,这是最主要的swiper的两个事件
在这里插入图片描述
这里的('id' + this.current) 就是对应上面的:id="'id'+index" 目的是为了动态的监听id的值 实现播放和暂停播放,要注意 this.currentcurrent
在这里插入图片描述
所有的代码还有数据格式(有用的值就这四个)
在这里插入图片描述

所有代码

<template>
    <view>
        <view class="uni-padding-wrap">
            <view class="page-section swiper">
                <view class="page-section-spacing">
                    <swiper class="swiper" @change="changefun" @animationfinish="animationfinishfun" :current="current" :circular="false" :vertical="true">
						<block v-if="PayVideo">
							<swiper-item v-for="(item,index) in PayVideo">
								<view class="swiper-item uni-bg-black">
									<video
										:custom-cache="false" 
										:show-fullscreen-btn="false"
										:controls="true"
										:show-center-play-btn="false"
										enable-play-gesture
										:initial-time="0"
										class="video" 
										:id="'id'+index" 
										:src="item.video_url"
										loop
										:enable-progress-gesture="false"
										v-if="index == current"
									>
									</video>
								</view>
							</swiper-item>
						</block>
                    </swiper>
                </view>
            </view>
        </view>
        <view>
            <view class="left">
                <cover-view class="left_box">
                    <cover-view class="ke_context height">{{description}}</cover-view>
					<!-- <cover-view class="auto">
						<cover-view>视频总时长:{{duration || 0}}</cover-view>
					</cover-view> -->
                </cover-view>
            </view>
        </view>
    </view>
</template>
 
<script>
    export default {
        data() {
            return {
                PayVideo: [],
				videoData: {},
				videoList: [],
				description: '',
				current: 0,
				index_: 0,
				videoContext: '',
				duration: '',//总视频时长
            }
        },
        computed: {
        },
		onLoad(options) {
			this.getVideoInfo(parseInt(options.id))
			if(options.videoList) {
				this.videoList = JSON.parse(decodeURIComponent(options.videoList))
			}
		},
        methods: {
			getVideoInfo(id){
				this.$http.get('/video/detail',{
					video_id:id
				}).then(res=>{
					if(res.code==0){
						this.videoData = res.data;
						this.id = res.data.id
						uni.setNavigationBarTitle({
							title:this.videoData.video_name
						})
						this.description = this.videoData.description
						this.PayVideo = this.videoList //上下滑动总数据
						this.current = this.PayVideo.findIndex((item) => {
							return item.id === res.data.id
						})
						this.duration = res.data.video_time
						// 自动播放当前视频
						this.$nextTick(function() {
							let videoContext = uni.createVideoContext('id' + this.current)
							videoContext.play()
						})
					}else{
						uni.showToast({
							title:res.msg,
							icon:'none'
						})
						setTimeout(()=>{
							uni.redirectTo({
								url:'/pages/index/index?index=2'
							})
						},1500)
					}
				})
			},
			// current改变时会触发change 事件
            changefun(e) {
                let current = e.detail.current
				uni.setNavigationBarTitle({
					title: this.PayVideo[current].video_name
				})
				if(this.PayVideo[current].description) {
					this.description = this.PayVideo[current].description
				}
				this.duration = this.PayVideo[current].video_time
				let videoContext = uni.createVideoContext('id' + this.current)
				videoContext.pause() //停止播放
            },
			// 动画结束时触发
			animationfinishfun(e) {
				let current = e.detail.current
				let videoContext = uni.createVideoContext('id' + this.current)
				videoContext.pause() //停止播放非当前视频
				videoContext = uni.createVideoContext('id' + current)
				videoContext.play() //开始播放当前视频
				this.current = current //保存当前下标 播放下一个视频时停止上一个视频 防止声音重复
			}
        },
    }
</script>
 
<style scoped lang="less">
    .circle {
        background: rgba(34, 34, 34, 0.4);
        border-radius: 50%;
        z-index: 2;
        height: 70px;
        width: 70px;
        position: fixed;
        top: 0;
        bottom: 441rpx;
        left: 31rpx;
 
        margin: auto;
 
        .red {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            margin: auto;
            z-index: 3;
            height: 35px;
            width: 35px;
        }
    }
 
    .swiper {
        height: 100vh;
 
        .swiper-item {
            height: 100vh;
            position: relative;
        }
 
        .uni-bg-black {
            background: black;
        }
    }
 
    .video {
        width: 100%;
        height: 98vh;
        position: relative;
    }
 
    .left_box {
        position: fixed;
        bottom: 90rpx;
        left: 24rpx;
        .ke_context {
			overflow-y: scroll;
			max-height: 300rpx;
			white-space:pre-wrap;
            width: 700rpx;
            font-size: 30rpx;
            font-family: PingFang SC;
            font-weight: 500;
            color: rgba(255, 255, 255, 1);
			white-space:pre-wrap;
            text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.4);
        }
		
		.height {
			margin-bottom: 40rpx;
		}
 
        .ren {
            margin: 20rpx 0;
            font-size: 36rpx;
            font-family: PingFang SC;
            font-weight: bold;
            color: rgba(255, 255, 255, 1);
            text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.4);
        }
 
        .auto {
            display: flex;
            align-items: center;
            width: 310rpx;
            height: 60rpx;
            margin-top: 24rpx;
            opacity: 1;
            border-radius: 8rpx;
            padding-left: 10rpx;
 
            cover-view {
                font-size: 26rpx;
                font-family: PingFang SC;
                font-weight: 500;
                color: rgba(255, 255, 255, 1);
                line-height: 90px;
                text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.4);
            }
 
            cover-image {
                margin-right: 10rpx;
                height: 28rpx;
                width: 26rpx;
            }
        }
 
        .ke {
            display: flex;
            align-items: center;
            width: 310rpx;
            height: 60rpx;
            background: rgba(0, 0, 0, 0.3);
            opacity: 1;
            border-radius: 8rpx;
            padding-left: 10rpx;
 
            cover-view {
                font-size: 26rpx;
                font-family: PingFang SC;
                font-weight: 500;
                color: rgba(255, 255, 255, 1);
                line-height: 90px;
                text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.4);
            }
 
            cover-image {
                margin-right: 10rpx;
                height: 40rpx;
                width: 40rpx;
            }
        }
    }
 
    .H_T {
        z-index: 2;
        width: 100%;
        display: flex;
        box-sizing: border-box;
        position: absolute;
        padding: 0 30rpx;
        background: transparent;
        justify-content: space-between;
 
        .back {
            height: 48rpx;
            width: 48rpx;
        }
 
        .search {
            height: 48rpx;
            width: 48rpx;
        }
    }
 
    .right_box {
        width: 100rpx;
        position: absolute;
        z-index: 2;
        bottom: 60rpx;
        right: 12rpx;
        display: flex;
        flex-direction: column;
 
        .top1 {
            position: relative;
            height: 124rpx;
 
            .avatar_img {
                width: 98rpx;
                height: 98rpx;
                border-radius: 50%;
            }
 
            .add_img {
                position: absolute;
                z-index: 99;
                width: 48rpx;
                height: 48rpx;
                bottom: 10rpx;
                left: 0;
                right: 0;
                margin: 0 auto;
            }
        }
 
        .top2 {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-top: 37rpx;
 
            .t_img {
                height: 72rpx;
                width: 72rpx;
                margin-bottom: 10rpx;
            }
            
            .font_t {
                font-size: 26rpx;
                font-family: SF Pro Text;
                font-weight: 500;
                color: rgba(255, 255, 255, 1);
 
                text-shadow: 0px 1rpx 1rpx rgba(0, 0, 0, 0.4);
                text-align: center;
            }
        }
 
    }
</style>
Uniapp中,实现上下滑动切换视频的方法如下: 首先,在uni-app的页面中,创建一个视频列表的父容器,并设置其样式为可滑动的: ```html <view class="video-container" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"> <!-- 视频列表 --> </view> ``` 然后,在页面的data中定义一些变量,用于记录手指触摸的起始位置、移动距离等信息: ```javascript data() { return { startX: 0, // 手指触摸的起始位置横坐标 startY: 0, // 手指触摸的起始位置纵坐标 moveX: 0, // 手指触摸后的横向移动距离 moveY: 0, // 手指触摸后的纵向移动距离 isMoving: false, // 标记手指是否在滑动 }; }, ``` 接下来,在methods中定义一些触摸事件的处理方法,实现手指触摸和滑动的监听和处理: ```javascript methods: { touchStart(event) { this.startX = event.touches[0].clientX; this.startY = event.touches[0].clientY; }, touchMove(event) { if (this.isMoving) { return; } this.moveX = event.touches[0].clientX - this.startX; this.moveY = event.touches[0].clientY - this.startY; if (Math.abs(this.moveY) > Math.abs(this.moveX)) { this.isMoving = true; } }, touchEnd() { if (this.isMoving) { if (this.moveY > 0) { // 下滑操作,切换到下一个视频 // 可以在这里执行切换视频的逻辑 } else { // 上滑操作,切换到上一个视频 // 可以在这里执行切换视频的逻辑 } } this.isMoving = false; this.moveX = 0; this.moveY = 0; }, }, ``` 最后,根据切换视频的逻辑来实现具体的操作即可。在上滑操作和下滑操作的代码注释处,可以编写逻辑来实现视频的切换。 通过以上步骤,我们可以实现Uniapp上下滑动切换视频的效果。当用户滑动操作时,通过触摸事件来获取滑动的方向和距离,然后根据判断执行相应的操作,达到切换视频的效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值