问题描述

项目开发遇到一个ios独有的问题,在wkwebview中稳定复现

问题: 弹出一个蒙版,当在蒙版上面滑动的时候蒙版后面的内容滚动了

这当然是ios的bug,但是经过我们测试iphone7也会复现这个问题,所以没办法需要兼容。

百度了下好多思路

方法1: 直接禁用滚动容器的overflow,然后记录scrollTop并恢复,这种方法不适合我们当前场景。

1. 浮层的入口有多个页面
2. 浮层后面可滚动的容器有多个(3个)
3. 滚动容器有横向和纵向滚动,很难记录scrollTop和scrollLeft

方法2: 禁用touchmove事件,同样会导致弹层容器无法滚动,很不幸我们的弹层需要能够滚动。
方法3: 基于方法2,滚动容器使用better-scroll来滚动,这个基本可以解决问题,但是有better-scroll的主要问题,任何修改了layout都需要手动调用refresh不利于维护。

我们的方法

同样基于方法2,我们执行以下2步

1. 浮层容器对touchmove禁用
2. 滚动容器对touchmove阻止其冒泡,
    判断当前是否可以滚动(scrollHeight>offsetHeight),
    当可以滚动的时候不会触发滚动穿透,因此
    1. 可以滚动:不禁用touchmove
    2. 不能滚动:禁用touchmove

代码:

// touchmoveFix.js
// ios滚动穿透问题解决指令
const touchFix = {
  bind: function (el, binding, vnode) {
    el.addEventListener('touchmove', (e) => {
      // 滚动容器阻止冒泡,因此是否prevent由当前函数决定
      e.stopPropagation();
      let scrollEl = e.currentTarget;
      // 判定当前滚动容器是否可以滚动
      if(scrollEl.scrollHeight <= scrollEl.offsetHeight) {
        // 不能滚动的时候依然需要阻止滚动穿透
        e.preventDefault();
      }
    }, false);
  }
};

// 使用指令
<!-- 弹层阻止touchmove -->
<section class="popup" @touchmove.prevent>
    ...
    <div class="content" v-touch-fix>...</div>
    ...
</section>

// js引入
import touchFix from './touchmoveFix';

export default {
  ...
  directives: {
    touchFix
  },
  ...
};

是否完美

可以看到思路并不复杂,无非是滚动子元素来决定是否禁用touchmove事件。
但是此方案并不完美,因为当弹出层有表单元素时,弹出键盘后表单本身一般需要可以滚动,此时滚动的是body元素,当touchmove禁用后body是无法滚动的,暂无解法只能暂时用方法1

总结:

此方案适用于弹层中有滚动容器,不适用于弹层本身为1个表单

经测试:iphone5s和android没有问题,更老的手机不在我们的兼容范围内了。

本文固定链接: http://www.js-code.com/ios/ios_53680.html