Modern istemci tarafı yönlendirme: Navigation API

Tek sayfalık uygulamalar oluşturmayı baştan sona elden geçiren yeni bir API ile istemci tarafı yönlendirmeyi standart hale getirme.

Deniz Tolga
Sam Thorogood
Jake Archibald
Jake Archibald

Tarayıcı Desteği

  • 102
  • 102
  • x
  • x

Kaynak

Tek sayfalık uygulamalar veya SPA'lar temel bir özellikle tanımlanır: Varsayılan sunucudan tümüyle yeni sayfalar yüklemek yerine, kullanıcı siteyle etkileşimde bulunurken içeriği dinamik olarak yeniden yazma.

SPA'lar bu özelliği Geçmiş API'si aracılığıyla (veya bazı durumlarda sitenin #hash bölümünü düzenleyerek) size sunabilse de bu, SPA'ların normal haline gelmesinden uzun zaman önce geliştirilen kullanışsız bir API'dir. Web ise bu konuda tamamen yeni bir yaklaşım istiyor. Gezinme API'si, sadece History API'nin tatsız yönlerine yama yapmaya çalışmak yerine bu alanı tümüyle elden geçiren, önerilen bir API'dir. (Örneğin, Scroll Restoration API'yi yeniden icat etmek yerine History API'ye yama uyguladı.)

Bu yayında, Navigation API'si genel hatlarıyla açıklanmaktadır. Teknik teklifi okumak için WICG deposundaki Taslak Raporu'na göz atın.

Ö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 veya geri ve ileri gitme) ya da gezinme programatik olarak (yani sitenizin kodu aracılığıyla) tetiklendiğinde, her türlü gezinme için tetiklenir. Ç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, muhtemelen kullanıcıyı aynı sayfada tutmak ve site içeriğini yüklemek veya değiştirmek anlamına gelir.

"navigate" işleyiciye, gezinmeyle ilgili bilgileri (ör. hedef URL) içeren ve gezinme işlemine tek bir merkezi yerden yanıt vermenize olanak tanıyan bir NavigateEvent iletilir. Temel bir "navigate" işleyicisi 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});
  }
});

Gezinmeyi iki şekilde yapabilirsiniz:

  • Navigasyonu gerçekleştirmek için intercept({ handler }) aranıyor (yukarıda açıklandığı gibi).
  • preventDefault() aranıyor. Bu telefon, navigasyonu tamamen iptal edebilir.

Bu örnek, etkinlikte intercept() öğesini çağırır. Tarayıcı, sitenizin sonraki durumunu yapılandırması gereken handler geri çağırma işleminizi çağırır. Bu işlem, navigation.transition adlı bir geçiş nesnesi oluşturur. Bu nesne, diğer kod tarafından gezinmenin ilerlemesini izlemek için kullanılabilir.

Genellikle hem intercept() hem de preventDefault() uygulamasına izin verilir, ancak çağrı yapılamadığı durumlar söz konusudur. Kaynaklar arası gezinme yöntemi kullanılıyorsa intercept() üzerinden gezinmeleri işleyemezsiniz. Ayrıca, kullanıcı tarayıcısındaki Geri veya İleri düğmelerine basıyorsa gezinmeyi preventDefault() üzerinden iptal edemezsiniz; kullanıcıları sitenizde tuzağa düşürmemelisiniz. (Bu konu, GitHub'da ele alınmaktadır.)

Gezinmeyi durduramasanız veya kesintiye uğrayamasanız bile "navigate" etkinliği tetiklenir. Bilgilendiricidir. Dolayısıyla kodunuz, örneğin bir 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, URL değişikliklerini bir SPA içinde merkezi hâle getirir. Bu, eski API'leri kullanan zor bir tekliftir. Daha önce 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, soruna yol açmamakla birlikte tam kapsamlı değildir. Bağlantılar sayfanızda gelip gidebilir ve kullanıcıların sayfalarda gezinmek için kullanabileceği tek yol bu değildir. Ör. form gönderebilir, hatta görsel haritası kullanabilirler. Sayfanız bunlarla ilgilenebilir ancak sadece basitleştirilebilecek birçok olasılık vardır. Bunları yeni Navigation API'si başarabilir.

Ayrıca, yukarıdaki yöntem geri-ileri gezinmeyi işlemez. Onun için başka bir etkinlik var: "popstate".

Geçmiş API'si genellikle bu olasılıklar konusunda yardımcı olabileceğini düşünüyor. Ancak, gerçekte yalnızca iki yüzey alanı vardır: kullanıcı tarayıcısında Geri veya İleri tuşlarına bastığında yanıt verme ve URL'leri aktarma ve değiştirme. Bunun "navigate" ile bağlantısı yoktur. Bunun tek istisnası, yukarıda gösterildiği gibi tıklama etkinlikleri için işleyicileri manuel olarak ayarlamanızdır.

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

navigateEvent, belirli bir gezinme işlevini nasıl ele alacağınıza karar verirken kullanabileceğiniz, gezinmeyle ilgili birçok bilgi içerir.

Temel özellikleri şunlardır:

canIntercept
Bu yanlışsa gezinmeye müdahale edemezsiniz. Kaynaklar arası gezinmelere ve dokümanlar arası geçişlere müdahale edilemez.
destination.url
Muhtemelen navigasyonu kullanırken dikkat edilmesi gereken en önemli bilgidir.
hashChange
Gezinme aynı dokümansa ve karma değeri, URL'nin mevcut URL'den farklı olan tek bölümüyse doğru değerini alır. Modern SPA'larda karma değeri, geçerli belgenin farklı bölümlerine bağlantı vermek için olmalıdır. Dolayısıyla, hashChange doğruysa muhtemelen bu gezinmeye müdahale etmeniz gerekmez.
downloadRequest
Bu durumda gezinme, download özelliğine sahip bir bağlantı tarafından başlatılmıştır. Çoğu durumda buna müdahale etmeniz gerekmez.
formData
Bu boş değer değilse bu gezinme işlemi, POST formu gönderiminin bir parçasıdır. Gezinmeyi yürütürken bunu göz önünde bulundurduğunuzdan emin olun. Yalnızca GET gezinmelerini işlemek istiyorsanız formData null olmayan gezinme işlemlerine müdahale etmekten kaçının. Bu makalenin ilerleyen kısımlarındaki form gönderimlerini işlemeyle ilgili örneğe bakın.
navigationType
Bu şunlardan biri: "reload", "push", "replace" veya "traverse". "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
  );
}

Pas Arası

Kodunuz, "navigate" işleyicisinden intercept({ handler }) çağırdığında tarayıcıya sayfayı yeni ve güncellenmiş duruma hazırladığı, gezinmenin ise biraz zaman alabileceği konusunda bilgi verir.

Tarayıcı, geçerli durumun kaydırma konumunu yakalayarak başlar. Böylece, daha sonra isteğe bağlı olarak geri yüklenebilir ve ardından handler geri çağırma işlevinizi çağırır. handler öğeniz bir söz döndürürse (async functions ile otomatik olarak gerçekleşir) 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);
      },
    });
  }
});

Bu nedenle bu API, tarayıcının anladığı anlamsal bir kavram sunar: Şu anda bir SPA gezinmesi gerçekleşmektedir ve bu durum zaman içinde dokümanın eski bir URL'si ve durumu yeni bir URL ile değiştirilmektedir. Bunun erişilebilirlik de dahil bir dizi potansiyel avantajı vardır: Tarayıcılar bir 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 durdur düğmesiyle etkileşimde bulunmasına olanak tanır. (Bu durum şu an için kullanıcı geri/ileri düğmelerini kullanarak gezindiğinde yaşanmıyor, ancak yakında düzeltilecektir.)

Gezinmelere müdahale ederken yeni URL, handler geri çağırmanız çağrılmadan hemen önce etkinleşir. DOM'yi hemen güncellemezseniz eski içeriğin yeni URL ile birlikte görüntülendiği bir dönem oluşturulur. Bu durum, veri getirilirken veya yeni alt kaynaklar yüklenirken göreli URL çözümlemesi gibi şeyleri etkiler.

URL değişikliğini ertelemenin bir yolu GitHub'da tartışılmaktadır, 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, URL çözümleme sorunlarını önlemenin yanı sıra kullanıcıya anında yanıt verdiğiniz için rahatça hissettirir.

İptal sinyalleri

intercept() işleyicisinde eşzamansız çalışma yapabildiğiniz için, gezinme gereksiz hale gelebilir. Bu durum aşağıdaki durumlarda gerçekleşir:

  • Kullanıcı başka bir bağlantıyı tıklar veya bazı kodlar başka bir gezinme gerçekleştirir. Bu durumda eski gezinme sonlandırılarak yerine yeni gezinme yapılır.
  • Kullanıcı, tarayıcıdaki "dur" düğmesini tıklar.

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

Kısacası, çalışmanızı durdurmanız gerektiğinde etkinliği tetikleyen bir nesne sağlar. fetch() hattına yaptığınız aramalara AbortSignal iletebilirsiniz. Bu durumda, navigasyonun kesilmesi halinde uçuş sırasındaki ağ istekleri iptal edilir. Bu işlem hem kullanıcının bant genişliğini korur hem de fetch() tarafından döndürülen Promise değerini reddederek aşağıdaki herhangi bir kodun, DOM'yi artık geçersiz bir sayfada gezinmeyi gösterecek şekilde güncellemek gibi işlemlerde çalışmasını önler.

Burada, getArticleContent satır içine alınarak AbortSignal öğesinin fetch() ile nasıl kullanılabileceğini gösteren ö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

Gezinmede intercept() işlemi gerçekleştirdiğinizde tarayıcı, kaydırma işlemini otomatik olarak gerçekleştirmeyi dener.

Yeni bir geçmiş girişine yapılan gezinmelerde (navigationEvent.navigationType değeri "push" veya "replace" olduğunda), URL parçası tarafından belirtilen bölüme (# işaretinden sonraki bit) gitmeye ç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.

Varsayılan olarak bu durum, handler tarafından döndürülen söz yerine getirildiğinde gerçekleşir ancak sayfayı daha erken kaydırmak mantıklı olursa navigateEvent.scroll() komutunu ç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() için scroll seçeneğini "manual" şeklinde ayarlayarak otomatik kaydırma işlemeyi tamamen devre dışı bırakabilirsiniz:

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

Odaklanma

handler tarafından döndürülen söz yerine getirildikten sonra tarayıcı, autofocus özelliği ayarlanmış ilk öğeye veya hiçbir öğe bu özelliğe sahip değilse <body> öğesine odaklanır.

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 iki şeyden biri gerçekleşir:

  • Döndürülen Promise öğesi karşılarsa (veya intercept() çağrısı yapmadıysanız) Navigation API "navigatesuccess" öğesini bir Event ile tetikler.
  • Döndürülen Promise reddederse API, "navigateerror" politikasını bir ErrorEvent ile tetikler.

Bu etkinlikler, kodunuzun başarılı veya başarısızlıkla merkezi bir şekilde başa çıkmasına olanak tanır. Örneğin, daha önce görüntülenen bir ilerleme göstergesini gizleyerek başarı elde edebilirsiniz. Örneğin:

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

Başarısız olması durumunda bir hata mesajı görebilirsiniz:

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

ErrorEvent alan "navigateerror" etkinlik işleyici, yeni sayfa oluşturan kodunuzdan tüm hataları alması garanti edildiği için özellikle kullanışlıdır. Ağ kullanılamazsa 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 bulunduğu yeri 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 veri, her girişin geçerli girişi ve alanını temsil eden benzersiz bir dize özelliği olan key öğesini 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şturduğundan key değişir.

Gezinme API'si kullanıcıyı eşleşen bir tuşa sahip girişe doğrudan yönlendirmenize olanak tanıdığından key, geliştiriciler için kullanışlıdır. Sayfalar arasında kolayca geçiş yapmak için diğer girişlerin durumlarında bile bu girişe bağlı kalabilirsiniz.

// 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"durum" kavramını ortaya çıkarır. Bu, geliştirici tarafından sağlanan ve geçerli 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 özelliğine son derece benzer, ancak bu işleve göre daha iyi hale getirilmiştir.

Gezinme API'sinde geçerli girişin (veya herhangi bir girişin) .getState() yöntemini çağırarak durumun 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 ayarlamanın doğru yolu komut dosyasında gezinirken şu şekildedir:

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

Burada newState değeri herhangi bir klonlanabilir nesne olabilir.

Geçerli girişin durumunu güncellemek istiyorsanız geçerli girişin yerini alan bir gezinme gerçekleştirmek en iyisidir:

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

Genel olarak, 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, kullanıcının <details> öğesini açıp kapatması veya form girişinin durumunu değiştirmesi gibi bazı durumlarda durum değişikliği, kodunuzun algılandığı zamana kadar tamamen uygulanmış olur. Bu gibi durumlarda, yeniden yüklemeler ve geçişler aracılığıyla bu değişikliklerin korunması için durumu güncellemek isteyebilirsiniz. Bu, updateCurrentEntry() kullanılarak yapılabilir:

navigation.updateCurrentEntry({state: newState});

Bu değişiklikle ilgili dinleyebileceğiniz bir etkinlik de var:

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

Ancak "currententrychange" özelliğindeki durum değişikliklerine tepki veriyorsanız eyalet denetimi kodunuzu "navigate" etkinliği ile "currententrychange" etkinliği arasında bölüyor, hatta kopyalıyor olabilirsiniz. Buna karşılık, navigation.reload({state: newState}) bunu tek bir yerden yönetmenize olanak tanır.

Durum ve URL parametreleri

Durum, yapılandırılmış bir nesne olabileceğinden tüm uygulama durumunuz için bunu kullanmak cazip bir seçenek olacaktır. Ancak birçok durumda, bu durumun URL'de saklanması 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 bir seçenektir.

Tüm girişlere erişme

Ancak "mevcut giriş" hepsinden ibaret değildir. API, kullanıcıların sitenizi kullanırken gezindikleri giriş listesinin tamamına erişmek için de bir yol sağlar. navigation.entries() Bu çağrı, girişlerin anlık görüntüsünü döndürür. Bu, ör. 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 öğelerinde bir "dispose" etkinliğini dinleyebilirsiniz. Bu etkinlik, giriş artık tarayıcı geçmişinin bir parçası olmadığında tetiklenir. Bu durum, genel temizlik sürecinin bir parçası olarak olabileceği gibi gezinme sırasında da gerçekleşebilir. Örneğin, 10 yer geri gidip sonra da ileri giderseniz bu 10 geçmiş girişi silinir.

Örnekler

"navigate" etkinliği, yukarıda belirtildiği gibi her tür gezinme için tetiklenir. (Olası tüm türlerin spesifikasyonlarında aslında uzun bir ek vardır.)

Birçok site için en yaygın durum kullanıcının bir <a href="..."> öğesini tıklaması olsa da, ele alınması gereken iki dikkate değer, daha karmaşık gezinme türü vardır.

Programlı gezinme

Birincisi, gezinmenin istemci tarafı kodunuzdaki bir yöntem çağrısından kaynaklandığı programlı gezinmedir.

Gezinmeyi sağlamak için kodunuzun herhangi bir yerinden navigation.navigate('/another_page') çağırabilirsiniz. Bu işlem, "navigate" işleyicisine kayıtlı merkezi etkinlik işleyici tarafından gerçekleştirilir ve merkezi işleyiciniz eşzamanlı olarak çağrılır.

Bu rapor, location.assign() ve arkadaşlar gibi eski yöntemlerin yanı sıra History API'nin pushState() ve replaceState() yöntemlerini daha iyi bir şekilde toplamak üzere tasarlanmıştır.

navigation.navigate() yöntemi, { committed, finished } içinde iki Promise örneği içeren bir nesne döndürür. Böylece, çağırıcının geçişin "taahhüt edilene" (görünür URL değişen ve yeni bir NavigationHistoryEntry kullanılabilir olana) veya "bitene" (intercept({ handler }) tarafından döndürülen tüm sözler tamamlandığı ya da hata nedeniyle veya başka bir gezinme tarafından önceden kesildiği durumlarda) bekleyebilmesine olanak tanır.

navigate yöntemi, aşağıdakileri ayarlayabileceğiniz bir seçenek nesnesi de içerir:

  • state: Yeni geçmiş girişinin durumu (NavigationHistoryEntry üzerinde .getState() yöntemi ile mevcut).
  • history: Mevcut geçmiş girişinin yerini alması için "replace" olarak ayarlanabilir.
  • info: navigateEvent.info üzerinden gezinme etkinliğine iletilecek bir nesne.

info özellikle de sonraki sayfanın görünmesini sağlayan belirli bir animasyonu belirtmek için yararlı olabilir. (Alternatif, genel değişken ayarlamak veya bunu #hash etiketinin bir parçası olarak eklemek olabilir. Her iki seçenek de biraz gariptir.) Özellikle, bir kullanıcı daha sonra geri ve İleri düğmeleri gibi gezinmeye neden olursa (ör. geri ve ileri düğmelerini kullanarak) bu info tekrar oynatılmaz. Hatta bu durumlarda her zaman undefined olacaktır.

Soldan veya sağdan açılış demosu

navigation çok sayıda 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 belirten key kabul edilir) ve navigate() değerlerinden 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 üzerinden HTML <form> gönderimi özel bir gezinme türüdür ve Navigation API'si ona müdahale edebilir. Ek yük içermesine rağmen navigasyon, "navigate" dinleyicisi tarafından merkezi olarak yönetilir.

Form gönderimi, NavigateEvent üzerinde formData özelliği arayarak algılanabilir. Bir form gönderimini, fetch() aracılığıyla geçerli sayfada kalacak bir forma dönüştüren bir örneği aşağıda görebilirsiniz:

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üklenişinde "navigate" özelliğini tetiklemez. Ayrıca, tüm durumlar için Sunucu Tarafı Oluşturma (SSR) kullanan siteler için bu durum sorun yaratmayabilir. Sunucunuz, kullanıcılarınıza içerik almanı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.

Gezinme API'sinin başka bir bilinçli tasarım seçimi de yalnızca tek bir çerçeve içinde, yani üst düzey sayfa veya tek bir <iframe> içinde çalışmasıdır. Bunun, spesifikasyonda daha ayrıntılı bir şekilde belgelenmiş ancak pratikte, geliştiricilerin kafa karışıklığı yaşamasını azaltan bir dizi ilginç etkisi vardır. Önceki Geçmiş API'si, çerçeve desteği gibi kafa karıştırıcı birçok uç durumlara sahipti ve yeniden tasarlanan Navigation API bu sıra dışı durumları başından itibaren hallediyor.

Son olarak, kullanıcının göz attığı giriş 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 bir seçenek yalnızca silme işlemlerine izin vermek olabilir: geçmiş girişler veya "gelecekteki tüm girişler". İkincisi geçici duruma izin verir. Örneğin, bir geliştirici olarak şunları yapabilirim:

  • Yeni URL'ye veya duruma giderek kullanıcıya bir soru sorun
  • kullanıcının çalışmasını tamamlamasına (veya Geri gitmesine) izin verme
  • bir görev tamamlandığında geçmiş girişini kaldırma

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

Gezinme API'sini deneyin

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

Klasik History API basit gibi görünse de, çok iyi tanımlanmış değildir, köşe durumları ve tarayıcılar arasında farklı şekilde uygulanma şekliyle ilgili çok sayıda sorun içerir. Yeni Navigation API'si hakkında geri bildirimde bulunmayı düşüneceğinizi umuyoruz.

Referanslar

Teşekkür

Bu gönderiyi değerlendirdikleri için Thomas Steiner, Domenic Denicola ve Nate Chapin'e teşekkür ederiz. Unsplash'tan Jeremy Zero'nun lokomotif resmi.