iScroll Scrolling Past Bottom? - PullRequest
       18

iScroll Scrolling Past Bottom?

3 голосов
/ 16 августа 2011

Вы можете легко увидеть проблему на первой странице здесь: http://m.vancouverislandlife.com/

Прокрутите вниз (сдвиньте вверх) и разрешите контенту покинуть страницу, и он не отскочит назад ипотерян навсегда.Однако на страницах, содержимое которых действительно переполняет страницу и, следовательно, должно быть прокручиваемым, прокрутка работает правильно (см. Раздел «Жилье»> «b & b» и прокрутите вниз для примера этого).

Iзаметил, что на моем компьютере прокрутка на первой странице всегда застряла на -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;

Ответы [ 6 ]

4 голосов
/ 25 августа 2011

Я думаю, что Эндрю был на правильном пути в отношении установки высоты #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;

scrollerH - это offsetHeight, что примерно соответствует высоте того, что вы видите в окне.scroller.scrollHeight - высота, которая считается прокручиваемой.Когда содержание не превышает длину страницы, они примерно эквивалентны друг другу.Это означает, что нет прокрутки.Когда контента много, разница между этими двумя значениями - это количество прокрутки, которое вам нужно.

Еще есть небольшая ошибка, и похоже, что она уже есть.Когда у вас много контента, последние несколько элементов закрываются панелью при прокрутке вниз.Чтобы исправить это, вы можете установить смещение, например,

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

Произвольное число 75.Вероятно, будет лучше, если это будет высота самой полосы с 2 или 3 пикселями для небольшого отступа.Удачи!

Редактировать:

Я забыл упомянуть вчера вечером, но вот два примера страниц, которые я использовал при попытке отладить эту проблему.

Длинная страница
Короткая страница

1 голос
/ 24 августа 2011

Нет определенного решения, но я бы выбрал направление, в котором: Переполнение #wrapper и # content: скрыто в паре # позиция содержимого: исправлена ​​и, по-видимому, является причиной проблемы.

Если position: fixed удален из #content, прокрутка возможна, но «пустые» элементы div расположены неправильно (проверено в Firefox 5).

1 голос
/ 23 августа 2011

Это может быть проблема CSS.В таблице стилей (строка 22 mobile.css) попробуйте удалить position:fixed из #content.

. Это должно позволить документу нормально прокручиваться (вертикальная полоса прокрутки на компьютере, «скользящая» в мобильном браузере)..

Элементы с position:fixed выходят из нормального потока документа, их расположение относительно окна браузера.Вероятно, поэтому у вас проблемы с прокруткой.Фиксированное позиционирование обычно применяется к элементам, которые всегда должны оставаться в одном и том же месте, даже когда страница прокручивается (т. Е. Панель уведомлений «закреплена» вверху страницы).

1 голос
/ 23 августа 2011

Кажется, ваш div-обертка имеет высоту 0. Таким образом, все вычисления отрицательны, установка его высоты на высоту окна исправит проблему с прокруткой. Когда я вручную устанавливаю высоту оберток с помощью firebug и панели отладки chromes, прокрутка работает как надо.

Похоже, что у вашего #content div изменился размер при изменении размера, вероятно, лучше было бы, чтобы у #wrapper div было изменение размера, а затем #content наследовал размер.

[Изменить] Ты мне не веришь, кодез, Из 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 > 0 ?? Если maxScrollY отрицателен, то прокрутка вверх * никогда не вернется.

0 голосов
/ 31 августа 2011

Измененный вопрос требует нового ответа. Я взглянул на код и увидел, что вы вычислили импульс на каждом шаге функции «перемещение». Это не имеет смысла, потому что импульс используется после окончания движения. Это означало захват позиции мыши в начале, а затем вычисление разницы в конце. Поэтому я добавил две новые переменные,

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

Я также удалил расчет импульса из движения мыши / касания. Это позволило устранить поведение, которое я наблюдаю на своем iPhone. Я также вижу другие нежелательные поведения (все окно "прокручивается"), но я предполагаю, что вы работали над тем, чтобы избавиться от них, поэтому я не пытался.

Удачи. Вот кодированная страница 1013 *, которую я продублировал для тестирования. Я также взял на себя смелость реорганизовать код для этого раздела, чтобы удалить некоторый дублированный код. Это под mobile3.js, если вы хотите посмотреть.

0 голосов
/ 26 августа 2011

В итоге я просто создал свой собственный небольшой скрипт для обработки прокрутки:

// 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 дней.

...