-webkit-overflow-scrolling:touch在移动端存在滚动卡死的bug

前言

最近用ionic来开发微信公众号,看好的就是ionic有成熟的UI框架,不需要自己去定义UI控件,当然微信也提供了自家的UI控件,但是数量实在太少,不敢恭维。
因为一直用的是chrome调试开发的页面,测试的时候也没有发现什么问题,但是直到将代码放上服务器,然后通过iPhone手机的微信公众号来访问开发的网页,在滑动到顶部或者底部的时候,重复上滑或者重复下滑,会导致页面卡死,需要2,3秒后才能恢复正常。瞬间奔溃,这是个什么玩意儿。在百度上查了一下资料原来是-webkit-overflow-scrolling:touch引起的,有前端开发经验的人都知道,这个属性是给网页在iOS设备中呈现并滚动的时候,起到更加流畅的作用,有一个回弹的效果,跟原生iOS滑动的效果一样,没想到反而给iOS设备挖了这么大的一个坑,wtf....

分析

经网上查找一些资料描述是Safari会对使用-webkit-overflow-scrolling的网页,会创建一个UIScrollView,给要显示的元素使用。具体可以参考这篇文章,文章的作者也是遇到这个问题,并且估计快被逼疯了...
通过chrome检查元素可以看到在网页编译并且跑起来之后,ionic有生成了一个类名为“scroll-content”div,这个div就是使用了-webkit-overflow-scrolling:touch,仔细查看了资料包括上面那篇文章,说是可以通过给滚动的元素的内部加一个div元素,然后设置这个内部的div的高度100%+1px100%+1%可以解决,有些人就说是通过修改z-index,还有些人说是不要让那个滚动的元素有relative或者absolute这样的css定位。由于是在ionic的框架上进行开发的页面,查找了元素“scroll-content”这个div确实有绝对定位,刚开始很担心是ionic框架的问题,难道这次要翔,但是上面的方法全部试了个遍,可以很负责任的告诉你,没有用,没有用,没有用,不论是ios设备的微信浏览器,safari浏览器,QQ浏览器,UC浏览器,都是会存在这个卡死的问题。

解决方案

想了好久,既然是-webkit-overflow-scrolling:touch引起的,那么不用这个属性就行了嘛,但是不用这个属性,页面滑动起来真的是还不如让这个bug留着,那感觉就像你看了一部无声的,黑白的,画质贼差的电影。接着往下思考,既然是在顶部或者底部的时候会出现卡死,那么不如通过touchstarttouchmove事件来判断是否到达顶部或者底部,然后移除-webkit-overflow-scrolling:touch,不满足的时候就重新加上-webkit-overflow-scrolling:touch,这样就不会影响滑动,实际上也是有点效果了,可以滑动一点点,但是你疯狂的滑动,还是会出现卡死。
当然这种方案是不行的,所以最后还是通过判断是否到达底部或者顶部添加event.preventDefault();来解决,在网上也有人
说这样是可行的。

stackoverflow上的建议

但是这边还有一个需要注意的点就是,如果你的页面有刷新和加载分页,那么你就需要注意设置event.preventDefault()的时机。

如果有下拉刷新,那么在scrollTop为0的时候,就不能设置event.preventDefault();如果有加载分页,那么你就需要直到滑动到最后一页的时候,才能设置event.preventDefault(),否者你一加载更多,页面立马就卡死了。

下面是我代码:

preventFreezeAtTopOrBottomForIOS(isGetRefresher,contenClassName){
    if(this.isIOS()){
      let contentEle = document.getElementsByClassName(contenClassName)[0];
      let lastY = 0; // Needed in order to determine direction of scroll.
      contentEle.getElementsByClassName("scroll-content")[0].addEventListener('touchstart', function(event) {
        lastY = event.touches[0].clientY;
      });
      //获取滚动元素
      let scrollEle = contentEle.getElementsByClassName("scroll-content")[0];
      //先移除监听事件
      scrollEle.removeEventListener('touchmove', function (event) {
        event.preventDefault();
      }, false);
      //再添加监听事件
      scrollEle.addEventListener('touchmove', function(event) {
        let top = event.touches[0].clientY;
        // Determine scroll position and direction.
        let scrollTop = scrollEle.scrollTop;
        // console.log("--scrollTop--" + scrollTop);
        let scrollHeight = scrollEle.scrollHeight;
        // console.log("--scrollHeight--" + scrollHeight);
        let clientHeight = scrollEle.clientHeight;
        // console.log("--clientHeight--" + clientHeight);
        let direction = (lastY - top) < 0 ? "up" : "down";
        // FIX IT!
        if (scrollTop == 0 && direction == "up") {
          console.log("--到顶部--");
          // Prevent scrolling up when already at top as this introduces a freeze.
          if(!isGetRefresher){//没有头部刷新的,需要设置防止头部freeze
            event.preventDefault();
          }
        } else if (scrollTop >= (scrollHeight - clientHeight) && direction == "down") {
          // Prevent scrolling down when already at bottom as this also introduces a freeze.
          event.preventDefault();
          console.log("--到底部--");
        }
        lastY = top;
      });
    }
  }

由于我是使用ionic框架来开发的,所以我这边实际上滚动是“scroll-content”这个div,并且每一个页面都有一个“scroll-content”,所以你在获取对应的页面对应不同的“scroll-content”的时候,可以通过给ion-content设置class来获取其下面的元素“scroll-content”

参数说明:
其中的contentClassName就是各个页面的ion-content对应的classname,注意需自己给ion-content设置唯一的classnameisGetRefresher 就是判断是否有下拉刷新,是boolean类型,至于加载更多,你不需要限制,只需要我上面说的,加载到最后再调用上面那段代码。反正就是内容高度一变化,你就得重新设置。

总结

感觉这种方法是比较好的解决方法了。如果你有其他更好的方法可以告诉我(估计你也没有😄),被这个bug折磨了很久,总算是消停了,当然还是希望官方可以解决这个bug

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345