资讯专栏INFORMATION COLUMN

ios局部滚动的坑及解决方案

yhaolpz / 3140人阅读

摘要:起因最近几天在写一个滚动加载更多数据的插件,为局部滚动写时,遇到了很多局部滚动的坑,在这里分享一下这些坑的解决方案。约定把产生滚动条的元素称之为视窗全局滚动滚动条在或者父级元素上。坑一浏览器局部滚动默认没有弹性滚动的效果。

起因

最近几天在写一个滚动加载更多数据的插件(Scrollload),为局部滚动写demo时,遇到了很多局部滚动的坑,在这里分享一下这些坑的解决方案。以下的坑只针对ios。

约定

把产生滚动条的元素称之为视窗

全局滚动:滚动条在body或者body父级元素上。

局部滚动:滚动条在body里的子孙元素上。

局部滚动优势

每个局部滚动拥有自己的滚动条,这是全局滚动所不能取代的。最典型的是列子如局部滚动,全局滚动。不难发现全局滚动不同的tab之间共享一个滚动条,也就是说其中一个tab滚动了,另一个tab也会跟着滚动。

可以解决input fixed定位失效问题。

全局滚动有出界情况,出界就是滑到最顶端和最底端后继续滑。这样会出现一个很恶心的效果。局部滚动虽然也会有这个情况,但是能修复,全局滚动至少我不会修。

坑(一)

ios浏览器局部滚动默认没有弹性滚动的效果。解决方法是为body或者视窗加-webkit-overflow-scrolling: touch。其实加这两个地方都一样,虽然在文档中并没有说该属性有继承性的,不过我在safari下测试出来是有继承性的。该属性具体说明看这里。

坑(二)
问题

先看一下视频效果:没用ScrollFix

ios局部滚动的出界情况,当你的滚动条在最顶端的时候,你会发现此时你的列表不再滚动而是产生全局滚动了。其实这个确实应该是这样的。如果此时你的视窗占了比整个window还要大,就会一直在视窗里滚动,你还让不让用户看其他内容了。但视窗的滚动条在最顶端的时候的时候下滑又迅速上滑你会发现还是在做全局滚动。这个也应该是这样的,全局滚动还没停下来不可能做局部滚动吧。同理当你滚动条在最下面的时候也会出现这样的状况。但有时候,你就不会想以上的效果。

解决方案

其实解决方案很简单,既然知道了问题是滚动条在最顶端和最底端的时候才会出现的,那么你只要在touchstart的时候判断scrollTop是否为这两个值,如果是就加1或者减1。这里有一个别人已经实现的库ScrollFix。视频效果:用了ScrollFix。贴一下核心代码

var ScrollFix = function(elem) {
    var startY, startTopScroll;
    elem.addEventListener("touchstart", function(event){
        startY = event.touches[0].pageY;
        startTopScroll = elem.scrollTop;
        //当滚动条在最顶部的时候
        if(startTopScroll <= 0)
            elem.scrollTop = 1;
        //当滚动条在最底部的时候
        if(startTopScroll + elem.offsetHeight >= elem.scrollHeight)
            elem.scrollTop = elem.scrollHeight - elem.offsetHeight - 1;
    }, false);
};

但是这个库一定要谨慎用。因为他监听了touchstart事件,这个事件会使滚动滞后(在这里并不明显),passive event listeners。当然你不能用文章里的解决方法,否则如果你快速滑动,由于touchstart事件的监听函数还没执行到就已经开始滚动了所以可能还是会发生上面的情况,ScrollFix这个库就无效了。

坑(三)

还是先看一下视频效果: 有问题的视频

这个坑就是你的内容不满视窗一个屏幕的时候,你向上滑动你会发现整个视窗都动了,也就成了全局滚动。这个现象是正常的,内容都不满一屏当然不需要滚动啊,甚至连滚动条都没产生。

解决方案

理由也说了,内容不足一个屏幕产生的现象,那么让内容时刻保持在一屏之上不就可以了。这里我写了一个库,LocalScrollFix。贴一下核心代码

    update() {
      //当内容超过一屏的时候isArrived为true
        if (this.isArrived) {
            return
        }
      //每次调用update方法时候都去更新fixDom的paddingTop值
        const fixDomPaddingTop = this.computerFixDomPaddingTop()
        
        if (fixDomPaddingTop >= 0) {
              //只有当计算后的值大于0才要更新
            this.fixDom.style.paddingTop = `${fixDomPaddingTop + 2}px`
        } else {
          //当计算后的值小于0的时候,也就是原来的内容就超过一屏幕了。arrived方法中会把fixDom移除。
            this.arrived()
        }
    }
    //计算fixDom所需要的paddingTop值
    computerFixDomPaddingTop() {
          //fixDom指的是append到最底部的dom。win指的是视窗
        const {fixDom, win} = this
        //一开始想内容的高度+paddingTop==数创的高度。因为直接求内容的高度其实并不简单。
        //所以稍微变通了以下,让窗口的top值减去fixDom的top值其实就是fixDom的paddingTop值
        //在把视窗的borderBottomWidth和视窗的paddingBottom考虑进去
        const fixDomTop = fixDom.getBoundingClientRect().top
        const winBottom = win.getBoundingClientRect().bottom
        const {paddingBottom: winPaddingBottom, borderBottomWidth: winBorderBottomWidth}= window.getComputedStyle(win, null)
        return winBottom - parseFloat(winPaddingBottom) - parseFloat(winBorderBottomWidth) - fixDomTop
    }

大概就是在视窗内append一个元素,当你调用update方法的时候就去更新这个元素的paddingTop值来使视窗的内容超过一屏。

最佳实践

ios下可以用局部滚动替代全局滚动,安卓用全局滚动(老的安卓手机在局部滚动上貌似有严重的性能问题)。可能很多人会担心这样比较麻烦,其实仔细思考一下并没有增加多少代码。可以参考最佳实践,源码。

顺便说一下,如果你使用Scrollload来作为滚动到底部加载的插件,那么坑二就只需要把配置useScrollFix设置为true,坑三只需要把配置useLocalScrollFix设置为true。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81188.html

相关文章

  • 原生js滚动到底部加载数据和下拉刷新 Scrollload

    摘要:原文地址初衷如今移动端站点越来越多,滚动到底部加载数据和下拉刷新的需求非常的常见,即使现在很多站点也会有这样的需求,比如百度首页就有。 原文地址 https://github.com/fa-ge/Scrollload/blob/master/README.md 初衷 如今移动端站点越来越多,滚动到底部加载数据和下拉刷新的需求非常的常见,即使现在很多pc站点也会有这样的需求,比如百度首页...

    HollisChuang 评论0 收藏0
  • 事务与多线程坑及调优Tips

    摘要:起因及介绍在处理原始对账文件的时候,我将数据归类后批量存入相应的表中。结论事务只能管着开启事务的线程,其他子线程出了问题都感知不到,所以在多线程环境操作要慎重。高频容易搞死服务器,低频会阻塞自身程序。重试次数和超时时间根据业务情况设置。 起因及介绍 在处理原始对账文件的时候,我将数据归类后批量存入相应的表中。在持久化的时候,用了parallelStream(),想着同时存入很多表这样可...

    wums 评论0 收藏0
  • TabLayout使用遇到坑及方案

    摘要:但对于我们的对于界面还原度要求较高,对于之间的间距也有一些要求,所以也要处理,对于间距部分的处理可以按照之前的方式通过反射来完成。注意,这种方式因为需要计算的文字宽度,所以要放到设置完所有的后调用。 修改下划线宽度的坑 效果如下: showImg(https://s2.ax1x.com/2019/04/18/ES2KYV.png); 代码实现方式: 如果想要实现这种效果,最主要控制的就...

    baishancloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<