swiper轮播图出现疯狂抖动,小程序

以前做小程序项目的时候,没专门测试人员,都是开发者自测,可能我的手机性能比较不错(哈哈)或时机不对,总之没发掘到这个bug;近期做项目,测试了不同的手机,发现在一些手机上会出现这个bug,尤其是对于性能差的一些手机,出现的概率尤其的大。由于本次项目是基于uni-app的,直接就用uni-app进行操作说明;

说明:uni-app编写小程序:采用的是微信小程序的API,Vue的语法,所以,他们很相似,只是在写法上有一点稍微的区别,小程序的那套东西也是适用于uni-app的。

在微信小程序的官方文档中,有这样个提示, 如果在 bindchange 的事件回调函数中使用 setData 改变 current 值,则有可能导致 setData 被不停地调用。

最终产生的后果是如果快速滑动或者息屏一段时间打开后,就出现轮播图的疯狂抖动。

一、解决方法是:

在动画播放结束后(@animationfinish)改变current的值,而不是一滑动(@change)就改变current的值。即用@animationfinish代替 @change。

二、@change与@animationfinish对比说明

1、相同点:都会改变current的值,current代表当前所在滑块的index

2、不同点:改变current的时机不同,@change滑动时立即改变,@animationfinish动画结束后改变!

三、说明:

如果想要自定义面板指示点,不建议与swiper共用一个索引值,最好将swiper与指示点的索引区分开,即用不同的变量,然后两者同步变化就可以了!

下面直接来展示一个自定义指示面板,又可以解决抖动问题的案例!

1、逻辑梳理

  1>先解决抖动问题,用@animationfinish改变当前滑块的值;

<template>
    <view class="swipers-wrap">
        <swiper @animationfinish="swiperChange"  :current="currentSwiper" circular="true"  class="swipers-view"
         :autoplay="autoplay"  @change="dotChange">
            <block v-for="(item,index) in swiperList" :key="index">
                <swiper-item>
                    <view class="swipers-best-hot-video">
                        美景展示~
                    </view>
                    <view class="swipers-image-view">
                        <image :src="item.imgUrl" mode="aspectFill" class="swipers-image"></image>
                        <view class="swipers-title">
                            {{item.title}}
                        </view>
                    </view>
                </swiper-item>
            </block>
        </swiper>
        
        <!--重置指示面板(小圆点)的样式  -->
        <view class="swipers-dots">
            <block v-for="(item,index) in swiperList" :key="index">
                <view class="dot" :class="{active:  currentDot == index}"></view>
            </block>
        </view>
    </view>
</template>

  2>改变指示面板的索引,用@change;

<template>
    <view class="swipers-wrap">
        <swiper @animationfinish="swiperChange"  :current="currentSwiper" circular="true"  class="swipers-view"
         :autoplay="autoplay"  @change="dotChange">
            <block v-for="(item,index) in swiperList" :key="index">
                <swiper-item>
                    <view class="swipers-best-hot-video">
                        美景展示~
                    </view>
                    <view class="swipers-image-view">
                        <image :src="item.imgUrl" mode="aspectFill" class="swipers-image"></image>
                        <view class="swipers-title">
                            {{item.title}}
                        </view>
                    </view>
                </swiper-item>
            </block>
        </swiper>
        
        <!--重置指示面板(小圆点)的样式  -->
        <view class="swipers-dots">
            <block v-for="(item,index) in swiperList" :key="index">
                <view class="dot" :class="{active:  currentDot == index}"></view>
            </block>
        </view>
    </view>
</template>

  3>同步:对两者赋值e.detail.current;

dotChange: function(e) {
  this.currentDot = e.detail.current
},
swiperChange: function(e) {
  this.currentSwiper = e.detail.current
},

2、完整代码展示

<template>
    <view class="swipers-wrap">
        <swiper @animationfinish="swiperChange"  :current="currentSwiper" circular="true"  class="swipers-view"
         :autoplay="autoplay"  @change="dotChange">
            <block v-for="(item,index) in swiperList" :key="index">
                <swiper-item>
                    <view class="swipers-best-hot-video">
                        美景展示~
                    </view>
                    <view class="swipers-image-view">
                        <image :src="item.imgUrl" mode="aspectFill" class="swipers-image"></image>
                        <view class="swipers-title">
                            {{item.title}}
                        </view>
                    </view>
                </swiper-item>
            </block>
        </swiper>
        
        <!--重置指示面板(小圆点)的样式  -->
        <view class="swipers-dots">
            <block v-for="(item,index) in swiperList" :key="index">
                <view class="dot" :class="{active:  currentDot == index}"></view>
            </block>
        </view>
    </view>
</template>
 
<script>
    export default {
        data() {
            return {
                currentDot: 0, //指示面板对应的索引
                currentSwiper: 0, //用来记录当前swiper对应的索引
                autoplay: true,
                swiperList:[
                    {
                        'imgUrl':'../../static/swiper.jpg',
                        'title':'白云朵朵!'
                    },
                    {
                        'imgUrl':'../../static/list.jpg',
                        'title':'蓝天绿树!'
                    },
                    {
                        'imgUrl':'../../static/user.jpg',
                        'title':'boy!'
                    }
                ]
            }
        },
 
        methods: {
            dotChange: function(e) {
                this.currentDot = e.detail.current
            },
            swiperChange: function(e) {
                this.currentSwiper = e.detail.current
            },
        }
    }
</script>
 
<style>
    .swipers-wrap {
        height: auto;
        position: relative;
        background-color: blue;
        padding: 0 15upx;
        padding-bottom: 54upx;
 
    }
 
    .swipers-view {
        height: 420upx;
    }
 
    .swipers-best-hot-video {
        height: 90upx;
        line-height: 90upx;
        color: #f8f3bf;
        font-size: 36upx;
        text-align: center;
    }
 
    .swipers-image-view {
        height: 100%;
        position: relative;
        z-index: 1;
    }
 
    .swipers-image {
        width: 100%;
        height: 100%;
    }
 
 
    .swipers-image-view .swipers-title {
        position: absolute;
        z-index: 99;
        left: 25upx;
        bottom: 105upx;
        font-size: 24upx;
        font-weight: bold;
 
        color: #fff;
        font-size: 36upx;
    }
 
    /*用来包裹所有的小圆点  */
    .swipers-dots {
        width: 100%;
        height: 50upx;
        display: flex;
        flex-direction: row;
        position: absolute;
        left: 0;
        bottom: 0upx;
        /* border:1upx solid red; */
        display: flex;
        justify-content: center;
        align-items: center;
        /* border:1rpx solid green; */
    }
 
    /*未选中时的小圆点样式 */
    .dot {
        width: 6px;
        height: 2upx;
        width: 55upx;
        background-color: #999;
        margin: 0 10upx;
        /* border:1upx solid red; */
    }
 
    /*选中以后的小圆点样式  */
    .dot.active {
        height: 2upx;
        width: 80upx;
        background-color: #fff;
        margin: 0 10upx;
    }
</style>