简体   繁体   中英

iScroll inside iScroll - nested iScroll unexpected behavior

I have 2 lists and I use iScroll for vertical scrolling.

The second list is inside the first list.

When I scroll the second list, the first list is also scrolling.
I want that when I scroll the inside list (the second list), the main list (the first list) will not scroll.

How can I do that?

Here is an Example:

<div id="wrapper" style="overflow: hidden;">
    <div id="scroller">
        <ul id="thelist">
            <li>Pretty row 1</li>
            <li>Pretty row 2</li>
            <li>Pretty row 3</li>
            <li>Pretty row 4</li>
            <li>Pretty row 5</li>
            <li>Pretty row 6</li>
            <li id='inWarper'>
                <div  id="scroller">
                    <br/>
                    <ul>
            <li>Pretty row 1</li>
            <li>Pretty row 2</li>
            <li>Pretty row 3</li>
            <li>Pretty row 4</li>
            <li>Pretty row 5</li>
            <li>Pretty row 6</li>
            <li>Pretty row 7</li>
            <li>Pretty row 8</li>
            <li>Pretty row 9</li>
            <li>Pretty row 10</li>
                    </ul>
                </div>
            </li>
            <li>Pretty row 7</li>
            <li>Pretty row 8</li>
            <li>Pretty row 9</li>
            <li>Pretty row 10</li>
            <li>Pretty row 11</li>
            <li>Pretty row 12</li>
            <li>Pretty row 13</li>
            <li>Pretty row 14</li>
            <li>Pretty row 15</li>
            <li>Pretty row 16</li>
            <li>Pretty row 17</li>
            <li>Pretty row 18</li>
        </ul>
         <br/>
    </div>
</div>

And in Load event:

myScroll = new iScroll('wrapper');
myScroll2 = new iScroll('inWarper');

CSS:

#scroller ul {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
text-align: left;
}

#scroller {
position: absolute;
z-index: 1;
/* -webkit-touch-callout: none; */
-webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100%;
padding: 0;
}

#wrapper {
position: absolute;
z-index: 1;
top: 45px;
bottom: 48px;
left: 0;
width: 100%;
background: #aaa;
overflow: auto;
    height:150px;
}

#inWarper {
    color:red;
position: absolute;
z-index: 1;
height:100px;
left: 0;
width: 100%;
background: #aaa;
overflow: auto;
}

JSFiddle: http://jsfiddle.net/PPtWs/64/

The idea to fix this problem is to prevent (stop) propagation of the scrolling firing event to the parent div

This is how to fix it

myScroll = new iScroll('wrapper');
myScroll2 = new iScroll('inWarper' , {
    onBeforeScrollStart : function(e) { 
    e.stopPropagation();
}});

Example http://jsfiddle.net/khaledalyawad/4p7t8ymp/

I know that this is an old thread, but for anyone who finds this:

Foreword: iScroll is now no longer maintained, so I recommend having a look at some alternatives, for example https://github.com/ustbhuangyi/better-scroll (which I did not try out myself, though). But if, for whatever reason, you have to use the iScroll and you want a smooth behaviour, the above answer might not be sufficient for you.

Issues with e.stopPropagation()

What the native browser does when scrolling is actually first detecting what content is being scrolled and then scrolling that content.

For example: if you touch a scrollable textarea on your mobile (imagine writing an answer here on StackOverflow on your mobile – you can try that out) it will scroll that area and not it's parent, even if your touch ends outside the area (you slide far up), as long as you hold your finger on the screen. That is first case where the e.stopPropagation fails.

Second issue is: if the nested scroll is fully scrolled to top/bottom and you scroll in that direction, then the above behaviour is negated and you actually scroll the outside area (again, try that on your mobile or even when mouse-wheel scrolling). Try it out: simply be at the bottom of an area, then scroll down for a while, then quickly up - the main scrollbar will scroll down at first and then up later - even if your mouse is actually over the nested area.

Solution

The only way around this is to first detect the parent iScroll (or even a natively scrolling element) and then, as long as it is „the same scroll“, keep scrolling that area. What is „the same scroll“ is simple for touch (from touch-start to touch-end event) and a bit complicated for mouse scroll (browsers seem to detect an „unbroken chain“ of succeeding scrolls, which is broken if you stop scrolling for a certain time - that time is browser-dependent, so it is up to you, what you want in your app).

That is what I came up after diving quite deep into this. I actually have a working code for iScroll that works very smooth and feels like a native browser/app behaviour. It has been a lot more work than I would like and it is quite long, but if anyone was interested, I can provide said code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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