恢复滚动方案
This commit is contained in:
@@ -38,13 +38,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 九宫格:保留方向性 v-reveal 新动画 -->
|
||||
<div v-else-if="page.type === 'nine-grid'" class="nine-grid grid grid-cols-3 gap-1.5 px-4 mt-6">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx"
|
||||
v-reveal="getRevealConfig(imgIdx)"
|
||||
class="aspect-square relative" :class="frameClass">
|
||||
<img :src="img" class="nine-grid-img preview-img" @click.stop="previewImage(img)" />
|
||||
</div>
|
||||
<!-- 九宫格:全入视口 activate 后再挂载/加载,播方向性 v-reveal -->
|
||||
<div v-else-if="page.type === 'nine-grid'" ref="nineGridRef" class="nine-grid grid grid-cols-3 gap-1.5 px-4 mt-6">
|
||||
<template v-if="activate">
|
||||
<div v-for="(img, imgIdx) in page.images" :key="imgIdx"
|
||||
v-reveal="getRevealConfig(imgIdx)"
|
||||
class="aspect-square relative" :class="frameClass">
|
||||
<img :src="img" class="nine-grid-img preview-img" @click.stop="previewImage(img)" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-for="(_, imgIdx) in (page.images || [])" :key="`ph-${imgIdx}`"
|
||||
class="aspect-square relative nine-grid-placeholder" :class="frameClass" aria-hidden="true" />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 瀑布流 -->
|
||||
@@ -83,16 +89,57 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { borderClass } from '@/composables/borderStyles'
|
||||
|
||||
const DECODE_TIMEOUT_MS = 4000
|
||||
|
||||
const props = defineProps({
|
||||
page: { type: Object, required: true },
|
||||
/** 九宫格专用:父级在 section 全入视口后设为 true 才加载 */
|
||||
activate: { type: Boolean, default: false },
|
||||
})
|
||||
const emit = defineEmits(['preview-image'])
|
||||
const emit = defineEmits(['preview-image', 'ready'])
|
||||
|
||||
const nineGridRef = ref(null)
|
||||
let readyEmitted = false
|
||||
|
||||
const frameClass = computed(() => borderClass(props.page.borderStyle))
|
||||
|
||||
const waitImagesReady = async () => {
|
||||
await nextTick()
|
||||
const root = nineGridRef.value
|
||||
if (!root) return
|
||||
const imgs = [...root.querySelectorAll('img[src]')]
|
||||
if (!imgs.length) return
|
||||
const decodeAll = Promise.allSettled(
|
||||
imgs.map((img) => {
|
||||
if (typeof img.decode === 'function') return img.decode().catch(() => {})
|
||||
if (img.complete) return Promise.resolve()
|
||||
return new Promise((resolve) => {
|
||||
img.addEventListener('load', resolve, { once: true })
|
||||
img.addEventListener('error', resolve, { once: true })
|
||||
})
|
||||
})
|
||||
)
|
||||
await Promise.race([
|
||||
decodeAll,
|
||||
new Promise((resolve) => setTimeout(resolve, DECODE_TIMEOUT_MS)),
|
||||
])
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.activate && props.page?.type === 'nine-grid',
|
||||
async (on) => {
|
||||
if (!on || readyEmitted) return
|
||||
await waitImagesReady()
|
||||
if (readyEmitted) return
|
||||
readyEmitted = true
|
||||
emit('ready')
|
||||
},
|
||||
{ flush: 'post' }
|
||||
)
|
||||
|
||||
const singleWrapClass = computed(() =>
|
||||
props.page.singleWidth === 'full' ? 'max-w-none' : 'max-w-[300px]'
|
||||
)
|
||||
@@ -174,6 +221,9 @@ function getRevealConfig(imgIdx) {
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
.nine-grid-img:hover { transform: translateZ(0) scale(1.03); }
|
||||
.nine-grid-placeholder {
|
||||
background: rgba(247, 246, 242, 0.85);
|
||||
}
|
||||
|
||||
.overlap-wrap { height: clamp(320px, 54vh, 460px); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user