H5端禁止蒙层底部页面跟随手势滚动

时间:2024-10-08 19:04:09

(一) 前言
说来真是搞笑,之前很多交互都是依赖UI库的modal实现,之前也遇到过类似天猫商品列表页面那种下拉筛选,也解决过相关手势问题,但是,后面一个同事再次问起这个问题,回头去总结下,发现之前通过选取dom并为背景和内容分别处理touchmove事件,但是这仅仅是对于h5的一个解决方案,所以总结常见在pc/h5上面分别的处理方案。

(二) PC处理方案

打开蒙层时,给body添加样式:

overflow: hidden;
height: 100%;
  • 1
  • 2

在某些机型下,你可能还需要给根节点添加样式:

overflow: hidden;
  • 1

关闭蒙层时,移除以上样式。
优点:
简单方便,只需添加css样式,没有复杂的逻辑。

缺点:
兼容性不好,适用于pc,移动端就尴尬了。
部分安卓机型以及safari中,无法无法阻止底部页面滚动。

如果需要应用于移动端,那么你可能需要方案二。

(三) 移动端处理方案
移动端可以直接阻止冒泡方式,处理这个问题,

const preventFun = e => ();
export function handleStopTouch() {
  ('touchmove', preventFun, { passive: true });
}

export function handleOpenTouch() {
  ('touchmove', preventFun, { passive: false });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

但是上面方式是直接阻止来所有的事件,所以如果内容需要滚动,就需要如下的方案

移动端类似抽屉这种,有两部分组成,一个蒙层,一个内容区域,因为内容区域需要滚动,所以我们的touch事件应该绑定在蒙层区域,类似如下

// 抽屉drawer处理滚动穿透
const preventFun = e => ();
export function noScroll(isInScroll = false) {
  ('.am-drawer-overlay').addEventListener('touchmove', preventFun, { passive: false });
  if (!isInScroll) {
    ('.am-drawer-sidebar').addEventListener('touchmove', preventFun, { passive: false });
  }
}
export function noScrollClose(isInScroll = false) {
  ('.am-drawer-overlay').removeEventListener('touchmove', preventFun, { passive: true });
  if (!isInScroll) {
    ('.am-drawer-sidebar').removeEventListener('touchmove', preventFun, { passive: true });
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(四) PC/H5兼容方案

既然我们要阻止页面滚动,那么何不将其固定在视窗(即position: fixed),这样它就无法滚动了,当蒙层关闭时再释放。
当然还有一些细节要考虑,将页面固定视窗后,内容会回头最顶端,这里我们需要记录一下,同步top值。

// 处理手势
export const modalHelper = {
  bodyEl: ,
  top: 0,

  handleStopScroll() {
     = ;
     = 'fixed';
     = `${-}px`;
  },
  handleOpenScroll() {
     = '';
     = '';
    (0, ); // 回到原先的top
  },
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16