cubiq / iscroll

Smooth scrolling for the web
http://iscrolljs.com
MIT License
12.87k stars 3.8k forks source link

Not able to scroll down to the bottom of the div #1194

Open haveamission opened 7 years ago

haveamission commented 7 years ago

So I'm using an IScroll script and I'm having trouble scrolling down to the bottom of my div. My ultimate goal is to have something like the iOS texting input, where I can pull down from the top and have older messages pop up, while still being able to scroll all the way to the bottom.

My code is setup as such (I added some things to it elsewhere, but this is the most basic code that is from a demo example) - https://github.com/cubiq/iscroll/issues/378:

/*var generatedCount = 0;*/
function pullDownAction(theScroller) {
    var el, li, i;  
    //TODO: do your things
    theScroller.refresh(); //just in case
}
function pullUpAction(theScroller) {
    var el, li, i;
    //TODO: doYourThings();
    theScroller.refresh(); //just in case
}

var IScrollPullUpDown = function(wrapperName, iScrollConfig, pullDownActionHandler, pullUpActionHandler) {
    var iScrollConfig, pullDownActionHandler, pullUpActionHandler, pullDownEl, pullDownOffset, pullUpEl, scrollStartPos;
    var pullThreshold = 5;
    var me = this;

    function showPullDownElNow(className) {
        // Shows pullDownEl with a given className
        pullDownEl.style.transitionDuration = '';
        pullDownEl.style.marginTop = '';
        pullDownEl.className = 'pullDown ' + className;
    }

    var hidePullDownEl = function(time, refresh) {
        // Hides pullDownEl
        pullDownEl.style.transitionDuration = (time > 0 ? time + 'ms' : '');
        pullDownEl.style.marginTop = '';
        pullDownEl.className = 'pullDown scrolledUp';

        // If refresh==true, refresh again after time+10 ms to update iScroll's "scroller.offsetHeight" after the pull-down-bar is really hidden...
        // Don't refresh when the user is still dragging, as this will cause the content to jump (i.e. don't refresh while dragging)
        if(refresh) setTimeout(function() {
            me.myScroll.refresh();
        }, time + 10);
    }

    function init() {
        var wrapperObj = document.querySelector('#' + wrapperName);
        var scrollerObj = wrapperObj.children[0];

        if(pullDownActionHandler) {
            // If a pullDownActionHandler-function is supplied, add a pull-down bar at the top and enable pull-down-to-refresh.
            // (if pullDownActionHandler==null this iScroll will have no pull-down-functionality)
            pullDownEl = document.createElement('div');
            pullDownEl.className = 'pullDown scrolledUp';
            pullDownEl.innerHTML = '<span class="pullDownIcon"></span><span class="pullDownLabel">Pull down to refresh...</span>';
            scrollerObj.insertBefore(pullDownEl, scrollerObj.firstChild);
            pullDownOffset = pullDownEl.offsetHeight;
        }
        if(pullUpActionHandler) {
            // If a pullUpActionHandler-function is supplied, add a pull-up bar in the bottom and enable pull-up-to-load.
            // (if pullUpActionHandler==null this iScroll will have no pull-up-functionality)
            pullUpEl = document.createElement('div');
            pullUpEl.className = 'pullUp';
            pullUpEl.innerHTML = '<span class="pullUpIcon"></span><span class="pullUpLabel">Pull up to load more...</span>';
            //scrollerObj.appendChild(pullUpEl);
        }

        me.myScroll = new IScroll(wrapperObj, iScrollConfig);

        me.myScroll.on('refresh', function() {
            if((pullDownEl) && (pullDownEl.className.match('loading'))) {
                pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
                if(this.y >= 0) {
                    // The pull-down-bar is fully visible:
                    // Hide it with a simple 250ms animation
                    hidePullDownEl(250, true);
                } else if(this.y > -pullDownOffset) {
                    // The pull-down-bar is PARTLY visible:
                    pullDownEl.style.marginTop = this.y + 'px';

                    // CSS-trick to force webkit to render/update any CSS-changes immediately: Access the offsetHeight property...
                    pullDownEl.offsetHeight;

                    var animTime = (250 * (pullDownOffset + this.y) / pullDownOffset);
                    this.scrollTo(0, 0, 0);   
                    setTimeout(function() { 
                        hidePullDownEl(animTime, true);
                    }, 0);

                } else {
                    hidePullDownEl(0, true);
                    this.scrollBy(0, pullDownOffset, 0);
                }
            }
            if((pullUpEl) && (pullUpEl.className.match('loading'))) {
                pullUpEl.className = 'pullUp';
                pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
            }
        });

        me.myScroll.on('scrollStart', function() {
            scrollStartPos = this.y; // Store the scroll starting point to be able to track movement in 'scroll' below
        });

        me.myScroll.on('scroll', function() {
            if(pullDownEl || pullUpEl) {
                if((scrollStartPos == 0) && (this.y == 0)) {
                    this.hasVerticalScroll = true;

                    // Set scrollStartPos to -1000 to be able to detect this state later...
                    scrollStartPos = -1000;
                } else if((scrollStartPos == -1000) &&
                    (((!pullUpEl) && (!pullDownEl.className.match('flip')) && (this.y < 0)) ||
                    ((!pullDownEl) && (!pullUpEl.className.match('flip')) && (this.y > 0)))) {
                    this.hasVerticalScroll = false;
                    scrollStartPos = 0;
                    this.scrollBy(0, -this.y, 0);   // Adjust scrolling position to undo this "invalid" movement
                }
            }

            if(pullDownEl) {
                if(this.y > pullDownOffset + pullThreshold && !pullDownEl.className.match('flip')) {
                    showPullDownElNow('flip');
                    this.scrollBy(0, -pullDownOffset, 0);   // Adjust scrolling position to match the change in pullDownEl's margin-top
                    pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh...';
                } else if(this.y < 0 && pullDownEl.className.match('flip')) { // User changes his mind...
                    hidePullDownEl(0, false);
                    this.scrollBy(0, pullDownOffset, 0);    // Adjust scrolling position to match the change in pullDownEl's margin-top
                    pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
                }
            }
            if(pullUpEl) {
                if(this.y < (this.maxScrollY - pullThreshold) && !pullUpEl.className.match('flip')) {
                    pullUpEl.className = 'pullUp flip';
                    pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to load more...';
                } else if(this.y > (this.maxScrollY + pullThreshold) && pullUpEl.className.match('flip')) {
                    pullUpEl.className = 'pullUp';
                    pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
                }
            }
        });

        me.myScroll.on('scrollEnd', function() {
            if((pullDownEl) && (pullDownEl.className.match('flip'))) {
                showPullDownElNow('loading');
                pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';
                pullDownActionHandler(this);    // Execute custom function (ajax call?)
            }
            if((pullUpEl) && (pullUpEl.className.match('flip'))) {
                pullUpEl.className = 'pullUp loading';
                pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...';
                pullUpActionHandler(this);  // Execute custom function (ajax call?)
            }
            if(scrollStartPos = -1000) {
                this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
            }
        });

        me.myScroll.refresh();
    }

    window.addEventListener('load', function() {
        init()
    }, false);
};

var scroller1 = new IScrollPullUpDown('messages-wrapper', {
    probeType: 2,
    bounceTime: 250,
    bounceEasing: 'quadratic',
    mouseWheel: false,
    scrollbars: true,
    fadeScrollbars: true,
    interactiveScrollbars: false,
    click: true,
    tap: true
}, pullDownAction, pullUpAction);

function blockTouchMove(e) {
    e.preventDefault();
}

document.addEventListener('touchmove', blockTouchMove, false);

My HTML looks like this:

<div id="messages-wrapper"><div id="messages"></div></div>

Where the messages will appear in the #messages div, and the iScroll functionality is applied to the #messages-wrapper div.

Why can't I scroll all the way to the bottom? Is it because I'm populating my div after the fact? This has been a huge bug that I just have not had any luck figuring out.