NavigateEvent の変更(Chrome 105)

Joe Medley
Joe Medley

Chrome 105 では、Navigation API の NavigateEvent に 2 つの新しいメソッドが導入されます(102 で導入)。これは、実務で問題となっているメソッドを改善するためのものです。intercept() は、使用が困難であることが判明した transitionWhile() に代わるもので、デベロッパーがナビゲーション後の状態を制御できるようにします。scroll() メソッドは、URL で指定されたアンカーにスクロールします。restoreScroll() はすべてのタイプのナビゲーションで機能しないため、scroll() に置き換えられます。

この記事では、両方の方法の問題と、新しい方法でそれらの問題を解決する方法について説明します。

NavigateEvent.trasitionWhile() メソッドは、Chrome 102 の Navigation API で導入され、シングルページ アプリのクライアントサイド遷移のナビゲーションをインターセプトします。最初の引数は、ブラウザとウェブ アプリケーションの他の部分に処理が完了したことを通知するプロミスです。

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

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

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

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

たとえば、スクロール復元ロジックで、スクロール位置を DOM の変更前ではなく変更後にキャプチャすると、アプリが混乱する可能性があります。

変更内容

transitionWhile() に代わる NavigateEvent.intercept() が現在の仕様に導入されています。新しいメソッドは、transitionWhile() でサポートされている focusReset プロパティと scrollRestoration プロパティに加えて、ハンドラを受け取ります。新しいハンドラは、ナビゲーション コミット後に常に実行され、スクロール位置などの情報がキャプチャされるため、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