轮播图可以预览
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
interface HomeBannerSlide {
|
||||
title?: string
|
||||
eyebrow?: string
|
||||
@@ -12,14 +14,43 @@ interface Props {
|
||||
banners: HomeBannerSlide[]
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const previewVisible = ref(false)
|
||||
const previewIndex = ref(0)
|
||||
|
||||
const previewUrls = computed(() =>
|
||||
props.banners
|
||||
.map(slide => slide.image_url?.trim() || '')
|
||||
.filter((url): url is string => Boolean(url))
|
||||
)
|
||||
|
||||
function openPreview(slide: HomeBannerSlide) {
|
||||
const url = slide.image_url?.trim()
|
||||
if (!url) return
|
||||
const index = previewUrls.value.indexOf(url)
|
||||
if (index < 0) return
|
||||
previewIndex.value = index
|
||||
previewVisible.value = true
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
previewVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="hero-board">
|
||||
<el-carousel height="240px" indicator-position="outside" :interval="3600">
|
||||
<el-carousel-item v-for="slide in banners" :key="slide.title || slide.image_url">
|
||||
<div class="hero-slide" :class="[`tone-${slide.tone}`, { 'has-image': slide.image_url }]">
|
||||
<div
|
||||
class="hero-slide"
|
||||
:class="[
|
||||
`tone-${slide.tone}`,
|
||||
{ 'has-image': slide.image_url, 'is-previewable': !!slide.image_url },
|
||||
]"
|
||||
@click="openPreview(slide)"
|
||||
>
|
||||
<img
|
||||
v-if="slide.image_url"
|
||||
:src="slide.image_url"
|
||||
@@ -34,6 +65,15 @@ defineProps<Props>()
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
|
||||
<el-image-viewer
|
||||
v-if="previewVisible"
|
||||
:url-list="previewUrls"
|
||||
:initial-index="previewIndex"
|
||||
teleported
|
||||
hide-on-click-modal
|
||||
@close="closePreview"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -69,6 +109,10 @@ defineProps<Props>()
|
||||
background: linear-gradient(135deg, #eff6ff 0%, #ffffff 58%, #fff7ed 100%);
|
||||
}
|
||||
|
||||
.hero-slide.is-previewable {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.hero-slide.tone-blue {
|
||||
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 56%, #fff7ed 100%);
|
||||
}
|
||||
|
||||
@@ -250,6 +250,10 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.mobile-banner.is-previewable {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.mobile-banner.tone-warm {
|
||||
background: #9a3412;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
type AWRecycleConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { showToast } from 'vant'
|
||||
import { showImagePreview, showToast } from 'vant'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
import MobileHomeFilterSheet, { type FilterSection } from './MobileHomeFilterSheet.vue'
|
||||
import {
|
||||
@@ -485,6 +485,21 @@ function openAWRecycle() {
|
||||
awRecyclePreviewVisible.value = true
|
||||
}
|
||||
|
||||
function openBannerPreview(slide: HomeBannerSlide) {
|
||||
const url = slide.image_url?.trim()
|
||||
if (!url) return
|
||||
const images = bannerSlides.value
|
||||
.map(item => item.image_url?.trim() || '')
|
||||
.filter((item): item is string => Boolean(item))
|
||||
const startPosition = images.indexOf(url)
|
||||
if (startPosition < 0) return
|
||||
showImagePreview({
|
||||
images,
|
||||
startPosition,
|
||||
closeable: true,
|
||||
})
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
refreshing.value = true
|
||||
try {
|
||||
@@ -830,7 +845,11 @@ syncMobileHomeQuery()
|
||||
<van-swipe-item v-for="slide in bannerSlides" :key="slide.title || slide.image_url">
|
||||
<div
|
||||
class="mobile-banner"
|
||||
:class="[`tone-${slide.tone}`, { 'has-image': slide.image_url }]"
|
||||
:class="[
|
||||
`tone-${slide.tone}`,
|
||||
{ 'has-image': slide.image_url, 'is-previewable': !!slide.image_url },
|
||||
]"
|
||||
@click="openBannerPreview(slide)"
|
||||
>
|
||||
<img
|
||||
v-if="slide.image_url"
|
||||
|
||||
Reference in New Issue
Block a user