1. 迎宾海报

This commit is contained in:
李琦
2026-08-04 10:26:00 +08:00
parent 05ff2cc7aa
commit 5a25304774
7 changed files with 929 additions and 29 deletions

View File

@@ -197,6 +197,31 @@
</div>
</div>
<!-- 爱心拼接绝对定位心形轮廓 + 串行挂载 -->
<div v-else-if="page.type === 'heart-collage'" ref="multiRootRef" class="g-heart mt-6">
<div
v-for="(slot, imgIdx) in HEART_SLOTS"
:key="imgIdx"
class="g-heart-slot"
:class="{ 'g-heart-placeholder': imgIdx >= shownCount }"
:style="heartSlotStyle(slot)"
>
<div
v-if="imgIdx < shownCount"
v-reveal="{ variant: heartReveal(imgIdx), immediate: true }"
class="absolute inset-0 g-heart-cell"
:class="frameClass"
>
<img
:src="displayAt(imgIdx)"
class="preview-img g-heart-img"
decoding="async"
@click.stop="previewImage(originalAt(imgIdx))"
/>
</div>
</div>
</div>
<div v-else class="text-center text-[#8A8680] text-[12px] mt-6">未识别的版式{{ page.type }}</div>
</div>
</template>
@@ -236,8 +261,26 @@ const SEQUENTIAL_SELF_TYPES = new Set([
'polaroid',
'nine-grid',
'one-large-five-small',
'heart-collage',
])
/** 爱心拼接槽位:百分比绝对定位,轮廓接近 ♥(顶开叉、中最宽、底收尖) */
const HEART_SLOTS = [
{ l: 10, t: 0, w: 32, h: 13 }, // 0 左上叶
{ l: 58, t: 0, w: 32, h: 13 }, // 1 右上叶(中间约 16% 开叉)
{ l: 0, t: 14, w: 14, h: 15.5 }, // 2 左外上
{ l: 0, t: 30.5, w: 14, h: 15.5 }, // 3 左外下
{ l: 15, t: 14, w: 26, h: 32 }, // 4 左大图
{ l: 42, t: 14, w: 16, h: 32 }, // 5 中轴
{ l: 59, t: 14, w: 26, h: 32 }, // 6 右大图
{ l: 86, t: 14, w: 14, h: 15.5 }, // 7 右外上
{ l: 86, t: 30.5, w: 14, h: 15.5 }, // 8 右外下
{ l: 10, t: 47, w: 13, h: 16 }, // 9 左下收腰
{ l: 24, t: 47, w: 52, h: 16 }, // 10 中下横
{ l: 77, t: 47, w: 13, h: 16 }, // 11 右下收腰
{ l: 38, t: 64, w: 24, h: 14 }, // 12 心尖
]
const props = defineProps({
page: { type: Object, required: true },
/** 九宫格:开启串行 v-reveal关闭则一次展示 */
@@ -447,7 +490,7 @@ const runSequentialByType = async () => {
await runOlfsSequential()
return
}
if (type === 'masonry' || type === 'polaroid') {
if (type === 'masonry' || type === 'polaroid' || type === 'heart-collage') {
await runMultiSequential()
}
}
@@ -608,6 +651,23 @@ function polaroidTransform(i) {
return `rotate(${a}deg) translateY(${s}px)`
}
/** 爱心:左右对称入场,中轴与心尖用缩放 */
function heartReveal(i) {
if (i === 5 || i === 12) return 'scale'
if (i === 0 || i === 2 || i === 3 || i === 4 || i === 9) return 'left'
if (i === 1 || i === 6 || i === 7 || i === 8 || i === 11) return 'right'
return 'up'
}
function heartSlotStyle(slot) {
return {
left: `${slot.l}%`,
top: `${slot.t}%`,
width: `${slot.w}%`,
height: `${slot.h}%`,
}
}
</script>
<style scoped>
@@ -706,6 +766,9 @@ function polaroidTransform(i) {
max-width: 400px;
height: clamp(340px, 48vh, 460px);
}
.g-heart {
max-width: 400px;
}
.g-carousel-slide {
height: min(52vh, 420px);
}
@@ -724,6 +787,75 @@ function polaroidTransform(i) {
.g-dot { width: 7px; height: 7px; border-radius: 9999px; border: none; background: rgba(168,140,107,0.3); padding: 0; cursor: pointer; transition: all 0.3s; }
.g-dot.active { background: #a88c6b; width: 18px; border-radius: 9999px; }
/* 爱心拼接:绝对定位块状心形 + 淡囍底纹 */
.g-heart {
position: relative;
width: 100%;
max-width: 400px;
margin-inline: auto;
aspect-ratio: 0.8 / 1;
padding: 4px 2px 8px;
box-sizing: border-box;
isolation: isolate;
}
.g-heart::before,
.g-heart::after {
content: '囍';
position: absolute;
z-index: 0;
font-family: var(--font-calligraphy), serif;
font-weight: 700;
color: #c97878;
pointer-events: none;
user-select: none;
line-height: 1;
}
.g-heart::before {
top: 22%;
left: 50%;
transform: translateX(-50%);
font-size: clamp(64px, 24vw, 108px);
opacity: 0.07;
}
.g-heart::after {
bottom: 10%;
left: 50%;
transform: translateX(-50%);
font-size: clamp(36px, 12vw, 56px);
opacity: 0.05;
}
.g-heart-slot {
position: absolute;
z-index: 1;
min-width: 0;
min-height: 0;
contain: layout paint;
}
.g-heart-placeholder {
visibility: hidden;
pointer-events: none;
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
.g-heart-cell {
overflow: hidden;
transition: transform 0.35s ease, box-shadow 0.35s ease;
}
@media (hover: hover) {
.g-heart-cell:hover {
transform: scale(1.03);
z-index: 3;
box-shadow: 0 6px 18px rgba(80, 50, 40, 0.16);
}
}
.g-heart-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.g-polaroid { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px 10px; padding: 14px 4px 4px; }
.g-polaroid-slot {
width: 42%;