看到這個標題,不少同窗都會疑惑,爲何swiper中要放iframe呢?事實上,當我遇到這個需求前,我也沒想到會有這樣的騷操做,swiper中嵌入網站,每次滑動切換一個網站?想一想聽炫酷的,可作起來就不酷了。
當你開開心心的把iframe
放到每個swiper-slide
中後,你會發現頁面不能滑動了,你哭了,你絕望了。你打開谷歌,搜解決方案時,你會發現這類相關庫的做者遇到這種bug比你還絕望:
css
pointer-events
是css3新增的屬性,它可讓設置這個屬性的元素沒法偵放任何事件,具體的API能夠參考這裏pointer-events
咱們能夠給iframe
設置這個屬性以後,網站之間就能夠來回切換。可是,這種方法有個弊端,正如官方介紹所說,它會是整個元素沒法偵聽事件,這會網站內的全部交互都沒法操做了,除非你得頁面是個純展現性質的靜態網站。
因此,若是你想用這種方法解決沒法滑動的問題,首先要確保你的網站是純靜態沒有任何事件須要觸發的。jquery
這種方法適合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
,而後監聽window
的touchstart和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
傳給父級頁面,而後父級頁面調用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的mouseover
和mouseout
事件的,而後,在頁面外寫一個input表單,當咱們鼠標懸浮在iframe上時,讓input表單執行focus
事件,當咱們在iframe上點擊時,會觸發input的blur
事件,同時也會觸發window
的blur
事件,這時咱們監聽window
的blur
事件,就算捕獲到iframe的click
事件了。
至於監聽移動端的touch事件,各位朋友們有沒有好主意呢?post