一个简单的适用于小程序端的中间放大轮播图
结构:
<!--轮播图 -->
<view class="moveSwiper">
<!--轮播图中间放大-->
<view class="carousel" onTouchStart="handleTouchStart" onTouchEnd="handleTouchEnd">
<view
a:for="{{images}}"
class="carousel-item"
a:key="index"
style="left: {{itemLefts[index]}}rpx; transform: scale({{itemScales[index]}});"
onTap="handleTap"
data-index="{{index}}"
>
<image src="{{item}}" mode="aspectFill" class="carousel-image" />
</view>
</view>
<!--轮播图指示器 -->
<view class="Tiparrow bgcf">
<view class="Movemsg pad26">
<view class="moveGradesBox">
<text class="MvTitle">拯救嫌疑人</text>
<text class="moveGrades">9.1分</text>
</view>
<view class="moveIntruduce MvIntroduce">
<text>119分钟</text>
<text>悬疑</text>
</view>
</view>
</view>
</view>
逻辑:(这里解释一下取模,其实也就是取余。假设 this.data.activeIndex
为 0(当前活动索引是第一个项目),this.data.images.length
为 3(总共有 3 个轮播图项目)。现在,用户向右滑(-1)动轮播图,我们需要计算新的活动索引。
根据表达式 (this.data.activeIndex - 1 + this.data.images.length) % this.data.images.length
,我们得到:(0 - 1 + 3) % 3
(-1 + 3) % 3
(2) % 3
2除以3的余数是2。因为2小于3,所以它无法被3整除,余数就是它本身。
结果为 2。
这意味着在向右滑动时,活动索引将从 0 变为 2。换句话说,轮播图将从第一个项目跳到第三个项目,实现了循环播放的效果。)
Page({
data:{
// 轮播图
images: [
'path/to/image1.jpg',
'path/to/image2.jpg',
'path/to/image3.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
'path/to/image2.jpg',
// ...
],
//默认高亮
activeIndex: 0,
itemLefts: [],
itemScales: [],
touchStartX: 0,
},
//电影轮播图
//更新展示列表
updateCarousel() {
//居中偏移值。750 是容器的总宽度(单位为 rpx),220 是一个轮播图项目的宽度(单位为 rpx)。计算公式 (750 - 220) / 2 用于确定将项目居中显示时的左边距。((index - this.data.activeIndex) * 220) + (750 - 220) / 2 得到每个轮播图项目的最终左边距值。
const itemLefts = this.data.images.map((_, index) => {
return ((index - this.data.activeIndex) * 220) + (750 - 220) / 2;
});
//判断是否放大
const itemScales = this.data.images.map((_, index) => {
return index === this.data.activeIndex ? 1.5 : 1;
});
this.setData({ itemLefts, itemScales });
},
//点击跳转对应图片位置
handleTap(e) {
const index = e.target.dataset.index;
if (index !== this.data.activeIndex) {
this.setData({ activeIndex: index }, () => {
this.updateCarousel();
});
}
},
handleTouchStart(e) {
//触摸开始的位置
this.setData({ touchStartX: e.touches[0].clientX });
},
handleTouchEnd(e) {
//触摸结束的位置
const touchEndX = e.changedTouches[0].clientX;
//计算触摸过程中的水平位移(deltaX)
const deltaX = touchEndX - this.data.touchStartX;
if (Math.abs(deltaX) > 50) {
// deltaX 大于 0(即向右滑动),将活动索引减 1。
// deltaX 小于等于 0(即向左滑动),将活动索引加 1。
// (...)% this.data.images.length取模,确保活动索引始终在有效范围内。
//比如展示的图片为['图一','图二','图三'];索引为0,1,2,长度为3;当向右侧滑动时,
const activeIndex = deltaX > 0
? (this.data.activeIndex - 1 + this.data.images.length) % this.data.images.length
: (this.data.activeIndex + 1) % this.data.images.length;
this.setData({ activeIndex }, () => {
this.updateCarousel();
});
}
},
})
样式代码:
// 电影轮播图
.moveSwiper {
// 轮播图
.carousel {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 300rpx;
overflow: hidden;
position: relative;
.carousel-item {
width: 200rpx;
height: 150rpx;
background-color: #ccc;
margin: 0 10rpx;
transition: transform 0.5s, left 0.5s;
position: absolute;
.carousel-image {
width: 100%;
height: 100%;
}
}
}
//轮播图指示器
.Tiparrow {
border-top: #e4e4e4 1px solid;
position: relative;
.Movemsg{
display: flex;
flex-direction: column;
align-items: center;
padding-top: 20rpx;
padding-bottom: 20rpx;
.moveGradesBox{
display: flex;
align-items: center;
.moveGrades{
color: #EE0A24;
font-size: 28rpx;
}
}
.moveIntruduce{
display: flex;
align-items: center;
padding-top: 16rpx;
box-sizing: border-box;
}
}
}
//轮播图指示器
.Tiparrow::after {
content: "";
position: absolute;
top: -20rpx;
left: 50%;
width: 0;
height: 0;
border-left: 10rpx solid transparent;
border-right: 10rpx solid transparent;
border-bottom: 20rpx solid #ee0606;
transform: translateX(-50%);
}
}