概要: このチュートリアルでは、JavaScript の history pushState()
メソッドの使い方を学びます。
JavaScript history pushState() メソッドの紹介
history.pushState()
メソッドを使用すると、ウェブブラウザのセッション履歴スタックにエントリを追加できます。
pushState()
メソッドの構文は次のとおりです。
history.pushState(state, title, [,url])
Code language: CSS (css)
pushState()
メソッドは3つのパラメータを受け入れます。
1) state
state
はシリアライズ可能なオブジェクトです。新しい状態に移動すると、popstate
イベントが発生します。そして、popstate
イベントには、履歴エントリの state
オブジェクトを参照する state
プロパティがあります。
2) title
ほとんどのブラウザは現在、この title プロパティを無視します。ドキュメントのタイトルを変更したい場合は、代わりに document.title
プロパティを使用できます。
実際には、title
パラメータには空の文字列を渡します。
3) url
オプションの url
を使用すると、新しい履歴エントリの URL を定義できます。URL は現在の URL と同じオリジンでなければならず、そうでない場合はメソッドが例外をスローします。
新しい url
を設定しても、ウェブブラウザは url
をロードしません。指定しない場合、url
はデフォルトで現在の URL になります。
JavaScript history pushState() の例
React、Vue、Angular の3つのタブを表示するシンプルなアプリケーションを作成します。
タブをクリックすると、選択したタブのコンテンツが表示されます。また、history.pushState()
メソッドを使用して URL を更新します。
ハッシュタグ付きの URL をコピーしてウェブブラウザからロードすると、アプリはその URL に関連付けられた対応するコンテンツをロードします。
index.html ページを作成する
以下は index.html
ページの定義です。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript History API: pushState Demo</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<div class="tabs">
<ul>
<li class="active" id="tab1">React</li>
<li id="tab2">Vue</li>
<li id="tab3">Angular</li>
</ul>
<div class="content">
A JavaScript library for building user interfaces
</div>
</div>
</div>
<script src="js/app.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
style.css
ファイルはこちらから入手できます。
app.js
ファイルでは
まず、querySelector()
メソッドを使用して、タブとコンテンツ要素を選択します。
const tabs = document.querySelector(".tabs");
const content = document.querySelector(".tabs > .content");
Code language: JavaScript (javascript)
次に、URL ハッシュを各タブ ID に関連付ける マップ オブジェクトを定義します。
const hashes = new Map([
["#react", "tab1"],
["#vue", "tab2"],
["#angular", "tab3"],
]);
Code language: JavaScript (javascript)
3つ目に、タブ ID をオブジェクトにマッピングする data という別のマップを定義します。オブジェクトには、url
と content
の2つのプロパティがあります。
const data = new Map([
[
"tab1",
{
url: "index.html#react",
content:
"React is a JavaScript library for building user interfaces.",
},
],
[
"tab2",
{
url: "index.html#vue",
content: "Vue is the Progressive JavaScript Framework.",
},
],
[
"tab3",
{
url: "index.html#angular",
content:
"Angular is a platform for building mobile and desktop web applications.",
},
],
]);
Code language: JavaScript (javascript)
4つ目に、各タブ (または li 要素) がクリックされると、click
イベントが発生します。効率を高めるために、イベント делегирование を使用します。
そのため、各タブで click
イベントを処理する代わりに、各タブの親で click
イベントを処理します。
tabs.addEventListener("click", function (event) {
if (!event.target.id) return;
update(event.target.id);
});
Code language: JavaScript (javascript)
if
文は、click
イベントが各タブで発生した場合にのみ、イベントハンドラがコンテンツと URL を更新することを保証します。タブのコンテンツ領域をクリックしても何も起こりません。
イベントハンドラ内で、update()
関数を呼び出し、タブ ID を渡します。
5つ目に、update()
関数を以下に定義します。
const update = (tabId) => {
// remove the active class of the previously selected tab
const currentTab = tabs.querySelector(".active");
if (currentTab.id != tabId) {
currentTab.classList.remove("active");
}
// add active class to the selected tab
const selectedTab = document.getElementById(tabId);
selectedTab.classList.add("active");
const entry = data.get(tabId);
if (entry) {
// update the URL
history.pushState(null, "", entry.url);
// change the content
content.innerHTML = entry.content;
}
};
Code language: JavaScript (javascript)
update()
関数は、現在のタブから .active
クラスを削除し、現在選択されているタブに同じ CSS クラスを設定します。
また、タブ ID に基づいて data から URL とコンテンツを取得します。URL を更新するために、history.pushState()
メソッドを使用します。
アプリは、1つの問題を除いて期待どおりに動作するはずです。
URL をコピーした場合
https://javascripttutorial.dokyumento.jp/sample/webapis/history/index.html#angular
Code language: JavaScript (javascript)
...そして新しいブラウザウィンドウに貼り付けると、アプリは `Angular` タブではなく `React` タブを表示します。
これを修正するために、location
オブジェクトを使用して URL からハッシュを取得し、ページがロードされたときに update()
関数を呼び出します。
(() => {
// get tab id from the hash
const tabId = hashes.get(window.location.hash);
// update the tab
if (tabId) update(tabId);
})();
Code language: JavaScript (javascript)
app.js
ファイル全体を以下に示します。
const tabs = document.querySelector(".tabs");
const content = document.querySelector(".tabs > .content");
// store the relationship between hash & tab id
const hashes = new Map([
["#react", "tab1"],
["#vue", "tab2"],
["#angular", "tab3"],
]);
// store the relationship between tab id and contents
const data = new Map([
[
"tab1",
{
url: "index.html#react",
content:
"React is a JavaScript library for building user interfaces.",
},
],
[
"tab2",
{
url: "index.html#vue",
content: "Vue is the Progressive JavaScript Framework.",
},
],
[
"tab3",
{
url: "index.html#angular",
content:
"Angular is a platform for building mobile and desktop web applications.",
},
],
]);
tabs.addEventListener("click", function (event) {
if (!event.target.id) return;
update(event.target.id);
});
const update = (tabId) => {
// remove the active class of the previously selected tab
const currentTab = tabs.querySelector(".active");
if (currentTab.id != tabId) {
currentTab.classList.remove("active");
}
// add active class to the selected tab
const selectedTab = document.getElementById(tabId);
selectedTab.classList.add("active");
const entry = data.get(tabId);
if (entry) {
// update the URL
history.pushState(null, "", entry.url);
// change the content
content.innerHTML = entry.content;
}
};
(() => {
// get tab id from the hash
const tabId = hashes.get(window.location.hash);
// update the tab
if (tabId) update(tabId);
})();
Code language: JavaScript (javascript)
まとめ
history.pushState()
メソッドを使用して、ウェブブラウザのセッション履歴スタックにエントリを追加します。