uniapp的swiper组件如何让首页不能往右划,尾页不能往左划
在 UniApp 开发中,swiper 组件默认提供了强大的滑动功能,但在实际应用中,我们经常需要限制用户在首页(索引 0)不能再向前(右滑),在尾页(最大索引)不能再向后(左滑)。
最终采用的优化方案:即时阻止 + 回弹兜底
我们最终采用的方案是结合了触摸事件的 实时干预 和 @change 事件的 保障回弹,以达到最佳的稳定性和用户体验。
通过在 <swiper-item> 上监听触摸事件,我们可以绕开 swiper 对事件的拦截,并在用户开始滑动时立即判断是否需要阻止。
-
监听事件:
-
@touchstart="handleTouchStart" -
@touchmove="handleTouchMove" -
@touchend="disableTouch = false"
-
-
核心逻辑 (
handleTouchMove):-
记录滑动距离
diffX = currentX - startX。 -
设置一个合理的 滑动阈值(如 10-15px),以过滤掉手指的微小抖动。
-
在首页 (current === 0) 时: 如果
diffX > 阈值(尝试右滑),立即设置disableTouch = true,阻止swiper继续接收手势。 -
在尾页 (current === maxIndex) 时: 如果
diffX < -阈值(尝试左滑),立即设置disableTouch = true。
-
2. 回弹兜底(最终保障)
为了应对 touchmove 拦截失败的极端情况,我们保留了 @change 事件中的回弹逻辑。
-
监听事件:
@change="changeSwiperType" -
核心逻辑 (
changeSwiperType):-
在
@change触发后,如果newIndex不符合边界规则(例如从尾页切换到了下一页),则立刻执行:-
disableTouch = true -
state.current = lastIndex(强制跳回原页) -
使用
setTimeout延迟解除disableTouch,确保动画完成后恢复正常手势。
-
-
<script setup>
const disableTouch = ref(false); // 控制 Swiper 禁用滑动
const startPointX = ref(0); // 记录触摸开始时的 X 坐标
const totalPage = 4; // 假设您的 nearby.vue 有 4 个页面
const THRESHOLD = 15; // 滑动阈值(防止微小抖动触发禁用)
const state = reactive({
current: 0,
all: [{}],
});
function handleTouchStart(e) {
if (e.touches.length > 0) {
startPointX.value = e.touches[0].clientX;
disableTouch.value = false;
}
}
/**
* 触摸移动:根据滑动方向在边界页立即阻止 (核心逻辑)
*/
function handleTouchMove(e) {
if (e.touches.length === 0) return;
const currentX = e.touches[0].clientX;
const diffX = currentX - startPointX.value; // > 0 为右滑,< 0 为左滑
// 1. 当前在首页 (0):只允许向左滑
if (state.current === 0) {
// 尝试右滑 (diffX > 0) 且超过阈值
if (diffX > THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
// 2. 当前在尾页 (totalPage - 1):只允许向右滑
if (state.current === totalPage - 1) {
// 尝试左滑 (diffX < 0) 且超过阈值
if (diffX < -THRESHOLD) {
disableTouch.value = true;
} else {
disableTouch.value = false;
}
return;
}
// 非边界页,允许正常滑动
disableTouch.value = false;
}
/**
* Swiper 切换事件 (@change) - 作为回弹兜底
*/
function changeSwiperType(e) {
const newIndex = e.detail.current;
const lastIndex = state.current;
const isSwipingRight = newIndex < lastIndex; // 索引变小 (向右滑/回退)
const isSwipingLeft = newIndex > lastIndex; // 索引变大 (向左滑/前进)
// 1. 首页 (0) 发生意外右滑 -> 强制回弹
if (lastIndex === 0 && isSwipingRight) {
disableTouch.value = true;
state.current = 0;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
// 2. 尾页 (totalPage - 1) 发生意外左滑 -> 强制回弹
if (lastIndex === totalPage - 1 && isSwipingLeft) {
disableTouch.value = true;
state.current = lastIndex;
setTimeout(() => {
disableTouch.value = false;
}, 50);
return;
}
// 正常切换
state.current = newIndex;
handleTabChange(newIndex); // 保持原有逻辑
disableTouch.value = false;
}
</script>
更多推荐
所有评论(0)