NavigateEvent の変更(Chrome 105)

Joe Medley
Joe Medley

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

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

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

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

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