171 lines
4.2 KiB
Vue
171 lines
4.2 KiB
Vue
<template>
|
|
<view class="image-swiper">
|
|
<swiper
|
|
class="swiper-box"
|
|
:style="swiperStyle"
|
|
:autoplay="false"
|
|
:interval="3000"
|
|
:duration="1000"
|
|
:current="active"
|
|
@change="handleSwiperChange"
|
|
>
|
|
<swiper-item
|
|
class="swiper-item"
|
|
v-for="(item, index) in thumbnails"
|
|
:key="index"
|
|
>
|
|
<image :src="item.photoUrl" mode="aspectFill"></image>
|
|
</swiper-item>
|
|
</swiper>
|
|
|
|
<view class="custom-indicator">
|
|
图片{{ active + 1 }}/{{ thumbnails.length }}
|
|
</view>
|
|
|
|
<!-- 缩略图部分 -->
|
|
<view v-if="showThumbnails" class="thumbnail-box">
|
|
<scroll-view
|
|
class="thumbnail-scroll"
|
|
scroll-x="true"
|
|
:scroll-left="scrollLeft"
|
|
:scroll-with-animation="true"
|
|
show-scrollbar="false"
|
|
>
|
|
<view class="thumbnail-list">
|
|
<view
|
|
v-for="(thumb, index) in thumbnails"
|
|
:key="index"
|
|
:class="['thumbnail-item', { active: index === active }]"
|
|
:id="`thumbnail-${index}`"
|
|
@click="handleThumbnailClick(index)"
|
|
>
|
|
<image :src="thumb.photoUrl" mode="aspectFill"></image>
|
|
<text>{{ thumb.photoName }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, nextTick } from "vue";
|
|
|
|
// Props定义
|
|
const props = defineProps({
|
|
// 轮播图圆角大小,支持数字(px)或字符串
|
|
borderRadius: {
|
|
type: [Number, String],
|
|
default: 8,
|
|
},
|
|
// 轮播图数据
|
|
images: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
// 轮播图高度,支持数字(px)或字符串
|
|
height: {
|
|
type: [Number, String],
|
|
default: 200,
|
|
},
|
|
// 是否显示缩略图
|
|
showThumbnails: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
});
|
|
|
|
const active = ref(0);
|
|
const scrollLeft = ref(0);
|
|
|
|
// 计算圆角样式
|
|
const borderRadiusStyle = computed(() => {
|
|
const radius =
|
|
typeof props.borderRadius === "number"
|
|
? `${props.borderRadius}px`
|
|
: props.borderRadius;
|
|
return {
|
|
borderRadius: radius,
|
|
};
|
|
});
|
|
|
|
// 计算轮播图样式(包含高度和圆角)
|
|
const swiperStyle = computed(() => {
|
|
const radius =
|
|
typeof props.borderRadius === "number"
|
|
? `${props.borderRadius}px`
|
|
: props.borderRadius;
|
|
const swiperHeight =
|
|
typeof props.height === "number" ? `${props.height}px` : props.height;
|
|
return {
|
|
borderRadius: radius,
|
|
height: swiperHeight,
|
|
};
|
|
});
|
|
|
|
// 默认图片数据
|
|
const defaultImages = [
|
|
{
|
|
photoUrl:
|
|
"https://fastly.picsum.photos/id/866/654/400.jpg?hmac=z3vI4CYrpnXEgimSlJCDwXRxEa-UDHiRwzGEyB8V-po",
|
|
photoName: "瑶山古寨",
|
|
},
|
|
{
|
|
photoUrl:
|
|
"https://fastly.picsum.photos/id/284/654/400.jpg?hmac=89XRCJxYTblKIFGLOp6hJ9U0GC8BQrcnJwE5pG21NAk",
|
|
photoName: "民俗表演",
|
|
},
|
|
{
|
|
photoUrl:
|
|
"https://fastly.picsum.photos/id/281/654/400.jpg?hmac=hcAJB7y2Xz3DVuz6S4XeQZgzaTJ_QWnxtbnaagZL6Fs",
|
|
photoName: "特色美食",
|
|
},
|
|
{
|
|
photoUrl:
|
|
"https://fastly.picsum.photos/id/435/654/400.jpg?hmac=TSVDxfo-zXbunxNQK0erSG_nmKcS20xfhbQsCAXLlHo",
|
|
photoName: "传统服饰",
|
|
},
|
|
{
|
|
photoUrl:
|
|
"https://fastly.picsum.photos/id/737/654/400.jpg?hmac=VED05oEK3XB0Aa_DUVoZjTAf0bHjAmNYyJky4lq5vVo",
|
|
photoName: "其他",
|
|
},
|
|
];
|
|
|
|
// 使用传入的图片数据或默认数据
|
|
const thumbnails = computed(() => {
|
|
return props.images.length ? props.images : defaultImages;
|
|
});
|
|
|
|
const handleThumbnailClick = (index) => {
|
|
active.value = index;
|
|
scrollToActiveItem(index);
|
|
};
|
|
|
|
// 滚动到选中项
|
|
const scrollToActiveItem = async (index) => {
|
|
await nextTick();
|
|
|
|
// 计算每个缩略图项的宽度(包括间距)
|
|
const itemWidth = 58; // 48px宽度 + 10px间距
|
|
const containerWidth = 300; // 大概的容器宽度
|
|
const targetScrollLeft = Math.max(
|
|
0,
|
|
index * itemWidth - containerWidth / 2 + itemWidth / 2
|
|
);
|
|
|
|
scrollLeft.value = targetScrollLeft;
|
|
};
|
|
|
|
// 监听主轮播图变化,同步缩略图滚动
|
|
const handleSwiperChange = (e) => {
|
|
const currentIndex = e.detail.current;
|
|
active.value = currentIndex;
|
|
scrollToActiveItem(currentIndex);
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import "./styles/index.scss";
|
|
</style>
|