JavaScript History pushState

概要: このチュートリアルでは、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 という別のマップを定義します。オブジェクトには、urlcontent の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#angularCode 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() メソッドを使用して、ウェブブラウザのセッション履歴スタックにエントリを追加します。
このチュートリアルは役に立ちましたか?