feat: 实现相关商品的样式调整
This commit is contained in:
155
src/components/SwipeCards/index.vue
Normal file
155
src/components/SwipeCards/index.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<view class="swipe-cards" @touchmove.stop>
|
||||
<view
|
||||
v-for="(card, index) in visibleCards"
|
||||
:key="`${card.commodityId}-${index}`"
|
||||
class="card"
|
||||
:style="cardStyle(index, card)"
|
||||
@touchstart="touchStart($event, index)"
|
||||
@touchmove="touchMove($event, index)"
|
||||
@touchend="touchEnd($event, index)"
|
||||
>
|
||||
<slot :card="card" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
cardsData: Array,
|
||||
threshold: { type: Number, default: 100 },
|
||||
});
|
||||
|
||||
const cards = ref([...props.cardsData]);
|
||||
const startX = ref(0);
|
||||
const startY = ref(0);
|
||||
const moveX = ref(0);
|
||||
const moveY = ref(0);
|
||||
const currentIndex = ref(null);
|
||||
const isHorizontal = ref(false); // 是否为水平滑动
|
||||
|
||||
const visibleCards = computed(() => cards.value.slice(0, 3));
|
||||
|
||||
function touchStart(e, index) {
|
||||
const touch = e.touches[0];
|
||||
startX.value = touch.clientX;
|
||||
startY.value = touch.clientY;
|
||||
currentIndex.value = index;
|
||||
isHorizontal.value = false;
|
||||
}
|
||||
|
||||
function touchMove(e, index) {
|
||||
if (currentIndex.value !== index) return;
|
||||
const touch = e.touches[0];
|
||||
moveX.value = touch.clientX - startX.value;
|
||||
moveY.value = touch.clientY - startY.value;
|
||||
|
||||
// 第一次移动时判断方向
|
||||
if (
|
||||
!isHorizontal.value &&
|
||||
(Math.abs(moveX.value) > 10 || Math.abs(moveY.value) > 10)
|
||||
) {
|
||||
if (Math.abs(moveX.value) > Math.abs(moveY.value)) {
|
||||
isHorizontal.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是水平滑动,阻止页面滚动
|
||||
if (isHorizontal.value) {
|
||||
e.preventDefault?.();
|
||||
}
|
||||
}
|
||||
|
||||
function touchEnd(e, index) {
|
||||
if (!isHorizontal.value) return; // 如果不是水平滑动,不处理
|
||||
if (Math.abs(moveX.value) > props.threshold) {
|
||||
const direction = moveX.value > 0 ? 1 : -1;
|
||||
animateSwipe(index, direction);
|
||||
} else {
|
||||
resetCard(index);
|
||||
}
|
||||
moveX.value = 0;
|
||||
moveY.value = 0;
|
||||
currentIndex.value = null;
|
||||
}
|
||||
|
||||
function animateSwipe(index, direction) {
|
||||
const card = cards.value[index];
|
||||
if (!card) return;
|
||||
card.swiped = true;
|
||||
card.direction = direction;
|
||||
setTimeout(async () => {
|
||||
const removed = cards.value.splice(index, 1)[0];
|
||||
removed.swiped = false;
|
||||
removed.direction = 0;
|
||||
cards.value.push(removed);
|
||||
await nextTick();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function resetCard(index) {
|
||||
const card = cards.value[index];
|
||||
if (!card) return;
|
||||
card.swiped = false;
|
||||
card.direction = 0;
|
||||
}
|
||||
|
||||
function cardStyle(index, card) {
|
||||
const baseIndex = visibleCards.value.length - index;
|
||||
const zIndex = baseIndex;
|
||||
const scale = 1 - index * 0.05;
|
||||
const translateY = index * 28;
|
||||
|
||||
const translateDrag =
|
||||
currentIndex.value === index
|
||||
? `translate(${moveX.value}px, ${moveY.value}px)`
|
||||
: `translate(0, ${translateY}rpx)`;
|
||||
const rotate =
|
||||
currentIndex.value === index
|
||||
? `rotate(${moveX.value / 15}deg)`
|
||||
: "rotate(0)";
|
||||
|
||||
let opacity = 1;
|
||||
if (card.swiped) opacity = 0;
|
||||
|
||||
let transform = `${translateDrag} scale(${scale}) ${rotate}`;
|
||||
|
||||
if (card.swiped) {
|
||||
const x = card.direction * 500;
|
||||
transform = `translate(${x}px, ${moveY.value}px) rotate(${
|
||||
card.direction * 45
|
||||
}deg)`;
|
||||
}
|
||||
|
||||
return `
|
||||
z-index: ${zIndex};
|
||||
background: ${card.color};
|
||||
transform: ${transform};
|
||||
opacity: ${opacity};
|
||||
transition: ${
|
||||
card.swiped ? "all 0.3s ease-out" : "transform 0.2s ease-out"
|
||||
};
|
||||
`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.swipe-cards {
|
||||
position: relative;
|
||||
height: 320px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 6px 6px 12px 6px;
|
||||
}
|
||||
|
||||
.card {
|
||||
position: absolute;
|
||||
width: calc(100% - 12px);
|
||||
height: calc(100% - 30px);
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 8px 8px rgba(0, 0, 0, 0.08);
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user