swiper loop:true引发绑定dom的click事件无效及解决方案

对于 swiper,只要做过轮播图的童鞋应该都再熟悉不过了。这是一个很强大的图片轮播插件,本身无任何第三方库依赖,即插即用。api 文档很清晰,所以很快能够上手。但是,再好的插件也会出现令人不愉快的地方,当然,今天所讨论的并不是插件本身的问题,只是开发者是按照常规做法去使用,而恰好此时出现了令人费解的问题。

原因:

在使用 swiper 这个库的时候,一旦设置 loop:true 的时候,会遇到 dom 绑定事件无法触发的问题。

环境:

采坑

下面来说说我是怎么一步一步采坑并最终解决这个问题的。这里只贴出关键性的代码片段。

第一版:

这是最常规的做法,把 click 事件绑定在 dom 上。但有两点不足之处:

  1. click 点击事件有时候无任何反应,并且这种情况必现
  2. 点击下面的 title,并不能触发 click 事件,因为并没有绑定

html 代码

<div class="banner" v-if="bannerList.length">
  <swiper :options="swiperOption" ref="mySwiper">
    <swiper-slide
      v-for="(banner, index) in bannerList"
      :key="banner.id"
      @click.native="handleClickSlide(index)">
      <div class="banner-item">
        <img :src="banner.imgUrl" alt="news">
        <p>{{banner.title}}</p>
      </div>
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>
  </swiper>
</div>复制代码

js 代码

new Vue({
  el: '#app',
  data: function () {
    return {
      swiperOption: {     // 轮播配置
        width: window.innerWidth,
        autoplay: {
          delay: 3000
        },
        loop: true,   // 循环滚动
        pagination: {   // 分页器
          el: '.swiper-pagination'
        },
        preventLinksPropagation: false   // 阻止点击事件冒泡
      },
      bannerList: [
        {
          id: '1',
          title: '世界杯揭幕战-超新星1球2助攻俄罗斯5-0沙特 格里兹曼宣布留马竞',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/AYes-hcyszrz3457297.jpg'
        },
        {
          id: '2',
          title: '颜值满分!世界杯首日美女球迷盘点',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/H3Wz-hcyszrz4804003.jpg'
        },
        {
          id: '3',
          title: '盘点历届世界杯大比分“屠杀”',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/FNuk-hcyszrz4805039.jpg'
        }
      ]
    }
  },
  methods: {
    // 坑在这里:
    // 会发现有的时候,click 事件点击无反应,而且这种情况是必现的
    handleClickSlide(index) {
      console.log('handleClickSlide current index', index);
    }
  }
});复制代码


改良的第二版:

解决了上述两个问题,但同时也存在以下几个问题

  1. 常用的 activeIndex (用来标识当前点击的第几张图片),但控制台输出的值是错乱的
  2. 左右作切换的时候,activeIndex 的值也是错乱的

html 代码

<div class="banner" v-if="bannerList.length">
  <swiper :options="swiperOption" ref="mySwiper" @click.native="handleClickSlide">
    <swiper-slide
      v-for="(banner, index) in bannerList"
      :key="banner.id">
      <div class="banner-item">
        <img :src="banner.imgUrl" alt="news">
        <p>{{banner.title}}</p>
      </div>
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>
  </swiper>
</div>复制代码

js 代码

new Vue({
  el: '#app',
  data: function () {
    return {
      swiperOption: {     // 轮播配置
        width: window.innerWidth,
        autoplay: {
          delay: 3000
        },
        loop: true,   // 循环滚动
        pagination: {   // 分页器
          el: '.swiper-pagination'
        },
        preventLinksPropagation: false   // 阻止点击事件冒泡
      },
      bannerList: [
        {
          id: '1',
          title: '世界杯揭幕战-超新星1球2助攻俄罗斯5-0沙特 格里兹曼宣布留马竞',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/AYes-hcyszrz3457297.jpg'
        },
        {
          id: '2',
          title: '颜值满分!世界杯首日美女球迷盘点',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/H3Wz-hcyszrz4804003.jpg'
        },
        {
          id: '3',
          title: '盘点历届世界杯大比分“屠杀”',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/FNuk-hcyszrz4805039.jpg'
        }
      ]
    }
  },
  computed: {
    swiper() {
      return this.$refs.mySwiper.swiper;
    }
  },
  methods: {
    // 坑在这里
    // 一开始点击第一张图片,控制台输出的 activeIndex 竟然是 1,难道不应该是 0吗?
    // 并且一个循环之后,点击第一张图片, 控制台输出的 activeIndex 竟然变成了 4。。。
    handleClickSlide() {
      // 这个应该是最为想到一个属性,用来标识当前点击图片的索引
      const {activeIndex} = this.swiper && this.swiper;
      console.log('handleClickSlide current index', activeIndex);
    }
  }
});复制代码

最终版

通过 swiper 强大的 api 文档,解决了上述出现的几个问题。关键点在于

  1. loop 设置为 true 的时候,不能再用 activeIndex 或者 clickedIndex。只能用realIndex。官方的解释为:当前活动块的索引,与activeIndex不同的是,在loop模式下不会将复制的块的数量计算在内。
  2. 点击事件不能绑定在 dom 

不过稍不注意,也会出现新的坑(代码里有指出)

html代码

<div class="banner" v-if="bannerList.length">
  <swiper :options="swiperOption" ref="mySwiper">
    <swiper-slide
      v-for="(banner, index) in bannerList"
      :key="banner.id">
      <div class="banner-item">
        <img :src="banner.imgUrl" alt="news">
        <p>{{banner.title}}</p>
      </div>
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>
  </swiper>
</div>复制代码

js 代码

let vm = null;
new Vue({
  el: '#app',
  data: function () {
    return {
      swiperOption: {     // 轮播配置
        width: window.innerWidth,
        autoplay: {
          delay: 3000
        },
        loop: true,   // 循环滚动
        pagination: {   // 分页器
          el: '.swiper-pagination'
        },
        on: {
          click: function () {
            // 这里有坑
            // 需要注意的是:this 指向的是 swpier 实例,而不是当前的 vue, 因此借助 vm,来调用 methods 里的方法 
            // console.log(this); // -> Swiper
            // 当前活动块的索引,与activeIndex不同的是,在loop模式下不会将 复制的块 的数量计算在内。            const realIndex = this.realIndex;
            vm.handleClickSlide(realIndex); 
          }
        },
        preventLinksPropagation: false   // 阻止点击事件冒泡
      },
      bannerList: [
        {
          id: '1',
          title: '世界杯揭幕战-超新星1球2助攻俄罗斯5-0沙特 格里兹曼宣布留马竞',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/AYes-hcyszrz3457297.jpg'
        },
        {
          id: '2',
          title: '颜值满分!世界杯首日美女球迷盘点',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/H3Wz-hcyszrz4804003.jpg'
        },
        {
          id: '3',
          title: '盘点历届世界杯大比分“屠杀”',
          imgUrl: 'http://n.sinaimg.cn/sports/180/w640h340/20180615/FNuk-hcyszrz4805039.jpg'
        }
      ]
    }
  },
  computed: {
    swiper() {
      return this.$refs.mySwiper.swiper;
    }
  },
  created() {
    vm = this;
  },
  methods: {
    handleClickSlide(index) {
      console.log('handleClickSlide current index', index);
    }
  }
});复制代码

希望借此可以帮助遇到此问题的小伙伴,祝大家的生活中再无 bug。


转载于:https://juejin.im/post/5b23b7cde51d4558b0354ad2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值