问题描述:

I have written a plugin for my personal homepage, which is supposed to scroll through a series of elements, snapping to each elements offsetTop.

I am using requestanimationframe to debounce the scrolling events but sometimes slides are being skipped and I just can't figure why. Additionally on Chrome and Safari I have the problem that window.pageYOffset can be smaller than 0 and bigger than document hight because of some kind of easing those browsers are using on mac (with the touchpad) – how would you handle that?

Here is the Code:

// requerstanimationframe for all browsers

window.rAF = (function(){

return window.requestAnimationFrame ||

window.webkitRequestAnimationFrame ||

window.mozRequestAnimationFrame ||

window.oRequestAnimationFrame ||

window.msRequestAnimationFrame ||

function( callback ){

window.setTimeout(callback, 1000 / 60);

};

})();

// main plugin code

var Slides = {

el: ".slide",

arrowUp: $(".btn-previous"),

arrowDown: $(".btn-next"),

lastSlide: 0,

lastY: 0,

scrolling: false,

scrollSpeed: 500,

init: function(){

this.$elem = $(this.el);

this.catchSlides();

this.newPos(true);

// event handler

this.registerHandler();

return this;

},

registerHandler: function(){

var that = this,

handler = {

"resize.slider": jQuery.proxy(this.onResize,this),

"scroll.slider": jQuery.proxy(this.onScroll,this),

"keydown.slider": jQuery.proxy(this.keyhandler,this),

"mousedown.slider": function(){ that.scrolling = true; },

"mouseup.slider": function(){ that.scrolling = false; }

};

$(window).on(handler);

$(".btn").on("click.slider", jQuery.proxy(this.btnhandler,this))

},

catchSlides: function(){

// count slides and save selectors

var array = [];

for(var i=0; i<this.$elem.length; i++){

var el = this.$elem.eq(i);

array[i] = el;

}

this.elements = array;

this.slideCount = this.elements.length;

},

getPositions: function(){

// what are the postions of those slides?

var array = [];

for(var i=0; i<this.slideCount; i++){

var el = this.elements[i];

array[i] = el[0].offsetTop;

}

this.posArray = array;

},

arrows: function(){

if(this.slideCount>1){

switch(this.lastSlide) {

case 0: // erster slide

if(this.arrowUp.is(":visible")) this.arrowUp.hide();

if(!this.arrowDown.is(":visible")) this.arrowDown.show();

break;

case this.slideCount-1: // letzter slide

if(this.arrowDown.is(":visible")) this.arrowDown.hide();

if(!this.arrowUp.is(":visible")) this.arrowUp.show();

break;

default:

this.arrowUp.show();

this.arrowDown.show();

}

}

else {

this.arrowUp.hide();

this.arrowDown.hide();

}

},

getY: function(){

return window.pageYOffset;

},

newPos: function(jump){

// go to the new coordinate, hide one of those arrows

// if first or last slide

this.arrows();

this.getPositions();

this.jumpTo(jump);

},

clear: function(){

this.lastY = this.getY();

this.scrolling = false;

},

onResize: function(){

if(!this.scrolling){

rAF(jQuery.proxy(this.newPos,this));

}

this.scrolling = true;

},

onScroll: function(){

if(!this.scrolling){

rAF(jQuery.proxy(this.update,this));

}

this.scrolling = true;

},

update: function(){

// which direction did the user scroll?

if(this.lastY<this.getY()){ // down?

this.slide("down");

}

else if(this.lastY>this.getY()){ // or up?

this.slide("up");

}

else this.clear();

},

slide: function(string){

if(string==="down" && this.lastSlide<this.slideCount-1){

this.lastSlide++;

this.newPos();

}

else if(string==="up" && this.lastSlide>0){

this.lastSlide--;

this.newPos();

}

else this.clear();

},

jumpTo: function(jump, slideIndex){

var that = this,

slideIndex = slideIndex || this.lastSlide,

destination = this.posArray[slideIndex];

this.scrolling = true;

if(jump && jump!==undefined){

// jump to position without animation

$("html,body").stop().animate({scrollTop: destination}, 0, function(){ that.clear(); });

}

else $("html,body").stop().animate({scrollTop: destination}, this.scrollSpeed, function(){ that.clear(); });

},

keyhandler: function(e){

switch(e.which) {

case 38:

e.preventDefault();

this.slide("up");// up

break;

case 40:

e.preventDefault();

this.slide("down");// down

break;

default: return;

}

},

btnhandler: function(e){

// register arrow-buttons from ui

var $next = $(".btn-next"),

$prev = $(".btn-previous");

e.preventDefault();

if(e.target===$next || $.contains($next[0], e.target)) this.slide("down");

else if(e.target===$prev || $.contains($prev[0], e.target)) this.slide("up");

}

};

Slides.init();

Hope someone can help. Thanks.

相关阅读:
Top