feat(CP页面): 处理触摸事件滑动和点击事件冲突的问题
This commit is contained in:
parent
06bff5843e
commit
e8cd6bed98
@ -63,6 +63,7 @@
|
|||||||
@touchstart="handleTouchStart"
|
@touchstart="handleTouchStart"
|
||||||
@touchmove="handleTouchMove"
|
@touchmove="handleTouchMove"
|
||||||
@touchend="handleTouchEnd"
|
@touchend="handleTouchEnd"
|
||||||
|
style="touch-action: pan-x"
|
||||||
>
|
>
|
||||||
<!-- 右占位 -->
|
<!-- 右占位 -->
|
||||||
<div style="width: 9vw; min-width: 0; flex-shrink: 0"></div>
|
<div style="width: 9vw; min-width: 0; flex-shrink: 0"></div>
|
||||||
@ -70,38 +71,44 @@
|
|||||||
<!-- top1情侣头像 -->
|
<!-- top1情侣头像 -->
|
||||||
<itemCenter
|
<itemCenter
|
||||||
v-for="(item, index) in seasonTop1List"
|
v-for="(item, index) in seasonTop1List"
|
||||||
|
:key="`couple-${item.userId || index}`"
|
||||||
style="z-index: 1; min-width: 0; flex-shrink: 0; transition: all 0.8s ease"
|
style="z-index: 1; min-width: 0; flex-shrink: 0; transition: all 0.8s ease"
|
||||||
:style="{ width: index === centerIndex ? '60vw' : '40vw' }"
|
:style="{
|
||||||
|
width: index === centerIndex ? '60vw' : '40vw',
|
||||||
|
zIndex: index === centerIndex ? 20 : 1,
|
||||||
|
}"
|
||||||
:imgUrl="twelveSigns[index]?.bgUrl"
|
:imgUrl="twelveSigns[index]?.bgUrl"
|
||||||
:contentStyle="``"
|
:contentStyle="``"
|
||||||
>
|
>
|
||||||
<!-- 非居中时显示遮罩层用于移动 -->
|
<!-- 非居中时显示遮罩层用于移动 -->
|
||||||
<div
|
<div
|
||||||
v-if="index !== centerIndex"
|
v-if="index !== centerIndex"
|
||||||
style="position: absolute; z-index: 10; inset: 0"
|
style="position: absolute; inset: 0; z-index: 9; pointer-events: auto"
|
||||||
@click.stop="moveToCenter(index)"
|
@click.stop="moveToCenter(index)"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- 点击事件 -->
|
<!-- 点击事件 -->
|
||||||
<div
|
<div
|
||||||
|
v-if="index === centerIndex"
|
||||||
style="
|
style="
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 9;
|
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
z-index: 20;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
pointer-events: none;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<!-- 情侣1 -->
|
<!-- 情侣1 -->
|
||||||
<div
|
<div
|
||||||
style="flex: 1; min-width: 0; align-self: stretch"
|
style="flex: 1; min-width: 0; align-self: stretch; pointer-events: auto"
|
||||||
@click="viewUserInfo(item.userId)"
|
@click.stop="handleAvatarClick(item.userId)"
|
||||||
></div>
|
></div>
|
||||||
<!-- 情侣2 -->
|
<!-- 情侣2 -->
|
||||||
<div
|
<div
|
||||||
style="flex: 1; min-width: 0; align-self: stretch"
|
style="flex: 1; min-width: 0; align-self: stretch; pointer-events: auto"
|
||||||
@click="viewUserInfo(item.cpUserId)"
|
@click.stop="handleAvatarClick(item.cpUserId)"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1448,9 +1455,14 @@ const resultShowIndex = ref(0) // 抽奖结果索引
|
|||||||
const seasonTop1List = ref([]) // 赛季榜Top1列表
|
const seasonTop1List = ref([]) // 赛季榜Top1列表
|
||||||
const listLeftPosition = ref('0') //top历史榜单
|
const listLeftPosition = ref('0') //top历史榜单
|
||||||
const centerIndex = ref(0) // 默认中间项的索引为1
|
const centerIndex = ref(0) // 默认中间项的索引为1
|
||||||
|
|
||||||
// 添加触摸滑动相关变量
|
// 添加触摸滑动相关变量
|
||||||
const touchStartX = ref(0)
|
const touchStartX = ref(0)
|
||||||
const touchEndX = ref(0)
|
const touchEndX = ref(0)
|
||||||
|
const isSwipe = ref(false) // ✅ 新增:标记是否为滑动
|
||||||
|
const isMoving = ref(false)
|
||||||
|
const lastClickTime = ref(0) // ✅ 新增:记录上次点击时间
|
||||||
|
const clickLock = ref(false) // ✅ 新增:点击锁,防止同一事件多次触发
|
||||||
|
|
||||||
const twelveSigns = ref([
|
const twelveSigns = ref([
|
||||||
{ name: 'Aquarius', time: '2026.1.20-2.18', bgUrl: imageUrl('AquariusCoupleFrame') }, // 水瓶座
|
{ name: 'Aquarius', time: '2026.1.20-2.18', bgUrl: imageUrl('AquariusCoupleFrame') }, // 水瓶座
|
||||||
@ -1467,54 +1479,141 @@ const twelveSigns = ref([
|
|||||||
{ name: 'Capricorn', time: '2026.12.22-1.19', bgUrl: imageUrl('') }, // 摩羯座
|
{ name: 'Capricorn', time: '2026.12.22-1.19', bgUrl: imageUrl('') }, // 摩羯座
|
||||||
]) // 十二星座
|
]) // 十二星座
|
||||||
|
|
||||||
// 计算移动到中心位置的函数
|
// 点击居中项头像
|
||||||
const moveToCenter = (targetIndex) => {
|
const handleAvatarClick = (userId, event) => {
|
||||||
if (centerIndex.value == targetIndex) return // 如果当前索引和目标索引相同,则不需要移动
|
const now = Date.now()
|
||||||
|
|
||||||
centerIndex.value = targetIndex
|
// 滑动中不触发点击(防止滑动时误触)
|
||||||
updatePosition() // 更新位置
|
if (isSwipe.value) {
|
||||||
}
|
event?.stopPropagation() // 滑动中阻止点击
|
||||||
|
return
|
||||||
// 触发触摸开始事件
|
|
||||||
const handleTouchStart = (event) => {
|
|
||||||
touchStartX.value = event.touches[0].clientX
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发触摸移动事件
|
|
||||||
const handleTouchMove = (event) => {
|
|
||||||
touchEndX.value = event.touches[0].clientX
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发触摸结束事件
|
|
||||||
const handleTouchEnd = () => {
|
|
||||||
if (!touchStartX.value) return
|
|
||||||
|
|
||||||
let minSwipeDistance = 50 //x轴最小滑动距离
|
|
||||||
let distance = touchEndX.value - touchStartX.value // 左滑<0 右滑>0
|
|
||||||
let isLeftSwipe = distance < -minSwipeDistance // 满足左滑
|
|
||||||
let isRightSwipe = distance > minSwipeDistance // 满足右滑
|
|
||||||
|
|
||||||
if (isLeftSwipe) {
|
|
||||||
// 左滑
|
|
||||||
if (centerIndex.value > 0) {
|
|
||||||
moveToCenter(centerIndex.value - 1)
|
|
||||||
}
|
|
||||||
} else if (isRightSwipe) {
|
|
||||||
// 右滑
|
|
||||||
if (centerIndex.value < seasonTop1List.value.length - 1) {
|
|
||||||
moveToCenter(centerIndex.value + 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置触摸变量
|
// 移动动画中不触发点击
|
||||||
|
if (isMoving.value) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击锁检查(防止重复触发)
|
||||||
|
if (clickLock.value) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖:100ms 内重复点击忽略
|
||||||
|
if (now - lastClickTime.value < 100) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clickLock.value = true
|
||||||
|
lastClickTime.value = now
|
||||||
|
viewUserInfo(userId)
|
||||||
|
|
||||||
|
// 50ms 后释放点击锁
|
||||||
|
setTimeout(() => {
|
||||||
|
clickLock.value = false
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
event?.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动到中心位置
|
||||||
|
const moveToCenter = (targetIndex, event) => {
|
||||||
|
const now = Date.now()
|
||||||
|
|
||||||
|
// 点击锁检查
|
||||||
|
if (clickLock.value) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 目标已是中心或正在移动中
|
||||||
|
if (centerIndex.value == targetIndex || isMoving.value) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖:100ms 内重复调用忽略
|
||||||
|
if (now - lastClickTime.value < 100) {
|
||||||
|
event?.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clickLock.value = true
|
||||||
|
isMoving.value = true
|
||||||
|
centerIndex.value = targetIndex
|
||||||
|
lastClickTime.value = now
|
||||||
|
|
||||||
|
updatePosition()
|
||||||
|
|
||||||
|
// 800ms 后释放锁(与 CSS transition 时间一致)
|
||||||
|
setTimeout(() => {
|
||||||
|
isMoving.value = false
|
||||||
|
clickLock.value = false
|
||||||
|
}, 800)
|
||||||
|
|
||||||
|
event?.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸开始
|
||||||
|
const handleTouchStart = (event) => {
|
||||||
|
touchStartX.value = event.touches[0].clientX
|
||||||
|
isSwipe.value = false // 每次触摸开始重置滑动标记
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸移动
|
||||||
|
const handleTouchMove = (event) => {
|
||||||
|
if (!event.touches || event.touches.length === 0) return
|
||||||
|
|
||||||
|
touchEndX.value = event.touches[0].clientX
|
||||||
|
const distance = touchEndX.value - touchStartX.value
|
||||||
|
|
||||||
|
// 滑动距离超过 10px 标记为滑动
|
||||||
|
if (Math.abs(distance) > 10) {
|
||||||
|
isSwipe.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸结束
|
||||||
|
const handleTouchEnd = (event) => {
|
||||||
|
if (!touchStartX.value) {
|
||||||
|
isSwipe.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.changedTouches && event.changedTouches.length > 0) {
|
||||||
|
touchEndX.value = event.changedTouches[0].clientX
|
||||||
|
}
|
||||||
|
|
||||||
|
const minSwipeDistance = 50
|
||||||
|
const distance = touchEndX.value - touchStartX.value
|
||||||
|
const isLeftSwipe = distance < -minSwipeDistance
|
||||||
|
const isRightSwipe = distance > minSwipeDistance
|
||||||
|
|
||||||
|
// 先执行移动(此时 isSwipe 仍为 true)
|
||||||
|
if (isLeftSwipe && centerIndex.value > 0) {
|
||||||
|
moveToCenter(centerIndex.value - 1)
|
||||||
|
} else if (isRightSwipe && centerIndex.value < seasonTop1List.value.length - 1) {
|
||||||
|
moveToCenter(centerIndex.value + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后重置触摸变量
|
||||||
touchStartX.value = 0
|
touchStartX.value = 0
|
||||||
touchEndX.value = 0
|
touchEndX.value = 0
|
||||||
|
isSwipe.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新位置
|
// 更新位置
|
||||||
const updatePosition = () => {
|
const updatePosition = () => {
|
||||||
const itemWidth = 40 // vw,根据您的代码中每个项目宽度
|
const itemWidth = 40 // vw,每个项目宽度
|
||||||
const itemSpacing = 2 // vw,根据您的代码中项目间距
|
const itemSpacing = 2 // vw,项目间距
|
||||||
const targetOffset = (itemWidth + itemSpacing) * centerIndex.value
|
const targetOffset = (itemWidth + itemSpacing) * centerIndex.value
|
||||||
listLeftPosition.value = targetOffset + 'vw'
|
listLeftPosition.value = targetOffset + 'vw'
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user