對於 swiper,只要作過輪播圖的童鞋應該都再熟悉不過了。這是一個很強大的圖片輪播插件,自己無任何第三方庫依賴,即插即用。api 文檔很清晰,因此很快可以上手。可是,再好的插件也會出現使人不愉快的地方,固然,今天所討論的並非插件自己的問題,只是開發者是按照常規作法去使用,而剛好此時出現了使人費解的問題。html
在使用 swiper 這個庫的時候,一旦設置 loop:true
的時候,會遇到 dom
綁定事件沒法觸發的問題。vue
下面來講說我是怎麼一步一步採坑並最終解決這個問題的。這裏只貼出關鍵性的代碼片斷。git
初版:github
這是最常規的作法,把 click 事件綁定在 dom 上。但有兩點不足之處:api
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
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 文檔,解決了上述出現的幾個問題。關鍵點在於:
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。