【问题标题】:iScroll Scrolling Past Bottom?iScroll 滚动到底部?
【发布时间】:2011-08-15 23:22:44
【问题描述】:

您可以在此处轻松查看第一页上的问题:http://m.vancouverislandlife.com/

向下滚动(向上滑动)并允许内容离开页面,它不会反弹并永远丢失。但是,在其内容确实溢出页面并因此应该是可滚动的页面上,滚动工作正常(参见Accomodations > b&b's and scroll down以获取此示例)。

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

(不过,这并不紧急,因为 iPhone 和 iPod Touch 的目标受众不会受到影响,因为它们的屏幕空间太小了。)

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

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

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;

【问题讨论】:

  • 如果你设置bounce:true会发生什么?你可能知道,但position:fixed 在移动 safari 中不起作用(直到 ios5)。但是在 ios5 中,您将不需要任何插件,因为它支持动态滚动natively。如果更改插件是一种选择,您是否看过touchScrollscrollability
  • @Mrchief:bounce: true 没有区别,我不希望用户无论如何都能够滚动到边缘。我知道position: fixed 在移动 Safari 中不起作用(但它并没有那么不受支持,因为它是无效的,因为移动 Safari 使用移动视口而不是固定视口),我不是针对 iOS5 的,是的,更改插件是一个选项,所以我会看看这些,谢谢。
  • 我尝试在本地设置,但没有成功(可能是由于我没有 php 的 ajax 调用,或者可能是深夜)。您是否可以转储我可以玩的静态 html(jsfiddle 会搞砸)?令人惊讶的是,去年我使用其他东西进行动态滚动效果很好,我现在找不到相同的插件(我也从那个客户端继续前进)。无论如何,我会再试一次。
  • @Mrchief:这是一个 jsFiddle:jsfiddle.net/minitech/QDuwk/1 链接当然不起作用,但滚动是存在的。您可以将其从页面上弹起,但无法取回。
  • @minitech 这个问题解决了吗?滚动到内容边界之外很烦人。

标签: javascript xhtml mobile-website iscroll4


【解决方案1】:

我认为 Andrew 在设置 #wrapper div 的高度方面是正确的。正如他所指出的,

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

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

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

当手动将高度设置为#wrapper,比如500px,它变成了,

that.maxScrollY = 500 - that.scrollerH;

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

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

由于#wrapper 实际上不包含任何内容,我们不能在计算中使用它。现在我们只剩下唯一可以可靠地从#content 获得这些尺寸的东西了。在这种特殊情况下,使用内容元素的scrollHeight 似乎会产生我们想要的结果。这很可能是具有预期行为的那个,

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

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

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

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

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

编辑:

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

Long page
Short page

【讨论】:

  • 嗯...当我访问任一测试页面时,滚动都无法正常工作...在我的测试中,修改 iScroll 脚本确实使事情变得更好,但仍然可以用一些快速的手势“丢失”页面。我最后做了一个定制的。不过还是谢谢。稍后我会决定将赏金授予谁。
  • 好的,问题现在变了-请尝试回答!
  • 我为你的努力提供了赏金,无论如何它都会给你。不过,请尝试帮助解决新问题。
  • 嗯,我以前从未做过移动设备编码。今晚或明晚我会尝试一下。
【解决方案2】:

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

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

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

【讨论】:

  • 我知道 - 但这是对先前问题的修复,显然没有其他解决方法。
  • 试试看 - 删除 position: fixed,然后换页 - 整个内容在过渡期间消失。
  • 尝试将position:fixed; 更改为position:absolute;,这样应该可以保留您的过渡效果。
  • 已经在第一个问题中尝试过。令人惊讶的是,它没有用。
【解决方案3】:

没有明确的解决方案,但更多的是我想要的方向: #wrapper 和 #content 的溢出:隐藏配对 #content 的位置:已修复,似乎是问题的原因。

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

【讨论】:

    【解决方案4】:

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

    #content div 的大小似乎在调整大小时发生了变化,最好让#wrapper div 的大小发生变化,然后让#content 继承大小。

    [编辑] 你不相信我这么 codez,来自 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; 
    

    在您的页面中,

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

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

    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);
    

    看到that.maxScrollY &gt; 0 ? 了吗?如果 maxScrollY 为负数,则向上滚动将永远弹回。

    【讨论】:

    • 设置高度完全阻止它滚动,即使在应该滚动的页面上......
    • @minitech 你确定吗?看看documentation 它说包装器需要设置一个高度。至少你需要设置高度,还有其他错误。
    • @minitech ps,设置为100%不行,你需要在pxs中设置#wrappers高度
    • 我很肯定。即使以像素为单位设置高度,它也不起作用。
    【解决方案5】:

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

    // 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);
    }
    

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

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

    【讨论】:

    • 非常好!有趣的是,您是根据第一个孩子进行计算的。我建议改变一些事情。您应该使用firstElementChild.offsetHeight,因为它似乎是您想要的。如果第一个元素有很多 overflow: hidden/scroll 内容,您的计算将被关闭。其次是使用content.children[0] 而不是getElementsByTagName()children 是一个包含所有 HTML 元素的数组,因此它不包含文本节点。第三,既然你在做-(A - B),我个人认为最好做(B - A),因为它更干净。
    • @Anh-Kiet Ngo:感谢offsetHeight 的提示,不知道我在想什么……但是关于overflow 可能的问题,我有一个专门的“内在” &lt;div&gt; 它实际上是唯一的孩子。还要感谢children 提示,我已将其从getElementsByTagName() 更改为我自己的方法,但当然看起来要快得多。最后,我将其更改为B - A。它现在是一个 alpha 版本 :) 自从我发布它以来,我已经像 iScroll 一样添加了动力并将其放入它自己的对象中。不过,仍然会取消默认滚动。
    • @Anh-Kiet Ngo:我已经编辑了我的问题以更改它并包含我更新的脚本。它最近已从“几乎没有 hacks 工作”更改为“几乎可以工作,但有 hacks”,所以它应该很容易修复。
    【解决方案6】:

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

    var startTime;
    var startY;
    

    在开始事件(mousedown/touchstart)中,我添加了,

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

    然后我的结束处理程序有以下内容,

    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;
    }
    

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

    祝你好运。这是我为测试而复制的coded up page。我还冒昧地重构了本节的代码以删除一些重复的代码。想看的话在mobile3.js下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-12
      • 2012-11-30
      • 2016-11-13
      • 2016-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多