對於 swiper
,只要作過輪播圖的童鞋應該都再熟悉不過了。這是一個很強大的圖片輪播插件,自己無任何第三方庫依賴,即插即用。api 文檔很清晰,因此很快可以上手。可是,再好的插件也會出現使人不愉快的地方,固然,今天所討論的並非插件自己的問題,只是開發者是按照常規作法去使用,而剛好此時出現了使人費解的問題。html
在使用 swiper
這個庫的時候,一旦設置 loop:true
的時候,會遇到 dom 綁定事件沒法觸發的問題。vue
● vuejs 2.5.16
● swiper 4.3.3
● vue-awesome-swiper 3.1.3git
下面來講說我是怎麼一步一步採坑並最終解決這個問題的。這裏只貼出關鍵性的代碼片斷。github
這是最常規的作法,把 click 事件綁定在 dom 上。但有兩點不足之處:api
html 代碼app
<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 代碼dom
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); } } });
解決了上述兩個問題,但同時也存在如下幾個問題ide
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 代碼this
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 文檔,解決了上述出現的幾個問題。關鍵點在於:當 loop
設置爲 true 的時候,不能再用 activeIndex
或者 clickedIndex
。只能用 realIndex
。官方的解釋爲:當前活動塊的索引,與 activeIndex
不一樣的是,在 loop
模式下不會將複製的塊的數量計算在內。
點擊事件不能綁定在 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。