小程序模仿抖音上下滑动视频
Posted 海龟先生plus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小程序模仿抖音上下滑动视频相关的知识,希望对你有一定的参考价值。
前景知识
要实现小程序类似抖音上下滑动预览视频,就我了解的,方案可以分为两种
1、利用原生组件swiper(据说很卡,我也试过,好像是有点不流畅)
2、自己实现一个上下滑动效果(只需要监听一组事件,判断上拉还是下拉,接着就是移动dom)
这里就采用第二种方案自己实现 ps: (本案例基于字节小程序,由于字节已经实现原生组件同层渲染,所以这里不考虑组件层级问题,如果是其他平台,可能需要结合实际解决同层渲染问题,思路应该是一致的)
先看效果:
布局
笔者准备在视频列表外嵌套一个大盒子,这个大盒子就用于监听触摸事件(由于是自己实现上下滑动画,所以这个盒子高度应该是内容区域高度,且设置 overflow: hidden 避免出现盒子自己的滚动条);内层就是需要添加动画的盒子+视频列表
<!-- 大盒子 -->
<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>
所以由上布局可以确定思路:在 video-box 上监听触摸事件,用 ani-box 控制上下滑动
触摸事件
原理就是记录下触摸开始位置+结束位置,两者y坐标差值,即可得知是上拉还是下拉(通常会有一个缓冲距离,这里设置为30,30以内不触发)
// 触摸开始
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)
,
动画
上面知道了是上拉还是下拉,接下来就是滚动整个列表。其实滚动高度始终是 内容区域高度的整数倍(这里暂时不做像swiper那样,边触摸边移动的效果,而直接滑动后,直接滚动到下一个视频,所以是整数倍)
// 获取内容高度高度
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)
)
)
,
// 动画实现
moveY = -1 * nowIndex * viewHeight
animation.translateY(moveY).step()
this.getVideoCtx(nowIndex)
this.setData(
animationData: animation.export()
)
如果对小程序动画api不熟悉的,可以去看下createAnimation。这里主要思路是:滚动总高度 = 内容高度 * 滚动到第几个 ;假设当是第一个视频,要滚动到第二个视频,则滚动高度 = 1 x 内容高度,要滚动到第三个视频则滚动高度 = 2 x 内容高度
完整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)
)
)
,
)
添加一下css
ps:这是后面补充的(仅供参考)
.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;
补充
动画:在做时踩了一个坑,添加动画的盒子需要设置初始css状态translateY = 0,导致一直没反应,这一点其实跟css过渡是一样的,整个动画应该是 0 --1 的过程,而不是 无 – 有 (好比 display none — block 添加过渡是无效的)
个人感觉 video标签 可以考虑始终使用一个,滑动只切换视频地址,或许这样性能会更好点(但是这样会导致滑动后,每一个视频都会重新加载,不会是上一次加载位置)
仿抖音上下滑动播放视频(兼容安卓,ios,小程序,h5)
仿抖音上下滑动播放视频(兼容安卓,ios,小程序,h5)
运行条件
HBuilder X 2.2.2
安装后,从插件市场导入,即可真机运行
vue
项目地址
github https://github.com/15157757001/scroll-video
uniapp插件市场 https://ext.dcloud.net.cn/plugin?id=664
说明
插件分别用swiper实现(多端兼容)和css3动画实现(暂时只支持app),可自行切换。
插件在uni-app编译模式下编写(已切换)。
默认为weex编译模式,在 manifest.json 的源码视图里配置是切换模式, manifest.json -> app-plus -> nvueCompiler 切换编译模式。
swiper在非App端内嵌video性能比较差,不建议导入过多视频。
项目效果
h5在线地址 https://github.com/15157757001/15157757001
以上是关于小程序模仿抖音上下滑动视频的主要内容,如果未能解决你的问题,请参考以下文章