【HTML・JS】Aタグでhrefのリンク先を読み込まずにアドレスバーのURLだけ変更する
公開日時: 2024-10-18 00:48:31更新日時: 2024-11-08 15:41:45タイトル通りです。SPA(シングルページアプリケーション)でも、SEO面や、リンクにマウスホバーしたときのURL表示などの都合から、AタグのhrefにはURLを入れておきたい、そして、そのAタグをクリックしたときの動作は、ブラウザのアドレスバーのURLはhrefに指定した通り変わるけど、内部的にはページ遷移せずにAjaxで済ませたいというときのテクニックを(ほぼ自分用に)まとめておきます。
要点
やることはシンプルで、ポイントは以下の4つだけです。- Aタグのhrefには、普通にリンク先のURLを記載する
- リンク先のURLに直接アクセスされたときはhtaccess等で内部リダイレクトを設定しといてよしなに処理する
- onclickでevent.preventDefaultを呼び出してhrefのURLを無視させる
- history.pushStateかhistory.replaceStateでURLを書き換える
仕組み
順に説明します。まあ、JSの関数の使い方はMDN見てもらったほうが早いと思うので、ここには書きません()
Aタグのhrefには、普通にリンク先のURLを記載する
Aタグのhrefには普通にリンク先のURLを記載しておきます。これにより、リンクにマウスをホバーさせたときには、通常のリンクと同様にリンク先のURLが表示されます。
ちなみに、(もう検索エンジンのクローラーですらonloadで実行されるJSは一通り実行してからインデックス登録していく時代ですが、)JSの無効化されているブラウザでは、このAタグをクリックすると、普通にリンク先に飛びます。
まあ、この記事のテクニックが役立つのは専らSPAなので、JSの使えないブラウザは考慮する必要もないと思います()
リンク先のURLに直接アクセスされたときはhtaccess等で内部リダイレクトを設定しといてよしなに処理する
後述のhistory.pushStateやhistory.replaceStateを使うと、書き換えた後のURLが普通にブラウザの履歴に残るので、そこから直接書き換え後URLにアクセスされた場合のことも考えておく必要があります。SPAの場合、htaccess辺りを使ってトップページにでも内部リダイレクトして、トップページでは、例えばPHPなら$_SERVER["PATH_INFO"]などを使ってPATH_INFOからリダイレクト元を判定するなり、うまいこと処理してあげればいいと思います。
onclickでevent.preventDefaultを呼び出してhrefのURLを無視させる
Aタグはonclickイベントの中でevent.preventDefault関数を実行すると、hrefに応じてリンク先に飛ぶ動作がキャンセルされます。なお、
<a href="hoge.html" onclick="fuga(); event.preventDefault();">ほげほげ</a>
のように、event.preventDefaultの前に別の関数を実行していると、その関数の中でエラーが発生して処理が止まってしまった場合、リンク先に飛ぶ動作がキャンセルされなくなってしまいます。
<a href="hoge.html" onclick="event.preventDefault(); fuga();">ほげほげ</a>
のように、event.preventDefaultはonclickの中で最初に呼び出すのが基本になります。
もちろん、JSコード中で、
document.getElementById("hoge").onclick = function (event) {
event.preventDefault();
}
のようにonclickの処理を設定しても、リンク先に飛ぶ動作はキャンセル可能です。
history.pushStateかhistory.replaceStateでURLを書き換える
ページ遷移せずにURLを書き換えるには、history.pushState、または、history.replaceStateを使います。前者を使用した場合、書き換え前のURLが履歴に残る(=ブラウザの戻るボタンを押すと書き換え前のURLにページ遷移する)ので、ブラウザの戻るボタンが押されたときにページ遷移せずなにかやりたい場合は、window.onpopstateに関数を紐付けて、そこで history.pushState(null, null, null); を実行してURL書き換えを拒否することも可能です。
URLを書き換えたあとは、普通にAjaxとかで鯖からデータを取ってきて画面に書き出してあげればOKですね(*`ᴗ´*)