swiper loop:true引起綁定dom的click事件無效及解決方案

對於 swiper,只要作過輪播圖的童鞋應該都再熟悉不過了。這是一個很強大的圖片輪播插件,自己無任何第三方庫依賴,即插即用。api 文檔很清晰,因此很快可以上手。可是,再好的插件也會出現使人不愉快的地方,固然,今天所討論的並非插件自己的問題,只是開發者是按照常規作法去使用,而剛好此時出現了使人費解的問題。html

緣由:

在使用 swiper 這個庫的時候,一旦設置 loop:true 的時候,會遇到 dom 綁定事件沒法觸發的問題。vue

環境:

採坑

下面來講說我是怎麼一步一步採坑並最終解決這個問題的。這裏只貼出關鍵性的代碼片斷。git

初版:github

這是最常規的作法,把 click 事件綁定在 dom 上。但有兩點不足之處:api

  1. click 點擊事件有時候無任何反應,而且這種狀況必現
  2. 點擊下面的 title,並不能觸發 click 事件,由於並無綁定

html 代碼bash

<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 代碼app

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);
    }
  }
});複製代碼


改良的第二版:dom

解決了上述兩個問題,但同時也存在如下幾個問題ide

  1. 經常使用的 activeIndex (用來標識當前點擊的第幾張圖片),但控制檯輸出的值是錯亂的
  2. 左右做切換的時候,activeIndex 的值也是錯亂的

html 代碼
oop

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

相關文章
相關標籤/搜索