Li RUONAN


一枚行走在前端道路上的程序媛 ~~


swiper

最近写大屏代码,经常用到很多动画和轮播,于是采用了有名的swiper。swiper的优点在于随意扩展,各种变形。有属性有事件有回调,常见的问题基本都能找到相对的处理方式。本项目基于vue开发,因此选用组件vue-awesome-swiper。

  1. 纵向轮播

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     <swiper v-if="adoplist.length>0" :options="swiperOption"  ref="mySwiper">
    <swiper-slide class="toplist-line" v-for="(adop,index) in adoplist" :key="index">
    <div class="headline" @click="jumpToDetail(adop)">{{adop.title}}</div>
    <div class="authors td">{{adop.authorNames}}</div>
    <div class="signtime td">{{adop.signTime}}</div>
    </swiper-slide>
    </swiper>
    ## 初始化
    data () {
    return {
    swiperOption: {
    direction: 'vertical', // 竖直方向轮播
    autoplay: {
    delay: 10 * 1000,
    disableOnInteraction: false
    },
    loop: true,
    slidesPerView: 7 // 每个slide可以7块
     }
    }
    }
    ### 特别说明,纵向轮播经常会出现不轮播的现象,此时要注意两点:
    1. v-if="adoplist.length>0" 该判断是充分必要条件,必须保证有数据
    2. 不可对每行设置定高,如果设置定高并overflow:hidden,会造成竖向只有一行数据,所以根本不可能滚动。因为container已有定高,再设置slidesPerView的参数,分片会自动计算高度的。
  2. tab轮播

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <swiper :options="swiperOption" id="myswiper">
    <div class="page-tab swiper-pagination swiper-pagination-bullets" slot="pagination"></div>
    <swiper-slide class ="container-tab" v-for="slide in swiperSlides" :key="slide" >
    <MapChart />
    </swiper-slide>
    </swiper>

    data () {
    return {
    swiperSlides: [1, 2, 3],
    swiperOption: {
    autoplay: {
    delay: 10 * 1000,
    disableOnInteraction: false
    },
    pagination: {
    el: '.swiper-pagination',
    renderBullet (index, className) {
    let text = '';
    switch (index + 1) {
    case 1:
    text = '北京';
    break;
    case 2:
    text = '上海';
    break;
    case 3:
    text = '广州';
    break;

    default:
    break;
    }
    return `<span class=${className} id="swiper-pagination-bullet-tab">${text}</span>`;
    }
    }
    }
    }

    ### 说明: 将tab标签当分页器逻辑使用,参考官方demo可自定义样式。
  3. 异常图片
    我遇到的问题是这样,因为要加载大量截图轮播展示,所以肯定会遇到截图加载失败的问题,有的时候是图片本身的问题。为了处理该异常情况,按照我以为做图片展示的思路,应该是有个占位的默认图片。所以,初期我是想:当图片加载失败的话,默认加载第一张图片。那么问题来了?当第一张图片也出错了,怎么办?因为图片在加载的时候,才会知道好与坏,因此在onerror事件的时候处理。

  • 方法一:加载默认图片不可行

  • 方法二:获取到图片index,将它从数组中剔除。但是因为swiper已经初始化了,此时对数据修改,理论上动态绑定的话,应该立即生效,但是并未生效。然后考虑了下,既然数据上去不掉,那就显示上禁调? 让当前slide,display:none;确实生效了,但是只对realIndex生效,因为swiper循环轮播的时候,会前后复制一些虚拟slide,虚拟slide的事件在真实dom节点是绑定不了的。于是,放弃。

  • 方法三: 努力看API文档,发现有函数 mySwiper.removeSlide(index), 并且当拿到第一张图的时候,就能对其index做移除,这样的话真实dom和虚拟dom同时生效。简直太好用了。

    问题完美解决!!

  1. 自定义轮播
    因为对于轮播里面的内容,会有不同的表现形式。比如:图片轮播、正文滚动、视频播放

    需要分别做处理。正常的图片轮播或者内容展示,设置默认30秒自动切换。但是正文滚动和视频播放的话,需要占用单独的时间,并且正文滚动完毕和视频播放完毕,才能切换至下一屏。

    因此,这里主要介绍,轮播时遇到的几个函数:

    • mySwiper.autoplay.stop() // 当判断正文高度大于盒子高度,停止slide自动播放,正文计算translateY向上滚动
    • mySwiper.slideNext(speed, runCallbacks) // 当滚动or播放完毕,切换至下一屏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
setScrollContent () {
var index = 0;
let time = 2000;
const contentHeight = this.$refs['doc-content'] && this.$refs['doc-content'].offsetHeight;
const wrapperHeight = this.$refs['doc-wrapper'] && this.$refs['doc-wrapper'].offsetHeight;
this.contentStyle.transition = `${time / 1000}s top linear`;
if (contentHeight > wrapperHeight) {
this.$bus.$emit('stop-autoplay');
const maxTop = contentHeight - wrapperHeight;
const scrollFun = () => {
const nowTop = index * 60;
if (nowTop > maxTop + 60) {
this.scrollNextDoc(time);
return;
}
this.contentStyle.top = -nowTop + 'px';
index++;
this.intervalId = setTimeout(scrollFun, time);
};
this.intervalId = setTimeout(scrollFun, time);
}
},
scrollNextDoc () {
this.$bus.$emit('slide-next');
this.initDom();
}
### 说明:'slide-next'事件中通过slideNext切换至下一屏。slideNext时注意最后一屏的情况,如果是loop模式,可使用mySwiper.slideToLoop(0)。
  1. 数据渲染问题

轮播的具体页面中,遇到图表渲染不出来,因为没与当前index绑定,同时要用ref去绑定。
因此,要保证每一屏幕的数据与返回值一致。用计算的swIndex,与当前的index去比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## 父组件
slideChange () {
this.swIndex = this.swiper.activeIndex;
},
## 子组件
mounted () {
if (this.swIndex === this.index) {
setTimeout(() => {
this.scrollNextDoc();
}, 3000);
}
},
watch: {
swIndex(val) {
if (val === this.index) {
this.scrollNextDoc();
}
}
}

总体来说,swiper已经很强大了,但是也有其固有的bug。对于loop情况,数据问题渲染问题滚动问题都会或多或少的出现,有些至今都没有比较好的解决方案。这也是与最初的设计有关,为了更加得心应手的使用,也让自己在底层开发水平得到提高,近期开始看swiper的源码。求监督~~