H5版抖音实现,注释全部在代码中,有不懂的请给我留言。
项目使用swiper + video + uni.createVideoContext(videoId, this)实现。API不懂的请参考uniapp官方文档。
先来看下效果图,阉割版的抖音,删除了右侧跟用户信息相关的代码。
methods中总共四个方法,简单易懂的方式让您了解视频模块代码的实现。
html
<template>
<view class="index">
<u-navbar title="我的抖音" title-color="#fff" :is-back="false" :border-bottom="false" :background="navbarBG"></u-navbar>
<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="name u-line-1">@{{item.name}}</view>
<view class="tips">
{{item.title}}
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
</template>
js
<script>
export default {
components: {},
data() {
return {
navbarBG: {
backgroundColor: '', // uview-ui配置
},
videoList: [], // 视频列表
videoCtx: null,
current_index: 0, // swiper滑动位置
play_state: true, // 播放状态(true播放,暂停false)
page: 0, // 视频分页
totalVideo: '', // 视频总条数
}
},
created() {
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; // 播放中,play_state = false
} else {
// 暂停
this.videoCtx = uni.createVideoContext(`video_${video_id}`, this);
this.videoCtx.pause(); // 暂停
this.play_state = true; // 已暂停,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.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=127397',
data:{
page: this.page,
pageSize: 10,
},
success: (res) => {
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)
}
})
setTimeout(() => {
uni.hideLoading()
}, 500)
}
}
})
}
},
},
}
</script>
css
<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>