方案一
此方案能解决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>