Kernpunkte
requestAnimationFrame
, um reibungslose Animationsaktualisierungen durchzuführen, die Leistung zu optimieren und eine reibungslosere Benutzererfahrung zu bieten. scroll-behavior
Eigenschaften zur Unterstützung des nativen reibungslosen Bildlaufs in Browsern, die diese Funktion erkennen, und der JavaScript -Fallback -Mechanismus wird bereitgestellt, wenn der Browser es nicht unterstützt. Dieser Artikel wurde von Adrian Sandu, Chris Perry, Jérémy Heleine und Mallory Van Achterberg überprüft. Vielen Dank an alle Peer -Rezensenten von SitePoint, um den besten Inhalt in SitePoint zu erhalten!
Smooth Scrolling ist ein Benutzeroberflächen-Modus, der das Standarderlebnis für die In-Page-Navigation allmählich verbessert und die Position innerhalb des Scroll-Feld im Clip angegeben.
Dies ist nichts Neues und ist seit Jahren ein bekanntes Muster. Schauen Sie sich beispielsweise diesen SitePoint -Artikel aus dem Jahr 2003 an! Übrigens ist dieser Beitrag historisch wertvoll, da er zeigt, wie sich die kundenseitige JavaScript-Programmierung, insbesondere DOM, im Laufe der Jahre verändert und weiterentwickelt hat, was die Entwicklung einfacher native JavaScript-Lösungen ermöglicht.
Im Jquery-Ökosystem gibt es viele Implementierungen dieses Musters, die direkt mit JQuery oder Plug-Ins implementiert werden können. In diesem Artikel interessieren wir uns jedoch für reine JavaScript-Lösungen. Insbesondere werden wir die Jump.js -Bibliothek erforschen und nutzen.
Nachdem wir einen Überblick über die Bibliothek und ihre Funktionen und Funktionen eingeführt haben, werden wir einige Änderungen am ursprünglichen Code vor unseren Anforderungen vornehmen. Dabei werden wir einige Kern -JavaScript -Sprachkenntnisse wie Funktionen und Schließungen überprüfen. Wir erstellen dann eine HTML -Seite, um das reibungslose Bildlaufverhalten zu testen und es dann als benutzerdefiniertes Skript zu implementieren. Die Unterstützung des nativen reibungslosen Scrollens in CSS wird dann (falls verfügbar) hinzugefügt, und schließlich werden wir einige Beobachtungen zur Historie der Browser -Navigation machen.
Dies ist die letzte Demonstration, die wir erstellen werden:
Smooth Scrolling Stift für SitePoint (@sinepoint) auf CodePen anzeigen.
Der vollständige Quellcode kann auf GitHub gefunden werden.
sprung.js ist in nativem ES6 -JavaScript geschrieben und hat keine externen Abhängigkeiten. Es handelt sich um ein kleines Dienstprogramm mit nur etwa 42 SLOC, aber das Minimierungspaket hat eine Größe von etwa 2,67 kb, wie es übersetzt werden muss. Auf der GitHub -Projektseite wird eine Demo bereitgestellt.
Wie der Name schon sagt, liefert es nur Sprünge: Die Animationsänderungen der Bildlaufleistenposition von ihrem aktuellen Wert zur Zielposition, angegeben durch Bereitstellung von Entfernungen in Form eines DOM -Elements, eines CSS -Selektors oder positiv oder negativ oder negativ Numerischer Wert. Dies bedeutet, dass wir bei der Implementierung des reibungslosen Scroll -Modus Link -Entführungen durchführen müssen. Weitere Informationen finden Sie im Abschnitt unten.
Bitte beachten Sie, dass derzeit nur vertikales Scrollen des Ansichtsfenpfels unterstützt wird.
Wir können Sprünge mit einigen Optionen konfigurieren, z. B. Dauer (dieser Parameter ist erforderlich), die Lockerungsfunktion und Rückrufe, die am Ende der Animation ausgelöst werden. Wir werden ihre praktische Anwendung später in der Demo sehen. In der Dokumentation finden Sie vollständige Details.
Jump.js läuft ohne Probleme mit "modernen" Browsern, einschließlich Internet Explorer Version 10 oder höher. Weitere Informationen finden Sie in der Dokumentation für eine vollständige Liste unterstützter Browser. Mit dem entsprechenden RequestAnimationFrame -Polyfill kann es sogar auf älteren Browsern ausgeführt werden.
Innen verwendet der Quellcode Jump.js die RequestAnimationFrame -Methode des Fensterobjekts, um die Position der vertikalen Position des Ansichtsfensters zu ordnen, die in jedem Frame der Scroll -Animation aktualisiert wurde. Dieses Update wird erreicht, indem der nächste Positionswert über die Locker -Funktion an das Fenster übergeben wird. Ausführliche Details finden Sie im Quellcode.
Wir werden einige geringfügige Änderungen am Originalcode vornehmen, bevor wir uns mit der Demo befassen, um zu zeigen, wie sprung.js verwendet wird, aber das wird nicht ändern, wie es intern funktioniert.
Der Quellcode ist in ES6 geschrieben und muss mit JavaScript -Build -Tools verwendet werden, um Module zu übersetzen und zu bündeln. Dies kann für einige Projekte ein bisschen zu viel sein, daher werden wir einige Refactoring anwenden, um den Code in ES5 für die Verwendung überall umzuwandeln.
Entfernen wir zuerst die ES6 -Syntax und die Funktionen. Das Skript definiert eine ES6 -Klasse:
<code>import easeInOutQuad from './easing' export default class Jump { jump(target, options = {}) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(time => this._loop(time)) } _loop(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(time => this._loop(time)) : this._end() } _end() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } } </code>
Wir können es mit Konstruktoren und einer Reihe von Prototypmethoden in ES5 -Klassen konvertieren. Beachten Sie jedoch, dass wir nie mehrere Instanzen dieser Klasse benötigen. Ein Singleton, das mit einem normalen Objektliteral implementiert ist
<code>var jump = (function() { var o = { jump: function(target, options) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(_loop) }, _loop: function(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(_loop) : this._end() }, _end: function() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } }; var _loop = o._loop.bind(o); // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/ function easeInOutQuad(t, b, c, d) { t /= d / 2 if(t t-- return -c / 2 * (t * (t - 2) - 1) + b } return o; })(); </code>
wird verwendet, um die Bildlaufleisteposition in jedem Frame zu aktualisieren. In dem ursprünglichen Code wird er über die ES6-Pfeilfunktion aufgerufen, die bei der Initialisierung vor dem Sprung-Singleton vorgebunden sind. Anschließend bündeln wir die Standard -Locker -Funktion in derselben Quelldatei. Schließlich wickeln wir den Code mit iife (sofort Ausdruck von Aufruffunktion) ein, um die Verschmutzung der Namespace zu vermeiden. requestAnimationFrame
<code>function jump(target, options) { var start = window.pageYOffset; var opt = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad }; var distance = typeof target === 'string' ? opt.offset + document.querySelector(target).getBoundingClientRect().top : target ; var duration = typeof opt.duration === 'function' ? opt.duration(distance) : opt.duration ; var timeStart = null, timeElapsed ; requestAnimationFrame(loop); function loop(time) { if (timeStart === null) timeStart = time; timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } function end() { window.scrollTo(0, start + distance); typeof opt.callback === 'function' && opt.callback(); timeStart = null; } // ... } </code>
Wie der endgültige Refactoring -Schritt, um wiederholte Zeitstart -Reset -Überprüfungen jedes Mal, wenn der Loop -Rückruf aufgerufen wird Schleifenfunktion Reset TimerStart Variable:
<code>import easeInOutQuad from './easing' export default class Jump { jump(target, options = {}) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(time => this._loop(time)) } _loop(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(time => this._loop(time)) : this._end() } _end() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } } </code>
Beachten Sie erneut, dass sich der Core -Scroll -Animationscode während des Rekonstruktionsprozesses nicht geändert hat.
Jetzt, da wir das Skript an unsere Bedürfnisse angepasst haben, sind wir bereit, eine Testdemo zusammenzustellen. In diesem Abschnitt werden wir eine Seite schreiben, die das sanfte Scrollen mit den im nächsten Abschnitt beschriebenen Skripten verbessert.
Diese Seite enthält eine Inhaltsverzeichnis (TOC), die auf Links innerhalb der Seite in den nachfolgenden Abschnitten des Dokuments sowie auf andere Links zum TOC verweist. Wir werden auch einige externe Links zu anderen Seiten mischen. Dies ist die Grundstruktur dieser Seite:
<code>var jump = (function() { var o = { jump: function(target, options) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(_loop) }, _loop: function(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(_loop) : this._end() }, _end: function() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } }; var _loop = o._loop.bind(o); // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/ function easeInOutQuad(t, b, c, d) { t /= d / 2 if(t t-- return -c / 2 * (t * (t - 2) - 1) + b } return o; })(); </code>
Am Kopf werden wir einige CSS -Regeln einfügen, um das einfachste Layout festzulegen, und am Ende des Body -Tags werden wir zwei JavaScript -Dateien einbeziehen Ist es das Skript, das wir jetzt diskutieren werden?
Dies ist ein Skript, das das Scrolling -Erlebnis der Testseite mit animierten Sprüngen aus unserer individuellen Version von Jump.js Library verbessert. Natürlich wird dieser Code auch in ES5 JavaScript geschrieben.
Lassen Sie uns einen kurzen Überblick über das, was es tun sollte Der Link und ersetzen Sie ihn durch einen Anruf auf unsere Sprung () -Funktion. Daher müssen Sie zunächst die Klicks auf die Links auf der Seite überwachen. Wir können dies auf zwei Arten tun, indem wir Ereignisdelegierte verwenden oder Handler an jedem verwandten Link anhängen.
Ereigniskommission
Natürlich müssen wir im registrierten Ereignishörer (Onclick) das Ziel des eingehenden Klick -Ereignisobjekts überprüfen, ob es sich um das Link -Element auf der Seite bezieht. Dies kann auf verschiedene Arten erfolgen, sodass wir sie als Helferfunktion isinpagelink () abstrahieren. Wir werden den Mechanismus dieser Funktion später betrachten.
<code>function jump(target, options) { var start = window.pageYOffset; var opt = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad }; var distance = typeof target === 'string' ? opt.offset + document.querySelector(target).getBoundingClientRect().top : target ; var duration = typeof opt.duration === 'function' ? opt.duration(distance) : opt.duration ; var timeStart = null, timeElapsed ; requestAnimationFrame(loop); function loop(time) { if (timeStart === null) timeStart = time; timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } function end() { window.scrollTo(0, start + distance); typeof opt.callback === 'function' && opt.callback(); timeStart = null; } // ... } </code>
Dies ist der Ereignishandler:
Single -Handler
<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); }); function loop(time) { timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } </code>
<code>import easeInOutQuad from './easing' export default class Jump { jump(target, options = {}) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(time => this._loop(time)) } _loop(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(time => this._loop(time)) : this._end() } _end() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } } </code>
Ereignishandler ist fast der gleiche wie zuvor, aber natürlich müssen wir das Klickziel nicht überprüfen:
<code>var jump = (function() { var o = { jump: function(target, options) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(_loop) }, _loop: function(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(_loop) : this._end() }, _end: function() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } }; var _loop = o._loop.bind(o); // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/ function easeInOutQuad(t, b, c, d) { t /= d / 2 if(t t-- return -c / 2 * (t * (t - 2) - 1) + b } return o; })(); </code>
Welche Methode ist am besten vom Gebrauchskontext abhängt. Wenn beispielsweise neue Link -Elemente dynamisch nach dem Laden der Anfangsseite hinzugefügt werden können, müssen wir Ereignisdelegierte verwenden.
Jetzt wenden wir uns der Implementierung von isinpagelink () zu, die wir diese Helferfunktion in unserem vorherigen Ereignis-Handler für abstrakte Tests von einseitigen Links verwendeten. Wie wir sehen können, nimmt diese Funktion einen DOM-Knoten als Parameter ein und gibt einen booleschen Wert zurück, um anzuzeigen, ob der Knoten ein In-Page-Verbindungselement darstellt. Es reicht nicht aus, nur zu überprüfen, ob der übergebene Knoten ein A -Tag ist und dass Hash -Fragment festgelegt ist, da der Link möglicherweise auf eine andere Seite zeigt. In diesem Fall darf die Standard -Browser -Aktion nicht deaktiviert werden. Daher prüfen wir, ob der in der Eigenschaft gespeicherte Wert "minus" Hash -Fragment href gleich der Seiten -URL ist:
<code>function jump(target, options) { var start = window.pageYOffset; var opt = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad }; var distance = typeof target === 'string' ? opt.offset + document.querySelector(target).getBoundingClientRect().top : target ; var duration = typeof opt.duration === 'function' ? opt.duration(distance) : opt.duration ; var timeStart = null, timeElapsed ; requestAnimationFrame(loop); function loop(time) { if (timeStart === null) timeStart = time; timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } function end() { window.scrollTo(0, start + distance); typeof opt.callback === 'function' && opt.callback(); timeStart = null; } // ... } </code>
striphash () ist eine weitere Helferfunktion, mit der wir auch den Wert des variablen Pageurl festlegen, wenn das Skript initialisiert wird:
<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); }); function loop(time) { timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } </code>
Diese String-basierte Lösung und das Beschneiden von Hash-Fragmenten funktionieren auch bei URLs mit Abfragebrägern einwandfrei, da die Hash-Teile in der allgemeinen Struktur der URL hinter ihnen stehen.
Wie ich bereits sagte, ist dies nur eine mögliche Möglichkeit, diesen Test zu implementieren. Der zu Beginn dieses Tutorials zitierte Artikel verwendet beispielsweise eine andere Lösung, um Vergleiche auf Komponentenebene mit Link-HREFs mit Standortobjekten durchzuführen.
Es ist zu beachten, dass wir diese Funktion in beiden Ereignisabonnementmethoden verwenden, aber in der zweiten Methode verwenden wir sie als Filter für Elemente, von denen wir bereits wissen überflüssig. Dies bleibt dem Leser als Übung überlassen.
Überlegungen zur ZugänglichkeitUm dieses Problem zu lösen, werden wir dem Hauptskript eine weitere Funktion hinzufügen:
<code>> <h1>></h1>Title> <nav> id="toc"></nav> <ul>></ul> <li>></li> <a> href="https://www.php.cn/link/db8229562f80fbcc7d780f571e5974ec"></a>Section 1>> <li>></li> <a> href="https://www.php.cn/link/ba2cf4148007ed8a8b041f8abd9bbf96"></a>Section 2>> ... > > id="sect-1"> <h2>></h2>Section 1> <p>></p>Pellentesque habitant morbi tristique senectus et netus et <a> href="https://www.php.cn/link/e1b97c787a5677efa5eba575c41e8688"></a>a link to another page> ac turpis egestas. <a> href="https://www.php.cn/link/e1b97c787a5677efa5eba575c41e8688index.html#foo"></a>A link to another page, with an anchor> quam, feugiat vitae, ...> <a> href="https://www.php.cn/link/7421d74f57142680e679057ddc98edf5"></a>Back to TOC> > id="sect-2"> <h2>></h2>Section 2> ... > ... src="jump.js">> src="script.js">> > </code>
<code>import easeInOutQuad from './easing' export default class Jump { jump(target, options = {}) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(time => this._loop(time)) } _loop(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(time => this._loop(time)) : this._end() } _end() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } } </code>
Die Funktion dieser Funktion besteht darin, das DOM -Element zu erhalten, das dem Hash -Wert entspricht, und zu testen, ob es sich bereits um ein Element handelt, das Fokus empfangen kann (z. B. ein Anker- oder Schaltflächenelement). Wenn das Element standardmäßig keinen Fokus empfangen kann (z. B. unserem Container), legt es seine Tabindex -Eigenschaft auf -1 fest (ermöglicht es programmgesteuert, fokussierte Fokus, jedoch nicht über die Tastatur). Der Fokus wird dann auf dieses Element eingestellt, was bedeutet, dass der nächste -Ristentaste des Benutzers den Fokus auf den nächsten verfügbaren Link verschiebt. Sie können den vollständigen Quellcode des Hauptskripts hier anzeigen, wobei alle Änderungen zuvor diskutiert wurden.
Unterstützen Sie den nativen glatten Scrollen mit CSS
scroll-behavior
Es kann zwei Werte annehmen,
die Animationsrolle repräsentiert. Diese Spezifikation bietet keine Möglichkeit, Scroll -Animationen wie die Dauer- und Zeitfunktionen (Lockerung) zu konfigurieren. auto
smooth
Kann ich CSS-Scroll-Verhalten verwenden? Daten von caniuse.com zeigen die Unterstützung von CSS-S-CROLL-Verhaltensfunktionen durch große Browser.
zum Zeitpunkt des Schreibens ist die Unterstützung leider sehr begrenzt. In Chrome befindet sich diese Funktion in der Entwicklung und kann teilweise implementiert werden, indem sie im Bildschirm von Chrome: // Flags aktiviert werden. Die CSS -Eigenschaft wurde noch nicht implementiert, daher funktioniert das reibungslose Scrollen auf Linkklicks nicht.
Wie auch immer, indem wir kleine Änderungen am Hauptskript vornehmen, können wir feststellen, ob diese Funktion im Benutzeragenten verfügbar ist, und vermeiden Sie es, den Rest unseres Codes auszuführen. Um das sanfte Scrollen im Ansichtsfenster zu verwenden, wenden wir das CSS -Attribut auf das HTML -Element des Stammelements an (aber auf unserer Testseite können wir es sogar auf das Körperelement anwenden):
Dann fügen wir zu Beginn des Skripts einen einfachen funktionalen Erkennungstest hinzu:
<code>var jump = (function() { var o = { jump: function(target, options) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(_loop) }, _loop: function(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(_loop) : this._end() }, _end: function() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } }; var _loop = o._loop.bind(o); // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/ function easeInOutQuad(t, b, c, d) { t /= d / 2 if(t t-- return -c / 2 * (t * (t - 2) - 1) + b } return o; })(); </code>
Wenn der Browser native Scrolling unterstützt, wird das Skript nichts bewirken und beendet sich ansonsten weiter wie zuvor und der Browser ignoriert nicht unterstützte CSS -Eigenschaften.
<code>function jump(target, options) { var start = window.pageYOffset; var opt = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad }; var distance = typeof target === 'string' ? opt.offset + document.querySelector(target).getBoundingClientRect().top : target ; var duration = typeof opt.duration === 'function' ? opt.duration(distance) : opt.duration ; var timeStart = null, timeElapsed ; requestAnimationFrame(loop); function loop(time) { if (timeStart === null) timeStart = time; timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } function end() { window.scrollTo(0, start + distance); typeof opt.callback === 'function' && opt.callback(); timeStart = null; } // ... } </code>
Schlussfolgerung
In dem von uns geschriebenen Code (wir können es jetzt als Fallback -Schema betrachten, wenn CSS -Unterstützung nicht verfügbar ist), haben wir das Verhalten von Skripten in Bezug auf die Browsergeschichte nicht in Betracht gezogen. Abhängig vom Kontext und des Anwendungsfalles kann dies etwas von Interesse sein oder nicht. Wenn wir jedoch der Meinung sind, dass Skripte die Standard -Scroll -Erfahrung verbessern sollten, sollten wir wie CSS genau wie CSS erwarten.
Verwenden Sie natives JavaScript, um ein reibungsloses Scrollen zu erreichen, ohne dass Bibliotheken verwendet werden. Sie können die Methode window.scrollTo
verwenden und die Option behavior
auf smooth
festlegen. Diese Methode dokumentiert im Fenster um eine bestimmte Anzahl von Male. Hier ist ein einfaches Beispiel:
<code>import easeInOutQuad from './easing' export default class Jump { jump(target, options = {}) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(time => this._loop(time)) } _loop(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(time => this._loop(time)) : this._end() } _end() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } } </code>
In diesem Beispiel klicken Sie in diesem Beispiel auf ein Element mit der Klasse your-element
, die Seite reibungslos nach oben scrollt.
glatte Scrolling -Funktion mit der Methode scrollTo
und das Festlegen der Option behavior
in smooth
wird in Safari nicht unterstützt. Damit Sie es funktionieren können, können Sie Polyfill verwenden, z. B. smoothscroll-polyfill
. Dies ermöglicht eine reibungslose Scrollen in Browsern, die es nicht nativ unterstützen.
Um reibungslos zu einem bestimmten Element zu scrollen, können Sie die Methode Element.scrollIntoView
verwenden und die Option behavior
auf smooth
festlegen. Hier ist ein Beispiel:
<code>var jump = (function() { var o = { jump: function(target, options) { this.start = window.pageYOffset this.options = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad } this.distance = typeof target === 'string' ? this.options.offset + document.querySelector(target).getBoundingClientRect().top : target this.duration = typeof this.options.duration === 'function' ? this.options.duration(this.distance) : this.options.duration requestAnimationFrame(_loop) }, _loop: function(time) { if(!this.timeStart) { this.timeStart = time } this.timeElapsed = time - this.timeStart this.next = this.options.easing(this.timeElapsed, this.start, this.distance, this.duration) window.scrollTo(0, this.next) this.timeElapsed ? requestAnimationFrame(_loop) : this._end() }, _end: function() { window.scrollTo(0, this.start + this.distance) typeof this.options.callback === 'function' && this.options.callback() this.timeStart = false } }; var _loop = o._loop.bind(o); // Robert Penner's easeInOutQuad - http://robertpenner.com/easing/ function easeInOutQuad(t, b, c, d) { t /= d / 2 if(t t-- return -c / 2 * (t * (t - 2) - 1) + b } return o; })(); </code>
In diesem Beispiel klicken Sie in diesem Beispiel auf ein Element mit der Klasse your-element
, die Seite sanft zu einem Element mit der Klasse target-element
scrollen.
Die Geschwindigkeit des glatten Scrollens kann nicht direkt gesteuert werden, da sie vom Browser behandelt wird. Sie können jedoch window.requestAnimationFrame
verwenden, um eine benutzerdefinierte reibungslose Scroll -Funktion zu erstellen, um eine bessere Kontrolle über die Scrolling -Animation einschließlich ihrer Geschwindigkeit zu erhalten.
Sie können horizontales glattes Scrollen in ähnlicher Weise wie vertikales glattes Scrollen erzielen. Die Methoden window.scrollTo
und Element.scrollIntoView
akzeptieren auch die left
-Optionen, um die horizontale Position anzugeben, in die sie scrollen sollen. Hier ist ein Beispiel:
<code>function jump(target, options) { var start = window.pageYOffset; var opt = { duration: options.duration, offset: options.offset || 0, callback: options.callback, easing: options.easing || easeInOutQuad }; var distance = typeof target === 'string' ? opt.offset + document.querySelector(target).getBoundingClientRect().top : target ; var duration = typeof opt.duration === 'function' ? opt.duration(distance) : opt.duration ; var timeStart = null, timeElapsed ; requestAnimationFrame(loop); function loop(time) { if (timeStart === null) timeStart = time; timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } function end() { window.scrollTo(0, start + distance); typeof opt.callback === 'function' && opt.callback(); timeStart = null; } // ... } </code>
scrollt das Dokument nach rechts reibungslos.
Die glatte Scrolling -Animation kann nicht direkt gestoppt werden, da sie vom Browser behandelt wird. Wenn Sie jedoch eine benutzerdefinierte reibungslose Scroll -Funktion verwenden, können Sie window.cancelAnimationFrame
den Animationsrahmen abbrechen, um die Animation zu stoppen.
Um ein reibungsloses Scrollen mit festen Headern zu erzielen, müssen Sie die Bildlaufposition einstellen, um die Höhe des Headers zu berücksichtigen. Sie können dies tun, indem Sie die Höhe des Headers von der Ziel -Scroll -Position subtrahieren.
Um ein reibungsloses Scrollen für Ankerlinks zu erzielen, können Sie Ereignishörer zum Klickereignis des Links hinzufügen und die Element.scrollIntoView
-Methode verwenden, um reibungslos zum Zielelement zu scrollen. Hier ist ein Beispiel:
<code>requestAnimationFrame(function(time) { timeStart = time; loop(time); }); function loop(time) { timeElapsed = time - timeStart; window.scrollTo(0, opt.easing(timeElapsed, start, distance, duration)); if (timeElapsed requestAnimationFrame(loop) else end(); } </code>
scrollen Sie alle Ankerlinks auf der Seite sanft zu seinem Zielelement.
Die Verwendung der Tastaturnavigation zur Erzielung eines reibungslosen Scrollens ist komplizierter, da die Abfangen von Tastaturereignissen und das manuelle Scrollen -Dokumente erforderlich sind. Sie können dies tun, indem Sie das Ereignisereignis zum keydown
-Event hinzufügen und das Dokument mit der window.scrollTo
-Methode reibungslos scrollen.
Sie können Online -Tools wie BrowsStack verwenden, um die Kompatibilität eines reibungslosen Scrolls zu testen. Mit diesen Tools können Sie Ihre Website auf verschiedenen Browsern und auf verschiedenen Geräten testen, um sicherzustellen, dass Ihre Implementierung in allen Umgebungen ordnungsgemäß funktioniert.
Das obige ist der detaillierte Inhalt vonSo implementieren Sie ein reibungsloses Scrollen in Vanille JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!