Cara Melaksanakan Menatal Lancar di Vanilla JavaScript
mata teras
- Gunakan Perpustakaan Jump.js untuk melaksanakan JavaScript Smooth Scrolling asli, memudahkan animasi menatal tanpa kebergantungan luaran.
- Ubah suai Jump.js Kod Asal untuk menukarnya dari ES6 hingga ES5 untuk memastikan keserasian yang lebih luas dengan pelayar yang berbeza.
- Gunakan kaedah
- untuk melakukan kemas kini animasi yang lancar, mengoptimumkan prestasi dan memberikan pengalaman pengguna yang lebih lancar.
requestAnimationFrame
Melaksanakan JavaScript tersuai untuk memintas tingkah laku pautan dalam halaman lalai, dan menggantikan lompatan tiba-tiba dengan animasi menatal yang lancar. - CSS bersepadu
- Ciri -ciri untuk menyokong skrol lancar asli dalam penyemak imbas yang mengiktiraf ciri ini, dan mekanisme sandaran JavaScript disediakan jika penyemak imbas tidak menyokongnya.
scroll-behavior
Memastikan kebolehcapaian dengan menetapkan fokus untuk menargetkan elemen selepas menatal, menangani isu -isu yang berpotensi dengan navigasi papan kekunci, dan meningkatkan kebolehgunaan untuk semua pengguna.
Artikel ini dikaji semula oleh Adrian Sandu, Chris Perry, Jérémy Heleine dan Mallory Van Achterberg. Terima kasih kepada semua pengulas rakan sebaya SitePoint untuk mendapatkan kandungan terbaik di sitepoint!
Smooth Scrolling adalah mod antara muka pengguna yang secara beransur-ansur meningkatkan pengalaman navigasi dalam halaman lalai, menghidupkan kedudukan dalam kotak tatal (viewport atau elemen scrollable), dari kedudukan pautan pengaktif ditunjukkan dalam klip.Ini bukan sesuatu yang baru dan telah menjadi corak yang diketahui selama bertahun -tahun, contohnya, lihat artikel SitePoint ini sejak tahun 2003! Dengan cara ini, jawatan ini secara historis berharga kerana ia menunjukkan bagaimana pengaturcaraan JavaScript, terutamanya DOM, telah berubah dan berkembang selama bertahun-tahun, yang membolehkan pembangunan penyelesaian JavaScript asli yang lebih mudah.
Dalam ekosistem jQuery, terdapat banyak pelaksanaan corak ini, yang boleh dilaksanakan secara langsung dengan jQuery atau dengan pemalam, tetapi dalam artikel ini, kami berminat dengan penyelesaian JavaScript tulen. Khususnya, kami akan meneroka dan menggunakan perpustakaan Jump.js.
Selepas memperkenalkan gambaran keseluruhan perpustakaan dan ciri -cirinya, kami akan membuat beberapa perubahan kepada kod asal yang sesuai dengan keperluan kami. Dalam proses ini, kami akan mengkaji beberapa kemahiran bahasa JavaScript teras seperti fungsi dan penutupan. Kami kemudian akan membuat halaman HTML untuk menguji tingkah laku menatal yang lancar dan kemudian melaksanakannya sebagai skrip tersuai. Sokongan untuk menatal lancar asli di CSS akan ditambah (jika ada), dan akhirnya kami akan membuat beberapa pemerhatian mengenai sejarah navigasi penyemak imbas.
Ini adalah demonstrasi terakhir yang akan kita buat:
Lihat pena skrol lancar untuk SitePoint (@SitePoint) pada CodePen.
Kod sumber lengkap boleh didapati di GitHub.
jump.js
jump.js ditulis dalam ES6 JavaScript asli dan tidak mempunyai kebergantungan luaran. Ia adalah utiliti kecil dengan hanya kira -kira 42 SLOC, tetapi pakej pengurangan yang disediakan adalah kira -kira 2.67 kb dalam saiz, kerana ia perlu diterjemahkan. Demo disediakan di halaman Projek GitHub.
seperti namanya, ia hanya memberikan lompatan: perubahan animasi kedudukan bar tatal dari nilai semasa ke kedudukan sasaran, yang ditentukan dengan menyediakan jarak dalam bentuk elemen DOM, pemilih CSS, atau positif atau negatif Nilai berangka. Ini bermakna bahawa dalam pelaksanaan mod tatal lancar, kita perlu melakukan pautan merampas diri kita sendiri. Lihat bahagian di bawah untuk maklumat lanjut.
Sila ambil perhatian bahawa hanya menatal menegak viewport yang disokong pada masa ini.
kita boleh mengkonfigurasi melompat dengan beberapa pilihan, seperti tempoh (parameter ini diperlukan), fungsi pelonggaran, dan panggilan balik yang dicetuskan pada akhir animasi. Kami akan melihat aplikasi praktikal mereka kemudian dalam demo. Lihat dokumentasi untuk butiran lengkap.
jump.js berjalan pada pelayar "moden" tanpa sebarang masalah, termasuk Internet Explorer versi 10 atau lebih baru. Sekali lagi, sila rujuk dokumentasi untuk senarai lengkap penyemak imbas yang disokong. Dengan Polyfill RequestAnimationFrame yang sesuai, ia juga boleh dijalankan pada pelayar yang lebih tua.
Cepat memahami di sebalik skrin
Secara dalaman, kod sumber jump.js menggunakan kaedah RequestAnimationFrame objek tetingkap untuk mengatur kedudukan kedudukan menegak Viewport yang dikemas kini dalam setiap bingkai animasi tatal. Kemas kini ini dicapai dengan lulus nilai kedudukan seterusnya yang dikira menggunakan fungsi pelonggaran ke kaedah window.scrollto. Lihat kod sumber untuk butiran lengkap.
Beberapa penyesuaian
Kami akan membuat beberapa perubahan kecil pada kod asal sebelum menyelidiki demo untuk menunjukkan bagaimana lompat.js digunakan, tetapi itu tidak akan mengubah cara ia berfungsi secara dalaman.
Kod sumber ditulis dalam ES6 dan perlu digunakan dengan alat binaan JavaScript untuk menterjemahkan dan modul bundle. Ini mungkin terlalu banyak untuk beberapa projek, jadi kami akan menggunakan beberapa refactoring untuk menukar kod ke ES5 untuk digunakan di mana sahaja.
Pertama, mari kita keluarkan sintaks dan ciri ES6. Skrip mentakrifkan kelas ES6:
<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>
kita boleh menukarnya kepada ES5 "kelas" menggunakan pembina dan sekumpulan kaedah prototaip, tetapi ambil perhatian bahawa kita tidak memerlukan banyak contoh kelas ini, jadi singleton dilaksanakan dengan objek biasa literal adalah baik:
<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>
Selain memadam kelas, kita perlu membuat beberapa perubahan lain. Panggilan balik 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>
sebagai langkah refactoring akhir, untuk mengelakkan pemeriksaan tetapan semula timestart berulang setiap kali panggilan balik gelung dipanggil, kali pertama requestanimationframe () dipanggil, kita akan lulus fungsi tanpa nama kepadanya, yang berfungsi sebelum memanggil Fungsi gelung menetapkan semula pembolehubah Timerstart:
<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>
Nota sekali lagi bahawa semasa proses pembinaan semula, kod animasi tatal teras tidak berubah.
halaman ujian
Sekarang kita telah menyesuaikan skrip untuk memenuhi keperluan kita, kita bersedia untuk memasang demo ujian. Dalam bahagian ini, kami akan menulis halaman yang meningkatkan skrol lancar menggunakan skrip yang diterangkan dalam bahagian seterusnya.
Halaman ini mengandungi jadual kandungan (TOC) yang menunjukkan pautan ke dalam halaman di bahagian berikutnya dokumen, serta pautan lain ke TOC. Kami juga akan mencampur beberapa pautan luaran ke halaman lain. Ini adalah struktur asas halaman ini:
<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>
Di kepala, kami akan memasukkan beberapa peraturan CSS untuk menetapkan susun atur asas yang paling mudah, dan pada akhir tag badan, kami akan memasukkan dua fail JavaScript: yang pertama adalah versi refactored kami jump.js, dan yang terakhir Adakah skrip itu akan dibincangkan sekarang.
skrip utama
Ini adalah skrip yang akan meningkatkan pengalaman menatal halaman ujian menggunakan lompatan animasi dari versi lompat.js versi tersuai kami. Sudah tentu, kod ini juga akan ditulis dalam ES5 JavaScript.
mari kita gambaran ringkas tentang apa yang harus dilakukan: ia mesti rampas klik pada pautan dalam halaman, matikan tingkah laku lalai penyemak imbas (tiba -tiba melompat ke serpihan hash atribut HREF dari pautan klik yang klik pautan, dan menggantikannya dengan panggilan ke fungsi lompat kami (). Oleh itu, pertama sekali, anda perlu memantau klik pada pautan di halaman. Kita boleh melakukan ini dalam dua cara, menggunakan perwakilan acara atau melampirkan pengendali ke setiap pautan yang berkaitan.
Suruhanjaya Acara
Dalam kaedah pertama, kami menambah pendengar klik ke dokumen elemen.body. Dengan cara ini, setiap peristiwa klik mana -mana elemen di halaman akan menggelegak di sepanjang cawangan nenek moyangnya ke dalam pokok Dom sehingga sampai ke dokumen.body:
Sudah tentu, sekarang dalam pendengar acara berdaftar (onclick), kita perlu menyemak sasaran objek acara klik masuk untuk memeriksa sama ada ia berkaitan dengan elemen pautan di halaman. Ini boleh dilakukan dalam beberapa cara, jadi kita akan abstrak sebagai fungsi penolong isInpageLink (). Kami akan melihat mekanisme fungsi ini kemudian.
<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>
Jika klik masuk berada di pautan dalam halaman, kami akan menghentikan gelembung acara dan menyekat tindakan lalai yang berkaitan. Akhirnya, kami memanggil fungsi lompat, menyediakannya dengan pemilih hash elemen sasaran dan parameter untuk mengkonfigurasi animasi yang diperlukan.
ini adalah pengendali acara:
pengendali tunggal
<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>
Gunakan kaedah kedua untuk memantau klik pautan, melampirkan versi yang sedikit diubahsuai dari pengendali acara yang diterangkan di atas ke elemen pautan dalam setiap halaman, jadi tidak ada gelembung peristiwa:
<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>
pengendali acara hampir sama seperti sebelumnya, tetapi sudah tentu kita tidak perlu menyemak sasaran klik:
<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>
Kaedah mana yang terbaik bergantung pada konteks penggunaan. Sebagai contoh, jika elemen pautan baru boleh ditambah secara dinamik selepas beban halaman awal, kita mesti menggunakan perwakilan acara.
Sekarang kita beralih kepada pelaksanaan IsInpageLink (), yang kami gunakan fungsi penolong ini dalam pengendali acara sebelumnya untuk ujian abstrak pautan dalam halaman. Seperti yang dapat kita lihat, fungsi ini mengambil nod DOM sebagai parameter dan mengembalikan nilai boolean untuk menunjukkan sama ada nod mewakili elemen pautan dalam halaman. Ia tidak mencukupi untuk memeriksa bahawa nod yang diluluskan adalah tag dan serpihan hash ditetapkan, kerana pautan mungkin menunjuk ke halaman lain, di mana tindakan penyemak imbas lalai tidak boleh dilumpuhkan. Oleh itu, kita periksa sama ada nilai "tolak" hash yang disimpan dalam harta href adalah sama dengan URL halaman:
<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 () adalah fungsi penolong lain, yang juga kami gunakan untuk menetapkan nilai pageArl berubah apabila skrip dimulakan:
<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>
Penyelesaian berasaskan rentetan ini dan pemangkasan serpihan hash berfungsi dengan baik walaupun pada URL dengan rentetan pertanyaan, kerana bahagian hash berada di belakangnya dalam struktur umum URL.
Seperti yang saya katakan sebelum ini, ini adalah satu cara yang mungkin untuk melaksanakan ujian ini. Sebagai contoh, artikel yang disebutkan pada permulaan tutorial ini menggunakan penyelesaian yang berbeza untuk melakukan perbandingan tahap komponen pautan HREFS ke objek lokasi.
Harus diingat bahawa kita menggunakan fungsi ini dalam kedua -dua kaedah langganan acara, tetapi dalam kaedah kedua kita menggunakannya sebagai penapis untuk unsur -unsur yang kita sudah tahu adalah tag, jadi pemeriksaan pertama harta tagname adalah berlebihan. Ini ditinggalkan kepada pembaca sebagai latihan.
Pertimbangan Kebolehcapaian
Buat masa ini, kod kami mudah terdedah kepada kesilapan yang diketahui (sebenarnya sepasang kesilapan yang tidak berkaitan yang mempengaruhi Blink/WebKit/KHTML dan satu yang mempengaruhi IE) yang mempengaruhi pengguna papan kekunci. Apabila melayari pautan TOC melalui kekunci TAB, mengaktifkan pautan akan lancar menatal ke bahagian yang dipilih, tetapi tumpuan akan kekal pada pautan. Ini bermakna apabila kekunci tab seterusnya ditekan, pengguna akan dihantar kembali ke TOC dan bukannya pautan pertama di bahagian pilihan mereka.
Untuk menyelesaikan masalah ini, kami akan menambah fungsi lain ke skrip utama:
<code>> <h1 id="gt">></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 id="gt">></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 id="gt">></h2>Section 2> ... > ... src="jump.js">> src="script.js">> > </code>
ia akan berjalan dalam panggilan balik yang kita akan lulus ke fungsi lompat dan lulus hash unsur yang kita mahu tatal ke masa lalu:
<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>
Fungsi fungsi ini adalah untuk mendapatkan elemen DOM yang sepadan dengan nilai hash dan menguji sama ada ia sudah menjadi elemen yang dapat menerima fokus (seperti elemen anchor atau butang). Jika elemen tidak dapat menerima fokus secara lalai (seperti bekas kami), ia menetapkan harta tabIndexnya kepada -1 (membolehkan untuk menerima fokus secara programatik, tetapi tidak melalui papan kekunci). Fokus kemudian akan ditetapkan ke elemen itu, yang bermaksud bahawa Tab Kunci pengguna seterusnya menggerakkan fokus ke pautan yang tersedia seterusnya.
anda boleh melihat kod sumber penuh skrip utama di sini, dengan semua perubahan yang dibincangkan sebelumnya.menyokong skrol lancar asli menggunakan CSS
Spesifikasi Modul Modul Model Objek CSS memperkenalkan harta baru untuk melaksanakan skrol lancar:
. scroll-behavior
mewakili tatal seketika lalai, dan auto
mewakili skrol animasi. Spesifikasi ini tidak menyediakan apa -apa cara untuk mengkonfigurasi animasi tatal, seperti fungsi tempoh dan masa (pelonggaran). smooth
Malangnya, pada masa penulisan, sokongan sangat terhad. Di Chrome, ciri ini sedang dibangunkan dan boleh dilaksanakan sebahagiannya dengan membolehkannya dalam skrin Chrome: // Flags. Harta CSS belum dilaksanakan, jadi tatal lancar pada klik pautan tidak berfungsi.
Bagaimanapun, dengan membuat perubahan kecil pada skrip utama, kita dapat mengesan jika ciri ini tersedia dalam ejen pengguna dan elakkan menjalankan kod kami yang lain. Untuk menggunakan tatal lancar di viewport, kami menggunakan atribut CSS ke elemen akar HTML (tetapi dalam halaman ujian kami, kami juga boleh memohon kepada elemen badan):
<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>
<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>
Kesimpulan
Selain daripada pelaksanaan kesederhanaan dan prestasi, satu lagi kelebihan penyelesaian CSS yang baru dibincangkan adalah bahawa tingkah laku sejarah penyemak imbas adalah konsisten dengan tingkah laku yang dialami ketika menggunakan menatal lalai penyemak imbas. Setiap lompatan dalam halaman ditolak ke timbunan sejarah penyemak imbas, dan kami boleh melayari lompatan ini ke belakang dan sebagainya dengan butang yang sepadan (tetapi sekurang-kurangnya tidak ada skrol lancar di Firefox).
Dalam kod yang kami tulis (kini kita boleh memikirkannya sebagai skema sandaran apabila sokongan CSS tidak tersedia), kami tidak menganggap tingkah laku skrip berbanding sejarah penyemak imbas. Bergantung pada konteks dan kes penggunaan, ini mungkin atau mungkin bukan sesuatu yang menarik, tetapi jika kita fikir skrip harus meningkatkan pengalaman menatal lalai, maka kita harus mengharapkan tingkah laku yang konsisten, seperti CSS.
Soalan Lazim (Soalan Lazim) pada Smooth Scrolling dengan JavaScript asli
Bagaimana untuk mencapai tatal lancar menggunakan JavaScript asli tanpa menggunakan mana -mana perpustakaan?
Gunakan JavaScript asli untuk mencapai tatal lancar tanpa menggunakan mana -mana perpustakaan sangat mudah. Anda boleh menggunakan kaedah window.scrollTo
dan tetapkan pilihan behavior
untuk smooth
. Kaedah ini menatal dokumen dalam tetingkap dengan beberapa kali. Berikut adalah contoh mudah:
<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>
Dalam contoh ini, apabila anda mengklik elemen dengan kelas your-element
, halaman akan tatal dengan lancar ke bahagian atas.
Mengapa tatal lancar saya tidak berfungsi di safari?
fungsi tatal lancar menggunakan kaedah scrollTo
dan menetapkan pilihan behavior
untuk smooth
tidak disokong dalam safari. Untuk menjadikannya berfungsi, anda boleh menggunakan polyfill, seperti smoothscroll-polyfill
. Ini akan membolehkan menatal lancar dalam penyemak imbas yang tidak menyokongnya secara asli.
Bagaimana untuk menatal dengan lancar ke elemen tertentu?
untuk menatal dengan lancar ke elemen tertentu, anda boleh menggunakan kaedah Element.scrollIntoView
dan tetapkan pilihan behavior
untuk smooth
. Berikut adalah contoh:
<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>
Dalam contoh ini, apabila anda mengklik elemen dengan kelas your-element
, halaman akan lancar menatal ke elemen dengan kelas target-element
.
Bolehkah saya mengawal kelajuan skrol licin?
Kelajuan skrol licin tidak boleh dikawal secara langsung kerana ia dikendalikan oleh penyemak imbas. Walau bagaimanapun, anda boleh menggunakan window.requestAnimationFrame
untuk membuat fungsi skrol lancar tersuai untuk kawalan yang lebih baik ke atas animasi menatal, termasuk kelajuannya.
Bagaimana untuk mencapai tatal lancar mendatar?
Anda boleh mencapai skrol lancar mendatar dengan cara yang sama dengan menatal lancar menegak. Kaedah window.scrollTo
dan Element.scrollIntoView
juga menerima pilihan left
untuk menentukan kedudukan mendatar untuk menatal ke. Berikut adalah contoh:
<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>
Ini akan menjadikan dokumen itu lancar tatal 100 piksel ke kanan.
Bagaimana untuk menghentikan animasi menatal yang lancar?
Animasi menatal yang lancar tidak boleh dihentikan secara langsung kerana ia dikendalikan oleh penyemak imbas. Walau bagaimanapun, jika anda menggunakan fungsi skrol lancar tersuai, anda boleh menggunakan window.cancelAnimationFrame
untuk membatalkan bingkai animasi untuk menghentikan animasi.
Bagaimana untuk mencapai tatal lancar dengan tajuk tetap?
Untuk mencapai tatal lancar dengan tajuk tetap, anda perlu menyesuaikan kedudukan tatal untuk mengambil kira ketinggian tajuk. Anda boleh melakukan ini dengan menolak ketinggian tajuk dari kedudukan tatal sasaran.
Bagaimana untuk mencapai tatal lancar untuk pautan utama?
3 Berikut adalah contoh:
Element.scrollIntoView
<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>
Bagaimana menggunakan navigasi papan kekunci untuk mencapai skrol lancar?
Menggunakan navigasi papan kekunci untuk mencapai skrol lancar lebih rumit kerana ia memerlukan memintas peristiwa papan kekunci dan dokumen menatal secara manual. Anda boleh melakukan ini dengan menambahkan pendengar acara ke acara keydown
dan menatal dokumen dengan lancar menggunakan kaedah window.scrollTo
.
Bagaimana untuk menguji keserasian pelaksanaan tatal lancar saya?
Anda boleh menggunakan alat dalam talian seperti BrowserStack untuk menguji keserasian skrol lancar. Alat ini membolehkan anda menguji laman web anda pada pelayar yang berbeza dan pada peranti yang berbeza untuk memastikan pelaksanaan anda berfungsi dengan baik di semua persekitaran.
Atas ialah kandungan terperinci Cara Melaksanakan Menatal Lancar di Vanilla JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











Python lebih sesuai untuk pemula, dengan lengkung pembelajaran yang lancar dan sintaks ringkas; JavaScript sesuai untuk pembangunan front-end, dengan lengkung pembelajaran yang curam dan sintaks yang fleksibel. 1. Sintaks Python adalah intuitif dan sesuai untuk sains data dan pembangunan back-end. 2. JavaScript adalah fleksibel dan digunakan secara meluas dalam pengaturcaraan depan dan pelayan.

Penggunaan utama JavaScript dalam pembangunan web termasuk interaksi klien, pengesahan bentuk dan komunikasi tak segerak. 1) kemas kini kandungan dinamik dan interaksi pengguna melalui operasi DOM; 2) pengesahan pelanggan dijalankan sebelum pengguna mengemukakan data untuk meningkatkan pengalaman pengguna; 3) Komunikasi yang tidak bersesuaian dengan pelayan dicapai melalui teknologi Ajax.

Aplikasi JavaScript di dunia nyata termasuk pembangunan depan dan back-end. 1) Memaparkan aplikasi front-end dengan membina aplikasi senarai TODO, yang melibatkan operasi DOM dan pemprosesan acara. 2) Membina Restfulapi melalui Node.js dan menyatakan untuk menunjukkan aplikasi back-end.

Memahami bagaimana enjin JavaScript berfungsi secara dalaman adalah penting kepada pemaju kerana ia membantu menulis kod yang lebih cekap dan memahami kesesakan prestasi dan strategi pengoptimuman. 1) aliran kerja enjin termasuk tiga peringkat: parsing, penyusun dan pelaksanaan; 2) Semasa proses pelaksanaan, enjin akan melakukan pengoptimuman dinamik, seperti cache dalam talian dan kelas tersembunyi; 3) Amalan terbaik termasuk mengelakkan pembolehubah global, mengoptimumkan gelung, menggunakan const dan membiarkan, dan mengelakkan penggunaan penutupan yang berlebihan.

Kedua -dua pilihan Python dan JavaScript dalam persekitaran pembangunan adalah penting. 1) Persekitaran pembangunan Python termasuk Pycharm, Jupyternotebook dan Anaconda, yang sesuai untuk sains data dan prototaip cepat. 2) Persekitaran pembangunan JavaScript termasuk node.js, vscode dan webpack, yang sesuai untuk pembangunan front-end dan back-end. Memilih alat yang betul mengikut keperluan projek dapat meningkatkan kecekapan pembangunan dan kadar kejayaan projek.

C dan C memainkan peranan penting dalam enjin JavaScript, terutamanya digunakan untuk melaksanakan jurubahasa dan penyusun JIT. 1) C digunakan untuk menghuraikan kod sumber JavaScript dan menghasilkan pokok sintaks abstrak. 2) C bertanggungjawab untuk menjana dan melaksanakan bytecode. 3) C melaksanakan pengkompil JIT, mengoptimumkan dan menyusun kod hot-spot semasa runtime, dan dengan ketara meningkatkan kecekapan pelaksanaan JavaScript.

Python lebih sesuai untuk sains data dan automasi, manakala JavaScript lebih sesuai untuk pembangunan front-end dan penuh. 1. Python berfungsi dengan baik dalam sains data dan pembelajaran mesin, menggunakan perpustakaan seperti numpy dan panda untuk pemprosesan data dan pemodelan. 2. Python adalah ringkas dan cekap dalam automasi dan skrip. 3. JavaScript sangat diperlukan dalam pembangunan front-end dan digunakan untuk membina laman web dinamik dan aplikasi satu halaman. 4. JavaScript memainkan peranan dalam pembangunan back-end melalui Node.js dan menyokong pembangunan stack penuh.

JavaScript digunakan secara meluas di laman web, aplikasi mudah alih, aplikasi desktop dan pengaturcaraan sisi pelayan. 1) Dalam pembangunan laman web, JavaScript mengendalikan DOM bersama -sama dengan HTML dan CSS untuk mencapai kesan dinamik dan menyokong rangka kerja seperti JQuery dan React. 2) Melalui reaktnatif dan ionik, JavaScript digunakan untuk membangunkan aplikasi mudah alih rentas platform. 3) Rangka kerja elektron membolehkan JavaScript membina aplikasi desktop. 4) Node.js membolehkan JavaScript berjalan di sisi pelayan dan menyokong permintaan serentak yang tinggi.
