【问题标题】:Javascript scrollbar class and mousewheel speed in different browsers不同浏览器中的Javascript滚动条类和鼠标滚轮速度
【发布时间】:2010-12-02 18:00:36
【问题描述】:

我收到很多报告,当使用此滚动条类时,鼠标滚轮在不同浏览器中的行为不同。在某些浏览器(如 Firefox)中速度极慢,而在其他浏览器(主要是 Snow Leopard 上较新版本的 Safari)中则非常完美。

任何想法这里发生了什么以及如何解决它?我正在使用 Mootools 库。这里要注意的一行是wheel: (Browser.firefox) ? 20 : 1 行。您可以在此处设置鼠标滚轮的速度或步数。

这里是在一个 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();
    }

});

【问题讨论】:

  • 发布一个 www.jsfiddle.net 示例,您如何使用它,它并不十分明显 - 或指向另一个演示的链接。
  • hrm event.wheel 在我向下滚动时总是返回为 -1 - 在 ie8、ff 3.6.13 和 chrome 7 中 - 由于 this.options.wheel 为 20,只有 firefox 似乎还可以。任何特殊原因为什么不对所有浏览器使用 20 步?此外,您可能希望通过this.dragging = true; 跟踪拖动并在mouseleave 函数中检查它是否会在您鼠标移出时隐藏滚动条——您不应在拖动时将其消失。更改 end 以将 this.dragging 再次设置为 false 并检查是否已被鼠标移出,以便在离开容器时将其隐藏。
  • 如果我对所有浏览器都使用 20,它在 Safari 中真的很快。我将该行更改为“wheel: (Browser.safari5) ? 1 : 20”,因为我认为 Safari 5 真的很奇怪。
  • 另外,您应该将您的建议作为答案发布,以便我接受。 :) 虽然我有你,但你能看到一种可靠的方法来设置句柄的静态高度而不是动态高度,而不会弄乱滚动功能背后的数学吗?我需要将手柄设置为始终为 200px 高。
  • 拖拽检查中添加:jsfiddle.net/brandondurham/6SUyM/2

标签: javascript scroll mootools mousewheel


【解决方案1】:

鼠标滚轮事件在 javascript 中非常狡猾,主要问题通常是 Safari,因为他们习惯于在每个点发布时调整比率,即使如此,事件报告的值在所有主要浏览器中也不相同。

前段时间在 MooTools 跟踪器 (link) 上对此进行了一些讨论,并比较了不同的解决方案,我得出的结论是没有标准的方法来规范化事件。
关于该问题的最后一条消息显示了一种可能的标准化解决方案 (link),但它破坏了 Safari 中的滚轮加速(可能还有其他浏览器/操作系统/鼠标驱动程序组合提供的任何其他加速),因此您需要权衡一下必须评估它是否符合您的使用场景的要求。

【讨论】:

    猜你喜欢
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多