Проверить scrollTop на сенсорном устройстве

У меня есть следующая функция, которая проверяет положение прокрутки пользователя так, чтобы меню фиксировалось после прокрутки мимо мачты

function checkScrolling() {
    if( $(window).scrollTop() > $('.masthead').height() ) { // we check against ACTUAL height
        $('.menu').addClass('fixed');
    }else {
        $('.menu').removeClass('fixed');
    }
}

и здесь прослушиватели событий на рабочем столе и сенсорном экране:

$(document).bind('touchstart touchend touchcancel touchleave touchmove', function(e){
    checkScrolling();
});

$(window).scroll(function(){
    checkScrolling();
});

Однако события касания только делают меню фиксированным во время сенсорной навигации надежно. Если я прокручиваю очень быстро, прокручивая вверх или вниз, происходит задержка до того, как меню станет фиксированным или незафиксированным.

Любые идеи о том, как это исправить? См. пример кода здесь: http://dev.driz.co.uk/mobileMasthead.html (был изменен на основе некоторых ответов ниже, но все еще не работает правильно на iPad или iPhone)

Обновление: И чтение по теме показывает, что JS, как проверка положения прокрутки, не происходит во время прокрутки... НО... Я заметил, что http://www.facebook.com/home/ не имеет этой проблемы при тестировании на моем iPad. Таким образом, это определенно возможно для достижения этого эффекта без использования каких-либо пользовательских полос прокрутки JavaScript, таких как iScroll или аналогичных.

Ответы

Ответ 1

Возможно, я понимаю, что вопрос неправильный, но чтобы обеспечить функциональность с высокой скоростью прокрутки, почему бы вам не заняться чистым стилем CSS (иначе он притворяется "причудливым" эффектом):

Старая школа (быстрая, но примитивная)

HTML

<div id="menu2"></div>
    <div class="scroll" id="scroller">
        <div id="overlay"></div>
        <div id="menu"></div>
    </div>

С помощью простого CSS:

html, body { overflow: hidden; height: 100% }
body { margin:0; padding:0; }

 .scroll {
     -webkit-overflow-scrolling: touch;
     height:960px;
     width:640px;
 }

 #menu2 {
     width:640px;
     height:20px;
     background:red;
     position:absolute;
     z-index:-1;
 }

 #menu {
     width:100%;
     height:20px;
     background:red;
     z-index:0;
 }

Вы можете увидеть рабочий пример ЗДЕСЬ.

Это может быть немного примитивно: но эй! Оно работает!:)

Новая школа (фантазия, но медленная)

Проверьте все остальные ответы.

Но обратите внимание, что "известно", что использование JavaScript в сочетании с прокруткой на мобильных устройствах вызывает много проблем в скорости.

Вот почему я думаю, что простой подход CSS может быть лучше.

Если вы хотите узнать о JavaScript и прокрутке на мобильных устройствах (и других функциях), то есть две статьи, которые я настоятельно рекомендую читать:

Ответ 2

Facebook не использует JavaScript, но чистый css:

position: -webkit-sticky;

Если я правильно его помню, это заставляет элемент придерживаться в верхней части родительского контейнера при прокрутке.

Ответ 3

Вам просто нужно было прикрепить свои события прокрутки, а не к окну, документу или телу, но к пользовательскому контейнеру.

В iOS вы не можете программно реагировать во время этих прокрутки окна с аппаратным ускорением.

Здесь скрипка: обертка:

<div id="content">

некоторые не очень релевантные css:

html,body,#content {
    width:100%;
    height:100%;
}
#content {
    background-color: lightblue;
    overflow:scroll;
}

прикрепление слушателей к контейнеру:

function checkScrolling() {
    if ($('#content').scrollTop() > mastheadHeight) {
        menu.addClass('fixed');
    } else {
        menu.removeClass('fixed');
    }
}

$('#content').scroll(function () {
    checkScrolling();
});

Вы можете увидеть, как он работает здесь для резервного копирования только JS:

http://jsfiddle.net/jaibuu/YqPzS/

прямой URL: http://fiddle.jshell.net/jaibuu/YqPzS/show/

Ответ 4

Однажды я попытался реализовать липкие заголовки на мобильной версии сайта, но столкнулся с целым набором проблем.

Во-первых, самое главное, что событие scroll не срабатывает на мобильных устройствах так часто, как на рабочем столе. Обычно он срабатывает при остановке страницы. Я не знаю точной причины этого, но могу предложить, потому что браузеры на мобильных устройствах "отправляют" такие задачи на GPU, в то время как ЦП не может обновлять объекты JS до того, что происходит с холстом (но это только мое предложение). Более новая версия iOSs делает ее лучше для нас, и, возможно, scroll будет работать на iPhone.

Вы должны использовать события touch. Это заставляет вас написать отдельную версию кода для устройств, поддерживающих сенсорный ввод. Поэтому нужно искать надежные способы тестирования для платформы.

Но события touch также сложны, особенно на Android. Я думал, что в обратном вызове для события touchmove я смогу вычислить текущие координаты и пойти дальше от этой точки.

Но вот этот вопрос https://code.google.com/p/android/issues/detail?id=5491 на Android, в итоге touchmove срабатывает один или два раза в самом начале действия касания и не срабатывает снова. Это делает его совершенно бесполезным. Люди предлагают preventDefault(), но вы больше не можете прокручивать с этим.

Итак, у меня появилась идея переопределить прокрутку с нуля с помощью CSS-преобразований. И вот мои результаты до сих пор:

http://jsbin.com/elaker/23

Откройте эту ссылку на своем устройстве и http://jsbin.com/elaker/23/edit на своем рабочем столе: вы сможете редактировать код и обновлять его на вы устройство, очень удобно.

Примечание: Я хотел бы предупредить вас о том, что эта прокрутка CSS является необработанной, и есть некоторые известные проблемы, которые еще не решены: например, вы иногда можете прокручивать верхнюю или нижнюю границу, или если вы просто касаетесь (не двигаетесь), она все равно будет прокручиваться. Также пресловутая строка URL-адресов не будет скрываться. Итак, есть работа.

Ответ 5

Вам нужны события касания, чтобы это вообще упустить? Современные устройства должны возвращать события $(window).scroll() и значения scrollTop. На старых Android и пре-ios5 (я думаю), position:fixed: работал не так, как ожидалось, из-за работы видового экрана. Но он был исправлен во всех новых выпусках.

Для дальнейшего отладки устройств я настоятельно рекомендую Adobe Edge Inspect. Вы можете console.log scrollTop и посмотреть, действительно ли устройства, о которых вы заботитесь, действительно работают с любыми обманами. Вы получите все, что вам нужно, с их бесплатной версией.

Ответ 6

Отличный способ справиться с событиями прокрутки - не прикреплять ваши чеки к событию прокрутки занимает много ресурсов и не очень хорошо работает со старыми браузерами. к счастью, у вас может быть намного больше контроля, если вы просто выполняете цикл времени для этого. это выглядит так: (Используется твиттером)

var MyMenu = $('#menu'),
    didScroll = false;

$(window).scroll(function() {
    didScroll = true;
});

setInterval(function() {
    if ( didScroll ) {
        didScroll = false;
        //Do your check here
        checkScrolling();
    }
}, 180);

Вы должны поместить свой $('. masthead'). height() вне этой функции checkScrolling вашего (в более высокой области), так как этот вид операций требует много ресурсов и всегда запрашивает jquery для "выбора вашего элемента", и вычислить его размер, в конечном итоге сделает ваше приложение лагги:

  var headerHeight = $('.masthead').height()
  function checkScrolling()
  .....

Последнее, вы можете изменить значение атрибута interval (прямо сейчас он 180 (бит больше, чем 60hz - время обновления экрана), вы можете сделать это значение больше, если вы хотите, чтобы ваше приложение было более эффективным но немного менее точный)

Спасибо, Джон Ресиг и твиттер: http://ejohn.org/blog/learning-from-twitter/

Надеюсь, что это помогло Ajios!

Ответ 7

setScrollTop: function(inTop) {
    var top = Math.max(0,inTop);

    if (wm.isMobile) { // should always be true for touch events 
        top = Math.min(top, this.listNode.clientHeight - this.listNodeWrapper.clientHeight);

        if (dojo.isWebKit) {
            this.listNode.style.WebkitTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isMoz) {
            this.listNode.style.MozTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isOpera) {
            this.listNode.style.OTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isIE) {
            this.listNode.style.MsTransform = "translate(0,-" + top + "px)";
        }
        this.listNode.style.transform = "translate(0,-" + top + "px)";
        this._scrollTop = top;
        this._onScroll();
    } else {
        this.listNode.scrollTop = top + "px";
    }
},

Ответ 8

Я только что проверил ваши функции на эффективность. Вы должны попробовать это

function checkScrolling() {         
    if( $(window).scrollTop() > mastheadHeight )menu.css('position','fixed');
    else menu.css('position','');
}

Это уменьшит вызов функции addClass и RemoveClass, и ваше время выполнения вступит в силу. Если вы хотите сократить время выполнения, то лучше использовать чистый JavaScript

Ответ 9

$(document).ready(function(){
     var p = $("#stop").offset().top;

    $(window).scroll(function(){
        if(p<$(window).scrollTop()){
            console.log("div reached");
            $("#stop").css({position:"fixed",top:0});
        }
        else{
            console.log("div out");
            $("#stop").css({position:"static"});
        }

    })
});

Я думаю, это поможет вам.

Полный код здесь в jsfiddle.net.

Я тестировал его для ipad, используя сафари онлайн-симулятора ipad2 в http://alexw.me/ipad2/, и он там работал, Итак, я думаю, что он будет работать и на реальном ipad.