swiper中使用iframe致使沒法滑動的3個解決方案

看到這個標題,不少同窗都會疑惑,爲何swiper中要放iframe呢?事實上,當我遇到這個需求前,我也沒想到會有這樣的騷操做,swiper中嵌入網站,每次滑動切換一個網站?想一想聽炫酷的,可作起來就不酷了。

當你開開心心的把iframe放到每個swiper-slide中後,你會發現頁面不能滑動了,你哭了,你絕望了。你打開谷歌,搜解決方案時,你會發現這類相關庫的做者遇到這種bug比你還絕望:
css

這個swipe做者的回答翻譯過來的大體意思是:「大哥了這問題很差搞我也不想搞了,拜拜」
而swiper的做者回答的更直接:

"這是iframe的鍋,我無法在iframe裏偵聽到事件"
而後close了這個issue...
難道就沒有辦法解決這個問題嗎?終於,通過各類百度谷歌翻issue,我找到了三種解決這個問題的方法,正好應對了三種不一樣的狀況,且聽我娓娓道來。

最簡單的辦法:pointer-events

pointer-events是css3新增的屬性,它可讓設置這個屬性的元素沒法偵放任何事件,具體的API能夠參考這裏pointer-events
咱們能夠給iframe設置這個屬性以後,網站之間就能夠來回切換。可是,這種方法有個弊端,正如官方介紹所說,它會是整個元素沒法偵聽事件,這會網站內的全部交互都沒法操做了,除非你得頁面是個純展現性質的靜態網站。
因此,若是你想用這種方法解決沒法滑動的問題,首先要確保你的網站是純靜態沒有任何事件須要觸發的。jquery

偵聽iframe內的滑動事件

這種方法適合iframe內的網址和外部的網址在同一域下,由於咱們須要直接在父級頁面監聽iframe內的事件:
css3

//  用來計算滑動方向的變量
let startX,startY,endX,endY,distanceX,distanceY; 
let iframe = document.querySelector('iframe');
const MOVE_RATE = 2;
iframe.contentWindow.addEventListener('touchstart',function (e) {
    startX = e.targetTouches[0].pageX;
    startY = e.targetTouches[0].pageY;
});
iframe.contentWindow.addEventListener('touchmove',function (e) {
    endX = e.targetTouches[0].pageX;
    endY = e.targetTouches[0].pageY;
    distanceX = endX - startX;
    distanceY = endY - startY;
    if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX > (body.clientWidth/MOVE_RATE)){
        //slideNext 和 slidePrev)()都是swiper的API
        myswiper.slideNext()
    }else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX < (body.clientWidth/MOVE_RATE)){
        myswiper.slidePrev()
    }else{
        console.log('點擊未滑動');
    }
});
複製代碼

這個方案的思路是先獲取iframe內部的window,而後監聽windowtouchstart和touchmove事件,根據滑動方向和距離判斷是左滑或者右滑,調用swiper向前或者向後滑的API便可。

這個方案其實百度一搜就有,若是你有研究過swiper中嵌入iframe話必定見過這個方案,但其實,這個方案有兩個弊端:

一是當swiper頁面3個以上時,因爲touchmove事件是屢次觸發的,致使屢次調用slideNext或者slidePrev方法,用戶輕輕滑一下頁面,直接會滑到最後一頁;

第二個問題是是不能處理跨域的網址,事實上有些需求是須要嵌入一些合做方的網址的,而這些網址不必定是同域的;

第一種狀況個人解決辦法是,聲明兩個變量,分別做爲向左滑和向右滑的計數器,讓touchmove事件僅執行一次,同時,當完成一次滑動後清空計數器,保證下次同方向的滑動:
git

let left_slide_count = 0, right_slide_count = 0;
const COUNT_LIMIT = 2;
...
...
if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX > (body.clientWidth/MOVE_RATE)){
   //slideNext 和 slidePrev)()都是swiper的API
   left_slide_count ++;
   if( left_slide_count < COUNT_LIMIT ){
       myswiper.slideNext()
   }
}else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX < (body.clientWidth/MOVE_RATE)){
   right_slide_count ++;
   if( right_slide_count < COUNT_LIMIT ){
       myswiper.slidePrev()
   }
}else{
   console.log('點擊未滑動');
}
複製代碼

同時,咱們還須要在swiper中加一些配置:
github

let swiper = new Swiepr({
    ...
    ...
    on: {
       //當滑動結束時,清空計數器
       slideChangeTransitionEnd: function(){
         left_slide_count = 0;
         right_slide_count = 0;
       },
    }
})
複製代碼

至於第二個問題,其實能夠用postMessage來解決。跨域

使用postMessage解決嵌入跨域網站的滑動

這種方法其實和上種方法的解決思路大體相同,不過是把滑動的監聽放到內部網站中,而後把滑動信息經過postMessage傳給父級頁面,而後父級頁面調用swiepr的API:
bash

let left_slide_count = 0, right_slide_count = 0;
const COUNT_LIMIT = 2;
...
...
if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX > (body.clientWidth/MOVE_RATE)){
   //slideNext 和 slidePrev)()都是swiper的API
   left_slide_count ++;
   if( left_slide_count < COUNT_LIMIT ){
       window.parent.postMessage("right-move", "*")
   }
}else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX < (body.clientWidth/MOVE_RATE)){
   right_slide_count ++;
   if( right_slide_count < COUNT_LIMIT ){
       window.parent.postMessage("left-move", "*")
   }
}else{
   console.log('點擊未滑動');
}

複製代碼

父級頁面須要監聽postMessage事件:
ide

window.postMessage("message", function(e){
    if(e.data == "right-move"){
       if( left_slide_count < COUNT_LIMIT ){
         myswiper.slideNext()
       }
    }else if(e.data == "left-move"){
       if( right_slide_count < COUNT_LIMIT ){
         myswiper.slidePrev()
       }
    }
})
複製代碼

固然,這種方法也要作計數器的處理。此外,這種方法也有兩個弊端,第一個是當你滑動一下屏幕時頁面能夠正常切換,可是手一直放在屏幕上滑不離開的話,屏幕達到某個臨界值會在兩個頁面不停切換,直到你鬆手;第二個弊端是它須要在嵌入的網站中植入一段js腳本才行,若是你想嵌入純第三方的網站好比淘寶等,那這種方法是行不通的。

那麼有沒有一種方法能夠直接嵌入第三方網站並支持滑動呢,很抱歉確實沒有找到,很少我在翻issue時找到了一個叫iframeTracker的庫,它能夠監聽到iframe中的點擊事件(固然,這是模擬出來的,事實上並不能監聽到),雖然它是一個jquery庫,可是內部源碼很簡單,能夠輕鬆轉成js的,作PC端的朋友同時須要監聽到iframe中的點擊事件的能夠看看這個庫,我在這裏也簡單介紹一下這個庫的實現:

在PC端上,咱們是能夠監聽到iframe的mouseovermouseout事件的,而後,在頁面外寫一個input表單,當咱們鼠標懸浮在iframe上時,讓input表單執行focus事件,當咱們在iframe上點擊時,會觸發input的blur事件,同時也會觸發windowblur 事件,這時咱們監聽windowblur事件,就算捕獲到iframe的click事件了。

至於監聽移動端的touch事件,各位朋友們有沒有好主意呢?post

相關文章
相關標籤/搜索