Modern istemci tarafı yönlendirme: Navigation API

Tek sayfalık uygulamaları tamamen yenileyen yepyeni bir API aracılığıyla istemci taraflı yönlendirmenin standartlaştırılması.

Tarayıcı desteği

  • Chrome: 102.
  • Edge: 102.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

Tek sayfalı uygulamalar (SPA'lar) temel bir özellikle tanımlanır: Varsayılan yöntem olan sunucudan tamamen yeni sayfalar yüklemek yerine, kullanıcı siteyle etkileşim kurarken içeriğini dinamik olarak yeniden yazar.

SPA'lar, History API aracılığıyla (veya sınırlı durumlarda sitenin #hash bölümünü ayarlayarak) bu özelliği sunabilse de History API, SPA'ların yaygınlaşmasından çok önce geliştirilmiş hantal bir API'dir ve web'de tamamen yeni bir yaklaşıma ihtiyaç duyulmaktadır. Navigation API, History API'nin eksikliklerini gidermeye çalışmak yerine bu alanı tamamen yenileyen önerilen bir API'dir. (Örneğin, Kaydırma Geri Yükleme, History API'yi yeniden icat etmeye çalışmak yerine bu API'ye bir yama uyguladı.)

Bu yayında, Gezinme API'si genel hatlarıyla açıklanmaktadır. Teknik öneriyi okumak için WICG deposundaki taslak raporu inceleyin.

Ö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, kodunuzun tarayıcının ilgili işlem için 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" dinleyicisine, hedef URL gibi gezinmeyle ilgili bilgileri içeren ve gezinmeye tek bir merkezi yerden 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 işlemleri iki şekilde yapabilirsiniz:

  • Gezinmeyi yönetmek için intercept({ handler }) (yukarıda açıklandığı gibi) çağrılıyor.
  • preventDefault() çağrısı yaparak navigasyonu tamamen iptal edebilirsiniz.

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

Genellikle hem intercept() hem de preventDefault()'e izin verilir ancak çağrılamayacakları durumlar da vardır. Gezinme kaynaktan farklı bir kaynaktaysa intercept() aracılığıyla gezinmeleri işleyemezsiniz. Ayrıca, kullanıcı tarayıcısında Geri veya İleri düğmelerine basıyorsa preventDefault() aracılığıyla gezinmeyi iptal edemezsiniz. Kullanıcılarınızı sitenizde hapsetmemeniz gerekir. (Bu konu GitHub'da ele alınmaktadır.)

Navigasyonu durduramaz veya durduramazsanız bile "navigate" etkinliği tetiklenir. Bilgilendirici olduğundan kodunuz, örneğin bir kullanıcının sitenizden ayrıldığını belirtmek için bir Analytics etkinliği günlüğe kaydedebilir.

Platforma neden başka bir etkinlik eklemelisiniz?

"navigate" etkinlik işleyicisi, URL değişikliklerini bir SPA içindeki merkezi bir şekilde ele alır. Bu, eski API'leri kullananlar için zor bir tekliftir. History API'yi kullanarak kendi SPA'nızın yönlendirmesini 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 iyi bir başlangıç olsa da yeterli değildir. Sayfanızdaki bağlantılar gelip gidebilir. Ayrıca, kullanıcıların sayfalar arasında gezinmesinin tek yolu bağlantılar değildir. Örneğin, bir form gönderebilir veya hatta resim haritası kullanabilirler. Sayfanız bu işlemleri gerçekleştirebilir ancak basitleştirilebilecek çok sayıda olasılık vardır. Yeni Navigation API'nin yaptığı da budur.

Ayrıca, yukarıdaki yöntem geri/ileri gezinmeyi desteklemez. Bunun için başka bir etkinlik var "popstate".

Kişisel olarak, History API'nin bu olasılıklara yardımcı olabileceğini düşünüyorum. Ancak aslında yalnızca iki yüzey alanı vardır: Kullanıcının tarayıcısında Geri veya İleri tuşuna basması durumunda yanıt verme ve URL'leri gönderme ve değiştirme. Yukarıda gösterildiği gibi, tıklama etkinlikleri için dinleyicileri manuel olarak ayarlamanız dışında "navigate" ile benzerliği yoktur.

Gezinme öğelerini nasıl ele alacağınıza karar verme

navigateEvent, belirli bir gezinmeyle nasıl başa çıkacağınıza karar vermek için kullanabileceğiniz gezinme hakkında çok sayıda bilgi içerir.

Önemli özellikler şunlardır:

canIntercept
Bu yanlışsa gezinmeye müdahale edemezsiniz. Kaynaklar arası gezinmeler ve dokümanlar arası geçişler engellenemez.
destination.url
Gezinmeyle ilgili dikkate almanız gereken en önemli bilgi muhtemelen budur.
hashChange
Gezinme aynı dokümandaysa ve karma oluşturma işlemi, URL'nin mevcut URL'den farklı olan tek parçasıysa doğru değerini döndürür. Modern SPA'larda karma oluşturma işlemi, geçerli dokümanın farklı bölümlerine bağlantı oluşturmak için kullanılmalıdır. Dolayısıyla, hashChange doğruysa bu gezinme işlemini durdurmanız gerekmez.
downloadRequest
Bu doğruysa gezinme, download özelliğine sahip bir bağlantı tarafından başlatılmıştır. Çoğu durumda bu işlemi durdurmanız gerekmez.
formData
Bu değer null değilse bu gezinme, POST form gönderme işleminin bir parçasıdır. Gezinme sırasında bunu göz önünde bulundurun. Yalnızca GET gezinmelerini işlemek istiyorsanız formData değerinin null olmadığı gezinmelerin yolunu kesmekten kaçının. Makalenin ilerleyen bölümlerinde form gönderimlerini işlemeyle ilgili örneği inceleyin.
navigationType
Bu, "reload", "push", "replace" veya "traverse" değerlerinden biridir. "traverse" ise bu navigasyon preventDefault() üzerinden iptal edilemez.

Örneğin, ilk örnekte kullanılan shouldNotIntercept işlevi şöyle 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" dinleyicisinden intercept({ handler })'ü çağrdığında, sayfayı yeni ve güncellenmiş duruma hazırladığını ve gezinmenin biraz zaman alabileceğini tarayıcıya 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 uygulamanız, eş zamansız işlevler ile otomatik olarak gerçekleşen 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. Bu, erişilebilirlik de dahil olmak üzere çeşitli potansiyel avantajlara sahiptir: Tarayıcılar, 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 durdurma düğmesiyle etkileşimde bulunmasına olanak tanır. (Bu durum şu anda kullanıcı geri/ileri düğmelerini kullanarak gezinirken gerçekleşmiyor ancak yakında düzeltilecek.)

Gezinme işlemlerine müdahale edildiğinde yeni URL, handler geri çağırma işleviniz ç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 erteleme yöntemi GitHub'da tartışılmaktadır ancak genellikle sayfayı, gelen içerik için bir tür yer tutucu ile 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, URL çözümleme sorunlarını önlemekle kalmaz, kullanıcıya anında yanıt verdiğiniz için hızlı bir deneyim de sunar.

İptal sinyalleri

intercept() işleyicisinde eşzamansız çalışma yapabildiğiniz için gezinmenin gereksiz hale gelmesi mümkündür. Bu, şu durumlarda gerçekleşir:

  • Kullanıcı başka bir bağlantıyı tıklar veya bazı kodlar başka bir gezinme işlemi gerçekleştirir. Bu durumda, eski gezinme menüsü yeni gezinme menüsü lehine terk edilir.
  • Kullanıcı tarayıcıda "durdur" düğmesini tıklar.

Bu olasılıklardan herhangi biriyle başa çıkmak için "navigate" dinleyicisine iletilen etkinlik, AbortSignal olan bir signal mülkü içerir. Daha fazla bilgi için İptal edilebilir getirme bölümüne bakın.

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, önceki örnekte getArticleContent satır içine yerleştirilmiş şekilde gösterilmektedir. Bu örnekte, AbortSignal'un fetch() ile nasıl kullanılabileceği gösterilmektedir:

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 navigasyonu intercept() ettiğinizde tarayıcı, kaydırma işlemini otomatik olarak gerçekleştirmeye çalışır.

Yeni bir geçmiş girişine yapılan gezinmelerde (navigationEvent.navigationType "push" veya "replace" olduğunda), bu, URL parçasıyla (#'ten sonraki kısım) belirtilen bölüme kaydırmaya çalışma veya kaydırma çubuğunu sayfanın en üstüne sıfırlama anlamına gelir.

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

Bu işlem varsayılan olarak, handler tarafından döndürülen söz çözüldükten sonra gerçekleşir. Ancak daha önce kaydırmanın mantıklı olduğu durumlarda 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() {
    // …
  },
});

Odak işleme

handler tarafından döndürülen söz çözüldükten sonra tarayıcı, autofocus özelliği ayarlanmış ilk öğeyi veya bu özelliğe sahip öğe yoksa <body> öğesini odaklar.

intercept() 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 aşağıdaki iki durumdan biri gerçekleşir:

  • 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 tetikler.

Bu etkinlikler, kodunuzun başarı veya başarısızlıkla merkezi bir şekilde ilgilenmesini sağlar. Örneğin, daha önce gösterilen bir ilerleme göstergesini gizleyerek başarıyı ele alabilirsiniz.

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

ErrorEvent alan "navigateerror" etkinlik dinleyicisi, özellikle yeni bir sayfa oluşturan kodunuzdan hata alacağı garanti edildiği için kullanışlıdır. Ağ kullanılamıyorsa hatanın "navigateerror" adresine yönlendirileceğini bilerek await fetch() yapabilirsiniz.

navigation.currentEntry, geçerli girişe erişim sağlar. Bu, kullanıcının şu anda nerede olduğunu açıklayan bir nesnedir. Bu giriş, geçerli 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 girişin mevcut girişi ve yuvasını temsil eden benzersiz bir dize özelliği olan key öğesini içerir. Mevcut girişin URL&#39;si veya durumu değişse bile bu anahtar aynı kalır. Hâlâ aynı aralıkta. Buna karşılık, kullanıcı Geri tuşuna basıp aynı sayfayı yeniden açarsa bu yeni giriş yeni bir yuva oluşturduğundan key değişir.

Gezinme API'si, kullanıcıyı doğrudan eşleşen bir anahtara sahip bir girişe yönlendirmenize olanak tanıdığından key geliştiriciler için kullanışlıdır. Sayfalar arasında kolayca atlamak için diğer girişlerin durumlarında bile bu düğmeyi basılı 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

Navigation API, geliştirici tarafından sağlanan ve mevcut geçmiş girişinde kalıcı olarak depolanan ancak kullanıcı tarafından doğrudan görülemeyen bir "durum" kavramı sunar. Bu, History API'deki history.state özelliğine çok benzer ancak ondan iyileştirilmiştir.

Navigation API'de, mevcut girişin (veya herhangi bir girişin) .getState() yöntemini çağırarak durumunun bir kopyasını döndürebilirsiniz:

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

Varsayılan olarak bu değer undefined olur.

Ayar durumu

Durum nesneleri değiştirilebilir olsa da bu değişiklikler geçmiş girişiyle birlikte geri kaydedilmez. Bu nedenle:

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 ayarlamak için doğru yöntem, komut dosyasında gezinme sırasındadır:

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

Burada newState, herhangi bir kopyalanabilir nesne olabilir.

Mevcut girişin durumunu güncellemek istiyorsanız en iyi yöntem, mevcut girişin yerini alacak bir gezinme gerçekleştirmektir:

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

Ardından "navigate" etkinlik dinleyiciniz, navigateEvent.destination aracılığıyla bu değişikliği algılayabilir:

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

Durumu senkronize olarak güncelleme

Genellikle durumu navigation.reload({state: newState}) aracılığıyla asenkron olarak güncellemek daha iyidir. Ardından "navigate" dinleyiciniz bu durumu uygulayabilir. Bununla birlikte, bazen durum değişikliği, kodunuzun duyulduğu ana kadar tam olarak uygulanmıştır. Örneğin, kullanıcının bir <details> öğesini değiştirmesi veya bir form girişinin durumunu değiştirmesi gibi. Bu gibi durumlarda, bu değişikliklerin yeniden yükleme ve geçiş işlemleri sırasında korunması için durumu güncelleyebilirsiniz. Bu işlem updateCurrentEntry() kullanılarak yapılabilir:

navigation.updateCurrentEntry({state: newState});

Bu değişiklik hakkında bilgi edinmek için katılabileceğiniz bir etkinlik de düzenlenmektedir:

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

Ancak "currententrychange"'te 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 veya hatta kopyalıyorsunuz demektir. navigation.reload({state: newState}) ise bu işlemi tek bir yerde yapmanıza olanak tanır.

Eyalet ve URL parametreleri

Durum, yapılandırılmış bir nesne olabileceğinden tüm uygulama durumunuz için kullanmak cazip gelebilir. 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ı istiyorsanız durumu URL'de saklayın. Aksi takdirde, durum nesnesi daha iyi bir seçenektir.

Tüm girişlere erişme

Fakat "geçerli giriş" bunlardan ibaret değildir. API, kullanıcının sitenizi kullanırken gezindiği girişlerin tamamına erişmenize de olanak tanır. Bunun için navigation.entries() çağrısı kullanılır. Bu çağrı, girişlerin anlık görüntü dizisini döndürür. Bu, ö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ının geçmişine bakmak için kullanılabilir. Mevcut History API ile bu işlem mümkün değildir.

Ayrıca, giriş artık tarayıcı geçmişinin bir parçası olmadığında tetiklenen NavigationHistoryEntry'larda "dispose" etkinliğini de dinleyebilirsiniz. Bu durum, genel temizlik kapsamında olabileceği gibi gezinme sırasında da gerçekleşebilir. Örneğin, 10 yer geri 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, mümkün olan tüm türlerin spesifikasyonda yer aldığı uzun bir ek vardır.)

Birçok sitede en sık karşılaşılan 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 işlemi başlatmak için kodunuzun herhangi bir yerinden navigation.navigate('/another_page') işlevini ç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.

Bu, location.assign() ve arkadaşlar gibi eski yöntemlerin yanı sıra History API'nin pushState() ve replaceState() yöntemlerinin geliştirilmiş bir toplama işlemi olarak tasarlanmıştı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ş "taahhütlü" olana (görünür URL değiştirilen ve yeni bir NavigationHistoryEntry kullanıma sunulana) veya "tamamlanana" (intercept({ handler }) tarafından verilen tüm taahhütler tamamlanıncaya ya da başarısız olması veya başka bir gezinme tarafından engellenmesi nedeniyle reddedilmesi) kadar bekleyebileceği anlamına gelir.

navigate yönteminde, aşağıdakileri ayarlayabileceğiniz bir options nesnesi de vardır:

  • state: NavigationHistoryEntry üzerindeki .getState() yöntemi aracılığıyla kullanılabilen yeni geçmiş girişinin durumu.
  • history: Geçerli geçmiş girişini değiştirmek için "replace" olarak ayarlanabilir.
  • info: navigateEvent.info aracılığıyla gezinme etkinliğine iletilecek 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, global bir değişken ayarlayabilir veya #hash'in bir parçası olarak dahil edebilirsiniz. Her iki seçenek de biraz tuhaf.) Kullanıcı daha sonra Geri ve İleri düğmelerini kullanarak gezinme yaparsa bu info yeniden oynatılmaz. Aslında bu durumlarda her zaman undefined olur.

Sol veya sağdan açma demo'su

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ı geçmişindeki belirli bir girişi belirten bir key kabul eder) ve navigate() hakkında daha önce bahsetmiştik. 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 Navigation API bu işlemin önüne geçebilir. Ek bir yükü olsa da gezinme, "navigate" dinleyici tarafından merkezi olarak yönetilir.

Form gönderimi, NavigateEvent üzerinde formData mülkü aranarak algılanabilir. Aşağıda, herhangi bir form gönderimini fetch() aracılığıyla mevcut sayfada kalan bir gönderime 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 dinleyicisinin merkezi yapısına rağmen mevcut Navigation API spesifikasyonu, bir sayfanın ilk yüklenmesinde "navigate"'ü tetiklemez. Tüm durumlar için sunucu tarafı oluşturma (SSR) kullanan sitelerde bu sorun olmayabilir. Sunucunuz, kullanıcılarınıza içerik sunmanın en hızlı yolu olan doğru ilk durumu döndürebilir. Ancak sayfalarını oluşturmak için istemci tarafı kodundan yararlanan sitelerin, sayfalarını başlatmak için ek bir işlev oluşturması gerekebilir.

Gezinme API'sinin bilinçli bir tasarım tercihi de yalnızca tek bir çerçevede (yani en üst düzey sayfa veya tek bir belirli <iframe>) çalışmasıdır. Bu, özellikte daha ayrıntılı olarak açıklanan bir dizi ilginç sonucu beraberinde getirse de uygulamada geliştiricilerin kafa karışıklığını azaltacaktır. Önceki History API'de, çerçeve desteği gibi kafa karıştırıcı bazı uç durumlar vardır. Yeniden tasarlanan Navigation API ise bu uç durumları baştan ele alır.

Son olarak, kullanıcının gezindiği girişlerin listesini programatik olarak değiştirme veya yeniden düzenleme konusunda henüz bir fikir birliğine varılmadı. Bu konu şu anda tartışılıyor ancak yalnızca silme işlemlerine izin vermek (geçmiş girişler veya "gelecekteki tüm girişler") bir seçenek olabilir. İkincisi, geçici duruma izin verir. Örneğin, geliştirici olarak şunları yapabilirim:

  • Yeni URL'ye veya duruma giderek kullanıcıya soru sorabilirsiniz.
  • Kullanıcının işini tamamlamasına izin verin (veya Geri'ye gidin)
  • görev tamamlandığında geçmiş girişini kaldırma

Bu, geçici modallar veya geçiş reklamları için mükemmel olabilir: Yeni URL, kullanıcının Geri hareketini kullanarak ayrılabileceği bir URL'dir ancak kullanıcı, giriş kaldırıldığı için yanlışlıkla İleri'ye giderek URL'yi tekrar açamaz. Bu, mevcut History API ile mümkün değildir.

Navigation API'yi deneyin

Navigation API, Chrome 102'de flag olmadan kullanılabilir. Domenic Denicola tarafından hazırlanan bir demoyu da deneyebilirsiniz.

Klasik History API basit görünse de çok iyi tanımlanmamıştır ve uç durumlar ile tarayıcılar arasında farklı şekilde uygulanmasıyla ilgili çok sayıda soruna sahiptir. Yeni Navigation API ile ilgili geri bildirimde bulunacağınızı umuyoruz.

Referanslar

Teşekkür ederiz

Bu gönderiyi değerlendirdikleri için Thomas Steiner, Domenic Denicola ve Nate Chapin'e teşekkür ederiz.