简体   繁体   English

显式设置scrollTop时,iOS Webkit浏览器上的无限滚动闪烁

[英]Infinite Scroll Flickering on iOS webkit browser when setting scrollTop explicitly

I have a strange problem and it is hard to explain. 我有一个奇怪的问题,很难解释。 Still I will go ahead and try it. 我仍然会继续尝试。 What is happening is I have an infinite scroll logic, where I load more content when user scrolls to the bottom of the page and if the no of DOM elements increases beyond a certain limit, I remove an equal chunk of DOM element from the top, to keep the no of DOM elements in the page constant and to keep the memory in check. 发生的是,我有一个无限滚动逻辑,当用户滚动到页面底部时,我会加载更多内容,并且如果DOM元素的数量增加到一定限制之外,我将从顶部移除相等的DOM元素块,以保持页面中DOM元素的数量不变并检查内存。 Now, when I add new elements at the bottom and remove old elements from the top, I have to set the scrollTop position of the scrollable element (the parent container) explicitly just to maintain the user's scroll position. 现在,当我在底部添加新元素并从顶部删除旧元素时,我必须显式设置可滚动元素(父容器)的scrollTop位置,以保持用户的滚动位置。 I am using Jquery's scrollTop() method call to set the scroll position at the moment. 我正在使用Jquery的scrollTop()方法调用来设置当前滚动位置。 As soon as I update the scroll position with a call to scrollTop() the page flickers and I can see a white patch for a brief moment on iOS devices. 当我通过调用scrollTop()更新滚动位置时,页面就会闪烁,并且在iOS设备上可以看到一小段白色补丁。 This happens even with the native Javacript scrollTop property. 即使使用本机Javacript scrollTop属性,也会发生这种情况。 The issue is seen only on iOS webkit browsers(both webviews and browsers on devices as well as simulator) and I am not seeing the same issue on Android webviews. 仅在iOS Webkit浏览器(网络视图和设备上的浏览器以及模拟器)上才看到该问题,而在Android网络视图上却没有看到相同的问题。 Even on desktop browsers, it runs just fine including Safari. 即使在桌面浏览器上,它也可以在包括Safari的环境下正常运行。

The code that I am writing is meant to be a bi-directional infinite scrolling but for this question I am only posting the code for downward scrolling. 我正在编写的代码是双向无限滚动的,但是对于这个问题,我只发布向下滚动的代码。

Here is the code snippet - 这是代码片段-

<!doctype html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, user-scalable=no" /> 
        <style type="text/css">
            html, body {
                margin: 0;
                padding: 0;
                height: 100%;
                background: #fff;
            }
            #holder {
                overflow-x: hidden;
                overflow-y: scroll;
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                right: 0;
            }


            ul {
                margin: 0;
                padding: 0;
            }
            ul li {
                list-style: none;
                padding: 20px;
                border-bottom: 1px solid #9a9a9a;
                background: #e5e5e4;
            }
            .androidFix {
              overflow: hidden !important;
              overflow-y: hidden !important;
              overflow-x: hidden !important;
            }
        </style>
    </head>
    <body>
        <div id="holder">
            <div id="container">

            </div>
        </div>

        <!-- Script goes here -->
        <script type="text/javascript" src="jquery-2.0.3.js"></script>
        <script type="text/javascript" src="handlebars.js"></script>

        <!-- Sample data -->
        <script type="text/javascript">
            var data = [{slno: '1', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '2', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '3', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '4', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '5', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '6', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '7', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '8', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '9', amount: '250', name: 'DAG Account', date: '16/07/2014'},
                        {slno: '10', amount: '250', name: 'DAG Account', date: '16/07/2014'}];
        </script>

        <!-- Handlebars template -->
        <script id="template" type="text/x-handlebars-template">
            {{#each data}}
                <li>
                     <div>
                        <span><b>sl no {{slno}}</b></span>
                        <span>{{amount}}</span>
                    </div>
                    <div>
                        <span>{{name}}</span>
                        <span>{{date}}</span>
                    </div>
                </li>
            {{/each}}
        </script>

        <!-- App logic -->
        <script type="text/javascript">

            var source   = $("#template").html();
            var template = Handlebars.compile(source);
            var html = template({data: data});
            //console.log(html);

            var holderRef = $("#holder");
            var holderHeight = $("#holder").height();

            var newChunk = $("<ul class='list-chunk' />");
            newChunk.append(html);

            var containerRef = $("#container");

            containerRef.append(newChunk);  //initial data load

            var chunkHeight = $(".list-chunk").height();


            $("#holder").scroll(function() {

                //test for bottom
                var scrollTopVal = this.scrollTop;

                var containerHeight = containerRef.height();

                //console.log('test', scrollTopVal);

                if(scrollTopVal + holderHeight >= containerHeight) {
                    console.log('bottom');

                    var newChunk = $("<ul class='list-chunk' />");
                    newChunk.append(html);

                    containerRef.append(newChunk);

                    //if($("#container").children().size() > 2) {
                    if(containerRef.children().size() > 2) {
                        var viewTop = $("#holder").scrollTop();

                        var oldChunk = containerRef.children().first();
                        var oldChunkHeight = oldChunk.height();
                        console.log(chunkHeight);
                        oldChunk.remove();

                        setScrollTop(viewTop - chunkHeight);  
                    }

                }


                function setScrollTop(amount) {
                    $("#holder").addClass("androidFix").scrollTop(amount).removeClass("androidFix");   //******* - the problem lies here
                }
            });
        </script>
    </body>
</html>

A couple of suggestions / guesses in the order I would try them: 我会按照以下顺序进行一些建议/猜测:

Your androidFix class is also being applied on other systems. 您的androidFix类也将应用于其他系统。 Instead of applying a class, change that elements style props directly (element.style.overflowX = "hidden" etc ) only on the system that needs it. 不必应用类,而仅在需要它的系统上直接更改元素样式道具(element.style.overflowX =“ hidden”等)。 Do browser sniffing perhaps. 做浏览器嗅探也许。 You could apply your scrollTop directly in the same call as well, which would save you having to toggle the class on then off around the scroll setting, and save multiple expensive DOM manipulations. 您也可以直接在同一调用中应用scrollTop,这将节省您不必在滚动设置周围切换类然后再将其关闭的方法,并节省了许多昂贵的DOM操作。

Scroll events fire a lot, DOM manipulations are very slow, especially mutating the DOM tree. 滚动事件触发得很多,DOM操作非常慢,尤其是使DOM树发生变异。 You could set a flag (changingDOM = true) then just return straight away from subsequent calls to the scroll handler, until you're done and set it back to false. 您可以设置一个标志(changingDOM = true),然后直接从随后的滚动处理程序调用返回,直到完成并将其设置为false。

Come to think of it, is this the reason for androidfix? 想一想,这是androidfix的原因吗? setting scrollTop recursively calls the scroll handler, unless you overflow=hidden? 设置scrollTop递归调用滚动处理程序,除非您溢出=隐藏? In that case, I would try the latter change first of all. 在这种情况下,我会首先尝试后者的更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM