swiper loop:true引發繫結dom的click事件無效及解決方案

liwb發表於2018-06-15

對於 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。


相關文章