Улучшение алгоритма колесика мыши для слайдера - PullRequest
2 голосов
/ 06 июля 2019

Введение

У меня есть страница с полноэкранными блоками fixed, и я хотел бы перемещаться по этим блокам, используя событие javascript wheel.

Если это не такне имеет смысла;Проще говоря, у меня есть специальная карусель, по которой я хотел бы перемещаться с помощью колесика мыши по одному блоку за раз, т.е. один прокрутка / клик перемещается к предыдущему / следующему элементу.

Мой текущийрешение работает, но для его улучшения требуется небольшая настройка.

Проблема

Проблема, с которой я столкнулся, состоит в том, что 1 прокрутка / нажатие на колесе мыши иногда прокручивает один блок, ииногда прокручивает 2 блока.

Я использую следующий алгоритм:

  • Для каждого события wheel, увеличение / уменьшение значения глобальной переменной deltaY на 1 (мое колесо мыши имеет тенденцию вызывать около 35-40 событий каждый раз, когда колесо прокручивается в режиме щелчка, не уверен, является ли это стандартным)
  • При каждом изменении значения deltaY определить, какой блок (по индексу)должно быть active.Я делаю это со следующим;Math.floor(deltaY / 35), где 35 - количество wheel событий, запущенных одним движением моего колеса мыши (очень неуверенно в этом, поскольку это может отличаться для других мышей)
  • Обновление индекса active и обновлениеdeltaY с целым числом, кратным 35

Код

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

Vanilla JS

Я не тестировал этот код, я просто смоделировал его на основе своего кода Vue.js дляте из вас, кто не знаком с Vue.

// Set the default values
let items  = ['x', 'y', 'z'];
let active = 0;
let deltaY = 0;

/**
 * Update the delta value and any other relevant
 * values.
 *
 * @param {event} event
 * @return void
 */
function updateDelta (value) {

    active = Math.floor(value / 35);
    deltaY = active * 35;

}

// Register the `wheel` event
window.addEventListener('wheel', (event) => {

    // The navigation is only active when the page has not
    // been scrolled
    if (document.documentElement.scrollTop === 0) {

        // If the last item is currently active then we do not need to
        // listen to `down` scrolls, or, if the first item is active, 
        // then we do not need to listen to `up` scrolls
        if (
            (event.deltaY > 0 && (active - 1) === items.length)
            || (event.deltaY < 0 && deltaY === 0)
        ) {
            return;
        }

        updateDelta(Math.sign(event.deltaY));

    }

}, { passive: true });

Мой код (Vue JS)

Я добавил четкие комментарии, чтобы проиллюстрировать, что делает Vue

export default {

    data() {
        return {
            items: ['x', 'y', 'z'],
            active: 0, // Define the active index
            deltaY: 0 // This is used for the scroll wheel navigation
        }
    },

    created() {

        // Register the `wheel` event
        window.addEventListener('wheel', this._handleWheel, { passive: true });

    },

    destroyed() {

        // Remove the `wheel` event
        window.removeEventListener('wheel', this._handleWheel, { passive: true });

    },

    watch: {

        // I have added watchers to both `deltaY` and `active`, however,
        // this may not be necessary. These will not create an endless loop
        // because the watcher is only called when a value is changed

        active: function(index) {

            // Whenever the `active` index changes, update the `deltaY` value
            this.deltaY = index * 35;

        },

        deltaY: function(value) {

            // Whenever the `deltaY` value changes, update the `active` index
            this.active = Math.floor(value / 35);

        }

    },

    methods: {

        /**
         * Handle the window wheel event.
         *
         * @param {event} event
         * @return void
         */
        _handleWheel (event) {

            // The navigation is only active when the page has not
            // been scrolled
            if (document.documentElement.scrollTop === 0) {

                // If the last item is currently active then we do not need to
                // listen to `down` scrolls, or, if the first item is active, 
                // then we do not need to listen to `up` scrolls
                if (
                    (event.deltaY > 0 && (this.active - 1) === this.items.length)
                    || (event.deltaY < 0 && this.deltaY === 0)
                ) {
                    return;
                }

                this.deltaY += Math.sign(event.deltaY);
            }

        }

    }

}

1 Ответ

0 голосов
/ 06 июля 2019

Как вы уже указали, количество раз, когда срабатывает событие wheel, может варьироваться от мыши к мыши и время от времени.Таким образом, полагаясь на количество событий как способ определить, когда сдвигать блок, всегда будет непредсказуемо.

Вместо этого я предлагаю попробовать альтернативный подход.Например, вы можете попытаться определить, когда пользователь прекращает прокрутку, и просто увеличить индекс на 1. Быстрый поиск в Google вернул эту вспомогательную функцию , которая именно это и делает.

...