NavigateEvent の変更(Chrome 105)

Joe Medley
Joe Medley

Chrome 105 では、Navigation API の NavigateEvent に 2 つの新しいメソッド(102 で導入)が導入され、実際に問題があることが判明したメソッドが改善されています。intercept() は、使いにくいことが判明した transitionWhile() に代わるもので、デベロッパーはナビゲーションに続く状態を制御できるようになります。URL で指定されたアンカーまでスクロールする scroll() メソッドは、restoreScroll() に代わるものですが、ナビゲーションの種類によっては機能しません。

この記事では、この 2 つの問題と、これらの問題を新しいメソッドでどのように解決するかについて説明します。

Chrome 102 の Navigation API で導入された NavigateEvent.trasitionWhile() メソッドは、シングルページ アプリのクライアントサイドでの遷移でナビゲーションをインターセプトします。1 つ目の引数は、ブラウザとウェブ アプリケーションの他の部分に終了を知らせる Promise です。

これは実際にはうまく機能しませんでした。次の一般的なコーディング パターンについて考えてみましょう。

event.transitionWhile((async () => {
  doSyncStuff();
  await doAsyncStuff();
})());

これは機能的には以下のコードと同等です。これにより、デベロッパーがナビゲーションをインターセプトしようとしていることを API が認識する前に、ナビゲーションの一部が実行されます。

doSyncStuff();
event.transitionWhile((async () => {
  await doAsyncStuff();
})());

これがアプリにおかしくなる可能性がある一例として、スクロール復元ロジックがあります。この場合、DOM 変更前ではなく後、スクロール位置がキャプチャされます。

変更内容

transitionWhile() を置き換えるために、現在の仕様では NavigateEvent.intercept() が導入されています。新しいメソッドは、transitionWhile() でサポートされている focusReset プロパティと scrollRestoration プロパティに加えて、ハンドラを受け取ります。新しいハンドラは常にナビゲーションの commit 後に実行され、スクロール位置などがキャプチャされるため、transitionWhile() の問題を回避できます。

transitionWhile() メソッドは引き続き使用できますが、非推奨となったため、Chrome 108 で削除される予定です。

intercept() の使用

NavigateEvent.intercept() はすべてのナビゲーション イベントで呼び出すことができないため、transitionWhile() と同じ制限が適用されます。クロスオリジン ナビゲーションはインターセプトできず、ドキュメント間のトラバーサルもインターセプトできません。これを行うと、"SecurityError" 型の DOMException がスローされます。

intercept() を使用するには、呼び出すときにカスタム ハンドラを渡します。

navigation.addEventListener("navigate", event => {
  event.intercept({
    async handler() {
      doSyncStuff();
      await doAsyncStuff();
    }
  });
});

ページの上部からアンカーへのナビゲーション(/a から /a#id に移動)などのナビゲーションは、単一ページアプリであってもブラウザで完全に処理されます。ただし、別の「ページ」(/a から /b#id)のアンカーに移動する(マルチページ アプリではシンプルですが、単一ページのアプリではより複雑になります)。アプリは、NavigateEvent.transitionWhile() を使用して /b#id へのナビゲーションをインターセプトしてから、NavigateEvent.restoreScroll() を呼び出してアンカーを表示する必要があります。前述のように、現時点では難しい課題となっています。

変更内容

シングルページ アプリでは、ブラウザでアンカーへのスクロールを処理するか、コードで処理するかをコントロールできます。

Scroll() の使用

デフォルトでは、インターセプト ハンダーが満たされると、ブラウザはスクロールを自動的に処理しようとします。スクロールを自分で処理する場合は、scroll"manual" に設定し、ブラウザがスクロール位置を設定しようとしたときに NavigateEvent.scroll() を呼び出します。

navigation.addEventListener("manual", event => {
  scroll: "manual",
  event.intercept({
    async handler() {
      doSyncStuff();
      // Handle scrolling earlier than by default:
      event.scroll();
      await doAsyncStuff();
    }
  });
});

restoreScroll() メソッドは引き続き使用できますが、非推奨となったため、Chrome 108 で削除される予定です。

おわりに

Navigation API に関する記事は近日中に更新される予定です。それまでの間、この API の仕様にはウェブ デベロッパー向けの情報が多く含まれています。

写真撮影: Tim GouwUnsplash より)