要实现小程序类似抖音上下滑动预览视频,就我了解的,方案可以分为两种
1、利用原生组件swiper(据说很卡,我也试过,好像是有点不流畅)
2、自己实现一个上下滑动效果(只需要监听一组事件,判断上拉还是下拉,接着就是移动dom)
这里就采用第二种方案自己实现 ps: (本案例基于字节小程序,由于字节已经实现原生组件同层渲染,所以这里不考虑组件层级问题,如果是其他平台,可能需要结合实际解决同层渲染问题,思路应该是一致的)

布局
笔者准备在视频列表外嵌套一个大盒子,这个大盒子就用于监听触摸事件(由于是自己实现上下滑动画,所以这个盒子高度应该是内容区域高度,且设置 overflow: hidden 避免出现盒子自己的滚动条);内层就是需要添加动画的盒子+视频列表。
抖音开发平台:tt.createVideoContext_小程序_抖音开放平台 (open-douyin.com)
index.wxml
<!-- 大盒子 -->
<view class="video-box" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd">
<!-- 上滑滑动 动画盒子 -->
<view class="ani-box" animation="{{animationData}}">
<!-- 视频列表 -->
<view tt:for="{{videoList}}" :key="{{item.id}}" class="item-{{item.id}} item">
<video id="video-{{index}}" src="{{item.src}}" autoplay="{{false}}" loop="{{true}}" object-fit="fill" show-fullscreen-btn="{{false}}" vslide-gesture-in-fullscreen="{{false}}" />
</view>
</view>
</view>
index.js
let animation = null
let viewHeight = 0
Page({
data: {
videoList: [{
id: 1,
src: 'xxx',
},
{
id: 2,
src: 'xxx',
},
{
id: 3,
src: 'xxxx',
}
],
oldId: -1,
startPage: 0,
animationData: {},
viewIndex: 0
},
onLoad: function () {
this.getViewHeight()
this.getVideoCtx(0)
},
getVideoCtx(id) {
// 有上一个
if (this.data.oldId > -1) {
tt.createVideoContext("video-${this.data.oldId}").pause()
}
const ctx = tt.createVideoContext("video-${id}")
// console.log(ctx)
ctx.play()
this.setData({
oldId: id
})
},
// 触摸开始
onTouchStart({
touches
}) {
const {
pageY
} = touches[0]
this.setData({
startPage: pageY
})
// console.log('按下',pageY)
},
// 触摸移动
onTouchMove({
touches
}) {
// const { pageY } = touches[0]
// console.log('移动',pageY)
},
// 触摸结束
onTouchEnd({
changedTouches
}) {
const {
pageY
} = changedTouches[0]
const diff = pageY - this.data.startPage
if (Math.abs(diff) <= 30) {
console.log('不触发')
return
}
if (diff > 0) {
this.setAni(1)
} else if (diff == 0) {
this.setAni(0)
} else {
this.setAni(-1)
}
},
// 滑动动画 0 不移动 -1 上拉 1 下拉
async setAni(status) {
if (status == 0) return false
if (!animation) {
animation = tt.createAnimation({
duration: 500,
timingFunction: 'ease'
});
}
if (!viewHeight) {
await this.getViewHeight()
}
// 计算位移
let moveY = 0
let nowIndex = this.data.viewIndex
status > 0 ? nowIndex-- : nowIndex++
if (nowIndex < 0) {
tt.showToast({
title: '到顶部了'
})
return
}
if (nowIndex == this.data.videoList.length) {
tt.showToast({
title: '到底了哦'
})
return
}
moveY = -1 * nowIndex * viewHeight
animation.translateY(moveY).step()
this.getVideoCtx(nowIndex)
this.setData({
animationData: animation.export(),
viewIndex: nowIndex
})
},
// 获取dom高度
getViewHeight() {
return new Promise((resolve) => {
const query = tt.createSelectorQuery()
query.select(".item-1").boundingClientRect()
query.exec(function (res) {
if (res.length && res[0]) {
viewHeight = res[0].height
resolve(viewHeight)
}
})
})
},
})
index.wxss
.video-box {
height: 100vh;
overflow: hidden;
position: relative;
}
.item {
width: 100%;
height: 100vh;
}
video {
width: 100%;
height: 100%;
}
.ani-box {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transform: translateY(0px);
z-index: -1;
}
原文链接:https://blog.csdn.net/qq_45219069/article/details/124164517