Modern istemci tarafı yönlendirme: Navigation API

Tek sayfalık uygulamaların oluşturulmasını tamamen değiştiren yepyeni bir API aracılığıyla istemci tarafı yönlendirmesini standartlaştırma.

Jake Archibald
Jake Archibald

Browser Support

  • Chrome: 102.
  • Edge: 102.
  • Firefox: 147.
  • Safari: 26.2.

Source

Tek sayfalı uygulamalar (SPA), temel bir özellik ile tanımlanır: Kullanıcı siteyle etkileşimde bulundukça içeriklerini sunucudan tamamen yeni sayfalar yükleme şeklindeki varsayılan yöntem yerine dinamik olarak yeniden yazma.

Tek sayfa uygulamaları, History API (veya sınırlı durumlarda sitenin #hash bölümünü ayarlayarak) aracılığıyla bu özelliği sunabilse de bu, tek sayfa uygulamaları norm haline gelmeden çok önce geliştirilmiş kullanışsız bir API'dir ve web, tamamen yeni bir yaklaşım için can atıyor. Navigation API, History API'nin eksik yönlerini düzeltmeye çalışmak yerine bu alanı tamamen yenileyen bir API önerisidir. (Örneğin, Scroll Restoration, History API'yi yeniden icat etmeye çalışmak yerine yamaladı.)

Bu yayında, Navigation API genel hatlarıyla açıklanmaktadır. Teknik öneriyi okumak için WICG deposundaki Taslak Rapor'a bakın.

Örnek kullanım

Navigation API'yi kullanmak için işe global navigation nesnesine "navigate" dinleyici ekleyerek başlayın. Bu etkinlik temel olarak merkezi bir etkinliktir: Kullanıcı bir işlem gerçekleştirmiş olsun (ör.bağlantıyı tıklama, form gönderme veya geri ve ileri gitme) ya da gezinme programatik olarak (ör. sitenizin kodu aracılığıyla) tetiklenmiş olsun, her tür gezinme için etkinleşir. Çoğu durumda, kodunuzun bu 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 durum, kullanıcının aynı sayfada kalmasını ve sitenin içeriğinin yüklenmesini veya değiştirilmesini ifade eder.

Hedef URL gibi gezinmeyle ilgili bilgileri içeren bir NavigateEvent, "navigate" dinleyicisine iletilir. Bu sayede, gezinmeye tek bir merkezi yerden yanıt verebilirsiniz. Temel bir "navigate" dinleyicisi şu şekilde 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});
  }
});

Gezinme işlemini iki şekilde yapabilirsiniz:

  • Gezinmeyi yönetmek için intercept({ handler }) (yukarıda açıklandığı gibi) çağrısı yapın.
  • Arama preventDefault(): Navigasyonu tamamen iptal edebilir.

Bu örnek, etkinlikte intercept() işlevini çağırır. Tarayıcı, handler geri çağırma işlevinizi çağırır. Bu işlev, sitenizin bir sonraki durumunu yapılandırmalıdır. Bu işlem, diğer kodların gezinme ilerleme durumunu izlemek için kullanabileceği bir geçiş nesnesi (navigation.transition) oluşturur.

Hem intercept() hem de preventDefault() genellikle kullanılabilir ancak bazı durumlarda arama yapılamaz. Gezinme, kaynaklar arası bir gezinme ise intercept() üzerinden gezinmeleri işleyemezsiniz. Ayrıca, kullanıcı tarayıcısında Geri veya İleri düğmelerine basıyorsa preventDefault() üzerinden gezinmeyi iptal edemezsiniz. Kullanıcılarınızı sitenizde sıkıştırmamalısınız. (Bu konu GitHub'da tartışılmaktadır.)

Navigasyonu durduramasanız veya engelleyemeseniz bile "navigate" etkinliği tetiklenmeye devam eder. Bilgi vericidir. Örneğin kodunuz, kullanıcının sitenizden ayrıldığını belirtmek için bir Analytics etkinliği kaydedebilir.

Platforma neden başka bir etkinlik eklemelisiniz?

"navigate" etkinlik işleyici, SPA'daki URL değişikliklerinin işlenmesini merkezileştirir. Bu, eski API'ler kullanılarak zor bir şekilde önerilir. History API'yi kullanarak kendi SPA'nız için yönlendirme yazdıysanız şuna benzer 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 kapsamlı değildir. Sayfanızdaki bağlantılar değişebilir ve kullanıcıların sayfalar arasında gezinmesinin tek yolu bağlantılar değildir. Örneğin, bir form gönderebilir veya resim haritası kullanabilirler. Sayfanız bu durumlarla ilgileniyor olabilir ancak yeni Navigation API'nin basitleştirebileceği çok sayıda olasılık vardır.

Ayrıca, yukarıdaki kod geri/ileri gezinmeyi işlemez. Bu konuyla ilgili başka bir etkinlik var, "popstate".

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

Gezinmenin nasıl ele alınacağına karar verme

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

Temel özellikler şunlardır:

canIntercept
Bu değer yanlışsa gezinmeyi durduramazsınız. Kaynaklar arası gezinmeler ve dokümanlar arası geçişler engellenemez.
destination.url
Gezinmeyi yönetirken dikkate alınması gereken en önemli bilgi olabilir.
hashChange
Gezinme aynı dokümanda gerçekleşiyorsa ve URL'nin yalnızca karma bölümü geçerli URL'den farklıysa doğru. Modern tek sayfa uygulamalarında karma, geçerli belgenin farklı bölümlerine bağlantı vermek için kullanılmalıdır. Bu nedenle, hashChange doğruysa bu gezinmeyi muhtemelen durdurmanız gerekmez.
downloadRequest
Bu doğruysa gezinme, download özniteliğine sahip bir bağlantı tarafından başlatılmıştır. Çoğu durumda bu isteği yakalamanız gerekmez.
formData
Bu değer boş değilse gezinme, POST formu gönderiminin bir parçasıdır. Gezinme işlemini yaparken bunu dikkate aldığınızdan emin olun. Yalnızca GET gezinmelerini işlemek istiyorsanız formData değerinin boş olmadığı gezinmeleri engellemeyin. Makalenin ilerleyen bölümlerinde form gönderimlerinin nasıl işleneceğiyle ilgili örneği inceleyin.
navigationType
Bu, "reload", "push", "replace" veya "traverse" değerlerinden biridir. "traverse" ise bu gezinme preventDefault() üzerinden iptal edilemez.

Örneğin, ilk örnekte kullanılan shouldNotIntercept işlevi şu şekilde 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" dinleyicisi içinden intercept({ handler }) işlevini çağırdığında tarayıcıya sayfayı yeni ve güncellenmiş duruma hazırladığını ve gezinmenin biraz zaman alabileceğini bildirir.

Tarayıcı, mevcut durumun kaydırma konumunu yakalayarak başlar. Böylece, bu konum daha sonra isteğe bağlı olarak geri yüklenebilir. Ardından, handler geri çağırma işleviniz çağrılır. handler işleviniz bir söz döndürürse (async işlevlerinde bu işlem otomatik olarak gerçekleşir) bu söz, tarayıcıya gezinmenin ne kadar süreceğini 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);
      },
    });
  }
});

Bu nedenle, bu API, tarayıcının anladığı bir semantik kavramı sunar: Şu anda bir SPA gezinmesi gerçekleşiyor ve zaman içinde dokümanı önceki bir URL ve durumdan yeni bir URL ve duruma değiştiriyor. Bu durum, erişilebilirlik de dahil olmak üzere çeşitli avantajlar sunar: Tarayıcılar, gezinmenin başlangıcını, sonunu veya olası başarısızlığını gösterebilir. Örneğin Chrome, yerel yükleme göstergesini etkinleştirir ve kullanıcının durdurma düğmesiyle etkileşime geçmesine izin verir. (Bu durum, kullanıcının geri/ileri düğmelerini kullanarak gezinmesi sırasında şu anda gerçekleşmemektedir ancak yakında düzeltilecektir.)

Gezinmeler engellendiğinde yeni URL, handler geri çağırma işleviniz çağrılmadan hemen önce geçerli olur. DOM'u hemen güncellemezseniz eski içeriğin yeni URL ile birlikte görüntülendiği bir dönem oluşur. Bu durum, veri getirilirken veya yeni alt kaynaklar yüklenirken göreli URL çözümlemesi gibi işlemleri etkiler.

URL değişikliğini geciktirmenin 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 sayede hem URL çözümleme sorunları önlenir hem de kullanıcıya anında yanıt verdiğiniz için hızlı bir deneyim sunulur.

Durdurma sinyalleri

intercept() işleyicisinde eşzamansız çalışma yapabildiğiniz için gezinme gereksiz hale gelebilir. Bu durum aşağıdaki koşullarda ortaya çıkar:

  • Kullanıcı başka bir bağlantıyı tıkladığında veya bir kod başka bir gezinme işlemi gerçekleştirdiğinde Bu durumda, yeni gezinme özelliği için eski gezinme özelliği devre dışı bırakılır.
  • Kullanıcı, tarayıcıda "durdur" düğmesini tıklar.

Bu olasılıkların herhangi biriyle başa çıkmak için "navigate" dinleyicisine iletilen etkinlik, signal özelliğini içerir. Bu özellik bir AbortSignal. Daha fazla bilgi için Abortable fetch (İptal edilebilir getirme) konusuna bakın.

Kısaca, çalışmayı bırakmanız gerektiğinde bir etkinlik tetikleyen bir nesne sağlar. Özellikle, AbortSignal öğesini fetch() için yaptığınız tüm çağrılara iletebilirsiniz. Bu, gezinme önceden gerçekleşirse devam eden ağ isteklerini iptal eder. Bu işlem hem kullanıcının bant genişliğini korur hem de fetch() tarafından döndürülen Promise öğesini reddederek DOM'u güncelleme gibi sonraki kodların artık geçersiz olan bir sayfa gezinmesini göstermesini engeller.

Aşağıda, getArticleContent öğesinin satır içi olarak kullanıldığı önceki örnek verilmiştir. Bu örnekte, AbortSignal öğesinin 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 intercept() yaptığınızda tarayıcı, kaydırma işlemini otomatik olarak yapmaya çalışır.

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

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

Bu işlem, varsayılan olarak handler tarafından döndürülen söz çözüldüğünde gerçekleşir. Ancak daha önce kaydırmak mantıklıysa navigateEvent.scroll() işlevini ç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() seçeneğinin scroll kısmını "manual" olarak 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ümlendiğinde tarayıcı, autofocus özelliği ayarlanmış ilk öğeye veya hiçbir öğede bu özellik yoksa <body> öğesine odaklanır.

intercept() seçeneğinin focusReset bölümünü "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 durumdan biri gerçekleşir:

  • Döndürülen Promise, intercept()'yi karşılıyorsa (veya intercept()'yi çağırmadıysanız) Navigation API, Event ile "navigatesuccess"'yi tetikler.
  • Döndürülen Promise reddedilirse API, ErrorEvent ile "navigateerror" etkinliğini tetikler.

Bu etkinlikler, kodunuzun başarı veya başarısızlığı merkezi bir şekilde ele almasına olanak tanır. Örneğin, daha önce gösterilen bir ilerleme göstergesini gizleyerek başarıyla ilgili durumu ele alabilirsiniz:

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

Alternatif olarak, başarısızlık durumunda bir hata mesajı gösterebilirsiniz:

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

ErrorEvent alanını alan "navigateerror" etkinlik dinleyicisi, yeni bir sayfa oluşturan kodunuzdaki hataları almayı garanti ettiği için özellikle kullanışlıdır. Ağ kullanılamıyorsa hatanın sonunda "navigateerror"'e yönlendirileceğini bilerek await fetch().

navigation.currentEntry, mevcut 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, zaman içinde bu girişi tanımlamak için kullanılabilecek meta verileri ve geliştirici tarafından sağlanan durumu içerir.

Meta veriler, mevcut girişi ve yuvasını temsil eden her girişin benzersiz dize özelliği olan key içerir. Bu anahtar, mevcut girişin URL'si veya durumu değişse bile aynı kalır. Kartınız aynı yuvada kalır. Tersine, bir kullanıcı Geri düğmesine basıp aynı sayfayı yeniden açarsa bu yeni giriş yeni bir yuva oluşturduğundan key değişir.

Navigation API, kullanıcıyı doğrudan eşleşen anahtara sahip bir girişe yönlendirmenize olanak tanıdığı için key geliştiriciler için yararlıdır. Sayfalar arasında kolayca geçiş yapmak için diğer girişlerin durumlarında bile bu öğeyi 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, "durum" kavramını ortaya çıkarır. Bu, 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 bilgilerdir. Bu, History API'deki history.state'ye çok benzer ancak ondan daha gelişmiş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ştirilebilse de 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 ayarlamanın doğru yolu, komut dosyası gezinmesi sırasında gerçekleşir:

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

Burada newState, herhangi bir klonlanabilir nesne olabilir.

Mevcut girişin durumunu güncellemek istiyorsanız mevcut girişi değiştiren bir gezinme işlemi yapmanız en iyisidir:

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

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

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

Durumu senkron olarak güncelleme

Genellikle, durumu navigation.reload({state: newState}) aracılığıyla eşzamansız olarak güncellemek daha iyidir. Ardından "navigate" dinleyiciniz bu durumu uygulayabilir. Ancak bazen, kodunuz durum değişikliğini öğrendiğinde bu değişiklik zaten tamamen uygulanmış olur. Örneğin, kullanıcı bir <details> öğesini açıp kapattığında veya bir form girişinin durumunu değiştirdiğinde bu durum geçerlidir. Bu gibi durumlarda, yeniden yükleme ve geçişler sırasında bu değişikliklerin korunması için durumu güncellemek isteyebilirsiniz. Bu işlem için updateCurrentEntry() kullanılabilir:

navigation.updateCurrentEntry({state: newState});

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

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

Ancak "currententrychange" iç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 veya hatta kopyalıyor olabilirsiniz. navigation.reload({state: newState}) ise bu kodu tek bir yerde işlemenize olanak tanır.

Durum ve URL parametreleri

Durum yapılandırılmış bir nesne olabileceğinden, uygulama durumunuzun tamamı için kullanmak cazip gelebilir. Ancak çoğu durumda bu durumu URL'de saklamak daha iyidir.

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

Tüm girişlere erişme

Ancak "mevcut giriş" her şeyi kapsamaz. API, kullanıcının sitenizi kullanırken gezdiği girişlerin tamamına navigation.entries() çağrısı aracılığıyla erişme olanağı da sunar. 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ına geri dönmek için kullanılabilir. Mevcut History API ile bu mümkün değildir.

Ayrıca, giriş artık tarayıcı geçmişinin bir parçası olmadığında tetiklenen tek tek NavigationHistoryEntry'lerde "dispose" etkinliğini de dinleyebilirsiniz. Bu durum, genel temizliğin bir parçası olarak veya gezinirken 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 spesifikasyonda olası tüm türlerin yer aldığı uzun bir ek vardır.)

Çoğu site için 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, gezinmenin istemci tarafı kodunuzdaki bir yöntem çağrısından kaynaklandığı programatik gezinmedir.

Gezinmeye neden olmak için kodunuzun herhangi bir yerinden navigation.navigate('/another_page') işlevini çağırabilirsiniz. Bu, "navigate" işleyicisine kaydedilen merkezi etkinlik işleyicisi tarafından ele alınır ve merkezi işleyiciniz 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 yöntemi 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ğıranın geçiş "işlenene" (görünür URL değişmiş ve yeni bir NavigationHistoryEntry kullanılabilir) veya "tamamlanana" (intercept({ handler }) tarafından döndürülen tüm sözler tamamlanmış ya da başarısızlık nedeniyle veya başka bir gezinme tarafından öncelenerek reddedilmiş) kadar beklemesine olanak tanır.

navigate yönteminde, aşağıdakileri ayarlayabileceğiniz bir seçenekler nesnesi de bulunur:

  • state: NavigationHistoryEntry üzerindeki .getState() yöntemiyle kullanılabilen yeni geçmiş girişinin durumu.
  • history: Geçerli geçmiş girişinin yerine "replace" olarak ayarlanabilir.
  • info: navigateEvent.info aracılığıyla gezinme etkinliğine iletilecek bir nesne.

Özellikle info, örneğin bir sonraki sayfanın görünmesine neden olan belirli bir animasyonu belirtmek için yararlı olabilir. (Alternatif olarak, genel bir değişken ayarlayabilir veya bunu #hash'in bir parçası olarak ekleyebilirsiniz. Her iki seçenek de biraz garip.) Özellikle, kullanıcı daha sonra gezinmeye neden olursa (ör. Geri ve İleri düğmelerini kullanarak) bu info yeniden oynatılmaz. Hatta bu durumlarda her zaman undefined olur.

Soldan veya sağdan açılma demosu

navigation ayrıca, { committed, finished } içeren bir nesne döndüren başka gezinme yöntemlerine de sahiptir. traverseTo() (kullanıcının geçmişindeki belirli bir girişi belirten key değerini kabul eder) ve navigate() hakkında daha önce bilgi vermiştim. Ayrıca back(), forward() ve reload() de dahildir. Bu yöntemlerin tümü, navigate() gibi merkezi "navigate" etkinlik işleyici tarafından işlenir.

Form Gönderimleri

İkincisi, POST aracılığıyla HTML <form> gönderme, özel bir gezinme türüdür ve Navigation API bunu engelleyebilir. Ek bir yük içerse de gezinme işlemi yine merkezi olarak "navigate" dinleyici tarafından gerçekleştirilir.

Form gönderimi, NavigateEvent üzerinde formData özelliği aranarak algılanabilir. Burada, fetch() aracılığıyla herhangi bir form gönderimini geçerli sayfada kalan bir gönderime dönüştüren basit 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şleyicinin 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 durum sorun olmayabilir. Sunucunuz, içeriği kullanıcılarınıza ulaştırmanın en hızlı yolu olan doğru başlangıç durumunu 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.

Navigation API'nin bir diğer kasıtlı tasarım tercihi de yalnızca tek bir çerçeve içinde çalışmasıdır. Bu çerçeve, en üst düzey sayfa veya tek bir belirli <iframe> olabilir. Bu durum, spesifikasyonda daha ayrıntılı olarak belgelenen bir dizi ilginç etkiye sahiptir ancak uygulamada geliştiricilerin kafasını karıştırmaz. Önceki History API'de çerçeve desteği gibi kafa karıştırıcı uç durumlar vardı. Yeniden tasarlanan Navigation API ise bu uç durumları en başından ele alıyor.

Son olarak, kullanıcının gezindiği girişler listesinin programatik olarak değiştirilmesi veya yeniden düzenlenmesi konusunda henüz fikir birliğine varılmamıştır. Bu konu şu anda tartışma aşamasındadır ancak bir seçenek olarak yalnızca silme işlemlerine izin verilebilir: geçmiş girişler veya "gelecekteki tüm girişler". İkincisi, geçici duruma izin verir. Örneğin, geliştirici olarak şunları yapabilirim:

  • Yeni URL'ye veya duruma giderek kullanıcıya soru sorma
  • kullanıcının çalışmasını tamamlamasına (veya Geri'ye gitmesine) izin verin.
  • bir 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 çıkabileceği bir şeydir ancak giriş kaldırıldığından yanlışlıkla İleri'ye giderek tekrar açamaz. Bu, mevcut Geçmiş API'si ile mümkün değildir.

Navigation API'yi deneyin

Navigation API, Chrome 102'de flags olmadan kullanılabilir. Ayrıca Domenic Denicola'nın demosunu da deneyebilirsiniz.

Klasik History API basit görünse de iyi tanımlanmamıştır ve çok sayıda sorunu vardır. Bu sorunlar, uç durumlar ve farklı tarayıcılarda farklı şekilde uygulanmasıyla ilgilidir. Yeni Navigation API hakkında geri bildirimde bulunmanızı rica ederiz.

Referanslar

Teşekkür

Bu yayını inceleyen Thomas Steiner, Domenic Denicola ve Nate Chapin'e teşekkür ederiz.