javascript iScroll 滚动过去底部?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7071936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 22:52:07  来源:igfitidea点击:

iScroll Scrolling Past Bottom?

javascriptxhtmlmobile-websiteiscroll4

提问by Ry-

You can easily see the problem on the first page here: http://m.vancouverislandlife.com/

你可以很容易地在第一页上看到这个问题:http: //m.vancouverislandlife.com/

Scroll down (slide up) and allow the content to leave the page, and it doesn't bounce back and is lost forever. However, on pages whose content doesoverflow the page and is therefore supposed to be scrollable, the scrolling works correctly (see Accomodations > b&b's and scroll down for an example of this).

I noticed that on my computer, the scrolling on the first page is always stuck at -899px. I can't find anybody else who's experienced this problem and no matter what I try, I just can't fix it! Help!

向下滚动(向上滑动)并让内容离开页面,它不会反弹并永远丢失。但是,在内容确实溢出页面并因此应该是可滚动的页面上,滚动可以正常工作(请参阅住宿 > b&b 并向下滚动以获取示例)。

我注意到在我的电脑上,第一页的滚动总是停留在-899px. 我找不到其他遇到此问题的人,无论我尝试什么,我都无法解决!帮助!

(It's not exactly urgent, however, as the target audience of iPhones and iPod Touches aren't affected by this since they have so little screen room.)

(不过,这并不完全紧迫,因为 iPhone 和 iPod Touch 的目标受众不受此影响,因为它们的屏幕空间很小。)

Okay, new problem. To solve the iScroll issue, I just created a custom script. However, it's not working correctly on the actual device. On desktop browsers, it works just fine. On mobile, it occasionally jumps back to the top and won't recognize some touches. This is probably because of the way I cancelled the default event and had to resort to a bit of a hack. How can I fix this? (Yup - simple problem for a +500 bounty. Not bad, huh?)

好的,新问题。为了解决 iScroll 问题,我刚刚创建了一个自定义脚本。但是,它在实际设备上无法正常工作。在桌面浏览器上,它工作得很好。在移动设备上,它偶尔会跳回顶部并且无法识别某些触摸。这可能是因为我取消默认事件的方式,不得不求助于一些黑客。我怎样才能解决这个问题?(是的 - +500 赏金的简单问题。不错,是吧?)

Here's the script, and the website is at the usual place:

这是脚本,网站位于通常的位置:

function Scroller(content) {
    function range(variable, min, max) {
        if(variable < min) return min > max ? max : min;
        if(variable > max) return max;
        return variable;
    }

    function getFirstElementChild(element) {
        element = element.firstChild;

        while(element && element.nodeType !== 1) {
            element = element.nextSibling;
        }

        return element;
    }

    var isScrolling = false;
    var mouseY = 0;
    var cScroll = 0;
    var momentum = 0;
    if("createTouch" in document) {
        content.addEventListener('touchstart', function(evt) {
            isScrolling = true;
            mouseY = evt.pageY;
            evt.preventDefault();
        }, false);
        content.addEventListener('touchmove', function(evt) {
            if(isScrolling) {
                evt = evt.touches[0];

                var dY = evt.pageY - mouseY;
                mouseY = evt.pageY;
                cScroll += dY;
                momentum = range(momentum + dY * Scroller.ACCELERATION, -Scroller.MAX_MOMENTUM, Scroller.MAX_MOMENTUM);

                var firstElementChild = getFirstElementChild(content);

                content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
            }
        }, false);
        window.addEventListener('touchend', function(evt) {
            isScrolling = false;
        }, false);
    } else {
        content.addEventListener('mousedown', function(evt) {
            isScrolling = true;
            mouseY = evt.pageY;
        }, false);
        content.addEventListener('mousemove', function(evt) {
            if(isScrolling) {
                var dY = evt.pageY - mouseY;
                mouseY = evt.pageY;
                cScroll += dY;
                momentum = range(momentum + dY * Scroller.ACCELERATION, -Scroller.MAX_MOMENTUM, Scroller.MAX_MOMENTUM);

                var firstElementChild = getFirstElementChild(content);

                content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
            }
        }, false);
        window.addEventListener('mouseup', function(evt) {
            isScrolling = false;
        }, false);
    }

    function scrollToTop() {
        cScroll = 0;
        content.style.WebkitTransform = '';
    }

    function performAnimations() {
        if(!isScrolling) {
            var firstElementChild = getFirstElementChild(content);
            cScroll = range(cScroll + momentum, -(firstElementChild.scrollHeight - content.offsetHeight), 0);
            content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
            momentum *= Scroller.FRICTION;
        }
    }

    return {
        scrollToTop: scrollToTop,
        animationId: setInterval(performAnimations, 33)
    }
}

Scroller.MAX_MOMENTUM = 100;
Scroller.ACCELERATION = 1;
Scroller.FRICTION = 0.8;

回答by Anh-Kiet Ngo

I think Andrew was on the right track with regards to setting the height of the #wrapperdiv. As he pointed out that,

我认为安德鲁在设置#wrapperdiv的高度方面走在正确的轨道上。正如他指出的那样,

that.maxScrollY = that.wrapperH - that.scrollerH;

Normally, this would work. But now that you've changed your #contentto position: fixed, the wrapper element is no longer "wrapping" your content, thus that.wrapperHhas a value of 0, things break.

通常,这会起作用。但是现在您已将您的更改#contentposition: fixed,包装元素不再“包装”您的内容,因此that.wrapperH其值为 0,事情就中断了。

Disclaimer: I did not go through the entire script so I may be wrong here

免责声明:我没有通读整个脚本,所以我在这里可能是错的

When manually setting a height to #wrapper, say 500px, it becomes,

当手动将高度设置为 时#wrapper,例如500px,它变为,

that.maxScrollY = 500 - that.scrollerH;

The folly here is that when there's a lot of content and the window is small, that.scrollerHis relatively close in value to 500, say 700px. The difference of the two would be 200px, so you can only scroll 200 pixels, thus giving the appearance that it is frozen. This boils down to how you set that maxScrollYvalue.

这里的愚蠢之处在于,当有很多内容并且窗口很小时,that.scrollerH它的值相对接近 500,例如700px。两者的区别是200px,因此您只能滚动 200 像素,从而给人以冻结的外观。这归结为您如何设置该maxScrollY值。

Solution (for Chrome browser at least):

解决方案(至少适用于 Chrome 浏览器):

Since #wrappereffectively contains no content, we cannot use it in the calculations. Now we are left with the only thing that we can reliably get these dimensions from, #content. In this particular case, it appears that using the content element's scrollHeightyield what we want. This is most likely the one that has the expected behavior,

由于#wrapper有效地不包含任何内容,我们不能在计算中使用它。现在我们只剩下我们可以可靠地从中获取这些维度的唯一方法了#content。在这种特殊情况下,使用内容元素的scrollHeight结果似乎是我们想要的。这很可能是具有预期行为的那个,

that.maxScrollY = that.scrollerH - that.scroller.scrollHeight;

scrollerHis the offsetHeight, which is roughly the height of what you see in the window. scroller.scrollHeightis the height that's considered scrollable. When the content does not exceed the length of the page, they are roughly equivalent to one another. That means no scroll. When there are a lot of content, the difference of these two values is the amount of scroll you need.

scrollerHoffsetHeight,大致是您在窗口中看到的高度。scroller.scrollHeight是被认为可滚动的高度。当内容不超过页面长度时,它们大致相等。这意味着没有滚动。当内容很多时,这两个值的区别就是你需要的滚动量。

There is still a minor bug, and this looks like it's already there. When you have a lot of content, the last few elements are covered up by the bar when scrolled to the bottom. To fix this, you can set an offset such as,

还有一个小错误,这看起来已经存在了。当你有很多内容时,最后几个元素在滚动到底部时被栏覆盖。要解决此问题,您可以设置一个偏移量,例如,

that.maxScrollY = that.scrollerH - that.scroller.scrollHeight - 75;

The number 75 arbitrary. It's probably best if it's the height of the bar itself with 2 or 3 pixels for a bit of padding. Good luck!

数字75任意。如果它是条形本身的高度,并带有 2 或 3 个像素的一些填充,那可能是最好的。祝你好运!

Edit:

编辑:

I forgot to mention last night, but here are the two sample pages that I used in trying to debug this problem.

我昨晚忘了提及,但这里有两个示例页面,我在尝试调试此问题时使用过。

Long page
Short page

长页
短页

回答by Andrew

Your wrapper div seems to have a height of 0. So all the calculations are negative, setting it's height to the window height will correct the scroll issue. When I manually set the wrappers height via firebug and chromes debug bar the scroll functions as it should.

您的包装器 div 的高度似乎为 0。因此所有计算都是负数,将其高度设置为窗口高度将更正滚动问题。当我通过 firebug 和 chromes 调试栏手动设置包装器高度时,滚动功能正常。

You #content div seems to have its size change on resize, probably a better idea to have the #wrapper div have its size change and then have #content inherit the size.

你 #content div 似乎在调整大小时改变了它的大小,让 #wrapper div 改变它的大小然后让 #content 继承大小可能是一个更好的主意。

[Edit]You don't believe me so codez, From iscroll-lite.js

[编辑]你不相信我这么编码,来自 iscroll-lite.js

refresh: function () {
  var that = this,
      offset;
  that.wrapperW = that.wrapper.clientWidth;
  that.wrapperH = that.wrapper.clientHeight;
  that.scrollerW = that.scroller.offsetWidth;
  that.scrollerH = that.scroller.offsetHeight;
  that.maxScrollX = that.wrapperW - that.scrollerW;
  that.maxScrollY = that.wrapperH - that.scrollerH; 

In your page that translates to,

在您翻译的页面中,

that.wrapperH = 0;
that.maxScrollY = -that.scrollerH

When a scroll finishes, this code gets called.

当滚动完成时,将调用此代码。

var that = this,

resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
resetY = that.y >= 0 || that.maxScrollY > 0 ? 0 : that.y < that.maxScrollY ? that.maxScrollY : that.y;
...
that.scrollTo(resetX, resetY, time || 0);

See that that.maxScrollY > 0 ?? If maxScrollY is negative then scrolling up will neverbounce back.

看到了that.maxScrollY > 0 ?吗?如果 maxScrollY 为负,则向上滚动将永远不会反弹。

回答by SteamDev

This may be a CSS issue. In your stylesheet (mobile.css line 22), try removing position:fixedfrom #content.

这可能是 CSS 问题。在您的样式表(mobile.css 第 22 行)中,尝试position:fixed#content.

That should allow the document to scroll normally (vertical scrollbar on a computer, "slideable" on a mobile browser).

这应该允许文档正常滚动(计算机上的垂直滚动条,移动浏览器上的“可滑动”)。

Elements with position:fixedexit the normal flow of the document, their positioning is relative to the browser window. This is probably why you're having issues with scrolling. Fixed positioning is generally for elements which should always remain in the same place, even when the page is scrolled (ie. a notification bar "pinned" at the top of a page).

带有position:fixed退出文档的正常流的元素,它们的定位是相对于浏览器窗口的。这可能就是您在滚动时遇到问题的原因。固定定位通常用于应该始终保持在同一位置的元素,即使在滚动页面时(即“固定”在页面顶部的通知栏)。

回答by TJ.

No definite solution, but more a direction I'd go for: #wrapper and #content's overflow:hidden paired #content's postion:fixed and seem to be the cause of the issue.

没有明确的解决方案,但更多的是我想要的方向:#wrapper 和 #content's overflow:hidden 配对 #content's postion:fixed 并且似乎是问题的原因。

If position: fixed is removed from #content, scrolling is possible but the "blank" divs are wrongly layered (tested in Firefox 5).

如果 position: fixed 从 #content 中删除,滚动是可能的,但“空白”div 被错误地分层(在 Firefox 5 中测试)。

回答by Ry-

I ended up just making my own, small script to handle the scrolling:

我最终只是制作了自己的小脚本来处理滚动:

// A custom scroller
function range(variable, min, max) {
    if(variable < min) return min > max ? max : min;
    if(variable > max) return max;
    return variable;
}

var isScrolling = false;
var mouseY = 0;
var cScroll = 0;
if("createTouch" in document) {
    // TODO: Add for mobile browsers
} else {
    content.addEventListener('mousedown', function(evt) {
        isScrolling = true;
        mouseY = evt.pageY;
    }, false);
    content.addEventListener('mousemove', function(evt) {
        if(isScrolling) {
            var dY = evt.pageY - mouseY;
            mouseY = evt.pageY;
            cScroll += dY;

            var firstElementChild = content.getElementsByTagName("*")[0];

            content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
        }
    }, false);
    window.addEventListener('mouseup', function(evt) {
        isScrolling = false;
    }, false);
}

and modifying a few other parts. It does save a lot of download time, I suppose, also.

并修改了一些其他部分。我想,它也确实节省了很多下载时间。

I'm still going to accept answers and award the bounty in 5 days, though.

不过,我仍然会接受答案并在 5 天内授予赏金。

回答by Anh-Kiet Ngo

Changed question warrants a new answer. I took a look at the code and I saw that you calculated the momentum on each step of the "move" function. This does not make sense because the momentum is used after the move has ended. What this meant was to capture the mouse position at the beginning, and then calculate the difference at the end. So I added two new variables,

更改的问题保证了新的答案。我看了一下代码,发现你计算了“移动”函数每一步的动量。这是没有意义的,因为动量是在移动结束后使用的。这意味着在开始时捕获鼠标位置,然后在结束时计算差异。所以我添加了两个新变量,

var startTime;
var startY;

Inside the start event (mousedown/touchstart), I added,

在开始事件(鼠标按下/触摸开始)中,我添加了,

startY = evt.pageY;
startTime = evt.timeStamp || Date.now();

Then I have the following for my end handler,

然后我的最终处理程序有以下内容,

var duration = (evt.timeStamp || Date.now()) - startTime;
if (duration < 300) {
    var dY = evt.pageY - startY;
    momentum = range(momentum + dY * Scroller.ACCELERATION, -Scroller.MAX_MOMENTUM, Scroller.MAX_MOMENTUM);
} else {
    momentum = 0;
}

I also removed the momentum calculation from inside of mousemove/touchmove. Doing this removed the jumping around behavior that I was seeing on my iPhone. I am seeing other unwanted behaviors as well (the whole window "scrolls"), but I'm guessing that you've been working to get rid of those so I didn't attempt.

我还从 mousemove/touchmove 内部删除了动量计算。这样做消除了我在 iPhone 上看到的跳跃行为。我也看到了其他不需要的行为(整个窗口“滚动”),但我猜你一直在努力摆脱这些,所以我没有尝试。

Good luck. Here's a coded up pagethat I duplicated for my testing. I also took the liberty to refactor the code for this section to remove some duplicated code. It's under mobile3.js if you want to look at it.

祝你好运。这是我为测试而复制的编码页面。我还冒昧地重构了本节的代码以删除一些重复的代码。如果你想看它,它在 mobile3.js 下。