Menstandarkan perutean sisi klien melalui API baru yang sepenuhnya merombak pembuatan aplikasi web satu halaman.
Aplikasi web satu halaman, atau SPA, ditentukan oleh fitur inti: menulis ulang kontennya secara dinamis saat pengguna berinteraksi dengan situs, bukan metode default untuk memuat halaman yang sepenuhnya baru dari server.
Meskipun SPA dapat menghadirkan fitur ini kepada Anda melalui History API (atau dalam kasus terbatas, dengan menyesuaikan bagian #hash situs), ini adalah API yang canggung yang dikembangkan jauh sebelum SPA menjadi norma—dan web membutuhkan pendekatan yang benar-benar baru. Navigation API adalah API yang diusulkan yang sepenuhnya merombak ruang ini, bukan hanya mencoba memperbaiki History API. (Misalnya, Scroll Restoration memperbaiki History API, bukan mencoba menciptakannya kembali.)
Postingan ini menjelaskan Navigation API di tingkat tinggi. Untuk membaca proposal teknis, lihat Laporan Draf di repositori WICG.
Contoh penggunaan
Untuk menggunakan Navigation API, mulailah dengan menambahkan pemroses "navigate"
pada objek navigation
global.
Peristiwa ini pada dasarnya terpusat: peristiwa ini akan diaktifkan untuk semua jenis navigasi, baik pengguna melakukan tindakan (seperti mengklik link, mengirimkan formulir, atau kembali dan maju) atau saat navigasi dipicu secara terprogram (yaitu, melalui kode situs Anda).
Dalam sebagian besar kasus, tindakan ini memungkinkan kode Anda mengganti perilaku default browser untuk tindakan tersebut.
Untuk SPA, hal ini mungkin berarti membuat pengguna tetap berada di halaman yang sama dan memuat atau mengubah konten situs.
NavigateEvent
diteruskan ke pemroses "navigate"
yang berisi informasi tentang navigasi, seperti URL tujuan, dan memungkinkan Anda merespons navigasi di satu tempat terpusat.
Pemroses "navigate"
dasar dapat terlihat seperti ini:
navigation.addEventListener('navigate', navigateEvent => {
// Exit early if this navigation shouldn't be intercepted.
// The properties to look at are discussed later in the article.
if (shouldNotIntercept(navigateEvent)) return;
const url = new URL(navigateEvent.destination.url);
if (url.pathname === '/') {
navigateEvent.intercept({handler: loadIndexPage});
} else if (url.pathname === '/cats/') {
navigateEvent.intercept({handler: loadCatsPage});
}
});
Anda dapat menangani navigasi dengan salah satu dari dua cara berikut:
- Memanggil
intercept({ handler })
(seperti yang dijelaskan di atas) untuk menangani navigasi. - Memanggil
preventDefault()
, yang dapat membatalkan navigasi sepenuhnya.
Contoh ini memanggil intercept()
pada peristiwa.
Browser memanggil callback handler
Anda, yang akan mengonfigurasi status situs Anda berikutnya.
Tindakan ini akan membuat objek transisi, navigation.transition
, yang dapat digunakan kode lain untuk melacak progres navigasi.
intercept()
dan preventDefault()
biasanya diizinkan, tetapi ada kasus saat keduanya tidak dapat dipanggil.
Anda tidak dapat menangani navigasi melalui intercept()
jika navigasi tersebut adalah navigasi lintas-asal.
Selain itu, Anda tidak dapat membatalkan navigasi melalui preventDefault()
jika pengguna menekan tombol Kembali atau Maju di browser mereka; Anda tidak boleh menjebak pengguna di situs Anda.
(Hal ini sedang dibahas di GitHub.)
Meskipun Anda tidak dapat menghentikan atau mencegat navigasi itu sendiri, peristiwa "navigate"
akan tetap diaktifkan.
Peristiwa ini informatif, sehingga kode Anda dapat, misalnya, mencatat peristiwa Analytics untuk menunjukkan bahwa pengguna meninggalkan situs Anda.
Mengapa harus menambahkan peristiwa lain ke platform?
Pemroses peristiwa "navigate"
memusatkan penanganan perubahan URL di dalam SPA.
Hal ini merupakan proposisi yang sulit menggunakan API lama.
Jika pernah menulis pemilihan rute untuk SPA Anda sendiri menggunakan History API, Anda mungkin telah menambahkan kode seperti ini:
function updatePage(event) {
event.preventDefault(); // we're handling this link
window.history.pushState(null, '', event.target.href);
// TODO: set up page based on new URL
}
const links = [...document.querySelectorAll('a[href]')];
links.forEach(link => link.addEventListener('click', updatePage));
Hal ini tidak masalah, tetapi tidak lengkap. Link mungkin muncul dan hilang di halaman Anda, dan link bukan satu-satunya cara pengguna dapat membuka halaman. Misalnya, mereka dapat mengirimkan formulir atau bahkan menggunakan peta gambar. Halaman Anda mungkin menangani hal ini, tetapi ada banyak kemungkinan yang dapat disederhanakan—sesuatu yang dicapai oleh Navigation API baru.
Selain itu, kode di atas tidak menangani navigasi kembali/maju. Ada peristiwa lain untuk itu, "popstate"
.
Secara pribadi, History API sering kali terasa dapat membantu kemungkinan ini.
Namun, sebenarnya hanya memiliki dua area platform: merespons jika pengguna menekan Kembali atau Maju di browser, serta mengirim dan mengganti URL.
Tidak memiliki analogi dengan "navigate"
, kecuali jika Anda menyiapkan pemroses secara manual untuk peristiwa klik, misalnya, seperti yang ditunjukkan di atas.
Menentukan cara menangani navigasi
navigateEvent
berisi banyak informasi tentang navigasi yang dapat Anda gunakan untuk memutuskan cara menangani navigasi tertentu.
Properti utamanya adalah:
canIntercept
- Jika nilainya salah (false), Anda tidak dapat mencegat navigasi. Navigasi lintas origin dan traversal lintas dokumen tidak dapat dicegat.
destination.url
- Mungkin informasi terpenting yang perlu dipertimbangkan saat menangani navigasi.
hashChange
- Benar jika navigasi adalah dokumen yang sama, dan hash adalah satu-satunya bagian dari URL yang berbeda dengan URL saat ini.
Di SPA modern, hash harus digunakan untuk menautkan ke berbagai bagian dokumen saat ini. Jadi, jika
hashChange
bernilai benar, Anda mungkin tidak perlu mencegat navigasi ini. downloadRequest
- Jika ini benar, navigasi dimulai oleh link dengan atribut
download
. Dalam sebagian besar kasus, Anda tidak perlu mencegatnya. formData
- Jika tidak null, navigasi ini adalah bagian dari pengiriman formulir POST.
Pastikan Anda mempertimbangkan hal ini saat menangani navigasi.
Jika Anda hanya ingin menangani navigasi GET, hindari intersepsi navigasi jika
formData
bukan null. Lihat contoh penanganan pengiriman formulir nanti dalam artikel ini. navigationType
- Ini adalah salah satu dari
"reload"
,"push"
,"replace"
, atau"traverse"
. Jika"traverse"
, navigasi ini tidak dapat dibatalkan melaluipreventDefault()
.
Misalnya, fungsi shouldNotIntercept
yang digunakan dalam contoh pertama dapat berupa hal seperti ini:
function shouldNotIntercept(navigationEvent) {
return (
!navigationEvent.canIntercept ||
// If this is just a hashChange,
// just let the browser handle scrolling to the content.
navigationEvent.hashChange ||
// If this is a download,
// let the browser perform the download.
navigationEvent.downloadRequest ||
// If this is a form submission,
// let that go to the server.
navigationEvent.formData
);
}
Intersepsi
Saat kode Anda memanggil intercept({ handler })
dari dalam pemroses "navigate"
, kode tersebut akan memberi tahu browser bahwa kode tersebut sekarang sedang menyiapkan halaman untuk status baru yang diperbarui, dan bahwa navigasi mungkin memerlukan waktu beberapa saat.
Browser dimulai dengan mengambil posisi scroll untuk status saat ini, sehingga dapat dipulihkan secara opsional nanti, lalu memanggil callback handler
Anda.
Jika handler
menampilkan promise (yang terjadi secara otomatis dengan fungsi asinkron), promise tersebut akan memberi tahu browser berapa lama navigasi berlangsung, dan apakah navigasi berhasil.
navigation.addEventListener('navigate', navigateEvent => {
if (shouldNotIntercept(navigateEvent)) return;
const url = new URL(navigateEvent.destination.url);
if (url.pathname.startsWith('/articles/')) {
navigateEvent.intercept({
async handler() {
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);
},
});
}
});
Dengan demikian, API ini memperkenalkan konsep semantik yang dipahami browser: navigasi SPA saat ini terjadi, dari waktu ke waktu, mengubah dokumen dari URL dan status sebelumnya menjadi yang baru. Hal ini memiliki sejumlah manfaat potensial, termasuk aksesibilitas: browser dapat menampilkan awal, akhir, atau potensi kegagalan navigasi. Misalnya, Chrome mengaktifkan indikator pemuatan native-nya, dan memungkinkan pengguna berinteraksi dengan tombol berhenti. (Saat ini, hal ini tidak terjadi saat pengguna menavigasi melalui tombol kembali/maju, tetapi akan segera diperbaiki.)
Commit navigasi
Saat mencegat navigasi, URL baru akan diterapkan tepat sebelum callback handler
Anda dipanggil.
Jika Anda tidak segera memperbarui DOM, akan ada periode saat konten lama ditampilkan bersama dengan URL baru.
Hal ini memengaruhi hal-hal seperti resolusi URL relatif saat mengambil data atau memuat sub-resource baru.
Cara menunda perubahan URL sedang dibahas di GitHub, tetapi umumnya direkomendasikan untuk segera memperbarui halaman dengan semacam placeholder untuk konten yang akan datang:
navigation.addEventListener('navigate', navigateEvent => {
if (shouldNotIntercept(navigateEvent)) return;
const url = new URL(navigateEvent.destination.url);
if (url.pathname.startsWith('/articles/')) {
navigateEvent.intercept({
async handler() {
// The URL has already changed, so quickly show a placeholder.
renderArticlePagePlaceholder();
// Then fetch the real data.
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);
},
});
}
});
Hal ini tidak hanya menghindari masalah resolusi URL, tetapi juga terasa cepat karena Anda langsung merespons pengguna.
Sinyal pembatalan
Karena Anda dapat melakukan pekerjaan asinkron di pengendali intercept()
, navigasi dapat menjadi redundan.
Hal ini terjadi jika:
- Pengguna mengklik link lain, atau beberapa kode melakukan navigasi lain. Dalam hal ini, navigasi lama ditinggalkan dan diganti dengan navigasi baru.
- Pengguna mengklik tombol 'berhenti' di browser.
Untuk menangani kemungkinan ini, peristiwa yang diteruskan ke pemroses "navigate"
berisi properti signal
, yang merupakan AbortSignal
.
Untuk informasi selengkapnya, lihat Pengambilan yang dapat dibatalkan.
Versi singkatnya adalah pada dasarnya menyediakan objek yang memicu peristiwa saat Anda harus menghentikan pekerjaan.
Secara khusus, Anda dapat meneruskan AbortSignal
ke panggilan apa pun yang Anda lakukan ke fetch()
, yang akan membatalkan permintaan jaringan yang sedang berlangsung jika navigasi didahului.
Tindakan ini akan menghemat bandwidth pengguna, dan menolak Promise
yang ditampilkan oleh fetch()
, sehingga mencegah kode berikutnya dari tindakan seperti memperbarui DOM untuk menampilkan navigasi halaman yang sekarang tidak valid.
Berikut adalah contoh sebelumnya, tetapi dengan getArticleContent
yang disisipkan, yang menunjukkan cara AbortSignal
dapat digunakan dengan fetch()
:
navigation.addEventListener('navigate', navigateEvent => {
if (shouldNotIntercept(navigateEvent)) return;
const url = new URL(navigateEvent.destination.url);
if (url.pathname.startsWith('/articles/')) {
navigateEvent.intercept({
async handler() {
// The URL has already changed, so quickly show a placeholder.
renderArticlePagePlaceholder();
// Then fetch the real data.
const articleContentURL = new URL(
'/get-article-content',
location.href
);
articleContentURL.searchParams.set('path', url.pathname);
const response = await fetch(articleContentURL, {
signal: navigateEvent.signal,
});
const articleContent = await response.json();
renderArticlePage(articleContent);
},
});
}
});
Penanganan scroll
Saat Anda intercept()
navigasi, browser akan mencoba menangani scroll secara otomatis.
Untuk navigasi ke entri histori baru (jika navigationEvent.navigationType
adalah "push"
atau "replace"
), ini berarti mencoba men-scroll ke bagian yang ditunjukkan oleh fragmen URL (bit setelah #
), atau mereset scroll ke bagian atas halaman.
Untuk pemuatan ulang dan penelusuran, ini berarti memulihkan posisi scroll ke posisi terakhir kali entri histori ini ditampilkan.
Secara default, hal ini terjadi setelah promise yang ditampilkan oleh handler
Anda diselesaikan, tetapi jika lebih masuk akal untuk men-scroll lebih awal, Anda dapat memanggil navigateEvent.scroll()
:
navigation.addEventListener('navigate', navigateEvent => {
if (shouldNotIntercept(navigateEvent)) return;
const url = new URL(navigateEvent.destination.url);
if (url.pathname.startsWith('/articles/')) {
navigateEvent.intercept({
async handler() {
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);
navigateEvent.scroll();
const secondaryContent = await getSecondaryContent(url.pathname);
addSecondaryContent(secondaryContent);
},
});
}
});
Atau, Anda dapat memilih untuk tidak menggunakan penanganan scroll otomatis sepenuhnya dengan menetapkan opsi scroll
dari intercept()
ke "manual"
:
navigateEvent.intercept({
scroll: 'manual',
async handler() {
// …
},
});
Penanganan fokus
Setelah promise yang ditampilkan oleh handler
Anda diselesaikan, browser akan memfokuskan elemen pertama dengan atribut autofocus
yang ditetapkan, atau elemen <body>
jika tidak ada elemen yang memiliki atribut tersebut.
Anda dapat memilih untuk tidak mengikuti perilaku ini dengan menetapkan opsi focusReset
dari intercept()
ke "manual"
:
navigateEvent.intercept({
focusReset: 'manual',
async handler() {
// …
},
});
Peristiwa sukses dan gagal
Saat pengendali intercept()
Anda dipanggil, salah satu dari dua hal berikut akan terjadi:
- Jika
Promise
yang ditampilkan terpenuhi (atau Anda tidak memanggilintercept()
), Navigation API akan mengaktifkan"navigatesuccess"
denganEvent
. - Jika
Promise
yang ditampilkan ditolak, API akan mengaktifkan"navigateerror"
denganErrorEvent
.
Peristiwa ini memungkinkan kode Anda menangani keberhasilan atau kegagalan dengan cara terpusat. Misalnya, Anda dapat menangani keberhasilan dengan menyembunyikan indikator progres yang ditampilkan sebelumnya, seperti ini:
navigation.addEventListener('navigatesuccess', event => {
loadingIndicator.hidden = true;
});
Atau, Anda dapat menampilkan pesan error saat gagal:
navigation.addEventListener('navigateerror', event => {
loadingIndicator.hidden = true; // also hide indicator
showMessage(`Failed to load page: ${event.message}`);
});
Pemroses peristiwa "navigateerror"
, yang menerima ErrorEvent
, sangat berguna karena dijamin akan menerima error dari kode Anda yang menyiapkan halaman baru.
Anda cukup await fetch()
mengetahui bahwa jika jaringan tidak tersedia, error pada akhirnya akan dirutekan ke "navigateerror"
.
Entri navigasi
navigation.currentEntry
menyediakan akses ke entri saat ini.
Ini adalah objek yang menjelaskan lokasi pengguna saat ini.
Entri ini mencakup URL saat ini, metadata yang dapat digunakan untuk mengidentifikasi entri ini dari waktu ke waktu, dan status yang disediakan developer.
Metadata menyertakan key
, properti string unik dari setiap entri yang mewakili entri saat ini dan slot-nya.
Kunci ini tetap sama meskipun URL atau status entri saat ini berubah.
Masih berada di slot yang sama.
Sebaliknya, jika pengguna menekan Kembali, lalu membuka kembali halaman yang sama, key
akan berubah karena entri baru ini membuat slot baru.
Bagi developer, key
berguna karena Navigation API memungkinkan Anda mengarahkan pengguna langsung ke entri dengan kunci yang cocok.
Anda dapat menyimpannya, bahkan dalam status entri lain, untuk beralih antar-halaman dengan mudah.
// On JS startup, get the key of the first loaded page
// so the user can always go back there.
const {key} = navigation.currentEntry;
backToHomeButton.onclick = () => navigation.traverseTo(key);
// Navigate away, but the button will always work.
await navigation.navigate('/another_url').finished;
Negara Bagian
Navigation API menampilkan konsep "status", yang merupakan informasi yang disediakan developer dan disimpan secara persisten di entri histori saat ini, tetapi tidak terlihat langsung oleh pengguna.
Ini sangat mirip dengan, tetapi lebih baik dari, history.state
di History API.
Di Navigation API, Anda dapat memanggil metode .getState()
entri saat ini (atau entri apa pun) untuk menampilkan salinan statusnya:
console.log(navigation.currentEntry.getState());
Secara default, nilainya adalah undefined
.
Menetapkan status
Meskipun objek status dapat diubah, perubahan tersebut tidak disimpan kembali dengan entri histori, sehingga:
const state = navigation.currentEntry.getState();
console.log(state.count); // 1
state.count++;
console.log(state.count); // 2
// But:
console.info(navigation.currentEntry.getState().count); // will still be 1
Cara yang benar untuk menetapkan status adalah selama navigasi skrip:
navigation.navigate(url, {state: newState});
// Or:
navigation.reload({state: newState});
Dengan newState
dapat berupa objek yang dapat di-clone.
Jika Anda ingin memperbarui status entri saat ini, sebaiknya lakukan navigasi yang menggantikan entri saat ini:
navigation.navigate(location.href, {state: newState, history: 'replace'});
Kemudian, pemroses peristiwa "navigate"
Anda dapat mengambil perubahan ini melalui navigateEvent.destination
:
navigation.addEventListener('navigate', navigateEvent => {
console.log(navigateEvent.destination.getState());
});
Memperbarui status secara sinkron
Umumnya, sebaiknya perbarui status secara asinkron melalui navigation.reload({state: newState})
, lalu pemroses "navigate"
Anda dapat menerapkan status tersebut. Namun, terkadang perubahan status telah diterapkan sepenuhnya pada saat kode Anda mengetahuinya, seperti saat pengguna mengalihkan elemen <details>
, atau pengguna mengubah status input formulir. Dalam kasus ini, Anda mungkin ingin memperbarui status sehingga perubahan ini dipertahankan melalui pemuatan ulang dan traversal. Hal ini dapat dilakukan menggunakan updateCurrentEntry()
:
navigation.updateCurrentEntry({state: newState});
Ada juga acara untuk mengetahui perubahan ini:
navigation.addEventListener('currententrychange', () => {
console.log(navigation.currentEntry.getState());
});
Namun, jika Anda bereaksi terhadap perubahan status di "currententrychange"
, Anda mungkin memisahkan atau bahkan menduplikasi kode penanganan status antara peristiwa "navigate"
dan peristiwa "currententrychange"
, sedangkan navigation.reload({state: newState})
akan memungkinkan Anda menanganinya di satu tempat.
Status vs. parameter URL
Karena status dapat berupa objek terstruktur, Anda mungkin ingin menggunakannya untuk semua status aplikasi. Namun, dalam banyak kasus, sebaiknya simpan status tersebut di URL.
Jika Anda ingin status dipertahankan saat pengguna membagikan URL kepada pengguna lain, simpan status tersebut di URL. Jika tidak, objek status adalah opsi yang lebih baik.
Mengakses semua entri
Namun, "entri saat ini" bukanlah satu-satunya.
API ini juga menyediakan cara untuk mengakses seluruh daftar entri yang telah dibuka pengguna saat menggunakan situs Anda melalui panggilan navigation.entries()
, yang menampilkan array snapshot entri.
Hal ini dapat digunakan untuk, misalnya, menampilkan UI yang berbeda berdasarkan cara pengguna membuka halaman tertentu, atau hanya untuk melihat kembali URL sebelumnya atau statusnya.
Hal ini tidak mungkin dilakukan dengan History API saat ini.
Anda juga dapat memproses peristiwa "dispose"
di setiap NavigationHistoryEntry
, yang diaktifkan saat entri tidak lagi menjadi bagian dari histori browser. Hal ini dapat terjadi sebagai bagian dari pembersihan umum, tetapi juga terjadi saat menavigasi. Misalnya, jika Anda menavigasi kembali 10 tempat, lalu menavigasi maju, 10 entri histori tersebut akan dihapus.
Contoh
Peristiwa "navigate"
diaktifkan untuk semua jenis navigasi, seperti yang disebutkan di atas.
(Sebenarnya ada lampiran panjang dalam spesifikasi untuk semua kemungkinan jenis.)
Meskipun untuk banyak situs, kasus yang paling umum adalah saat pengguna mengklik <a href="...">
, ada dua jenis navigasi yang lebih kompleks dan penting untuk dibahas.
Navigasi terprogram
Pertama adalah navigasi terprogram, yang menyebabkan navigasi oleh panggilan metode di dalam kode sisi klien Anda.
Anda dapat memanggil navigation.navigate('/another_page')
dari mana saja dalam kode untuk menyebabkan navigasi.
Hal ini akan ditangani oleh pemroses peristiwa terpusat yang terdaftar di pemroses "navigate"
, dan pemroses terpusat Anda akan dipanggil secara sinkron.
Ini dimaksudkan sebagai agregasi yang lebih baik dari metode lama seperti location.assign()
dan sejenisnya, serta metode History API pushState()
dan replaceState()
.
Metode navigation.navigate()
menampilkan objek yang berisi dua instance Promise
di { committed, finished }
.
Hal ini memungkinkan pemanggil menunggu hingga transisi "di-commit" (URL yang terlihat telah berubah dan NavigationHistoryEntry
baru tersedia) atau "selesai" (semua promise yang ditampilkan oleh intercept({ handler })
sudah selesai—atau ditolak, karena kegagalan atau didahului oleh navigasi lain).
Metode navigate
juga memiliki objek opsi, tempat Anda dapat menetapkan:
state
: status untuk entri histori baru, seperti yang tersedia melalui metode.getState()
diNavigationHistoryEntry
.history
: yang dapat ditetapkan ke"replace"
untuk mengganti entri histori saat ini.info
: objek yang akan diteruskan ke peristiwa navigasi melaluinavigateEvent.info
.
Secara khusus, info
dapat berguna untuk, misalnya, menunjukkan animasi tertentu yang menyebabkan halaman berikutnya muncul.
(Alternatifnya adalah menetapkan variabel global atau menyertakannya sebagai bagian dari #hash. Kedua opsi tersebut agak canggung.)
Secara khusus, info
ini tidak akan diputar ulang jika pengguna kemudian menyebabkan navigasi, misalnya, melalui tombol Kembali dan Maju.
Bahkan, dalam kasus tersebut, nilainya akan selalu undefined
.
navigation
juga memiliki sejumlah metode navigasi lainnya, yang semuanya menampilkan objek yang berisi { committed, finished }
.
Saya telah menyebutkan traverseTo()
(yang menerima key
yang menunjukkan entri tertentu dalam histori pengguna) dan navigate()
.
Ini juga mencakup back()
, forward()
, dan reload()
.
Semua metode ini ditangani—sama seperti navigate()
—oleh pemroses peristiwa "navigate"
terpusat.
Pengiriman Formulir
Kedua, pengiriman <form>
HTML melalui POST adalah jenis navigasi khusus, dan Navigation API dapat mencegatnya.
Meskipun menyertakan payload tambahan, navigasi masih ditangani secara terpusat oleh pemroses "navigate"
.
Pengiriman formulir dapat dideteksi dengan mencari properti formData
di NavigateEvent
.
Berikut adalah contoh yang mengubah pengiriman formulir apa pun menjadi formulir yang tetap berada di halaman saat ini melalui fetch()
:
navigation.addEventListener('navigate', navigateEvent => {
if (navigateEvent.formData && navigateEvent.canIntercept) {
// User submitted a POST form to a same-domain URL
// (If canIntercept is false, the event is just informative:
// you can't intercept this request, although you could
// likely still call .preventDefault() to stop it completely).
navigateEvent.intercept({
// Since we don't update the DOM in this navigation,
// don't allow focus or scrolling to reset:
focusReset: 'manual',
scroll: 'manual',
handler() {
await fetch(navigateEvent.destination.url, {
method: 'POST',
body: navigateEvent.formData,
});
// You could navigate again with {history: 'replace'} to change the URL here,
// which might indicate "done"
},
});
}
});
Apa yang kurang?
Meskipun pemroses peristiwa "navigate"
bersifat terpusat, spesifikasi Navigation API saat ini tidak memicu "navigate"
saat halaman dimuat pertama kali.
Dan untuk situs yang menggunakan Rendering Sisi Server (SSR) untuk semua status, hal ini mungkin tidak masalah—server Anda dapat menampilkan status awal yang benar, yang merupakan cara tercepat untuk mengirimkan konten kepada pengguna.
Namun, situs yang memanfaatkan kode sisi klien untuk membuat halamannya mungkin perlu membuat fungsi tambahan untuk melakukan inisialisasi halaman.
Pilihan desain yang disengaja lainnya dari Navigation API adalah bahwa API ini hanya beroperasi dalam satu frame—yaitu, halaman tingkat teratas, atau satu <iframe>
tertentu.
Hal ini memiliki sejumlah implikasi menarik yang didokumentasikan lebih lanjut dalam spesifikasi, tetapi dalam praktiknya, akan mengurangi kebingungan developer.
History API sebelumnya memiliki sejumlah kasus ekstrem yang membingungkan, seperti dukungan untuk frame, dan Navigation API yang didesain ulang menangani kasus ekstrem ini sejak awal.
Terakhir, belum ada konsensus tentang cara mengubah atau mengatur ulang daftar entri yang telah dibuka pengguna secara terprogram. Hal ini saat ini sedang dibahas, tetapi salah satu opsinya adalah hanya mengizinkan penghapusan: entri historis atau "semua entri mendatang". Opsi kedua akan mengizinkan status sementara. Misalnya, sebagai developer, saya dapat:
- mengajukan pertanyaan kepada pengguna dengan membuka URL atau status baru
- mengizinkan pengguna menyelesaikan pekerjaannya (atau kembali)
- menghapus entri histori setelah tugas selesai
Hal ini sangat cocok untuk modal atau interstisial sementara: URL baru adalah sesuatu yang dapat digunakan pengguna dengan gestur Kembali untuk keluar, tetapi mereka tidak dapat secara tidak sengaja membukanya lagi dengan gestur Maju (karena entri telah dihapus). Hal ini tidak dapat dilakukan dengan History API saat ini.
Mencoba Navigation API
Navigation API tersedia di Chrome 102 tanpa flag. Anda juga dapat mencoba demo oleh Domenic Denicola.
Meskipun History API klasik tampak sederhana, API ini tidak terlalu jelas dan memiliki banyak masalah terkait kasus ekstrem dan cara penerapannya yang berbeda di seluruh browser. Kami harap Anda mempertimbangkan untuk memberikan masukan tentang Navigation API baru.
Referensi
Ucapan terima kasih
Terima kasih kepada Thomas Steiner, Domenic Denicola, dan Nate Chapin yang telah meninjau postingan ini.