如果我知道我是一只井底之蛙,那我还是井底之蛙吗

这成了一个系列,从选项卡中间点击闪屏,到选项卡点击动画,如今继续上压力;10分钟!手搓uni-pp微信小程序左右滑动选项卡列表
# 前提阅读
《【继续作死】 20行代码 uni-app 小程序选项卡重复点击 执行列表左侧滑入动画》
思路
uni-app监听手势滑动,判断用户是在选项卡列表中有滑动。再使用滑动时间长差和滑动阈值优化事件,最后判断用户发动方向来实现不同滑动特效
核心
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
效果

代码
<template>
<view>
<!-- 选项卡 -->
<view class="login-type-switch">
<view
class="switch-item"
v-for="(item, index) in tab"
:class="{ active: active == index }"
@tap="tabTap(index)"
>
{{ item }}
</view>
</view>
<!-- 公告列表 -->
<view
class="slide-container"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
:style="{'min-height': screenHeight - '260' + 'px'}"
:class="{ 'slide-in-right': slideDirection === 'right' && isSlide, 'slide-in-left': slideDirection === 'left' && isSlide }"
>
<view v-for="(item, index) in oneDa" :key="index">
<view
class="list-view"
v-if="item.type == active"
:class="{ 'fade-in': !isSlide }"
>
<view class="list-title">
{{ item.title }}
</view>
<view class="list-content">
<view class="list-content-item">
发表于:{{ item.create_time }}
</view>
<view class="list-content-item">
阅读:{{ item.number ? item.number : '0' }}
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
tab: ['系统通知', '产品推送'], //选项卡
active: 0,
isSlide: false, // 滑动动画
touchStartX: 0, // 触摸开始的X坐标
touchEndX: 0, // 触摸结束的X坐标
touchStartTime: 0, // 触摸开始的时间
touchEndTime: 0, // 触摸结束的时间
swipeThreshold: 50, // 滑动阈值
swipeTimeThreshold: 150, // 滑动时间阈值
screenHeight: 0, //屏幕高度
slideDirection: '', // 滑动方向
oneDa: [
{
title: '今天是周一',
create_time: '2025-04-22',
number: 12,
type: 0
},
{
title: '今天是周二',
create_time: '2025-04-22',
number: 12,
type: 0
},
{
title: '今天是周三',
create_time: '2025-04-22',
number: 12,
type: 1
},
{
title: '今天是周四',
create_time: '2025-04-22',
number: 12,
type: 1
}
]
}
},
onLoad() {
uni.getSystemInfo({
success: (res) => {
this.screenHeight = res.screenHeight
}
});
this.slideDirection = 'left';
this.tabTap(0)
},
methods: {
// 选项卡
tabTap(e) {
this.active = e;
this.isSlide = false;
this.getList();
},
getList() {
// 动画结束后重置状态 可以丢到请求数据成功后执行
setTimeout(() => {
this.isSlide = true;
}, 100);
},
// 触摸开始事件
onTouchStart(e) {
this.touchStartX = e.touches[0].clientX;
this.touchStartTime = Date.now();
},
// 触摸移动事件
onTouchMove(e) {
this.touchEndX = e.touches[0].clientX;
},
// 触摸结束事件
onTouchEnd() {
this.touchEndTime = Date.now();
const deltaX = this.touchEndX - this.touchStartX;
if (this.touchEndX == 0) {
return
}
const deltaTime = this.touchEndTime - this.touchStartTime;
if (Math.abs(deltaX) > this.swipeThreshold && deltaTime > this.swipeTimeThreshold) {
if (deltaX > 0) {
// 右滑
if (this.active > 0) {
this.slideDirection = 'left';
this.tabTap(this.active - 1);
}
} else {
// 左滑
if (this.active < this.tab.length - 1) {
this.slideDirection = 'right';
this.tabTap(this.active + 1);
}
}
}
}
}
}
</script>
<style scoped>
.list-content {
margin-top: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 20rpx;
color: #999;
}
.list-title {
font-size: 36rpx;
font-weight: bold;
padding-bottom: 30rpx;
border-bottom: 1px #f4f4f4 solid;
}
.list-view {
padding: 30rpx 40rpx;
border-radius: 20px;
margin: 40rpx 20rpx;
background-color: #ffffff;
overflow: hidden;
position: relative;
}
/* 登录方式切换样式 */
.login-type-switch {
display: flex;
padding: 30rpx 20rpx;
justify-content: center;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.switch-item {
padding: 12rpx 24rpx;
font-size: 26rpx;
color: #999;
position: relative;
margin-right: 24rpx;
white-space: nowrap;
transition: all 0.3s ease;
}
.switch-item.active {
color: #000;
font-weight: 600;
}
.switch-item.active::after {
content: "";
position: absolute;
bottom: 0.0625rem;
left: 50%;
transform: translateX(-50%);
width: 0.5rem;
height: 0.125rem;
background: #000;
border-radius: 0.0625rem;
}
.form-wrapper {
position: relative;
min-height: 400rpx;
}
/* 滑动动画 */
.slide-container {
overflow: hidden;
transition: all 0.3s ease-out;
}
.slide-in-right {
animation: slideInRight 0.3s ease-out forwards;
}
.slide-in-left {
animation: slideInLeft 0.3s ease-out forwards;
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideInLeft {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* 添加淡入动画 */
.fade-in {
opacity: 0;
animation: fadeIn 3s ease-out forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
page {
background-color: #f5f7fa;
}
</style>