🚀 微信小程序实现 swiper 滑动/释放查看详情效果
“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
大家好,我是疯狂的小波。最近在小程序中要实现一个图片切换 滑动查看详情的效果,如上图:切换到最后一张图片时,继续左滑,显示滑动查看详情模块,并且左滑指定距离后,文案变成释放查看详情,此时手势释放就会跳转到详情页;如果没有到指定距离释放则图片回到原位,什么都不做。
其实这样的效果在各大平台现在都用的非常多了。基本都是用于商品的头图。
看了下原生的 swiper
组件,并没有提供相关的功能。本来想自己实现一个类似 swiper
组件的效果,再加上滑动查看详情功能;但是由于开发周期较短,短时间内基本很难实现和 swiper
完全一样的功能和效果,所以就想能不能基于 swiper
组件进行扩展,来达到这个目标。这样也能够避免重复造轮子,并且自己实现的不一定有原生的好用。
接下来我们就来看看,如何基于 swiper
组件来实现这个效果。
方案尝试
最开始想的是,在最后一张图片上面增加一个遮罩层,在遮罩层上面绑定一个滑动事件,通过滑动事件的移动距离来控制 swiper
和 滑动查看更多模块 的位置,同时判断左滑超过指定距离时触发释放查看详情的状态。
理论来说这种方案是可行的,但是实际操作过程中发现,存在很多问题,如:swiper
滑动到最后一张图片,再左滑时是有阻尼效果的(图片滑动距离小于手势拖动距离,并且距离越大,阻尼效果越明显);而右滑没有阻尼效果,并且达到一定距离还会切换到上一张图片,而我们自己在遮罩层实现的滑动事件默认是没有这种效果的,这样就和原生的 swiper
效果不同步了。
虽然这种也可以解决,但是成本比较高,不符合我们的预期;并且显然也不是一个好的方案,原生的 swiper
一旦有这方便的改动,我们的实现又会不一定能契合。
最终方案
查看官方文档发现,swiper
组件提供 bindtransition
事件监听,也就是左右滑动时 swiper-item
位置改变的回调,基于这个回调事件,我们就可以拿到实际左右滑动距离了,而不用考虑阻尼效果的影响。(所以还是得多看文档啊)
那查看详情模块的显示位置处理呢?如果根据 transition
的回调移动距离来设置位置,会发现移动时存在抖动的情况,效果并不流畅,这是因为 transition
回调有一个类似节流的处理,并不是每移动1个像素都会触发回调,而是在一定距离或时间后才触发,所以无法保证效果的流畅性。
思考后发现,我们可以直接将这个模块放在最后一个图片的模块内,通过定位展示在图片右侧,这样左滑拖动时,模块就会自动显示了。并且滑动距离也能够保持与图片完全一致。
接下来只要实现:在最后一张图片左滑时,如果达到指定距离,变更查看文案,释放时触发查看详情事件,如果没有达到指定距离,什么都不做。
这个可以结合 touchstart
、touchend
事件来处理。
大概流程如下:
有了思路之后,代码就好实现了。我们来看下最终实现的代码吧。
wxml 页面:
// wxml代码
<swiper
bind:transition="intervalTransition"
bind:touchstart="swiperTouchStart"
bind:touchend="swiperTouchEnd"
>
<swiper-item wx:for="{{imageList}}" wx:key="*this">
<image src="{{item}}" />
<!-- 最后一张图片插入 滑动查看更多模块 -->
<view wx:if="{{index + 1 === imageList.length}}" class="swiper-more-item">
<view class="swiper-see-more {{isSwiperMore ? 'sure-more' : ''}}">
<image class="image" src="/assets/images/left_more.png" />
<text class="txt">
{{isSwiperMore ? '释放查看更多' : '滑动查看更多'}}
</text>
</view>
</view>
</swiper-item>
</swiper>
滑动查看更多模块样式:
// 设置超出 swiper-item 模块显示,否则滑动查看更多模块会被隐藏
swiper-item {
overflow: visible;
}
// 查看更多样式
.swiper-more-item {
position: absolute;
left: 100%;
top: 0;
width: 750rpx;
height: 100%;
margin-left: 24rpx;
background: #f7f7f7;
border-radius: 16rpx 0 0 16rpx;
.swiper-see-more {
width: 128rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: space-evenly;
.image {
width: 32rpx;
height: 32rpx;
}
.txt {
width: 40rpx;
font-size: 24rpx;
color: #999999;
line-height: 28rpx;
}
&.sure-more {
.image {
transform: rotate(180deg);
}
}
}
}
js 事件处理:
// swiper手动滑动 - 开始
swiperTouchStart() {
// 当前最后一张图片时,进行监听
if (this.data.curIndex === imageList.length) {
this.canSwiperLeft = true;
}
}
// swiper滑动过程监听
intervalTransition(e: any) {
if (!this.canSwiperLeft) return;
// 根据滑动的偏移量判断是否达到查看详情状态
const offset = e.detail.dx;
const isSwiperMore = offset > SWIPER_MORE_RANGE;
if (isSwiperMore !== this.data.isSwiperMore) {
this.setData({
isSwiperMore
});
}
}
// swiper手动滑动 - 释放
swiperTouchEnd() {
if (!this.canSwiperLeft) return;
this.canSwiperLeft = false;
// 释放时,如果是查看详情状态,则执行指定方法
if (this.data.isSwiperMore) {
this.setData({
isSwiperMore: false
});
this.toDetail();
}
}
这样就可以实现我们想要的效果了,并且很好的利用了 swiper
本身的功能;和 swiper
进行了很好的结合。以最少的代码量实现我们的需求。
最终效果如下:
第一次左滑释放时,未达到指定位置,不做处理;第二次左滑释放时,达到指定位置,跳转到详情页面。并且左滑到指定距离时,滑动查看更多文案变更为释放查看更多。
总结
在小程序中要实现图片切换,滑动/释放查看详情的效果,可以合理的利用 swiper
组件本身的功能。
在样式上,可以在最后一张图片后插入滑动查看详情模块,并通过样式定位到指定位置,让模块的展示始终跟随 swiper
本身的滑动效果;
通过绑定 touchstart
事件,当处于最后一张图片时,才处理 swiper
的 transition
事件,监听滑动位置的切换,根据滑动距离是否达到指定值来设置滑动状态,手势释放时触发 touchend
事件,根据滑动状态判断是否执行查看详情事件。
这样就能够实现我们想要的效果了,如果觉得有用顺便点个赞👍支持一下呗!