126 lines
2.6 KiB
Vue
126 lines
2.6 KiB
Vue
<template>
|
||
<view class="laser-variant-pyramid">
|
||
<view
|
||
v-for="(image, index) in paths"
|
||
:key="index"
|
||
class="card-item"
|
||
:class="{ 'card-selected': selectedIndex === index }"
|
||
:style="getCardStyle(index)"
|
||
@tap="onSelect(index)"
|
||
>
|
||
<view class="card-frame">
|
||
<image class="card-image" :src="image" mode="aspectFill" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
|
||
const props = defineProps({
|
||
paths: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
selectedIndex: {
|
||
type: Number,
|
||
default: -1,
|
||
},
|
||
})
|
||
|
||
const emit = defineEmits(['select'])
|
||
|
||
const onSelect = (index) => {
|
||
emit('select', index)
|
||
}
|
||
|
||
// 复用 generation-result 中「金字塔」视觉参数(rpx)
|
||
const getCardStyle = (index) => {
|
||
// 顶部:1张大(z=30) | 中间:2张中 | 底部:2张小
|
||
const allPositions = [
|
||
{ left: 40, top: 624, rotate: '-5deg', scale: 0.72, zIndex: 10 }, // 0
|
||
{ left: 130, top: 580, rotate: '-8deg', scale: 0.82, zIndex: 20 }, // 1
|
||
{ left: 275, top: 500, rotate: '0deg', scale: 1.15, zIndex: 30 }, // 2
|
||
{ left: 420, top: 580, rotate: '8deg', scale: 0.82, zIndex: 20 }, // 3
|
||
{ left: 510, top: 624, rotate: '5deg', scale: 0.72, zIndex: 10 }, // 4
|
||
]
|
||
|
||
let posIndex
|
||
if (props.selectedIndex === -1) {
|
||
posIndex = index
|
||
} else {
|
||
if (index === props.selectedIndex) {
|
||
posIndex = 2
|
||
} else {
|
||
const relativePos = (index - props.selectedIndex + 5) % 5
|
||
if (relativePos === 1) posIndex = 3
|
||
else if (relativePos === 2) posIndex = 4
|
||
else if (relativePos === 3) posIndex = 0
|
||
else if (relativePos === 4) posIndex = 1
|
||
else posIndex = 2
|
||
}
|
||
}
|
||
|
||
const pos = allPositions[posIndex]
|
||
|
||
if (props.selectedIndex === index) {
|
||
return {
|
||
left: `${pos.left}rpx`,
|
||
top: `${pos.top}rpx`,
|
||
transform: `scale(${pos.scale * 1.15})`,
|
||
filter: 'brightness(1.15) drop-shadow(0 0 40rpx rgba(100, 200, 255, 0.9))',
|
||
zIndex: 100,
|
||
}
|
||
}
|
||
|
||
return {
|
||
left: `${pos.left}rpx`,
|
||
top: `${pos.top}rpx`,
|
||
transform: `scale(${pos.scale})`,
|
||
zIndex: pos.zIndex,
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.laser-variant-pyramid {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 20;
|
||
}
|
||
|
||
.card-item {
|
||
position: absolute;
|
||
width: 200rpx;
|
||
height: 260rpx;
|
||
transition: all 0.2s ease;
|
||
filter: drop-shadow(0 15rpx 40rpx rgba(0, 0, 0, 0.5));
|
||
}
|
||
|
||
.card-frame {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(180, 220, 255, 0.95) 0%,
|
||
rgba(200, 230, 255, 0.95) 50%,
|
||
rgba(220, 240, 255, 0.95) 100%
|
||
);
|
||
border-radius: 20rpx;
|
||
overflow: hidden;
|
||
border: 5rpx solid rgba(255, 255, 255, 0.9);
|
||
padding: 10rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.card-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 14rpx;
|
||
}
|
||
</style>
|
||
|