NavigateEvent の変更(Chrome 105)

ジョー・メドレー
Joe Medley

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

この記事では、両方の問題と、新しい方法でこれらの問題がどのように解決されるかについて説明します。

Chrome 102 で Navigation API で導入された NavigateEvent.trasitionWhile() メソッドは、シングルページ アプリでクライアントサイドの移行でナビゲーションをインターセプトします。最初の引数は、終了をブラウザやウェブ アプリケーションの他の部分に伝える 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 で削除される予定です。

Interconnect() の使用

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 Gouw(出典: Unsplash