业务需求:
小程序tab页面, 用户左右滑动屏幕实现切换tab的功能;
实现思路:
使用@touchstart, @touchmove, @touchend, @touchcancel四个事件监听用户行为, 从而实现tab切换功能;
优化重点:
当左右滑动的x, y坐标偏移量值达到多少差值时触发切换事件是直接关乎用户使用体验, 举例:
- 当用户想切换tab进行左右滑动的时候, X的差值会大, Y的差值小;
- 用户滑动突然反悔了, 想要取消一般手指会上下移动, Y的差值会增大.
- 用户仅仅是上下移动, 但是手指轨迹是比较大的弧形, 这时候Y差值大, X差值小 综上, 结合比对手机app左右滑动使用体验, 得出适合小程序tab页面切换使用体验优的参数为: X最小偏移量50,X最大偏移量200,Y最大偏移量50,最小时间60;
// useSwiper.js文件
import { ref, onMounted, onUnmounted } from "vue";
export function useSwiper({
tabList, //tab数据
curTabId,// 当前tab id
curTabIndex,// 当前tab 索引
tabChange,// tab改变事件
animation,// 动画
animationData,// 动画
}) {
let minOffset = ref(50); //最小偏移量,低于这个值不响应滑动处理
let maxOffset = ref(200); //最大偏移量,低于这个值不响应滑动处理
let minTime = ref(60); // 最小时间,单位:毫秒,低于这个值不响应滑动处理
let startX = ref(0); //开始时的X坐标
let startY = ref(0); //开始时的Y坐标
let startTime = ref(0); //开始时的毫秒数
function touchStart(e) {
startX.value = e.touches[0].pageX; // 获取触摸时的x坐标
startY.value = e.touches[0].pageY; // 获取触摸时的y坐标
startTime.value = new Date().getTime(); //获取毫秒数
}
function touchMove(e) {
animation.translateY(20).step();
animationData.value = animation.export();
setTimeout(() => {
animation.translateY(0).step();
animationData.value = animation.export();
}, 150);
}
function touchCancel(e) {
startX.value = 0; //开始时的X坐标
startY.value = 0; //开始时的Y坐标
startTime.value = 0; //开始时的毫秒数
}
function touchEnd(e) {
var endX = e.changedTouches[0].pageX;
var endY = e.changedTouches[0].pageY;
var touchTime = new Date().getTime() - startTime.value; //计算滑动时间
//开始判断
//1.判断时间是否符合
if (touchTime >= minTime.value) {
//2.判断偏移量:分X、Y
var xOffset = endX - startX.value;
var yOffset = endY - startY.value;
if (
Math.abs(xOffset) >= Math.abs(yOffset) &&
Math.abs(xOffset) >= minOffset.value &&
Math.abs(yOffset) <= 50 &&
Math.abs(xOffset) / Math.abs(yOffset) > 3
) {
//左右滑动
console.log("滑动");
if (xOffset < 0) {
// console.log('向左滑动')
if (curTabIndex.value + 1 < tabList.value.length) {
curTabIndex.value++;
} else return;
} else {
// console.log('向右滑动')
if (curTabIndex.value > 0) {
curTabIndex.value--;
} else return;
}
curTabId.value = tabList.value[curTabIndex.value].id;
tabChange();
}
} else {
// console.log('滑动时间过短', touchTime)
}
}
return { touchStart, touchMove, touchCancel, touchEnd };
}
页面使用示例:
// vue页面
<template>
<div
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@touchcancel="touchCancel"
:animation="animationData"
>
// 滑动内容
</div>
</template>
<script setup>
import { useSwiper } from "@/utils/useSwiper";
const tabList = reactive([
{
name: "新闻",
id: '101',
index: 0,
},
{
name: "动漫",
id: '102',
index: 1,
},
]);
let curTabId = ref(tabList[0].id); // 当前tab的id
let curTabIndex = ref(tabList[0].index); // 当前tab的索引
let animation = reactive(uni.createAnimation()); // uni动画(选用)
let animationData = ref({}); // 动画(选用)
const { touchStart, touchMove, touchEnd, touchCancel } = useSwiper({
tabList,
curTabId,
curTabIndex,
tabChange,
animation,
animationData,
});
// tab切换事件
function tabChange(item) {
// do something
}
</script>