效果图
有上翻的动画,有商品展示,有分享,以及跳到视频库。之前网上找了很多,说swiper不能套video,现在已经可以了,第二种是把封面平铺下来,滚动的是封面那种,效果不好
思路如下:
首先用一个cover-view来控制上下滚空,监听touch事件,让swiper的index+1或者-1
swiper包裹这video,swiper不能自动滚动,但是必须要设置衔接的属性。
代码如下:
<view class="video-contain">
<!-- 自定义头部 -->
<cover-view class="nav-myself" style="height:{{navigationBarHeight+'px'}}">
<cover-view class="status-title" style="height:{{statusBarHeight+'px'}}"></cover-view>
<cover-view class="title-content">
<cover-view class="back" bindtap="goback" wx:if="{{showBack}}"><cover-image src="/image/shop/back.png"></cover-image></cover-view>
</cover-view>
</cover-view>
<!-- 滑动遮罩 -->
<cover-view class="touch-cover" bindtouchstart="touchStart" bindtouchend="touchEnd" bindtap='changeStatus'>
</cover-view>
<!-- 暂无数据 -->
<view wx:if="{{!lists.length&&!isLoading}}" >
<no-data type="common" txt="暂无数据"></no-data>
</view>
<swiper vertical="true" skip-hidden-item-layout="{{true}}" loop="{{true}}" current="{{swiperCurrent}}"
circular="{{true}}">
<swiper-item wx:for="{{lists}}" wx:key="{{index}}" wx:if="{{lists.length>0}}">
<video src="{{item.product.img_video.video[0].url}}" objectFit="contain" controls="{{false}}" loop="{{true}}" id="video{{item.id}}" data-id="{{item.id}}" custom-cache="{{false}}"></video>
</swiper-item>
</swiper>
<!-- 右侧工具 -->
<cover-view class="tools" wx:if="{{lists.length}}">
<cover-image src="https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963723_UXAJkemkT3.png" class="home-icon right-icon" bindtap='goList'></cover-image>
<button open-type="share" class="share-button">
<cover-image class="share-icon right-icon" src="https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963641_Fkf2m79fFb.png"></cover-image>
</button>
</cover-view>
<!-- 暂停按钮 -->
<cover-image class="play-btn" wx:if="{{!playState}}" bindtap='changeStatus' src="https://img.kemanyun.com/qianhuituan/2019-10-11/69_1570790815_yUO3cyjQTB.png"></cover-image>
<!-- 商品信息 -->
<cover-view class="video-goods" bindtap='goDeatil' wx:if="{{lists.length>0}}">
<cover-image src="{{lists[swiperCurrent].product.img_video.img[0]}}"></cover-image>
<cover-view class="goods-right">
<cover-view class="title">{{lists[swiperCurrent].product.title}}</cover-view>
<cover-view class="goods-price">
<cover-view class="price">
<cover-view style="color:rgb({{themeColor.mainColor}});font-size:36rpx">¥{{lists[swiperCurrent].product.price}}
</cover-view>
<cover-view class="market-price" style='width:100%'>
<cover-view class="market-box">
¥{{lists[swiperCurrent].product.market_price + ' '}}<cover-view class="hidden-box">一</cover-view>
<cover-view class="line"></cover-view>
</cover-view>
</cover-view>
</cover-view>
<cover-view class="goBuy" style='background:rgb({{themeColor.mainColor}})'>{{video_buy_button_title}}</cover-view>
</cover-view>
</cover-view>
</cover-view>
<!-- 轮播购买记录 -->
<view class="buy-info" wx:if="{{video_goods_buy_data==1}}">
<swiper indicator-dots="{{false}}" autoplay="true" vertical circular style="height:270rpx">
<block>
<swiper-item wx:for="{{lists[swiperCurrent].trade_users}}" wx:key="img">
<view class="item-li" wx:for="{{item}}" wx:for-item="oneItem" wx:for-index="idx" wx:key="idx">
<image src="{{oneItem.headimgurl}}" ></image>
<text>{{numberUtil.strLong(oneItem.name,3)}}{{video_buy_success_hint}}</text>
</view>
</swiper-item>
</block>
</swiper>
</view>
</view>
/* pages/Main/myVideo/index.wxss */
page{
width: 100%;
height: 100%;
}
.video-contain{
width: 100%;
height: 100%;
}
swiper{
height: 100%;
width: 100%;
}
swiper video{
width: 100%;
height: 100%;
}
.touch-cover{
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-image: url('https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568967223_obtnfpoWy3.png');
background-size:100% 100%;
}
.nav-myself{
position: fixed;
top: 0;
width: 100%;
display: flex;
flex-direction: column;
z-index: 999;
}
.title-content{
display: flex;
flex:1;
align-items: center;
}
.title{
display: inline-block;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}
.back{
position: absolute;
left: 30rpx;
width: 19rpx;
height: 32rpx;
}
.back image{
width: 100%;
height: 100%;
}
.tools {
position: fixed;
right: 5rpx;
top: 500rpx;
display: flex;
flex-direction: column;
width: 125rpx;
z-index: 9999;
}
.share-icon {
width: 73rpx;
height: 70rpx;
/* background-image: url(https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963641_Fkf2m79fFb.png);
background-size: 100% 100%; */
}
.right-icon {
margin: 20rpx 20rpx 28rpx 0;
}
.home-icon{
width: 75rpx;
height: 75rpx;
/* background-image: url(https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963723_UXAJkemkT3.png);
background-size: 100% 100%; */
}
.like-icon{
width: 74rpx;
height: 64rpx;
}
.text {
color: white;
width: 100rpx;
text-align: center;
margin: 0rpx 20rpx;
}
.share-button{
background-color: transparent !important;
margin:20rpx 20rpx 28rpx 0;
padding:0 !important;
}
.video-goods{
width: 578rpx;
height: 186rpx;
border-radius: 8rpx;
background: #fff;
position: fixed;
bottom: 50rpx;
left: 20rpx;
padding: 0 15rpx;
display: flex;
align-items: center;
z-index: 9999;
}
.video-goods cover-image{
height: 156rpx;
width: 156rpx;
border-radius: 8rpx;
margin-right: 20rpx;
}
.goods-right{
font-size: 28rpx;
color: #1a1a1a;
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
height: 156rpx;
}
.goods-price{
display: flex;
justify-content: space-between;
align-items: center;
}
.price{
flex:1;
}
.goBuy{
height: 52rpx;
padding: 0 30rpx;
border-radius: 26rpx;
color: #fff;
font-size: 24rpx;
line-height: 52rpx;
display: inline-block;
}
.buy-info{
position: fixed;
bottom:280rpx;
left: 20rpx;
min-width: 320rpx;
z-index: 9999;
}
.buy-info .item-li{
height: 68rpx;
padding: 0 10rpx;
border-radius: 34rpx;
background-color: rgba(0,0,0,.4);
color: #fff;
font-size: 24rpx;
display: flex;
align-items: center;
margin-bottom:20rpx;
}
.buy-info .item-li image{
width: 60rpx;
height: 60rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
height: 128rpx;
width: 128rpx;
/* background-image: url(https://img.kemanyun.com/qianhuituan/2019-10-11/69_1570790815_yUO3cyjQTB.png);
background-size: 100% 100%; */
z-index: 200;
}
.market-price{
color:#ccc;
margin-top: 5rpx;
flex:1;
width: 100%;
}
.market-box{
position: relative;
display: inline-block;
font-size:28rpx;
}
.line{
width: 100%;
position: absolute;
height: 1px;
background-color: #ccc;
top: 16rpx;
}
.hidden-box{
width: 2rpx;
background: #fff;
color: #fff;
display: inline-block;
height: 100%;
vertical-align: middle;
overflow: hidden;
}
// pages/Main/myVideo/index.js
var app = getApp()
var videoObj = ''
Page({
data: {
p: 1, // 分页
newId: 0, // 下一个要播放视频的id
oldId: 0, // 当前播放的视频id
isEnd: false, // 是否已经全部请求完毕
lists: [], // 视频数组
showBack: false, // 是否展示返回按钮
isLoading: false, // 是否加载中,供暂无数据出来
swiperCurrent: 0, // 控制swiper的current
playState: true // 暂停的开关
},
onLoad: function (options) {
// 获取头部高度, 全屏播放要兼容齐刘海各种手机型号的高度
wx.getSystemInfo({
success: res => {
const navigationBarHeight = res.statusBarHeight + 44
const statusBarHeight = res.statusBarHeight
const windowHeight = res.windowHeight
this.setData({
navigationBarHeight,
statusBarHeight
})
}
})
},
onShow: function () {
this.selfReset() //重置方法
this.getData() // 获取视频接
},
// 重置
selfReset() {
this.setData({
p: 1,
newId: 0,
oldId: 0,
lists: [],
isEnd: false,
swiperCurrent: 0,
playState: true
})
},
getData() {
if (this.data.isLoading || this.data.isEnd) {
return
}
wx.showLoading({
title: '加载中'
})
this.setData({
isLoading: true
})
let sendData = {}
sendData.page = this.data.p++
const postData = {
page: sendData.page
} // 视频播放接口传的参数
// 替换成自己封装的api请求的方法
wx.request('get', `获取视频的接口`,
postData, res => {
const data = res.data
if (data.status_code == 200) {
wx.hideLoading()
const lists = data.data.list
if (sendData.page == 1) {
this.setData({
lists: lists,
newId: lists.length>0?lists[this.data.swiperCurrent || 0].id:0,
total_pages: data.meta.pagination.total_pages,
video_buy_button_title: data.data.video_buy_button_title,
video_buy_success_hint: data.data.video_buy_success_hint,
video_goods_buy_data: data.data.video_goods_buy_data,
video_list_title: data.data.video_list_title
})
// 增加浏览量
if (this.data.lists.length>0) {
videoObj = wx.createVideoContext('video' + this.data.newId)
videoObj.play()
this.addBrowse()
}
} else {
this.setData({
lists: this.data.lists.concat(lists)
})
}
if (lists.length < 1) {
this.setData({
isEnd: true
})
}
this.setData({
isLoading: false
})
}
})
},
// 设置swiper的current,tag==1下滑+1,tag==-1上滑-1
playActive(tag) {
var lists = this.data.lists
var currentId = 0
var swiperCurrent = 0
for (var i in lists) {
// 如果找到当前播放的视频,那么要判断下一个是加1还是重头播放
if (lists[i]['id'] == this.data.newId) {
if (tag == 1) {
if (i < lists.length - 1) {
i = parseInt(i) + 1
currentId = lists[i]['id']
swiperCurrent = parseInt(this.data.swiperCurrent) + 1
} else {
//播放到最后了
currentId = lists[0]['id']
swiperCurrent = 0
}
}
if (tag == -1) {
if (i != 0) {
i = parseInt(i) - 1
currentId = lists[i]['id']
swiperCurrent = parseInt(this.data.swiperCurrent) - 1
} else {
//播放到第一个了,要把swiper的current变成数组最后一个,才能循环无缝
currentId = lists[lists.length - 1]['id']
swiperCurrent = lists.length - 1
}
}
}
}
this.setData({
swiperCurrent: swiperCurrent,
oldId: this.data.newId,
newId: currentId,
playState: true
})
var scale = this.data.swiperCurrent % 10
wx.createVideoContext('video' + this.data.oldId).pause()
// wx.createVideoContext('video' + this.data.newId).play()
videoObj = wx.createVideoContext('video' + this.data.newId)
videoObj.play()
// 增加浏览量
this.addBrowse()
// 如果还剩下5条去请求下一页
if (scale == 5) {
this.getData()
}
},
// 点击暂停
changeStatus() {
if (this.data.lists.length != 0) {
let playState = !this.data.playState
if (playState) {
// wx.createVideoContext('video' + this.data.newId).play()
videoObj = wx.createVideoContext('video' + this.data.newId)
videoObj.play()
} else {
wx.createVideoContext('video' + this.data.newId).pause()
}
this.setData({
playState: playState
})
}
},
// 浏览量
addBrowse() {
wx.request('post', 获取浏览量的接口)
},
// 跳转视频列表页面
goList() {
wx.navigateTo({
url: '../list/list',
})
},
// 商品分享
onShareAppMessage() {
const data = this.data.lists[this.data.swiperCurrent]
const product = this.data.lists[this.data.swiperCurrent].product
return {
title: product.title,
imageUrl: product.img_video.img[0],
path:''
},
// 立即购买
goDeatil() {
let uri = ''
const data = this.data.lists[this.data.swiperCurrent]
const product = this.data.lists[this.data.swiperCurrent].product
wx.navigateTo({
url: uri
})
},
// 返回
goback() {
var pages = getCurrentPages()
if (pages.length > 1) {
wx.navigateBack({
delta: 1
})
} else {
wx.switchTab({
url: '/pages/Main/index/index'
})
}
},
// 开始滑动事件
touchStart(e) {
this.setData({
startY: e.touches[0]['clientY'],
moveY: 0
})
},
// 结束滑动事件
touchEnd(e) {
var that = this
that.setData({
endY: e.changedTouches[0]['clientY']
})
var moveY = that.data.startY - that.data.endY
if (moveY > 0) {
// 手指上划,查看下一个
var sensitive = Math.abs(moveY)
if (sensitive > 50) {
that.playActive(1)
}
} else if (moveY < 0) {
// 手指下划,查看上一个
var sensitive = Math.abs(moveY)
if (sensitive > 50) {
that.playActive(-1)
}
}
}
})
js里面onshow的那个地方是我们点击tabbar的时候不需要再次调接口,做的处理,如果不是tabbar,可以直接再onload里面调后端数据
注意的是,在开发中,只要不是本地的视频,掉了接口,然后ios的前两个视频就是黑屏,后来加上了custom-cache="{{false}}">就解决了
注意的另一个兼容的是,只有cover-view才能覆盖再原生video之上,像轮播购买记录的那个地方,cover-view不能包swiper,所有有的手机是被视频遮住的
如果不妨到tabbar里的话,就是全屏播放了,头部自定义,然后左右两边也没有黑色没撑满了