Modern istemci tarafı yönlendirme: Navigation API

Tek sayfalık uygulama oluşturmayı tamamen revize eden yeni bir API aracılığıyla istemci taraflı yönlendirmenin standartlaştırılması.

Tarayıcı Desteği

  • Chrome: 102..
  • Kenar: 102..
  • Firefox: Desteklenmez..
  • Safari: desteklenmez..

Kaynak

Tek sayfalık uygulamalar veya SPA'lar temel bir özellikle tanımlanır: Sunucudan tamamen yeni sayfalar yüklemek için varsayılan yöntem yerine, kullanıcı siteyle etkileşim kurarken içeriklerini dinamik olarak yeniden yazmak.

SPA'lar bu özelliği size History API aracılığıyla (veya bazı durumlarda sitenin #karma kısmını düzenleyerek) sunabilse de, SPA'ların standart hale gelmesinden çok önce geliştirilmiş hantal bir API'dir ve web tamamen yeni bir yaklaşım için ısrarcıdır. Gezinme API'si, yalnızca History API'nin taslaklarına yama yapmaya çalışmak yerine bu alanı tamamen elden geçiren önerilen bir API'dir. (Örneğin, Kaydırma Geri Yükleme, yeniden tasarlamaya çalışmak yerine History API'ye yama uygulamıştır.)

Bu yayında, Navigasyon API'si üst düzeyde açıklanmaktadır. Teknik teklifi okumak isterseniz WICG deposundaki Taslak Rapor'a göz atabilirsiniz.

Örnek Kullanım

Gezinme API'sini kullanmak için genel navigation nesnesine bir "navigate" işleyici ekleyerek başlayın. Bu etkinlik temel olarak merkezidir: Kullanıcı bir işlem gerçekleştirdiğinde (ör.bir bağlantıyı tıklama, form gönderme, geri ve ileri gitme) veya gezinme, programatik olarak (ör. sitenizin kodu aracılığıyla) tetiklendiğinde her tür gezinme için tetiklenir. Çoğu durumda, bu işlem kodunuzun söz konusu işlem için tarayıcının varsayılan davranışını geçersiz kılmasına olanak tanır. SPA'lar için bu, muhtemelen kullanıcıyı aynı sayfada tutmak ve sitenin içeriğini yüklemek veya değiştirmek anlamına gelir.

"navigate" işleyicisine, gezinmeyle ilgili bilgileri (ör. hedef URL) içeren ve gezinme işlemine tek bir merkezi yerde yanıt vermenize olanak tanıyan bir NavigateEvent iletilir. Temel bir "navigate" dinleyicisi aşağıdaki gibi görünebilir:

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});
  }
});

Gezinmeyle ilgili olarak iki yöntemden birini kullanabilirsiniz:

  • Gezinmeyi gerçekleştirmek için intercept({ handler }) (yukarıda açıklandığı gibi) çağrılıyor.
  • preventDefault() aranıyor. Bu durumda navigasyon tamamen iptal edilebilir.
ziyaret edin.

Bu örnekte, etkinlikte intercept() çağrılmaktadır. Tarayıcı, handler geri aramanızı çağırır. Bu geri çağırma, sitenizin bir sonraki durumunu yapılandırır. Bu işlem, gezinmenin ilerlemesini izlemek için diğer kodların kullanabileceği bir geçiş nesnesi (navigation.transition) oluşturur.

Hem intercept() hem de preventDefault() genellikle izin verilir ancak çağrılamanın mümkün olmadığı durumlar vardır. Gezinme, kaynaklar arası gezinme ise intercept() üzerinden gerçekleştirilemez. Ayrıca kullanıcı tarayıcısında Geri veya İleri düğmesine basıyorsa preventDefault() üzerinden gezinmeyi iptal edemezsiniz; kullanıcılarınızı sitenize hapsetmemeniz gerekir. (Bu konu GitHub'da ele alınmaktadır.)

Navigasyonu durduramasanız veya müdahalede bulunamasanız bile "navigate" etkinliği yine de tetiklenir. Bilgilendirme amaçlıdır. Bu nedenle kodunuz, örneğin bir kullanıcının sitenizden ayrıldığını belirtmek için bir Analytics etkinliği kaydedebilir.

Neden platforma başka bir etkinlik eklemelisiniz?

"navigate" etkinlik işleyicisi, URL değişikliklerini bir SPA içindeki merkezi bir şekilde ele alır. Eski API'ler kullanıldığında bu zor bir tekliftir. Daha önce geçmiş API'sini kullanarak kendi SPA'nız için yönlendirme yazdıysanız aşağıdaki gibi bir kod eklemiş olabilirsiniz:

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));

Bu bir sorun değildir, ancak olası her örneğe yer verilmemiştir. Bağlantılar sayfanıza gelebilir veya sayfanıza gidebilir ve kullanıcıların sayfalarda gezinebileceği tek yol bunlar değildir. Örneğin, form gönderebilir ve hatta resim haritası kullanabilirler. Sayfanız bu sorunları yaşıyor olabilir, ancak sadeleştirilebilecek çok sayıda olasılık vardır. Yeni Navigation API bunu sağlar.

Ayrıca, yukarıdaki değişiklik geri-ileri gezinme işlemini gerçekleştirmez. Onun için başka bir etkinlik var "popstate".

Şahsen History API genellikle bu olasılıklar konusunda bir şekilde yardımcı olacak gibi geliyor. Ancak gerçekte yalnızca iki yüzey alanı vardır: kullanıcı tarayıcısında Geri veya İleri düğmesine bastığında yanıt verme, ayrıca URL'leri gönderme ve değiştirme. Yukarıda gösterildiği gibi, tıklama etkinlikleri için manuel olarak işleyiciler ayarladığınız durumlar dışında "navigate" ile benzer değildir.

Gezinmenin nasıl yapılacağına karar verme

navigateEvent, belirli bir gezinmeyi nasıl ele alacağınıza karar vermek için kullanabileceğiniz, gezinmeyle ilgili çok sayıda bilgi içerir.

Önemli özellikler şunlardır:

canIntercept
Bu yanlışsa gezinmeye müdahale edemezsiniz. Kaynaklar arası gezinmeler ve belgeler arası geçişlere müdahale edilemez.
destination.url
Muhtemelen navigasyonu kullanırken göz önünde bulundurulması gereken en önemli bilgidir.
hashChange
Gezinme bölümü aynı dokümansa ve karma, URL'nin geçerli URL'den farklı tek bölümüyse doğru değerini döndürür. Modern SPA'larda karma, geçerli belgenin farklı bölümlerine bağlantı vermek için kullanılmalıdır. Dolayısıyla, hashChange doğruysa muhtemelen bu gezinmede müdahale etmenize gerek yoktur.
downloadRequest
Bu doğruysa gezinme, download özelliğine sahip bir bağlantı tarafından başlatılmıştır. Çoğu durumda bu soruna müdahale etmenize gerek yoktur.
formData
Bu değer boş değilse gezinme işlevi POST formu gönderiminin bir parçasıdır. Gezinmeyi kullanırken bunu dikkate aldığınızdan emin olun. Yalnızca GET gezinmelerini işlemek istiyorsanız formData değerinin null olmadığı gezinmelere müdahale etmekten kaçının. Makalenin ilerleyen bölümlerinde form gönderimlerini yönetmeyle ilgili örneği inceleyin.
navigationType
Bu "reload", "push", "replace" veya "traverse" seçeneklerinden biri. "traverse" ise bu navigasyon preventDefault() üzerinden iptal edilemez.

Örneğin, ilk örnekte kullanılan shouldNotIntercept işlevi aşağıdaki gibi olabilir:

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
  );
}

Araya girme

Kodunuz "navigate" işleyicisinden intercept({ handler }) öğesini çağırdığında tarayıcıya artık sayfayı yeni ve güncellenmiş duruma hazırladığını ve gezinmenin biraz zaman alabileceğini bildirir.

Tarayıcı, işe geçerli durum için kaydırma konumunu yakalayarak başlar. Böylece, daha sonra isteğe bağlı olarak geri yüklenebilir. Ardından handler geri çağırmanızı çağırır. handler öğeniz eş zamansız işlevler ile otomatik olarak gelen bir söz döndürürse bu söz, tarayıcıya gezinmenin ne kadar sürdüğünü ve başarılı olup olmadığını bildirir.

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);
      },
    });
  }
});

Böylelikle bu API, tarayıcının anladığı anlamsal bir kavram sunar: Zaman içinde dokümanın önceki URL'si ve durumu yeni bir SPA gezinmesi gerçekleşmektedir. Bunun erişilebilirlik de dahil olmak üzere bir dizi potansiyel avantajı vardır: Tarayıcılar bir gezinmenin başlangıcını, sonunu veya olası hatasını gösterebilir. Örneğin Chrome, yerel yükleme göstergesini etkinleştirir ve kullanıcının durdur düğmesiyle etkileşimde bulunmasına olanak tanır. (Bu sorun, şu anda kullanıcı geri/ileri düğmeleriyle gezindiğinde yaşanmıyor, ancak yakında düzeltilecek.)

Gezinmelere müdahale ettiğinizde yeni URL, handler geri çağırmanız çağrılmadan hemen önce geçerli olur. DOM'yi hemen güncellemezseniz bu, eski içeriğin yeni URL ile birlikte görüntülendiği bir dönem oluşturur. Bu durum, veri getirirken veya yeni alt kaynaklar yüklerken göreli URL çözünürlüğü gibi durumları etkiler.

URL değişikliğini ertelemenin bir yolu GitHub'da tartışılıyor, ancak genellikle sayfayı gelen içerik için bir tür yer tutucuyla hemen güncellemeniz önerilir:

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);
      },
    });
  }
});

Bu hem URL çözümleme sorunlarını önler hem de kullanıcıya anında yanıt verdiğiniz için hızlıdır.

Sinyalleri iptal et

Bir intercept() işleyicide eşzamansız olarak çalışabildiğiniz için, gezinme gereksiz hale gelebilir. Bu, aşağıdaki durumlarda gerçekleşir:

  • Kullanıcı başka bir bağlantıyı tıklar veya bir kod başka bir gezinme gerçekleştirir. Bu durumda eski seyyar, yeni navigasyon lehine bırakılır.
  • Kullanıcı 'durdur'u tıklar tıklayın.

Bu olasılıklardan herhangi birini ele almak için "navigate" işleyiciye geçirilen etkinlik, AbortSignal olan bir signal özelliği içerir. Daha fazla bilgi için İptal edilebilir getirme bölümünü inceleyin.

Kısa versiyon temel olarak, çalışmanızı durdurmanız gerektiğinde bir etkinliği tetikleyen bir nesne sağlamasıdır. Özellikle, fetch() numaralı telefona yaptığınız tüm çağrılara AbortSignal iletebilir ve navigasyonun geçici olarak kesilmesi durumunda yayındaki ağ isteklerini iptal edebilirsiniz. Bu, hem kullanıcının bant genişliğini korur hem de fetch() tarafından döndürülen Promise öğesini reddeder. Böylece, DOM'yi güncelleme gibi işlemleri, sayfada artık geçersiz olan bir sayfayı gösterecek şekilde güncellemek gibi işlemler engellenir.

Aşağıda, AbortSignal öğesinin fetch() ile nasıl kullanılabileceğini gösteren, getArticleContent satır içi olarak oluşturulmuş önceki örnek verilmiştir:

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);
      },
    });
  }
});

Kaydırma işleme

Bir gezinme için intercept() işlemi gerçekleştirdiğinizde tarayıcı, kaydırmayı otomatik olarak işlemeye çalışır.

Yeni bir geçmiş girişine gitmede (navigationEvent.navigationType değeri "push" veya "replace" olduğunda), URL parçasının (# işaretinden sonraki bit) gösterdiği bölüme gitmeye çalışılması veya kaydırmanın sayfanın en üstüne sıfırlanması anlamına gelir.

Yeniden yükleme ve geçişlerde bu, kaydırma konumunun bu geçmiş girişinin en son görüntülendiği yere geri yüklenmesi anlamına gelir.

Varsayılan olarak bu, handler uygulamanız tarafından verilen söz çözümlendikten sonra gerçekleşir ancak daha önce kaydırmak mantıklıysa navigateEvent.scroll() çağırabilirsiniz:

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);
      },
    });
  }
});

Alternatif olarak, intercept() olan scroll seçeneğini "manual" şeklinde ayarlayarak otomatik kaydırma işlemeyi tamamen devre dışı bırakabilirsiniz:

navigateEvent.intercept({
  scroll: 'manual',
  async handler() {
    // …
  },
});

Odaklanma kullanımı

handler işlevinizin döndürdüğü taahhüt çözümlendikten sonra tarayıcı, autofocus özelliği ayarlanmış ilk öğeye veya bu özelliğe sahip bir öğe yoksa <body> öğesine odaklanır.

intercept() olan focusReset seçeneğini "manual" olarak ayarlayarak bu davranışı devre dışı bırakabilirsiniz:

navigateEvent.intercept({
  focusReset: 'manual',
  async handler() {
    // …
  },
});

Başarı ve başarısızlık etkinlikleri

intercept() işleyiciniz çağrıldığında iki şeyden biri olur:

  • Döndürülen Promise değeri karşılanırsa (veya intercept() çağrısı yapmadıysanız) Navigasyon API'si, "navigatesuccess" öğesini bir Event ile tetikler.
  • Döndürülen Promise reddederse API "navigateerror" öğesini bir ErrorEvent ile etkinleştirir.

Bu etkinlikler, kodunuzun başarı veya başarısızlıkla merkezi bir şekilde ilgilenmesini sağlar. Örneğin, önceden görüntülenen bir ilerleme durumu göstergesini aşağıdaki gibi gizleyerek başarıyı yakalayabilirsiniz:

navigation.addEventListener('navigatesuccess', event => {
  loadingIndicator.hidden = true;
});

Hata durumunda bir hata mesajı da görüntüleyebilirsiniz:

navigation.addEventListener('navigateerror', event => {
  loadingIndicator.hidden = true; // also hide indicator
  showMessage(`Failed to load page: ${event.message}`);
});

Yeni bir sayfa oluşturan kodunuzdan hata alacağı garanti edildiğinden ErrorEvent alan "navigateerror" etkinlik işleyicisi özellikle kullanışlıdır. Ağ kullanılamıyorsa hatanın sonunda "navigateerror" adresine yönlendirileceğini bilerek await fetch().

navigation.currentEntry, geçerli girişe erişim sağlar. Bu, kullanıcının o anda nerede olduğunu açıklayan bir nesnedir. Bu giriş; mevcut URL'yi, bu girişi zaman içinde tanımlamak için kullanılabilecek meta verileri ve geliştirici tarafından sağlanan durumu içerir.

Meta veriler, her bir girişin geçerli girişi ve alanını temsil eden benzersiz bir dize özelliği olan key içerir. Bu anahtar, geçerli girişin URL'si veya durumu değişse bile aynı kalır. Hâlâ aynı aralıkta. Buna karşılık, kullanıcı Geri düğmesine bastıktan sonra aynı sayfayı yeniden açarsa bu yeni giriş yeni bir alan oluşturdukça key değişir.

Navigasyon API'si, kullanıcıyı eşleşen bir anahtara sahip bir girişe doğrudan yönlendirmenize olanak tanıdığından key, geliştiriciler için yararlıdır. Sayfalar arasında kolayca geçiş yapmak için, diğer girişlerin durumunda bile bu öğeyi elinizde tutabilirsiniz.

// 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;

Eyalet

Gezinme API'si bir "durum" kavramını gösterir. Bu, geliştirici tarafından sağlanan ve geçerli geçmiş girişinde kalıcı olarak saklanan, ancak kullanıcının doğrudan göremediği bilgilerdir. Bu, History API'deki history.state özelliğine çok benzer ancak ondan iyileştirilmiştir.

Gezinme API'sinde geçerli girişin (veya herhangi bir girişin) .getState() yöntemini çağırarak durumunun bir kopyasını döndürebilirsiniz:

console.log(navigation.currentEntry.getState());

Bu, varsayılan olarak undefined değerine ayarlanır.

Ayar durumu

Durum nesnelerinde değişiklik yapılabilir, ancak bu değişiklikler geçmiş girişine geri kaydedilmez. Dolayısıyla:

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

Durumu ayarlamanın doğru yolu komut dosyası gezinmesi sırasındadır:

navigation.navigate(url, {state: newState});
// Or:
navigation.reload({state: newState});

Burada newState, herhangi bir klonlanabilir nesne olabilir.

Geçerli girişin durumunu güncellemek istiyorsanız en iyi yöntem, geçerli girişin yerine geçen bir gezinme gerçekleştirmektir:

navigation.navigate(location.href, {state: newState, history: 'replace'});

Ardından, "navigate" etkinlik işleyiciniz bu değişikliği navigateEvent.destination üzerinden alabilir:

navigation.addEventListener('navigate', navigateEvent => {
  console.log(navigateEvent.destination.getState());
});

Durumu eşzamanlı olarak güncelleme

Genellikle durumu navigation.reload({state: newState}) aracılığıyla eşzamansız olarak güncellemek daha iyidir. Sonrasında "navigate" işleyiciniz bu durumu uygulayabilir. Bununla birlikte, bazen durum değişikliği, kodunuzun duyulduğu ana kadar tam olarak uygulanmıştır (ör. kullanıcının bir <details> öğesini değiştirmesi veya bir form girişinin durumunu değiştirmesi). Bu gibi durumlarda, durumu güncelleyerek bu değişikliklerin yeniden yüklemeler ve geçişler yoluyla korunmasını sağlamak isteyebilirsiniz. Bu, updateCurrentEntry() kullanıldığında mümkündür:

navigation.updateCurrentEntry({state: newState});

Bu değişikliği öğrenebileceğiniz bir etkinlik de var:

navigation.addEventListener('currententrychange', () => {
  console.log(navigation.currentEntry.getState());
});

Ancak "currententrychange" etkinliğindeki durum değişikliklerine tepki verdiğinizi fark ederseniz, durum işleme kodunuzu "navigate" etkinliği ile "currententrychange" etkinliği arasında bölüyor ve hatta çoğaltıyor olabilirsiniz. navigation.reload({state: newState}) ise bu işlemi tek bir yerde gerçekleştirmenizi sağlar.

Durum ve URL parametreleri

Durum, yapılandırılmış bir nesne olabileceğinden, tüm uygulama durumunuz için onu kullanmak cazip bir fikirdir. Ancak birçok durumda bu durumu URL'de depolamak daha iyidir.

Kullanıcı URL'yi başka bir kullanıcıyla paylaştığında durumun korunmasını bekliyorsanız bunu URL'de depolayın. Aksi takdirde, durum nesnesi daha iyi seçenektir.

Tüm girişlere erişme

"Geçerli giriş" hepsi mümkün değildir. API, bir kullanıcının sitenizi kullanırken gezindiği giriş listesinin tamamına, girişlerin anlık görüntüsünü döndüren bir navigation.entries() çağrısı ile erişmek için de bir yol sunar. Örneğin, kullanıcının belirli bir sayfaya nasıl gittiğine bağlı olarak farklı bir kullanıcı arayüzü göstermek veya yalnızca önceki URL'lere ya da durumlarına bakmak için kullanılabilir. Mevcut History API ile bu mümkün değildir.

Ayrıca, bağımsız NavigationHistoryEntry öğelerindeki "dispose" etkinliğini dinleyebilirsiniz. Bu etkinlik, giriş artık tarayıcı geçmişinin parçası olmadığında tetiklenir. Bu durum, genel temizlik için yapılabileceği gibi rotayı izlerken de yaşanabilir. Örneğin, 10 yer geriye gidip ileri giderseniz, bu 10 geçmiş girişi silinir.

Örnekler

"navigate" etkinliği, yukarıda belirtildiği gibi tüm gezinme türleri için tetiklenir. (Aslında olası tüm türlerin özelliklerinde uzun bir ek vardır.)

Birçok sitede en yaygın durum kullanıcının <a href="..."> tıklaması olsa da ele alınması gereken iki önemli ve daha karmaşık gezinme türü vardır.

Programatik gezinme

Birincisi, programatik gezinmedir. Bu yöntemde gezinme, istemci tarafı kodunuzun içindeki bir yöntem çağrısından kaynaklanır.

Gezinme sağlamak için kodunuzdaki herhangi bir yerden navigation.navigate('/another_page') yöntemini çağırabilirsiniz. Bu işlem, "navigate" işleyiciye kayıtlı merkezi etkinlik işleyici tarafından işlenir ve merkezi dinleyiciniz eşzamanlı olarak çağrılır.

Bunun amacı, location.assign() ve arkadaşları gibi eski yöntemlerin yanı sıra History API'sinin pushState() ve replaceState() yöntemlerini daha iyi bir şekilde toplamaktır.

navigation.navigate() yöntemi, { committed, finished } içinde iki Promise örneği içeren bir nesne döndürür. Bu, çağırıcının, geçişten herhangi biri "taahhüt edilene" kadar bekleyebilmesini sağlar (görünür URL değişti ve yeni bir NavigationHistoryEntry kullanılabilir) veya "tamamlandı" (intercept({ handler }) tarafından verilen tüm vaatler tamamlandıysa veya başarısız oldukları ya da başka bir gezinme tarafından engellendikleri için reddedildi).

navigate yöntemi, şunları ayarlayabileceğiniz bir seçenekler nesnesini de içerir:

  • state: NavigationHistoryEntry üzerinde .getState() yöntemi ile bulunduğu şekliyle yeni geçmiş girişinin durumu.
  • history: Bu değer, geçerli geçmiş girişinin yerini alması için "replace" olarak ayarlanabilir.
  • info: navigateEvent.info aracılığıyla gezinme etkinliğine aktarılacak bir nesne.

Özellikle, info örneğin, sonraki sayfanın görünmesine neden olan belirli bir animasyonu göstermek için yararlı olabilir. (Alternatif olarak, bir genel değişken ayarlayabilir veya bunu #hash özelliğinin bir parçası olarak dahil edebilirsiniz. Her iki seçenek de biraz tuhaf.) Bu info, kullanıcı daha sonra gezinmeye neden olursa (ör. Geri ve İleri düğmeleriyle) tekrar oynatılmaz. Hatta bu gibi durumlarda bu değer her zaman undefined olur.

Soldan veya sağdan açma tanıtımı

navigation, bir dizi başka gezinme yöntemine de sahiptir. Bunların tümü { committed, finished } içeren bir nesne döndürür. traverseTo() (kullanıcının geçmişinde belirli bir girişi temsil eden bir key kabul edilir) ve navigate() konusundan daha önce bahsettim. Ayrıca back(), forward() ve reload() dahildir. Bu yöntemlerin tümü, navigate() gibi merkezi "navigate" etkinlik işleyici tarafından işlenir.

Form Gönderimleri

İkinci olarak, POST aracılığıyla HTML <form> gönderimi özel bir gezinme türüdür ve Gezinme API'si buna müdahale edebilir. Ek bir yük içerse de navigasyon, "navigate" dinleyicisi tarafından merkezi olarak yürütülmeye devam eder.

Form gönderimi, NavigateEvent içindeki formData özelliği aratılarak algılanabilir. Aşağıda, herhangi bir form göndermeyi fetch() aracılığıyla geçerli sayfada kalan bir forma dönüştüren bir örnek verilmiştir:

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"
      },
    });
  }
});

Eksikler

"navigate" etkinlik işleyicisinin merkezi yapısına rağmen, geçerli Navigation API spesifikasyonu bir sayfanın ilk yüklemesinde "navigate" öğesini tetiklemez. Tüm durumlar için Sunucu Tarafı Oluşturma (SSR) kullanan siteler için de bu sorun olabilir. Sunucunuz doğru başlangıç durumunu döndürebilir. Bu, kullanıcılarınıza içerik almanın en hızlı yoludur. Ancak sayfalarını oluşturmak için istemci taraflı koddan yararlanan sitelerin, sayfalarını başlatmak için ek bir işlev oluşturması gerekebilir.

Gezinme API'sinin bilinçli bir başka tasarım seçimi, yalnızca tek bir çerçeve içinde (yani üst düzey sayfa veya belirli bir <iframe>) çalışmasıdır. Bunun, spesifikasyonda daha ayrıntılı olarak açıklanmış bir dizi ilginç etkisi vardır, ancak pratikte geliştiricilerin kafa karışıklığını azaltacaktır. Önceki History API, çerçeve desteği gibi bir dizi kafa karıştırıcı uç durum içerir ve yeniden tasarlanmış Navigation API bu uç durumları en başından itibaren ele alır.

Son olarak, kullanıcının gezindiği girişlerin listesinin programlı bir şekilde değiştirilmesi veya yeniden düzenlenmesi konusunda henüz fikir birliği yoktur. Bu konu şu anda tartışılmaktadır ancak seçeneklerden biri, yalnızca silme işlemlerine izin vermek olabilir: geçmiş girişler veya "gelecekteki tüm girişler". İkincisi ise geçici duruma izin verir. Örneğin, bir geliştirici olarak şunları yapabilirim:

  • yeni URL'ye giderek veya duruma giderek kullanıcıya soru sormak
  • kullanıcının işini tamamlamasına (veya Geri Dönmesine) izin verme
  • görev tamamlandığında geçmiş girişini kaldırma

Bu, geçici kalıcı öğeler veya geçiş reklamları için mükemmel olabilir: Yeni URL, kullanıcının gitmek için Geri hareketini kullanabileceği bir şeydir, ancak kullanıcı yanlışlıkla İleri'ye gidip tekrar açamaz (çünkü giriş kaldırılmış). Bu, mevcut History API ile mümkün değildir.

Navigasyon API'sini deneyin

Gezinme API'si, Chrome 102'de bayraklar olmadan kullanılabilir. Ayrıca Domenic Denicola'nın demosunu da deneyebilirsiniz.

Klasik History API basit gibi görünse de çok iyi tanımlanmamıştır, köşe durumlarıyla ve tarayıcılarda nasıl farklı şekilde uygulandığıyla ilgili birçok sorun içerir. Yeni Navigation API ile ilgili geri bildirimde bulunmanızı umuyoruz.

Referanslar

Teşekkür

Bu gönderiyi değerlendirdikleri için Thomas Steiner, Domenic Denicola ve Nate Chapin'e teşekkür ederiz. Jeremy Zero'dan Unsplash'teki hero resim.