利用uniapp中模仿抖音、滑动视频组件、双击点赞、首个视频自动播放

前言

仿抖音截图
在这里插入图片描述

在这里插入图片描述

基于uniapp模仿抖音的视频播放,其核心就是播放器,因此记录一下实现该功能的组件,我喜欢组件化开发,就放重点的一些组件,可以在下面的代码中学到父组件调用子组件的方法,父组件向子组件传值,子组件向父组件传值等操作

在这里插入图片描述
组件化开发

videoList.vue //主要组件

<template>
	<view class="videoList">
		<view class="swiper-box">
			<swiper class="swiper"  :vertical="true" @change="changeplay" @touchstart="touchStart" @touchend="touchEnd">
				<swiper-item v-for="(item,index) in videos" :key="item.id">
					<view class="swiper-item"  style="color: #000000;">
						<video-player @changeClick='changeClick' ref="player" :video="item" :index="index"></video-player>
					</view>
					<view class="listleftbox">
						<list-left></list-left>
					</view>
					<view class="listrightbox">
						<list-right ref="right"></list-right>
					</view>
				</swiper-item>
			</swiper>
		</view>
		
	</view>
</template>

<script>
	import videoPlayer from './videoPlayer.vue'
	import listLeft from './listLeft.vue'
	import listRight from './listRight.vue'
	var time = null
	export default {
		props:['list'],
		name:"videoList",
		components:{
			videoPlayer,
			listLeft,
			listRight
		},
		data() {
			return {
				videos:[],
				pageStatrY:0,
				pageEndY:0,
				page:0
			};
		},
		//监听传过来的list
		watch:{
			//当list发生改变 就触发这个方法 所以用watch
			list(){
				this.videos = this.list
				console.log(this.videos)
			}
		},
		methods:{
			changeClick(){
				//双击点赞 调用子组件listright的方法
				this.$refs.right[0].change()
			},
			//上下滑动触发事件
			changeplay(res){
				clearTimeout(time)
				this.page = res.detail.current
				time=setTimeout(()=>{
					if(this.pageStatrY < this.pageEndY){
						console.log('向上滑动')
						setTimeout(()=>{
							this.$refs.player[this.page].player()
						},20)
						
						this.$refs.player[this.page+1].pause()
						this.pageStatrY=0
						this.pageEndY=0
					}else{
						console.log('向下滑动')
						setTimeout(()=>{
							this.$refs.player[this.page].player()
						},20)
						
						this.$refs.player[this.page-1].pause()
						this.pageStatrY=0
						this.pageEndY=0
					}
				},1)	
			},
			//获取向下滑动的值
			touchStart(res){
				
				this.pageStatrY = res.changedTouches[0].pageY
				console.log(this.pageStatrY)
			},
			//获取向上滑动的值
			touchEnd(res){		
				
				this.pageEndY = res.changedTouches[0].pageY
				console.log(this.pageEndY)
			}
		}
	}
</script>

<style>
.videoList{
	height: 770px;
	width: 100%;
}
.swiper-box{
	height: 100%;
	width: 100%;
}
.swiper{
	height: 100%;
	width: 100%;
}
.swiper-item{
	height: 100%;
	width: 100%;
	z-index:19;
}
.title{
	color: #FFFFFF;
}
/deep/.listleftbox{
	z-index:20;
	position: absolute;
	bottom: 50px;
	left: 10px;
}
/deep/.listrightbox{
	z-index:20;
	position: absolute;
	bottom: 50px;
	right: 10px;
	color: #FFFFFF;
}


</style>

videoPlayer.vue //存放视频的组件
下面存放视频的地址可以自己在Apache的服务器上自己存放好视频
<template>
	<view class="videoPlayer">	
		<video 
		id="myVideo" 
		class="video" 
		:controls="false" 
		:src="'http://192.168.112.1:80/video/'+video.src" 
		:loop="true" 
		:autoplay="autoplay"
		controls
		@click="click"></video>
	</view>
</template>

<script>
	var timer=null
	export default {
		props:['video','index'],
		data() {
			return {
				play:false,
				dblClick:false,
				autoplay:false
			};
		},
		mounted(){
			this.videoContext=uni.createVideoContext('myVideo',this)
		},
		methods:{
			click(){
				clearTimeout(timer)
				this.dblClick=!this.dblClick
				timer=setTimeout(()=>{
					if(this.dblClick){ //判断是单击 即为true
						//单击
						if(this.play===false){
							this.playThis()
						}else{
							this.pause()
						}
					}else{
						//双击
						this.$emit('changeClick') //向父组件传递一个事件
					}
					this.dblClick=false //点击后重置状态 重置为false
				},300)
			},
			player(){
				//从头播放视频
				if(this.play===false){
					this.videoContext.seek(0)
					this.videoContext.play()
					this.play=true
				}
			},
			pause(){
				//暂停视频
				if(this.play===true){
					this.videoContext.pause()
					this.play=false
				}
			},
			playThis(){
				//播放当前视频
				if(this.play===false){
					this.videoContext.play()
					this.play=true
				}
			},
			//首个视频自动播放
			atuo(){
				//首个视频自动播放
				if(this.index===0){
					this.autoplay=true
				}
			}
		},
		created() {
			this.atuo()
		}
	}
	
</script>
 
<style>
.videoPlayer{
	height: 100%;
	width:100%;
}
.video{
	height: 100%;
	width:100%;
	z-index: 1;
}
</style>

listRight.vue //页面右组件的内容
<template>
	<view class="listright">
		<view class="author-img">
			<image mode="widthFix" src="../static/img/author.jpg" class="img"></image>
			<view class="iconfont icon-jiahao add" v-show="show" @click="hide"></view>
		</view>
		<view class="iconfont icon-xin right-box" :style="color" @click="changeColor">
			
		</view>
		<view class="number">
			123
		</view>
		<view class="iconfont icon-53pinglun- right-box">
			
		</view>
		<view class="number">
			521
		</view>
		<view class="iconfont icon-fenxiang right-box">
			
		</view>
		<view class="number">
			521
		</view>
		<view class="around">
			<image src="../static/logo.png" class="img"></image>
		</view>
	</view>
</template>

<script>
	export default {
		name:"listright",
		data() {
			return {
				show:true,
				color:''
			};
		},
		methods:{
			hide(){
				this.show =false
			},
			//点击爱心变红(即点赞)或者变白(取消点赞)
			changeColor(){
				this.color = this.color === ''?'color:red;':''
			},
			//双击点赞
			change(){
				this.color = "color:red;"
			}
		}
	}
</script>

<style>
.listright{
	width: 50px;
	margin: 0 auto;
}
.author-img{
	width: 50px;
	height: 50px;
	border-radius: 50%;
	border: 3px solid #FFFFFF;
	position: relative;
}
.right-box{
	width: 50px;
	height: 40px;
	margin-top: 13px;
	text-align: center;
	line-height: 40px;
	color: #FFFFFF;
	font-size: 30px;
}
.img{
	width: 50px;
	height: 50px;
	border-radius: 50%;
}

.number{
	font-size: 10px;
	text-align: center;
	color: #FFFFFF;
}
.around{
	margin-top: 15px;
	width: 50px;
	height: 50px;
	animation: rotate 1.5s linear 0.2s infinite;
}
.add{
	background-color: red;
	position: absolute;
	bottom: -9px;
	left:16px;
	text-align: center;
	line-height: 18px;
	color: #FFFFFF;

}

@keyframes rotate{
	0%{
		transform: rotate(0deg);
	}
	100%{
		transform: rotate(360deg);
	}
}
</style>

listLeft.vue //左边组件的内容
<template>
	<view class="listLeft">
		<view class="author">
			sina
		</view>
		<view class="title">
			nihaonihaonihaonihaonihaonih
		</view>
		<view class="box">
			<view class="music">
				你要的爱你要的爱你要的爱你要的爱你要的爱
			</view>
		</view>
		
	</view>
</template>

<script>
	export default {
		name:"list",
		data() {
			return {
				
			};
		}
	}
</script>

<style>
.listLeft{
	height: 150px;
	margin-left: 10px ;
	color: #FFFFFF;
	width: 150px;
	
}

.author{
	height: 35px;
	line-height: 35px;
	font-size: 17px;
}

.title{

	line-height: 20px;
	font-size: 15px;
	width: 100%;
	word-wrap: break-word;
}
.box{
	width: 100px;
	overflow: hidden;
}
.music{
	height: 35px;
	line-height: 35px;
	font-size: 15px;
	width: 200px;
	animation: music 4s linear 0.2s infinite;
}

@keyframes music{
	0%{
		transform: translate3d(80%,0,0);
	}
	100%{
		transform: translate3d(-80%,0,0);
	}
}
</style>

  • 15
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
<template> <view class="video-list" @scroll="onScroll"> <view v-for="(video, index) in videos" :key="index" class="video-item"> <video :src="video.url" :poster="video.poster" @play="onPlay(index)" @pause="onPause(index)" ref="videoRef" /> <view class="video-info"> <image :src="video.avatar" class="avatar" /> <text class="nickname">{{ video.nickname }}</text> <text class="desc">{{ video.desc }}</text> </view> </view> </view> </template> <script> export default { data() { return { videos: [ { url: 'https://example.com/video1.mp4', poster: 'https://example.com/poster1.png', avatar: 'https://example.com/avatar1.png', nickname: 'User1', desc: 'Video 1' }, { url: 'https://example.com/video2.mp4', poster: 'https://example.com/poster2.png', avatar: 'https://example.com/avatar2.png', nickname: 'User2', desc: 'Video 2' }, { url: 'https://example.com/video3.mp4', poster: 'https://example.com/poster3.png', avatar: 'https://example.com/avatar3.png', nickname: 'User3', desc: 'Video 3' } ], playingIndex: -1 }; }, methods: { onPlay(index) { if (this.playingIndex !== -1 && this.playingIndex !== index) { this.pauseVideo(this.playingIndex); } this.playingIndex = index; }, onPause(index) { if (this.playingIndex === index) { this.playingIndex = -1; } }, pauseVideo(index) { const video = this.$refs.videoRef[index]; if (video) { video.pause(); } }, onScroll(event) { const scrollTop = event.detail.scrollTop; const windowHeight = uni.getSystemInfoSync().windowHeight; const videoList = this.$refs.videoList; const videoItems = this.$refs.videoRef; for (let i = 0; i < videoItems.length; i++) { const item = videoItems[i]; const rect = item.$el.getBoundingClientRect(); if (rect.top < windowHeight && rect.bottom > 0) { item.play(); } else { item.pause(); } } } } }; </script> <style> .video-list { display: flex; flex-direction: column; } .video-item { position: relative; margin-bottom: 20px; } .video-info { position: absolute; bottom: 10px; left: 10px; display: flex; align-items: center; color: #fff; } .avatar { width: 30px; height: 30px; border-radius: 50%; margin-right: 10px; } .nickname { font-size: 14px; font-weight: bold; margin-right: 10px; } .desc { font-size: 12px; } </style>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值