移动端模态窗口的滚动和橡皮筋问题解决方案
1、什么是模态窗口[浮层]?
模态窗口就是用户只能与该窗口进行交互,而其他用户界面收不到输入信息。只有关闭该窗口后,其他界面才能与用户交互,且仍可以读取模态窗口中的信息。
其特点就是:
a、用户的交互被锁定在该窗口[浮层]上;
b、窗口关闭时,未被实际销毁,仍然可以读取窗口相关的信息。
以vue组件为例子,实现一个模态窗口[浮层]~我们将使用v-show来控制窗口的展现,如此其变量[状态]都保存在内存当中,不被销毁;当关闭以后,再次打开,依然能保留上次的操作状态。这就初步创建了一个模态窗口。
2、移动端上web模态浮层的交互问题:滑屏联动、ios橡皮筋
上例中创建的模态窗口可实现b特点,即保留状态,但无法实现交互的完全锁定。这里咱们来解决其中的两个交互问题:滑屏联动、ios橡皮筋。
滚屏联动,就是在上层窗口[浮层]滚动,下层内容区域跟随一起滚动。如果在ios下,还会出现橡皮筋问题。这都违背了模态窗口的第一个特点,交互应被锁定在窗口上。这些问题实质上都是由touch事件触发,所以解决问题的关键就是如何处理touch事件。
最终的解决方案如下,禁用全局touchmove,窗体内的touchmove自定义。具体操作如下:
step1:窗口开启时,禁用全局touchmove事件;[防止触发滚动及橡皮筋这类touch事件]
step2:对窗口内需要touchmove事件的部分进行功能自定义;[如窗口内的scroll]
step3:窗口关闭时,解除全局touchmove事件的绑定。
3、实例:解决模态下的scroll及橡皮筋问题
step1:窗口开启时,禁用全局touchmove
// 模态弹窗模式下,禁止滚动及ios下的橡皮筋效果 document.addEventListener('touchmove', this.stopScroll, false)
stopScroll(event) {
// 使用阻止默认事件,来阻止scroll和橡皮筋
event.preventDefault()
}
通过设置event.preventDefault(),禁止touchmove事件的默认操作。将监听绑定在document上,实现全局禁止。[橡皮筋效果解决]
step2:自定义窗口内的scroll事件
由于全局touchmove事件禁用,窗体内的scroll也受其影响,无法滚动;所以需要自定义窗体内的scroll。
stopScroll(event) {
// 使用阻止默认事件,来阻止scroll和橡皮筋
event.preventDefault()
// 对弹窗区域允许滚动,并自定义滚动方式
// 判断触发touchmove的元素是否为滚动区域内的元素?如果是,则自定义scroll功能
this.pElem = this.isInnerParents(event.target, 'aui-popup__bd')
if (this.pElem) {
this.movePosList.push(this.startPos - event.touches[0].pageY)
let len = this.movePosList.length
this.pElem.scrollTop += this.movePosList[len - 1] - this.movePosList[len - 2]
}
}
其中的stopScroll函数与step1中相同,在阻止touchmove事件默认操作的同时,处理自定义功能。进入自定义功能的条件是,事件触发元素在scroll区域内。[滚屏联动解决]
step3:窗口关闭时,解除全局touchmove事件的绑定
// 关闭弹窗时,释放touchmove document.removeEventListener('touchmove', this.stopScroll, false)
4、关于web端模态窗口交互的几点思考
a、禁用掉引发全局交互的事件,及窗体内受禁用影响的相应交互操作的抽象。如禁用touchmove事件,窗体内受禁用影响的内容滚动、滑屏轮播等的抽象。
b、相应表单操作的处理。如表单项的聚焦,使用tab切换时,该切换操作应保留在窗体内;窗口打开时,聚焦应移动之模态窗口内等。