Подтвердить что ты не робот

Можно ли определить, где свиток будет работать с помощью javascript? Если да, то как?

У меня есть ситуация, когда, например, если пользовательский прокрутка приведет к изменению в 1000 пикселей в scrollTop, я бы хотел знать заранее.

Прекрасным примером является контроль iCalendar над прокруткой пользователя. Независимо от того, насколько сильно вы прокручиваете приложение iCalendar, самый дальний из них можно прокручивать до следующего или предыдущего месяца.

В настоящее время у меня очень хакерское решение для ограничения поведения прокрутки, которое учитывает только то, где сейчас выполняется прокрутка пользователя.

MyConstructor.prototype._stopScroll = function(){

    //Cache the previous scroll position and set a flag that will control
    //whether or not we stop the scroll
    var previous = this._container.scrollTop;
    var flag     = true;

    //Add an event listener that stops the scroll if the flag is set to true
    this._container.addEventListener('scroll', function stop(){
        if(flag) {
            this._container.scrollTop = previous;
        }
    }.bind(this), false);

    //Return a function that has access to the stop function and can remove it
    //as an event listener
    return function(){
        setTimeout(function(){
            flag = false;
            this._container.removeEventListener('scroll', stop, false);
        }.bind(this), 0);
    }.bind(this);
};

Этот подход работает и останавливает прокрутку, но он не является гладким, и мне бы хотелось узнать, есть ли лучший способ выполнить это.

Ключом к этому вопросу я могу узнать раньше времени, где прокрутка закончится. Спасибо!!!

4b9b3361

Ответ 1

Изменить: просто нашел следующий проект в github:

https://github.com/jquery/jquery-mousewheel

Я попробовал демонстрацию и смог сообщить о скорости прокрутки сенсорной панели и мыши. Также он может остановить прокрутку без каких-либо фиксированных хаков: D

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

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


Невозможно предсказать, где закончится прокрутка мыши.

С другой стороны, сенсорный экран/сенсорная панель имеет определенную скорость, которая замедляется после того, как пользователь перестает прокручивать, например, автомобиль, который получил толчок и начинает замедляться впоследствии.

К сожалению, каждый браузер /os/driver/touchscreen/touchpad/etc имеет свою собственную реализацию для этой замедляющей части, поэтому мы не можем этого предсказать.


Но мы можем, конечно, написать нашу собственную реализацию.

Мы получили 3 реализации, которые можно было бы сделать:

а. Направление

В. Направление и скорость

С. Направление, скорость и скорость


iCalender, вероятно, использует реализацию A.


Реализация A:

Выводит направление прокрутки на консоль, пользователь может прокручивать +/- 1px до обнаружения направления.

Демо на JSFiddle

Демо с анимацией на JSFiddle

(function iDirection() {
    var preventLoop = true;
    var currentScroll = scrollTop();
    function scroll() {
        if(preventLoop) {
            //Get new scroll position
            var newScroll = scrollTop();

            //Stop scrolling
            preventLoop = false;
            freeze(newScroll);

            //Check direction
            if(newScroll > currentScroll) {
                console.log("scrolling down");
                //scroll down animation  here
            } else {
               console.log("scrolling up");
                //scroll up animation here
            }
            /*
            Time in milliseconds the scrolling is disabled,
            in most cases this is equal to the time the animation takes
            */
            setTimeout(function() {
                //Update scroll position
                currentScroll = newScroll;

                //Enable scrolling
                unfreeze();

                /*
                Wait 100ms before enabling the direction function again
                (to prevent a loop from occuring).
                */
                setTimeout(function() {
                    preventLoop = true;
                }, 100);
            }, 1000);
        }
    }
    $(window).on("scroll", scroll);
})();


Реализация B:

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

Если пользователь быстро прокручивает, они могут прокручивать еще несколько пикселей.

Демо на JSFiddle

(function iDirectionSpeed() {
    var distance = 50; //pixels to scroll to determine speed
    var preventLoop = true;
    var currentScroll = scrollTop();
    var currentDate = false;
    function scroll() {
        if(preventLoop) {
            //Set date on scroll
            if(!currentDate) {
                currentDate = new Date();
            }

            //Get new scroll position
            var newScroll = scrollTop();

            var scrolledDistance = Math.abs(currentScroll - newScroll);

            //User scrolled `distance` px or scrolled to the top/bottom
            if(scrolledDistance >= distance || !newScroll || newScroll == scrollHeight()) {
                //Stop scrolling
                preventLoop = false;
                freeze(newScroll);

                //Get new date
                var newDate = new Date();

                //Calculate time
                var time = newDate.getTime() - currentDate.getTime();

                //Output speed
                console.log("average speed: "+scrolledDistance+"px in "+time+"ms");

                /*
                To calculate the animation duration in ms:
                x: time
                y: scrolledDistance
                z: distance you're going to animate

                animation duration = z / y * x
                */

                //Check direction
                if(newScroll > currentScroll) {
                    console.log("scrolling down");
                    //scroll down animation  here
                } else {
                   console.log("scrolling up");
                    //scroll up animation here
                }

                /*
                Time in milliseconds the scrolling is disabled,
                in most cases this is equal to the time the animation takes
                */

                setTimeout(function() {
                    //Update scroll position
                    currentScroll = newScroll;

                    //Unset date
                    currentDate = false;

                    //Enable scrolling
                    unfreeze();

                    /*
                    Wait 100ms before enabling the direction function again
                    (to prevent a loop from occuring).
                    */
                    setTimeout(function() {
                        preventLoop = true;
                    }, 100);
                }, 1000);
            }
        }
    }
    $(window).on("scroll", scroll);
})();


Реализация C:

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

Если пользователь быстро прокручивает, они могут прокручивать еще несколько пикселей.

Демо на JSFiddle

(function iDirectionSpeedVelocity() {
    var distance = 100; //pixels to scroll to determine speed
    var preventLoop = true;
    var currentScroll = [];
    var currentDate = [];
    function scroll() {
        if(preventLoop) {
            //Set date on scroll
            currentDate.push(new Date());

            //Set scrollTop on scroll
            currentScroll.push(scrollTop());

            var lastDate = currentDate[currentDate.length - 1];
            var lastScroll = currentScroll[currentScroll.length - 1];

            //User scrolled `distance` px or scrolled to the top/bottom
            if(Math.abs(currentScroll[0] - lastScroll) >= distance || !lastScroll || lastScroll == scrollHeight()) {
                //Stop scrolling
                preventLoop = false;
                freeze(currentScroll[currentScroll.length - 1]);

                //Total time
                console.log("Time: "+(lastDate.getTime() - currentDate[0].getTime())+"ms");

                //Total distance
                console.log("Distance: "+Math.abs(lastScroll - currentScroll[0])+"px");

                /*
                Calculate speeds between every registered scroll
                (speed is described in milliseconds per pixel)
                */
                var speeds = [];
                for(var x = 0; x < currentScroll.length - 1; x++) {
                    var time = currentDate[x + 1].getTime() - currentDate[x].getTime();
                    var offset = Math.abs(currentScroll[x - 1] - currentScroll[x]);
                    if(offset) {
                        var speed = time / offset;
                        speeds.push(speed);
                    }
                }

                //Output array of registered speeds (milliseconds per pixel)
                console.log("speeds (milliseconds per pixel):");
                console.log(speeds);

                /*
                We can use the array of speeds to check if the speed is increasing
                or decreasing between the first and last half as example
                */ 
                var half = Math.round(speeds.length / 2);
                var equal = half == speeds.length ? 0 : 1;
                var firstHalfSpeed = 0;
                for(var x = 0; x < half; x++ ) {
                    firstHalfSpeed += speeds[x];
                }
                firstHalfSpeed /= half;
                var secondHalfSpeed = 0;
                for(var x = half - equal; x < speeds.length; x++ ) {
                    secondHalfSpeed += speeds[x];
                }
                secondHalfSpeed /= half;
                console.log("average first half speed: "+firstHalfSpeed+"ms per px");
                console.log("average second half speed: "+secondHalfSpeed+"ms per px");
                if(firstHalfSpeed < secondHalfSpeed) {
                    console.log("conclusion: speed is decreasing");
                } else {
                    console.log("conclusion: speed is increasing");
                }

                //Check direction
                if(lastScroll > currentScroll[0]) {
                    console.log("scrolling down");
                    //scroll down animation  here
                } else {
                   console.log("scrolling up");
                    //scroll up animation here
                }

                /*
                Time in milliseconds the scrolling is disabled,
                in most cases this is equal to the time the animation takes
                */
                setTimeout(function() {
                    //Unset scroll positions
                    currentScroll = [];

                    //Unset dates
                    currentDate = [];

                    //Enable scrolling
                    unfreeze();

                    /*
                    Wait 100ms before enabling the direction function again
                    (to prevent a loop from occuring).
                    */
                    setTimeout(function() {
                        preventLoop = true;
                    }, 100);
                }, 2000);
            }
        }
    }
    $(window).on("scroll", scroll);
})();


Вспомогательные функции, используемые в следующих реализациях:

//Source: https://github.com/seahorsepip/jPopup
function freeze(top) {
    if(window.innerWidth > document.documentElement.clientWidth) {
        $("html").css("overflow-y", "scroll");
    }
    $("html").css({"width": "100%", "height": "100%", "position": "fixed", "top": -top});
}
function unfreeze() {
    $("html").css("position", "static");
    $("html, body").scrollTop(-parseInt($("html").css("top")));
    $("html").css({"position": "", "width": "", "height": "", "top": "", "overflow-y": ""});
}
function scrollTop() {
    return $("html").scrollTop() ? $("html").scrollTop() : $("body").scrollTop();
}
function scrollHeight() {
    return $("html")[0].scrollHeight ? $("html")[0].scrollHeight : $("body")[0].scrollHeight;
}

Просто посмотрел на scrollify, упомянутый в комментариях, он 10kb и должен зацепиться за каждое простое событие: сенсорный, прокрутка мыши, кнопки клавиатуры и т.д.

Это не похоже на будущее доказательство, кто знает, какое возможное взаимодействие пользователя может вызвать прокрутку в будущем?

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

Ответ 2

Как указывает @seahorsepip, обычно не известно, где будет прокручиваться без добавления пользовательского поведения с JavaScript. Документы MDN не перечисляют способ доступа к событиям с прокруткой в ​​очереди: https://developer.mozilla.org/en-US/docs/Web/Events/scroll

Я нашел эту информацию полезной: Нормализация скорости колесика мыши в браузерах

В нем подчеркивается трудность знать, куда будет идти страница, на основе ввода пользователем. Мое предложение состоит в том, чтобы вызвать свиток к событию Y, когда код предсказывает пороговое значение. В вашем примере, если прокрутка переместила страницу 800 из 1000 пикселей во временное окно 250 мс, затем установите прокрутку до отметки в 1000 пикселей и отключите прокрутку в течение 500 мс.

https://developer.mozilla.org/en-US/docs/Web/API/window/scrollTo

Ответ 3

Я не уверен, что у меня есть то, что вы ищете. У меня был проект один раз, где мне пришлось управлять прокруткой. Тогда я перезаписал событие прокрутки по умолчанию, после чего вы можете установить собственное расстояние для "одного" прокрутки. Дополнительно добавлена ​​анимация jQuery для перехода к определенной позиции. Здесь вы можете посмотреть: http://c-k.co/zw1/ Если это то, что вы ищете, вы можете связаться со мной, и я увижу, насколько я все еще понимаю свою собственную вещь.