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

相关文章
相关标签/搜索