fix(listings): 手机轮播改为居中裁切,左右滑只切换图片

超宽海报在图内横滑不好看。轮播和预览都只保留中间一段,左右滑动回到切换下一张。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-10-05 15:38:06 +08:00
co-authored by Cursor
parent bd502bfa63
commit c559287ee4
2 changed files with 17 additions and 134 deletions
@@ -330,59 +330,23 @@
.banner-swipe.is-poster { .banner-swipe.is-poster {
height: 168px; height: 168px;
background: #eef3f8;
} }
.mobile-banner.is-poster { .mobile-banner.is-poster {
height: 168px; height: 168px;
min-height: 0; min-height: 0;
padding: 0; padding: 0;
background: #eef3f8;
}
.poster-scroller {
height: 100%;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.poster-scroller::-webkit-scrollbar {
display: none;
} }
.mobile-banner.is-poster .banner-image { .mobile-banner.is-poster .banner-image {
position: static; object-fit: cover;
display: block; object-position: center;
width: auto;
max-width: none;
height: 168px;
object-fit: unset;
background: transparent;
} }
.mobile-banner.is-poster .banner-badge { .mobile-banner.is-poster .banner-badge {
display: none; display: none;
} }
.banner-step-row {
display: flex;
justify-content: flex-end;
gap: 8px;
margin: -4px 0 12px;
}
.banner-step-row button {
border: 0;
padding: 4px 10px;
border-radius: 999px;
background: #e8eef5;
color: #334155;
font-size: 12px;
font-weight: 700;
}
.banner-lightbox { .banner-lightbox {
position: fixed; position: fixed;
inset: 0; inset: 0;
@@ -412,39 +376,29 @@
border-radius: 999px; border-radius: 999px;
} }
.banner-lightbox-count,
.banner-lightbox-hint {
margin: 0;
text-align: center;
}
.banner-lightbox-count { .banner-lightbox-count {
position: absolute; position: absolute;
top: calc(18px + env(safe-area-inset-top)); top: calc(18px + env(safe-area-inset-top));
left: 0; left: 0;
right: 0; right: 0;
margin: 0;
text-align: center;
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
} }
.banner-lightbox-scroller { .banner-lightbox-frame {
overflow-x: auto; width: 100%;
overflow-y: hidden; aspect-ratio: 2.15 / 1;
-webkit-overflow-scrolling: touch; overflow: hidden;
} }
.banner-lightbox-scroller img { .banner-lightbox-frame img {
display: block; display: block;
width: auto; width: 100%;
max-width: none; height: 100%;
height: 58vh; object-fit: cover;
margin: 0 auto; object-position: center;
}
.banner-lightbox-hint {
margin-top: 14px;
color: rgba(255, 255, 255, 0.72);
font-size: 12px;
} }
.banner-lightbox-nav { .banner-lightbox-nav {
@@ -103,10 +103,8 @@ const displayBanners = computed<HomeBannerSlide[]>(() => {
} }
return bannerSlides.value return bannerSlides.value
}) })
const bannerSwipeRef = ref<{ prev: () => void; next: () => void } | null>(null)
const bannerPreviewVisible = ref(false) const bannerPreviewVisible = ref(false)
const bannerPreviewIndex = ref(0) const bannerPreviewIndex = ref(0)
const bannerPreviewScroller = ref<HTMLElement | null>(null)
const bannerPreviewImages = computed(() => const bannerPreviewImages = computed(() =>
displayBanners.value displayBanners.value
.map(slide => slide.image_url?.trim() || '') .map(slide => slide.image_url?.trim() || '')
@@ -520,42 +518,6 @@ function openCooperationFeedback() {
cooperationFeedbackPreviewVisible.value = true cooperationFeedbackPreviewVisible.value = true
} }
let posterDragged = false
function centerWideImage(event: Event) {
const img = event.target as HTMLImageElement
const scroller = img.parentElement
if (!scroller) return
scroller.scrollLeft = Math.max(0, (scroller.scrollWidth - scroller.clientWidth) / 2)
}
function onPosterTouchStart() {
posterDragged = false
}
function onPosterTouchMove() {
posterDragged = true
}
function onPosterClick(slide: HomeBannerSlide) {
if (posterDragged) {
posterDragged = false
return
}
openBannerPreview(slide)
}
function stepBanner(step: number) {
if (step < 0) bannerSwipeRef.value?.prev()
else bannerSwipeRef.value?.next()
}
function centerBannerPreview() {
const scroller = bannerPreviewScroller.value
if (!scroller) return
scroller.scrollLeft = Math.max(0, (scroller.scrollWidth - scroller.clientWidth) / 2)
}
function openBannerPreview(slide: HomeBannerSlide) { function openBannerPreview(slide: HomeBannerSlide) {
const url = slide.image_url?.trim() const url = slide.image_url?.trim()
if (!url) return if (!url) return
@@ -575,11 +537,8 @@ function shiftBannerPreview(step: number) {
bannerPreviewIndex.value = (bannerPreviewIndex.value + step + total) % total bannerPreviewIndex.value = (bannerPreviewIndex.value + step + total) % total
} }
watch([bannerPreviewVisible, bannerPreviewIndex], async ([open]) => { watch(bannerPreviewVisible, open => {
document.body.style.overflow = open ? 'hidden' : '' document.body.style.overflow = open ? 'hidden' : ''
if (!open) return
await nextTick()
centerBannerPreview()
}) })
function hasBannerCopy(slide: HomeBannerSlide) { function hasBannerCopy(slide: HomeBannerSlide) {
@@ -973,7 +932,6 @@ if (!restoreHomeConfigFromCache()) {
<!-- Banner 轮播 --> <!-- Banner 轮播 -->
<van-swipe <van-swipe
ref="bannerSwipeRef"
class="banner-swipe" class="banner-swipe"
:class="{ :class="{
'is-poster': displayBanners.some(slide => slide.image_url && !hasBannerCopy(slide)), 'is-poster': displayBanners.some(slide => slide.image_url && !hasBannerCopy(slide)),
@@ -994,23 +952,9 @@ if (!restoreHomeConfigFromCache()) {
}, },
]" ]"
@click="openBannerPreview(slide)" @click="openBannerPreview(slide)"
>
<div
v-if="slide.image_url && !hasBannerCopy(slide)"
class="poster-scroller"
@touchstart.stop="onPosterTouchStart"
@touchmove.stop="onPosterTouchMove"
@click.stop="onPosterClick(slide)"
> >
<img <img
class="banner-image" v-if="slide.image_url"
:src="slide.image_url"
:alt="slide.title || '首页轮播图'"
@load="centerWideImage"
/>
</div>
<img
v-else-if="slide.image_url"
class="banner-image" class="banner-image"
:src="slide.image_url" :src="slide.image_url"
:alt="slide.title || slide.eyebrow || '首页轮播图'" :alt="slide.title || slide.eyebrow || '首页轮播图'"
@@ -1024,16 +968,6 @@ if (!restoreHomeConfigFromCache()) {
</div> </div>
</van-swipe-item> </van-swipe-item>
</van-swipe> </van-swipe>
<div
v-if="
displayBanners.length > 1 &&
displayBanners.some(slide => slide.image_url && !hasBannerCopy(slide))
"
class="banner-step-row"
>
<button type="button" @click="stepBanner(-1)">上一张</button>
<button type="button" @click="stepBanner(1)">下一张</button>
</div>
<div class="biz-entry-grid" aria-label="业务入口"> <div class="biz-entry-grid" aria-label="业务入口">
<RouterLink class="biz-entry" to="/"> <RouterLink class="biz-entry" to="/">
@@ -1388,14 +1322,9 @@ if (!restoreHomeConfigFromCache()) {
<p class="banner-lightbox-count"> <p class="banner-lightbox-count">
{{ bannerPreviewIndex + 1 }}/{{ bannerPreviewImages.length }} {{ bannerPreviewIndex + 1 }}/{{ bannerPreviewImages.length }}
</p> </p>
<div ref="bannerPreviewScroller" class="banner-lightbox-scroller"> <div class="banner-lightbox-frame">
<img <img :src="bannerPreviewImages[bannerPreviewIndex]" alt="轮播图预览" />
:src="bannerPreviewImages[bannerPreviewIndex]"
alt="轮播图预览"
@load="centerBannerPreview"
/>
</div> </div>
<p class="banner-lightbox-hint">左右滑动查看完整海报</p>
<div v-if="bannerPreviewImages.length > 1" class="banner-lightbox-nav"> <div v-if="bannerPreviewImages.length > 1" class="banner-lightbox-nav">
<button type="button" @click="shiftBannerPreview(-1)">上一张</button> <button type="button" @click="shiftBannerPreview(-1)">上一张</button>
<button type="button" @click="shiftBannerPreview(1)">下一张</button> <button type="button" @click="shiftBannerPreview(1)">下一张</button>