officialAccount/compontent/public/photohuadong.vue

249 lines
5.9 KiB
Vue
Raw Normal View History

2025-06-09 17:33:50 +08:00
<template>
<view
class="carousel"
@touchstart="onTouchStart"
@touchmove.prevent="onTouchMove"
@touchend="onTouchEnd"
>
<view
v-for="(img, i) in visibleImages"
:key="img"
class="carousel-item"
:style="itemStyle(i)"
>
<image :src="img" mode="aspectFill" class="carousel-image" />
<view class="font" :style="i==1?{fontWeight:600}:{}" >{{img.includes('0') ? imageName[0] : (img.includes('1') ? imageName[1] : imageName[2])}} </view>
</view>
<view
class="carousel-item"
:style="leftCopyStyle"
key="left-copy"
>
<image :src="leftCopyImage" mode="aspectFill" class="carousel-image" />
</view>
<view
class="carousel-item"
:style="rightCopyStyle"
key="right-copy"
>
<image :src="rightCopyImage" mode="aspectFill" class="carousel-image" />
</view>
</view>
</template>
<script setup>
import { ref, computed,watch } from 'vue';
const emit = defineEmits(['updateCenterIndex'])
const images = ref([
'/static/index/three/0.png',
'/static/index/three/1.png',
'/static/index/three/2.png',
])
const imageName = ref([
"长者入住",
"机构加盟",
"员工入驻",
])
const len = images.value.length
const startX = ref(0)
const position = ref(0)
const isDragging = ref(false)
const enableTransition = ref(false)
const dragDirection = ref(0)
const imageSpacing = 220
const centerIndex = computed(() => {
return mod(Math.floor(position.value), len)
})
const leftIndex = computed(() => mod(centerIndex.value - 1, len))
const rightIndex = computed(() => mod(centerIndex.value + 1, len))
const visibleImages = computed(() => [
images.value[leftIndex.value],
images.value[centerIndex.value],
images.value[rightIndex.value],
])
const leftCopyImage = computed(() => images.value[leftIndex.value])
const rightCopyImage = computed(() => images.value[rightIndex.value])
function mod(n, m) {
return ((n % m) + m) % m
}
function onTouchStart(e) {
if (enableTransition.value) enableTransition.value = false
isDragging.value = true
startX.value = e.touches[0].clientX
dragDirection.value = 0
}
function onTouchMove(e) {
if (!isDragging.value) return
const currentX = e.touches[0].clientX
const delta = currentX - startX.value
dragDirection.value = delta > 0 ? 1 : -1
position.value -= delta / imageSpacing
startX.value = currentX
}
function onTouchEnd() {
if (!isDragging.value) return
isDragging.value = false
enableTransition.value = true
position.value = Math.round(position.value)
}
function itemStyle(i) {
const floorPos = Math.floor(position.value)
const offset = position.value - floorPos // [-1, 1)
const absOff = Math.abs(offset) // 0 → 1
// 计算水平偏移
const baseX = (i - 1) * imageSpacing
const translateX = baseX - offset * imageSpacing
// 透明度和 zIndex保持原来逻辑不变
let opacity = 0.5
let zIndex = 1
if (i === 1) {
opacity = 1 - 0.5 * absOff
zIndex = 3
} else if ((i === 2 && offset >= 0) || (i === 0 && offset < 0)) {
opacity = 0.5 + 0.5 * absOff
zIndex = 2
}
// ← 这里是关键:统一用 absOff 计算 scale
let scale = 0.8
if (i === 1) {
// 中心项目offset 0 时放到 1.1offset 1 时收到 0.8
scale = 1.1 - 0.3 * absOff
} else if ((i === 2 && offset >= 0) || (i === 0 && offset < 0)) {
// 侧边项目offset 0 时 0.8offset 1 时 1.1
scale = 0.8 + 0.3 * absOff
}
return {
transform: `translate(-50%, -50%) translateX(${translateX}rpx) scale(${scale})`,
opacity,
zIndex,
transition: enableTransition.value
? 'transform 0.3s ease, opacity 0.3s ease'
: 'none',
}
}
const leftCopyStyle = computed(() => {
const show = dragDirection.value === 1
const floorPos = Math.floor(position.value)
const offset = position.value - floorPos
const translateX = 2.2 * imageSpacing - offset * imageSpacing
let scale = 0.8
let opacity = 0.5
let zIndex = 2
if (offset < 0) {
const posOffset = -offset
scale = 0.8 + 0.5 * posOffset
opacity = 0.5 + 0.5 * posOffset
}
return {
transform: `translate(-50%, -50%) translateX(${translateX}rpx) scale(${scale})`,
opacity,
zIndex,
pointerEvents: 'none',
position: 'absolute',
top: '40%',
left: '50%',
opacity: show ? 0.5 : 0,
willChange: 'transform, opacity',
transition: enableTransition.value
? 'transform 0.3s ease, opacity 0.3s ease'
: 'none',
}
})
const rightCopyStyle = computed(() => {
const show = dragDirection.value === 1
const floorPos = Math.floor(position.value)
const offset = position.value - floorPos
const translateX = -2.2 * imageSpacing - offset * imageSpacing
let scale = 0.8
let opacity = 0.5
let zIndex = 2
if (offset >= 0) {
scale = 0.8 + 0.5 * offset
opacity = 0.5 + 0.5 * offset
}
return {
transform: `translate(-50%, -50%) translateX(${translateX}rpx) scale(${scale})`,
opacity,
zIndex,
pointerEvents: 'none',
position: 'absolute',
top: '40%',
left: '50%',
opacity: show ? 0.5 : 0,
willChange: 'transform, opacity',
transition: enableTransition.value
? 'transform 0.3s ease, opacity 0.3s ease'
: 'none',
}
})
// 3. 监听 centerIndex 的变化,一旦改变就 emit
watch(centerIndex, (newIdx) => {
// console.log("???",newIdx)
emit('updateCenterIndex', newIdx)
})
</script>
<style scoped>
.carousel {
position: relative;
width: 90%;
height: 650rpx;
display: flex;
justify-content: center;
overflow: hidden;
}
.carousel-item {
position: absolute;
width: 300rpx;
height: 450rpx;
top: 40%;
left: 50%;
margin: 0;
backface-visibility: hidden;
will-change: transform, opacity;
}
.carousel-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
user-select: none;
touch-action: pan-y;
pointer-events: none;
}
.font{
width: 100%;
display: flex;
justify-content: center;
margin-top: 20rpx;
}
</style>