對於 swiper,只要做過輪播圖的童鞋應該都再熟悉不過了。這是一個很強大的圖片輪播外掛,本身無任何第三方庫依賴,即插即用。api 文件很清晰,所以很快能夠上手。但是,再好的外掛也會出現令人不愉快的地方,當然,今天所討論的並不是外掛本身的問題,只是開發者是按照常規做法去使用,而恰好此時出現了令人費解的問題。
原因:
在使用 swiper 這個庫的時候,一旦設定 loop:true
的時候,會遇到 dom
繫結事件無法觸發的問題。
環境:
採坑
下面來說說我是怎麼一步一步採坑並最終解決這個問題的。這裡只貼出關鍵性的程式碼片段。
第一版:
這是最常規的做法,把 click 事件繫結在 dom 上。但有兩點不足之處:
- click 點選事件有時候無任何反應,並且這種情況必現
- 點選下面的 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);
}
}
});複製程式碼
改良的第二版:
解決了上述兩個問題,但同時也存在以下幾個問題
- 常用的 activeIndex (用來標識當前點選的第幾張圖片),但控制檯輸出的值是錯亂的
- 左右作切換的時候,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 文件,解決了上述出現的幾個問題。關鍵點在於:
- 當
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。