Javascript scrollbar class and mousewheel speed in different browsers

久未见 提交于 2019-12-07 15:15:47

问题


I'm getting many reports that the mousewheel behaves differently in different browsers when using this scrollbar class. In some browsers (like Firefox) it's extremely slow while in others (mostly newer versions of Safari on Snow Leopard) it's perfect.

Any ideas what's going on here and how to fix it? I'm using the Mootools library. One line to pay attention to here is the wheel: (Browser.firefox) ? 20 : 1 line. This is where you set the speed or steps for the mousewheel.

Here it is set up in a jsFiddle: http://jsfiddle.net/brandondurham/6SUyM/

var ScrollBar = new Class({

    Implements: [Events, Options],

    options: {
        wheel: (Browser.firefox) ? 20 : 1
    },

    initialize: function(main, options) {

        this.setOptions(options);

        this.main = $(main);
        this.content = this.main.getFirst();

        this.vScrollbar = new Element('div', {
            'class': 'scrollbar'
        }).inject(this.content, 'after');

        this.vTrack = new Element('div', {
            'class': 'track'
        }).inject(this.vScrollbar);

        this.vThumb = new Element('div', {
            'class': 'handle'
        }).inject(this.vTrack);

        this.bound = {
            'vStart': this.vStart.bind(this),
            'end': this.end.bind(this),
            'vDrag': this.vDrag.bind(this),
            'vTouchDrag': this.vTouchDrag.bind(this),
            'wheel': this.wheel.bind(this),
            'vPage': this.vPage.bind(this),
        };

        this.vScrollbar.set('tween', {
            duration: 200,
            transition: 'cubic:out'
        });
        this.main.addEvent('mouseenter', function(event){
            this.vScrollbar.get('tween').cancel();
            this.vScrollbar.tween('width', 12);
        }.bind(this));
        this.main.addEvent('mouseleave', function(event){
            this.vScrollbar.get('tween').cancel();
            this.vScrollbar.tween('width', 0);
        }.bind(this));

        this.vPosition = {};
        this.vMouse = {};
        this.update();
        this.attach();

        this.scrollContent = new Fx.Scroll(this.content, {
            duration: 800,
            transition: Fx.Transitions.Cubic.easeOut,
        });
        this.scrollThumb = new Fx.Morph(this.vThumb, {
            duration: 400,
            transition: Fx.Transitions.Cubic.easeOut,
        });
    },

    update: function() {

        var panel_id = (this.content.getFirst()) ? this.content.getFirst().get('id') : '';

        if ((this.content.scrollHeight <= this.main.offsetHeight) || panel_id == 'random-doodle') this.main.addClass('noscroll');
        else this.main.removeClass('noscroll');

        this.vContentSize = this.content.offsetHeight;
        this.vContentScrollSize = this.content.scrollHeight;
        this.vTrackSize = this.vTrack.offsetHeight;

        this.vContentRatio = this.vContentSize / this.vContentScrollSize;

        this.vThumbSize = (this.vTrackSize * this.vContentRatio).limit(12, this.vTrackSize);

        this.vScrollRatio = this.vContentScrollSize / this.vTrackSize;

        this.vThumb.setStyle('height', this.vThumbSize);

        this.vUpdateThumbFromContentScroll();
        this.vUpdateContentFromThumbPosition();

    },

    vUpdateContentFromThumbPosition: function() {
        this.content.scrollTop = this.vPosition.now * this.vScrollRatio;
    },

    vUpdateContentFromThumbPosition2: function() {
        var pos = this.vPosition.now * this.vScrollRatio;
        this.scrollContent.start(0, pos);
    },

    vUpdateThumbFromContentScroll: function() {
        this.vPosition.now = (this.content.scrollTop / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));
        this.vThumb.setStyle('top', this.vPosition.now);
    },

    vUpdateThumbFromContentScroll2: function(pos) {
        this.vPosition.now = (this.content.scrollTopNew / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));           
        this.scrollThumb.start({
            'top': this.vPosition.now       
        });
    },

    attach: function() {
        if (this.options.wheel) this.content.addEvent('mousewheel', this.bound.wheel);
        this.content.addEvent('touchstart', this.bound.vStart);
        this.vThumb.addEvent('mousedown', this.bound.vStart);
        this.vTrack.addEvent('mouseup', this.bound.vPage);
    },

    wheel: function(event) {
        this.content.scrollTop -= event.wheel * this.options.wheel;
        this.vUpdateThumbFromContentScroll();
        event.stop();
    },

    scrollTo: function(pos){
        myInstance = this;
        this.content.scrollTopNew = pos;
        this.scrollContent.start(0, this.content.scrollTopNew);
        myInstance.vUpdateThumbFromContentScroll2(pos);
    },

    vPage: function(event) {
        // if scrolling up
        if (event.page.y > this.vThumb.getPosition().y) {
            myInstance = this;
            this.content.scrollTopNew = this.content.scrollTop.toInt() + this.content.offsetHeight.toInt();
            this.scrollContent.start(0, this.content.scrollTopNew);
        }
        // if scrolling down
        else {
            myInstance = this;    
            this.content.scrollTopNew = this.content.scrollTop.toInt() - this.content.offsetHeight.toInt();    
            this.scrollContent.start(0, this.content.scrollTopNew);       
        }
        myInstance.vUpdateThumbFromContentScroll2(event.page.y);
        event.stop();
    },

    vStart: function(event) {
        this.vMouse.start = event.page.y;
        this.vPosition.start = this.vThumb.getStyle('top').toInt();
        document.addEvent('touchmove', this.bound.vTouchDrag);
        document.addEvent('touchend', this.bound.end);
        document.addEvent('mousemove', this.bound.vDrag);
        document.addEvent('mouseup', this.bound.end);
        this.vThumb.addEvent('mouseup', this.bound.end);
        event.stop();
    },

    end: function(event) {
        document.removeEvent('touchmove', this.bound.vTouchDrag);
        document.removeEvent('mousemove', this.bound.vDrag);
        document.removeEvent('mouseup', this.bound.end);
        this.vThumb.removeEvent('mouseup', this.bound.end);
        event.stop();
    },

    vTouchDrag: function(event) {
        this.vMouse.now = event.page.y;
        this.vPosition.now = (this.vPosition.start - (this.vMouse.now - this.vMouse.start)).limit(0, (this.vTrackSize - this.vThumbSize));
        this.vUpdateContentFromThumbPosition();
        this.vUpdateThumbFromContentScroll();
        event.stop();
    },

    vDrag: function(event) {
        this.vMouse.now = event.page.y;
        this.vPosition.now = (this.vPosition.start + (this.vMouse.now - this.vMouse.start)).limit(0, (this.vTrackSize - this.vThumbSize));
        this.vUpdateContentFromThumbPosition();
        this.vUpdateThumbFromContentScroll();
        event.stop();
    }

});

回答1:


The mouse wheel event is very dodgy in javascript, main issue being usually Safari as they used to adjust the ratio on every point release, and even then the values reported by the event are not the same in all major browsers.

There has been some discussion about this on the MooTools tracker some time ago (link) and comparing different solutions I concluded that there's no standard way to normalize the event.
The last message on that issue shows a possible solution for normalizing (link), but it breaks wheel acceleration in Safari (and probably any other acceleration that other Browser/OS/Mouse Driver combination offers) so it is a tradeoff that you will have to evaluate if it fits to the requirements of your usage scenario.



来源:https://stackoverflow.com/questions/4338214/javascript-scrollbar-class-and-mousewheel-speed-in-different-browsers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!