Document.ontouchmove и прокрутка на iOS 5

iOS 5 принес много приятных вещей в JavaScript/Web Apps. Одна из них - улучшенная прокрутка. Если вы добавите

-webkit-overflow-scroll:touch;

в стиле элемента textarea, прокрутка будет работать с одним пальцем.

Но есть проблема. Чтобы предотвратить прокрутку всего экрана, рекомендуется, чтобы веб-приложения добавили эту строку кода:

document.ontouchmove = function(e) {e.preventDefault()};

Это, однако, отключает новую прокрутку.

Есть ли у кого-нибудь хороший способ разрешить новую прокрутку в текстовом поле, но не разрешить прокрутку всей формы?

Ответ 1

Обновление Согласно комментарию Alvaro, это решение может больше не работать с iOS 11.3.

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

document.ontouchmove = function(e) {
    var target = e.currentTarget;
    while(target) {
        if(checkIfElementShouldScroll(target))
            return;
        target = target.parentNode;
    }

    e.preventDefault();
};

В качестве альтернативы это может сработать, если событие не достигнет уровня документа.

elementYouWantToScroll.ontouchmove = function(e) {
    e.stopPropagation();
};

Редактировать Для тех, кто читает позже, альтернативный ответ работает и намного проще.

Ответ 2

Единственная проблема с ответом Брайана Никеля заключается в том, что (как указано пользователем1012566) stopPropagation не мешает пузыриться, когда вы нажимаете свои прокручиваемые границы. Вы можете предотвратить это со следующим:

elem.addEventListener('touchstart', function(event){
    this.allowUp = (this.scrollTop > 0);
    this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
    this.prevTop = null; 
    this.prevBot = null;
    this.lastY = event.pageY;
});

elem.addEventListener('touchmove', function(event){
    var up = (event.pageY > this.lastY), 
        down = !up;

    this.lastY = event.pageY;

    if ((up && this.allowUp) || (down && this.allowDown)) 
        event.stopPropagation();
    else 
        event.preventDefault();
});

Ответ 3

Для тех, кто пытается добиться этого с помощью PhoneGap, вы можете отключить прокрутку в режиме cordova.plist, установите для параметра UIWebViewBounce значение NO значение UIWebViewBounce. Надеюсь, что это поможет любому, кто потратил на это время (как и я).

Ответ 4

ScrollFix кажется идеальным решением. Я тестировал его, и он работает как шарм!

https://github.com/joelambert/ScrollFix

/**
 * ScrollFix v0.1
 * http://www.joelambert.co.uk
 *
 * Copyright 2011, Joe Lambert.
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */

var ScrollFix = function(elem) {
    // Variables to track inputs
    var startY, startTopScroll;

    elem = elem || document.querySelector(elem);

    // If there is no element, then do nothing  
    if(!elem)
        return;

    // Handle the start of interactions
    elem.addEventListener('touchstart', function(event){
        startY = event.touches[0].pageY;
        startTopScroll = elem.scrollTop;

        if(startTopScroll <= 0)
            elem.scrollTop = 1;

        if(startTopScroll + elem.offsetHeight >= elem.scrollHeight)
            elem.scrollTop = elem.scrollHeight - elem.offsetHeight - 1;
    }, false);
};

Ответ 5

Было неприятно обнаружить известную проблему с stopPropagation и прокруткой родной div. Кажется, что это не мешает потоку onTouchMove, так что при прокрутке за пределы div (вверху вверху или внизу внизу) вся страница будет отскакивать.

Подробнее обсуждение здесь и здесь.