やりたいこと
モダンなJavaScriptフレームワークが行っているようなSPAをJavaScriptのみで似たようなものでもいいから実装したい。(Vue.jsとかReactでいいとかは置いといて)
SPA(Single Page Application)とは
従来のウェブアプリケーションの構造であるMPA(Multi Page Applicaton)では、ページごとにサーバーから新しいHTMLを取得していました。
一方SPAではページ遷移を行わずに動的なコンテンツを表示する仕組みです。
初回のページ読み込み時に必要なデータを取得し、動的にHTMLを更新することで、高速なパフォーマンスと優れた保守性を実現します。
ディレクトリ構成
プロジェクトディレクトリ
├── docker-compose.yml //httpサーバー
├── html
│ ├── index.html // 表示されるhtmlファイル
│ ├── pages // 差し込まれるHTMLファイル
│ │ ├── index.html
│ │ ├── About.html
│ │ ├── Contact.html
│ │ ├── 404.html
├── js
│ ├── Router.js //ルーティングファイル
環境構築
C:file上では動かないので最低限でもhttpサーバーを作っておきます。
docker-compose.yml
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
表示されるhtmlファイル
htmlディレクトリ直下のindex.htmlを編集します
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<script src="js/Router.js"></script>
</head>
<body>
<nav>
<a href="/" onclick="route()">Home</a>
<a href="/About/" onclick="route()">私たちについて</a>
<a href="/Contact/" onclick="route()">お問い合わせ</a>
</nav>
<hr />
<div id="main-contents"></div>
</body>
</html>
ルーティングファイル
ルーティングするためのRoute.jsを以下のように実装します。
routesにルートを追加していきます。
・キー = ルートパス
・template = pagesのhtmlファイル
・title = 各ページのタイトル
その他詳細は各所コメントアウトに書いてあります。
Router.js
"use strict";
// ——————————————————————————————————————
// ルートごとのテンプレートファイルとページタイトルを管理
// ——————————————————————————————————————
const routes = {
"/": { template: "/pages/index.html", title: "Home" },
"/About/": { template: "/pages/About.html", title: "わたしたちについて"},
"/Contact/": {template: "/pages/Contact.html", title: "お問い合わせ"},
404: { template: "/pages/404.html", title: "404"},
};
// ——————————————————————————————————————
// リンククリック時に実行
// ——————————————————————————————————————
function route(event) {
event = event || window.event; // eventが未定義ならwindow.eventから取得
event.preventDefault(); //デフォルトの操作をキャンセル
// 履歴に追加(タイトルは各自 handleLocation でセットするので第2引数は空文字)
window.history.pushState({}, "", event.target.href);
handleLocation();
}
// ——————————————————————————————————————
// ページの描画
// ——————————————————————————————————————
async function handleLocation() {
const path = window.location.pathname; // 現在のパスを取得
const route = routes[path] || routes[404]; // 定義ルートから該当パスを取得。なければ404
// HTML読み込み
try {
const res = await fetch(route.template); // route.templateからHTMLファイルを取得
const html = await res.text(); // レスポンスの本文をテキストとして取り出す
document.getElementById("main-contents").innerHTML = html; // main-contentsへ本文を追加
} catch (err) {
console.error(err);
}
document.title = route.title; // タイトルを書き換え
}
// 履歴操作(popstate/戻る・進)を監視し再描画を行う
window.addEventListener("popstate", handleLocation);
// 初回ロード時の描画
window.addEventListener("DOMContentLoaded", handleLocation);
まとめ
JavaScriptでSPAモドキを構成しました。
作ってみるとフレームワークの素晴らしさがよくわかりました。