Angular アプリの画面遷移を実現するブックマークレットを作る

とある Angular 製アプリの使い勝手を向上すべく、ブックマークレットを駆使して独自の追加メニューを実装してみた。

document.body.insertAdjacentHTML('beforeend', `<a href="/admin-menu" style="position: absolute; top: 0; right: 0; background: #fff;">Admin Menu</a>`);

上のコードをブックマークレットとして実行すると、ページ右上に「Admin Menu」というリンクが登場する。リンク先は /admin-menu としており、押下すると通常のリンクとしてページ遷移が発生する。

コレでもまぁ良いのだが、SPA なのにページ全体が再読み込みされてしまうのはちょっと鬱陶しい。せっかくなら Router Link による画面遷移を実行したいのだが、ブックマークレットのように外部のスクリプトから router.navigateTo() メソッドなどは叩けないだろうし、ということで違う方法を調べた。

色々試したところ、history.back() ないしは history.forward() だと SPA としての画面遷移が発火することが判明。対して history.go()location.reload() と同じく、F5 ボタンを押した時のようなページ全体の再読み込みが発生してしまった。

で、history.back() を利用して任意の URL に飛ばしてやるには、history.pushState() を2回実行する、という方法でなんとかなった。

つまり以下のようなコードにすると、Angular の Router Link による、SPA としての画面遷移が実現できる。

document.body.insertAdjacentHTML('beforeend', `
  <a style="position: absolute; top: 0; right: 0; background: #fff;"
     href="javascript:history.pushState({},'','/admin-menu'); history.pushState({},'','/admin-menu'); history.back();">Admin Menu</a>`);

insertAdjacentHTML()innerHTML では、script 要素が埋め込めなかった。なので遷移用の関数を作っておいて onclick で呼ぶ、みたいな実装は失敗した。href 属性に javascript: から繋げてインラインにコードを書いておけば保持された。

最終的にブックマークレットとして動かすため、次のように書いて完成。

javascript:(x=>document.body.insertAdjacentHTML('beforeend',`<a style="position:absolute;top:0;right:0;background:#fff" href="javascript:history.pushState({},'','/admin-menu');history.pushState({},'','/admin-menu');history.back()">Admin Menu</a>`))();

やりたいことは一応実現できたのでよきよき。試してはいないけど、React Router や Vue Router など、他の SPA でも使えるかもしれない。