Ich habe mich kürzlich vorgenommen, dieses Problem in einer Situation zu lösen, in der jQuery keine Option war. Deshalb protokolliere ich meine Lösung hier nur für die Nachwelt.
var scroll = (function() {
var elementPosition = function(a) {
return function() {
return a.getBoundingClientRect().top;
};
};
var scrolling = function( elementID ) {
var el = document.getElementById( elementID ),
elPos = elementPosition( el ),
duration = 400,
increment = Math.round( Math.abs( elPos() )/40 ),
time = Math.round( duration/increment ),
prev = 0,
E;
function scroller() {
E = elPos();
if (E === prev) {
return;
} else {
prev = E;
}
increment = (E > -20 && E < 20) ? ((E > - 5 && E < 5) ? 1 : 5) : increment;
if (E > 1 || E < -1) {
if (E < 0) {
window.scrollBy( 0,-increment );
} else {
window.scrollBy( 0,increment );
}
setTimeout(scroller, time);
} else {
el.scrollTo( 0,0 );
}
}
scroller();
};
return {
To: scrolling
}
})();
scroll.To('elementID');
Die scroll()Funktion verwendet das Revealing Module Pattern , um die ID des Zielelements an seine scrolling()Funktion zu übergeben, über scroll.To('id')die die von der scroller()Funktion verwendeten Werte festgelegt werden .
Nervenzusammenbruch
In scrolling():
el : das Ziel-DOM-Objekt
elPos: gibt eine Funktion zurück, über elememtPosition()die bei jedem Aufruf die Position des Zielelements relativ zum oberen Rand der Seite angegeben wird.
duration : Übergangszeit in Millisekunden.
increment : unterteilt die Startposition des Zielelements in 40 Schritte.
time : Legt das Timing für jeden Schritt fest.
prev: die vorherige Position des Zielelements in scroller().
E: hält die Position des Zielelements in scroller().
Die eigentliche Arbeit erledigt die scroller()Funktion, die sich weiterhin (via setTimeout()) aufruft, bis sich das Zielelement oben auf der Seite befindet oder die Seite nicht mehr scrollen kann.
Bei jedem scroller()Aufruf wird die aktuelle Position des Zielelements (in Variable gehalten E) überprüft. Wenn dies > 1OR ist < -1und die Seite noch scrollbar ist, wird das Fenster um incrementPixel verschoben - nach oben oder unten, je nachdem, ob Ees sich um einen positiven oder einen negativen Wert handelt. Wenn Eweder > 1ODER < -1noch E=== ist , stoppt prevdie Funktion. Ich habe die DOMElement.scrollTo()Methode nach Abschluss hinzugefügt , um sicherzustellen, dass das Zielelement oben im Fenster angezeigt wird (nicht, dass Sie bemerken würden, dass es um einen Bruchteil eines Pixels entfernt ist!).
Die ifAnweisung in Zeile 2 von scroller()prüft, ob die Seite gescrollt wird (in Fällen, in denen sich das Ziel möglicherweise am unteren Rand der Seite befindet und die Seite nicht weiter scrollen kann), indem sie mit Eihrer vorherigen Position verglichen wird ( prev).
Die darunter liegende ternäre Bedingung verringert den incrementWert, wenn er Esich Null nähert. Dies verhindert, dass die Seite in eine Richtung überschießt und dann zurückspringt, um die andere zu überschießen, und dann zurückspringt, um die andere wieder zu überschießen, im Ping-Pong-Stil, bis ins Unendliche und darüber hinaus.
Wenn Ihre Seite mehr als ca. 4000 Pixel hoch ist, möchten Sie möglicherweise die Werte in der ersten Bedingung des ternären Ausdrucks (hier bei +/- 20) und / oder im Divisor, der den incrementWert festlegt (hier bei 40) , erhöhen .
Wenn Sie mit durationdem Divisor spielen, der festgelegt wird increment, und den Werten im ternären Zustand von scroller()sollten Sie die Funktion an Ihre Seite anpassen können .