仿淘宝商品详情页的轮播
实现放淘宝详情页商品介绍
博客园不支持上传视频,或者我没找到上传视频的位置,只能放几张图片配上注释介绍下实现的效果。

蓝色文字,左侧轮播写错了,应该是右侧轮播,依次在左侧放大显示。

一、轮播下的按钮,比较简单也说下怎么做的

<div class="indicators-bottom">
<div class="select-tabs">
<div :class="['common-tab', activeTab === 'video' ? 'acvtive-tab' : 'normal-tab']" @click="selectTab('video')">视频</div>
<div :class="['common-tab', activeTab === 'pic' ? 'acvtive-tab' : 'normal-tab']" @click="selectTab('pic')">图文</div>
</div>
</div>
样式
.indicators-bottom{ display: flex; justify-content: center; margin-top: 16px; width: 460px; } .select-tabs{ @extend .flex-center; width: 123px; height: 36px; border-radius: 6px; background-color: #EAEFF5; .common-tab{ width: 60px; height: 30px; border-radius: 6px; text-align: center; line-height: 30px; font-size: 14px ; cursor: pointer; } .acvtive-tab{ background-color: #fff; color: #161B2C; font-weight: 500; } .normal-tab{ color: #86909C; font-weight: 400; } }
方法
// 选择活跃方式 const selectTab = (val) => { activeTab.value = val if(val === 'pic') { resStartAutoPlay() // 如果选择图文,开始轮播 } else if(val === 'video') { scrollY.value = 0 // 滚回最上面 currentIndex.value = -1 // 左侧的活跃index为-1,图文从0开始 stopAutoPlay() // 如果是视频,停止轮播 } }
二、左侧回显视频以及图片的代码
<div class="carousel-inner" :style="innerStyle">
<div v-if="activeTab === 'video'">
<video :src="workDetailData.fileVideo" controls autoplay class="video"></video>
</div>
<template v-else-if="activeTab === 'pic'">
<div
class="carousel-item"
v-for="(item, index) in imgList"
:key="`carousel${item.id}${index}`"
>
<img v-if="item.showGoodsCover" :src="item.url" class="carousel-item-img" @error="imgRecommondLoad($event, item)"/>
<view class="default-goodspic-img" v-else>
<img src="/images/common/no-cover-img.png" class="img" />
</view>
</div>
</template>
</div>
样式
.carousel-inner { display: flex; width: 460px; height: 460px; .carousel-item { min-width: 100%; box-sizing: border-box; background-size: 100% 100%; .carousel-item-img{ width: 460px; height: 460px; object-fit: cover; border-radius: 20px; } .line { width: 70px; height: 16px; background: #fff; } .carousel-index { font-family: DIN; font-size: 130px; font-weight: 600; color: #fff; margin: 20px 0 40px 0; } .carousel-label { font-family: Source Han Sans SC; font-weight: 500; color: #fff; } .default-goodspic-img{ width: 460px; height: 460px; background-color: #E6E9F0; @extend .flex-center; .img{ width: 160px; height: 104px; object-fit: cover; } } } }
元素滚动的关键配置!!!!
const innerStyle = computed(() => { return { transform: `translateX(-${currentIndex.value == -1 ? 0 : currentIndex.value * 100}%)`, transition: `transform 0.3s ease-in-out`, }; });
左侧显示涉及到的方法
// 轮播作品封面加载错误提示 const imgRecommondLoad = (e, data) => { data.showGoodsCover = false; }
三、轮播图列表以及按钮控件的代码
<div class="goodspic-right" >
<div class="common-move up" @click="scrollUp" v-if="scrollY < 0">
<img src="/images/marketplace/icon/up.png" class="move-img" />
</div>
<div ref="imageContainer" class="image-wrapper" :style="{ transform: `translateY(${scrollY}px)` }">
<div v-if="workDetailData.fileVideo && workDetailData.fileVideo !== ''" :class="['right-item', currentIndex === -1 ? 'active-item' : '']">
<img :src="workDetailData.coverUrl" class="carousel-item-img" @mouseover="hoverfirstVideo"/>
</div>
<div
v-for="(item, index) in imgList"
:key="`right${item.id}${index}`"
:class="['right-item', currentIndex === index ? 'active-item' : '']"
>
<img v-if="item.showGoodsCover" :src="item.url" class="carousel-item-img" @error="imgRecommondLoad($event, item)" @mouseover="hoverGoodPic(index)" @mouseout="mouseoutGoodPic"/>
<div class="default-right-img" v-else>
<img src="/images/common/no-cover-img.png" class="img" />
</div>
</div>
</div>
<div class="common-move down" @click.stop="scrollDown" v-if="!isLastImage()">
<img src="/images/marketplace/icon/down.png" class="move-img" />
</div>
</div>
首先上下两个按钮的显示时机,当悬浮到列表上,列表超出当前范围高度时,显示向下的按钮,如果滚到底部则不显示;当列表向下滚动时,才会出现向上的按钮,滚到顶部,向上的按钮不出现。
// hover轮播图片 const hoverGoodPic = (index) => { currentIndex.value = index; activeTab.value = 'pic' stopAutoPlay() } // out轮播图片 const mouseoutGoodPic = (index) => { startAutoPlay() }
向上或者向下按钮事件
const scrollDown = () => {
const newScrollY = scrollY.value - 2 * imageHeightWithGap;
const maxScroll = -(imgList.value.length - 2) * imageHeightWithGap;
scrollY.value = Math.max(newScrollY, maxScroll);
console.log('scrollDown', scrollY.value);
}
const scrollUp = () => {
const newScrollY = scrollY.value + 2 * imageHeightWithGap;
scrollY.value = Math.min(newScrollY, 0);
}
判断是否最后一张图片
const isLastImage = () => { // console.log('?????????', -(imgList.value.length - 1) * imageHeightWithGap, scrollY.value <= -(imgList.value.length - 1) * imageHeightWithGap); if(imgList.value.length <= 4) { return true; } return scrollY.value <= -(imgList.value.length - 3) * imageHeightWithGap; };
计算滚动的距离
const imageContainer = ref(null) const scrollY = ref(0); const showDownBtn = ref(false); const showUpBtn = ref(false); const imgList = ref([]) const imageHeightWithGap = 100 + 20; // 检查元素距离底部的距离,计算需要滚动的距离 const checkScrollPosition = () => { const scrollContainerHeight = 460; const threshold = 120; let imageBottom = 0; // 计算选中图片底部到容器底部的距离 if(workDetailData.value.fileVideo && workDetailData.value.fileVideo !== '') { imageBottom = (currentIndex.value + 2) * imageHeightWithGap; } else { imageBottom = (currentIndex.value + 1) * imageHeightWithGap; } const distanceToBottom = scrollContainerHeight - imageBottom; // 如果选中图片距离底部小于阈值,则滚动 if (distanceToBottom < threshold) { // 计算需要滚动的距离 scrollY.value = -(imageBottom - scrollContainerHeight + threshold); } else if (currentIndex.value * imageHeightWithGap < threshold) { // 如果选中图片距离顶部小于阈值,则向上滚动 scrollY.value = 0 } } function startAutoPlay() { autoPlayInterval.value = setInterval(() => { const len = imgList.value.length currentIndex.value = (currentIndex.value + 1) % len; checkScrollPosition() }, 3000); } const resStartAutoPlay = () => { currentIndex.value = 0 startAutoPlay() } function stopAutoPlay() { clearInterval(autoPlayInterval.value); }
浙公网安备 33010602011771号