看到这个标题,不少同窗都会疑惑,为何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