一.前言
前阵子做公司的项目,是用混合开发cordova
来开发APP,开发过程中,需要用到从底部向上的弹窗。之前用到的弹窗是使用jqm
的,但是在开发过程中发现,如果jqm
的popup
外部的window
也是可以滚动的话,popup
会跟随着背后的window
滚动,这个当然是不可取的,所以想自定义一个弹窗来满足需求。
二.制作思路
在自定这个弹窗的时候,有大概构思过步骤,就是要有一个遮罩层,一个显示内容。其中遮罩层需要覆盖这个mobile
界面,当用户点击遮罩层的时候,可以关闭这个弹窗或者不关闭弹窗,可以自行设置;显示内容当然是可以滚动的,可以给显示内容设置一个max-height
,这样,当内容少的时候就显示内容高度,当内容过多时候,高度就为max-height
。弹窗是从下面向上升起,那么显示内容的position
就可以设置为absolute
,bottom
为0,只是在打开或者关闭的时候,改变遮罩层和显示内容的高度和显示的问题。
三.遇到的bug
在具体的开发中也是按照这样的步骤去做,但是其中遇到了一个比较大的坑,就是自定义的弹窗有滚动条,并且弹窗背后的整个页面也是可以滚定的话,当滚动弹窗里面的内容,背后的window
也会跟着滚动。这样肯定是不可取的,在网上也找了很多解决方法,很多说在打开弹窗的时候,设置window
的overflow
为hidden
就行,但是这样设置后,解决不了。后面在网上看到了张鑫旭的也遇到过类似的问题,所以就用了他的解决方法smartscroll
。
看了其中的源码,解决的核心问题就是弹窗滚动到上下边缘的滚定问题。
// 上下边缘检测
if (distanceY > 0 && scrollTop == 0) {
// 往上滑,并且到头
// 禁止滚动的默认行为
event.preventDefault();
return;
}
// 下边缘检测
if (distanceY < 0 && (scrollTop + 1 >= data.maxscroll)) {
// 往下滑,并且到头
// 禁止滚动的默认行为
event.preventDefault();
return;
}
运用到自己的项目里面,测试一遍后发现,iPhone
运行没有问题,但是在Android
上发现,当弹窗的内容接近上下边缘的时候,此时快速滚动弹窗,背后的window
还是会跟着滚动,所以自己在其中改动了些代码,具体的方案是,当open
弹窗的时候,记录下window
当前的x
和y
,然后绑定window
的onscroll
方法,在这个方法中call window
的scrollTo
方法,滚动的x
和y
就是上面记录的x
和y
值,需要注意的是,在close
这个弹窗的时候,需要window
的onscroll
方法,方法里面do nothing
,这样关闭弹窗后,才不会影响到window
的滑动。
1) open弹窗时需要调用
//fiexd position for android
var x=window.scrollX;
var y=window.scrollY;
window.onscroll=function(){
window.scrollTo(x, y);
};
2)close弹窗时需要调用
window.onscroll=function(){};
当然,在Android
中不能做到跟iOS
一样,弹窗的滑动完全不会影响到window
,在Android
中快速滑动弹窗,window
会有稍微的移动吗,但是会马上回弹到window
原先的位置。
因为smartscroll中,传入了当前页面作为container,绑定了touchmove,所以close弹窗的时候,需要给这个页面解除绑定。
张鑫旭浮层滚动解决方法
四.总结
使用jqm
中的popup
效果不佳,popup
跟着window
滑动的问题之前就存在了,所以自定义的弹窗也要尽量避免出现这个问题。在解决这个问题花费了很多时间,其中最最重要的就是解决有滚动条的弹窗的下上边缘的问题,在临界点进行处理。
五.Github地址
GitHub上,导入了jqm的相关代码,因为custom_alert.js文件中用到了jqm来获取当前页面,如果UI框架不使用jqm,可以用你项目的UI框架来获取当前页面,然后代替里面的代码即可,承载的弹窗的div放在page的footer中(即使显示弹窗的页面不需要用到footer,承载的弹窗的div放在page的footer中也不会影响)。
有实例展示,直接下载源码,就可以测试。其中做得不好的请指正,相互交流😀。
源码下载
六.运行后样式
制作后简单展示(如果需要美化弹窗,可以自行在我这个小组件上进行修改):