小程序视频滑动效果
<!--index.wxml-->
<view class="container" catchtap="changePlayStatus" bindtouchstart="touchStart" bindtouchend="touchEnd" bindtouchcancel="touchCancel">
<view class="animation-wrapper" animation="{{animation}}">
<block wx:for="{{videos}}" wx:key="{{index}}">
<view class="animation-image-wrapper">
<image mode="aspectFill" class="animation-image" src="{{item.poster}}"></image>
</view>
</block>
</view>
<video class="vvideo" bindtimeupdate="bindtimeupdate" id="kdvideo" binderror="binderror" autoplay="{{autoplay}}" hidden="{{animationShow}}" objectFit="fill" src="{{videos[videoIndex].videoUrl}}" bindplay="bindplay" controls="{{controls}}" loop="true"></video>
<image class="play-btn" wx:if="{{!playState && !animationShow}}" src="../../icons/play.png"></image>
<progress class="progress" percent="{{percent}}" activeColor="#ffffff" backgroundColor="#A9A9A9" stroke-width="1" wx:if="{{!animationShow}}" />
</view>
```
**//index.js**
//获取应用实例
import * as event from '../utils/event.js'
const app = getApp()
const windowHeight = wx.getSystemInfoSync().windowHeight
Page({
data: {
percent: 1,
autoplay: true,
controls: false,
showFullscreenBtn: false,
showPlayBtn: false,
showFullscreenBtn: false,
showCenterPlayBtn: false,
enableProgressGesture: false,
showProgress: false,
playState: true,
animationShow: false,
currentTranslateY: 0,
touchStartingY: 0,
videos: [
{
videoUrl: "/video/124/102786/video/gnsw252jizltonrsi5rtm2cwgi2g2scdjjat2pi.mp4?v=1577685896",
poster: "/video/124/102786/video_thum/pf2ug3kzlj4dkyrrifuuq3dqjmyfqz3ygjat2pi.jpg?v=1577685896"
},
{
videoUrl: "/video/162/103466/video/hfxgwy3hoyvtm3kgobvwsl3qijhgks3iifat2pi.mp4?v=1575176526",
poster: "/video/162/103466/video_thum/jnuvc2tehfwuuqlkljgtcy3limztqnszljat2pi.jpg?v=1575176526"
},
{
videoUrl: "/video/3/103558/video/n5igyrdso5muywljifcxsyrvnvygmztfnr3t2pi.mp4?v=1577433921",
poster:"/video/3/103558/video_thum/njegqm2qmv5hgztnkjrwiwdej53e43cqnvit2pi.jpg?v=1577433921"
},
{
videoUrl:"/video/3/104902/video/ojdhg3sgkyyvi3ctlaysw2cnmjxgku3vjfit2pi.mp4?v=1583722798",
poster: "/video/3/104902/video_thum/j4vvgrzsmfzfa6rsm5yuwzkigzfvs6dym5at2pi.jpg?v=1583722798"
}
],
videoIndex: 0,
objectFit: "contain"
},
onLoad: function () {
// 滑动
this.videoChange = throttle(this.touchEndHandler, 200)
// 绑定updateVideoIndex事件,更新当前播放视频index
event.on('updateVideoIndex', this, function (index) {
console.log('event updateVideoIndex:', index)
setTimeout(() => {
this.setData({
animationShow: false,
playState: true
}, () => {
// 切换src后,video不能立即播放,settimeout一下
setTimeout(() => {
this.vvideo.play()
}, 100)
})
}, 500)
})
},
bindplay() {
console.log('--- video play ---')
},
binderror(err) {
console.log(err)
},
bindtimeupdate(e) {
let percent = (e.detail.currentTime / e.detail.duration) * 100
this.setData({
percent: percent.toFixed(2)
})
},
onReady: function () {
this.vvideo = wx.createVideoContext("kdvideo", this)
this.animation = wx.createAnimation({
duration: 500,
transformOrigin: '0 0 0'
})
},
// 播放暂停
changePlayStatus() {
console.log('changePlayStatus')
let playState = !this.data.playState
if (playState) {
this.vvideo.play()
} else {
this.vvideo.pause()
}
this.setData({
playState: playState
})
},
touchStart(e) {
let touchStartingY = this.data.touchStartingY
console.log('------touchStart------')
touchStartingY = e.touches[0].clientY
this.setData({
touchStartingY: touchStartingY
})
},
touchMove(e) {
// this.videoChange(e)
},
touchEndHandler(e) {
let touchStartingY = this.data.touchStartingY
let deltaY = e.changedTouches[0].clientY - touchStartingY
console.log('deltaY ', deltaY)
let index = this.data.videoIndex
if (deltaY > 100 && index !== 0) {
// 更早地设置 animationShow
this.setData({
animationShow: true
}, () => {
console.log('-1 切换')
this.createAnimation(-1, index).then((res) => {
console.log(res)
this.setData({
animation: this.animation.export(),
videoIndex: res.index,
currentTranslateY: res.currentTranslateY,
percent: 1
}, () => {
event.emit('updateVideoIndex', res.index)
})
})
})
} else if (deltaY < -100 && index !== (this.data.videos.length - 1)) {
this.setData({
animationShow: true
}, () => {
console.log('+1 切换')
this.createAnimation(1, index).then((res) => {
console.log(res)
this.setData({
animation: this.animation.export(),
videoIndex: res.index,
currentTranslateY: res.currentTranslateY,
percent: 1
}, () => {
event.emit('updateVideoIndex', res.index)
})
})
})
}
},
touchEnd(e) {
console.log('------touchEnd------')
this.videoChange(e)
},
touchCancel(e) {
console.log('------touchCancel------')
console.log(e)
},
createAnimation(direction, index) {
// direction为-1,向上滑动,animationImage1为(index)的poster,animationImage2为(index+1)的poster
// direction为1,向下滑动,animationImage1为(index-1)的poster,animationImage2为(index)的poster
let videos = this.data.videos
let currentTranslateY = this.data.currentTranslateY
console.log('direction ', direction)
console.log('index ', index)
// 更新 videoIndex
index += direction
currentTranslateY += -direction * windowHeight
console.log('currentTranslateY: ', currentTranslateY)
this.animation.translateY(currentTranslateY).step()
return Promise.resolve({
index: index,
currentTranslateY: currentTranslateY
})
}
})
function throttle(fn, delay) {
var timer = null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
}
/**index.wxss**/
page {
height: 100vh;
width: 100vw;
position: fixed;
}
.container {
height: 100vh;
width: 100vw;
}
.vvideo {
height: 100vh;
width: 100vw;
position: absolute;
top: 0;
left: 0;
}
.play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
height: 128rpx;
width: 128rpx;
}
.progress {
position: absolute;
left: 0;
bottom: 60px;
height: 4px;
width: 100vw;
}
.animation-wrapper {
position: relative;
height: 100vh;
width: 100vw;
background-color: #000;
}
.animation-image {
height: 100vh;
width: 100vw;
display: block;
}
.animationPre {
transform: translateY(-100%);
}