改进滑条的鼠标滚轮算法导航

时间:2019-07-06 18:44:34

标签: javascript vue.js math mousewheel

简介

我的页面上有全屏fixed块,我想使用JavaScript wheel事件浏览这些块。

如果那没有道理;简而言之,我有一个自定义轮播,我想一次使用鼠标滚轮浏览一个块,即一次滚动滚动/单击移动到上一个/下一个项目。

我当前的解决方案有效,但需要进行一些调整以使其更好地工作。

问题

我遇到的问题是,在鼠标滚轮上滚动1次/单击有时会滚动一个块,有时会滚动2个块。

我正在使用的算法如下:

  • 对于每个触发的wheel事件,将全局变量deltaY的值增加/减少1(在点击模式下,每次滚动鼠标滚轮,鼠标滚轮都会触发35-40个事件,不确定这是否标准)
  • 只要deltaY值发生变化,就应确定哪个块(按索引)应为active。我用以下方法做到这一点; Math.floor(deltaY / 35),其中35是我的鼠标滚轮引发的wheel个事件的数量(对此不太确定,因为其他鼠标可能会有所不同)
  • 更新active索引,并用deltaY可除的整数更新35

代码

我正在使用Vue.js,但是不用担心,如果您不熟悉它,我真正需要的只是算法,可以将其实现到我的代码中。

香草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 :(得分:0)

正如您已经指出的那样,wheel事件触发的次数可能会因鼠标的不同而有所不同。因此,依靠事件的数量来确定何时移动块始终是不可预测的。

相反,我建议尝试一种替代方法。例如,您可以尝试检测用户何时停止滚动,仅将索引增加1。快速的Google搜索返回了this helper function,就可以了。