9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[ページ遷移しないWebシステム] JavaScriptによるURLの操作と、ページ遷移しないプログラム

Last updated at Posted at 2018-07-04

 ページ遷移しないWebシステムを作成する場合、いくつかの問題点に遭遇します。今回はその一つである、ブラウザの戻るボタン問題について解決していきます。

####以前の内容
[ページ遷移しないWebシステム] JavaScriptによるWindow Framework
https://qiita.com/SoraKumo/items/18197b5b61cf8061ae5d
[ページ遷移しないWebシステム]Qiitaの投稿をページ遷移無しで表示してみる
https://qiita.com/SoraKumo/items/0e017195d4ad8a88d762

####関連リンク
サンプルプログラム  https://mofon001.github.io/npage/
サンプルソース    https://github.com/mofon001/npage
ページ遷移しないBlog https://croud.jp/

戻れない戻るボタン

 たとえば、JavaScriptでページ遷移しないブログシステムがあったとします。Ajaxによってコンテンツを非同期で拾ってきます。ユーザは操作を行い、いくつかの記事を切り替えました。そして、ふと、一つ前の記事が読みたくなり、ブラウザの戻るボタンを押します。

###「うわぁぁ、別のサイトに切り替わったぁぁぁ!!!!」

 そうです、JavaScriptで画面を書き換えたページは、ブラウザの履歴には残らないのです。そして戻るボタンによって、一つ前に見ていたサイトに切り替わるのです。

オーイ、ミズシマ、イッショニ、マエノキジヘカエロウ

 このネタが分かる人は少なそうです。それはどうでもいいとして、解決方法を考えます。実はJavaScriptには、履歴を操る方法が存在しているのです。

 重要なのは以下の三つです

  • location.search
  • history.pushState
  • popstateイベント

 これらを利用して、理想的な戻るボタンの動きを実現します。

#ページの構築手順

 以下の手順に従えば、だいたいうまくいきます。

  1. location.searchからページに関するパラメータを抽出
  2. パラメータに従い画面を書き換える
  3. ページ切り替えの操作が行われたら、history.pushStateで履歴をねつ造する
  4. ブラウザの戻るや進むボタンが押された場合、popstateが呼び出されるのでlocation.searchのパラメータに従い画面を書き換える

 popstateで画面の書き換えを行う場合は、history.pushStateは呼び出してはいけません。既に履歴に入っているからです。

#サンプルプログラム
 御託は良いから、とっとと出すもの出せやといわれそうなので、出しますサンプル

index.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8"/>
	<link rel="stylesheet" href="Main.css"/>
	<script type="text/javascript" src="Main.js"></script>
	<title>ページ遷移しないための履歴制御</title>
</head>
<body>
</body>
</html>
Main.css
div:nth-child(1){
	background-color: #cccccc;
	padding: 10px;
}
div:nth-child(2){
	margin:10px 0px;
	background-color: #88ff88;
	padding: 10px;
}

div:nth-child(3){
	border: 1px solid;
	height: 300px;
	padding: 20px;
}
Main.js
(function(){
//最初に実行するファンクションを設定
document.addEventListener("DOMContentLoaded",onLoad);

//ページが読み込まれた際に最初に呼び出される
function onLoad(){
	//--------------------------------------------
	//ページタイトルと経過時間表示場所の作成
	var header = document.createElement("div");
	document.body.appendChild(header);
	header.innerHTML = "<span>ページ遷移しないプログラム 経過時間:</span><span>0</span>";
	//ページが遷移していないことを確認するため、経過時間を表示
	var t = header.querySelector("span:nth-child(2)");
	setInterval(function(){t.textContent=parseInt(t.textContent)+1},1000);

	//--------------------------------------------
	//ページ切り替えボタンの作成
	var menu = document.createElement("div");
	document.body.appendChild(menu);
	menu.innerHTML = "<button>ページ0</button><button>ページ1</button><button>ページ2</button>";
	var buttons = menu.querySelectorAll("button");
	buttons.forEach(function(v,i){v.addEventListener("click",function(){changePage(i,true)})})

	//--------------------------------------------
	//メインメッセージ表示領域の作成
	var main = document.createElement("div");
	document.body.appendChild(main);

	//--------------------------------------------
	//URLのパラメータ部分から、表示ページを切り替え
	function goLocation(){
		//パラメータの読み出し
		var p = {};
	    location.search.substring(1).split('&').forEach(function(v){s=v.split('=');p[s[0]]=s[1];});
		//指定ページに飛ぶ
		changePage(p['p']>=0?p['p']:0,false);
	}

	//--------------------------------------------
	//ページ切り替えとブラウザの履歴管理
	function changePage(page,flag){
		//flagがtrueなら、ページの状態を履歴に保存
		if(flag)
			history.pushState(null,null,"?p="+page);
		//ページ内容を書き換え
		main.innerHTML = ["あいうえお","かきくけこ","さしすせそ"][page];
	}

	//ブラウザの「戻る」「進む」ボタンが押された場合のイベント処理
	addEventListener('popstate', function(){goLocation();}, false);
	//初期ページへ飛ぶ
	goLocation();
}

})();

 私がWeb系のプログラムを作る際は、ちょっとした例外を除けばBODYタグの中は空です。ページ遷移しないプログラムは、基本的にベタでHTMLを書きません。JavaScriptで生成するのが基本なのです。HTMLを書くのは一番最初にjsファイルを読み出す部分と、innerHTMLなどに突っ込む部分だけです。

 それから今回、DOMのノードを探す際、セレクターにclassやidを指定していません。使ってはいけない訳ではありませんが、それらに頼らないで目的のものが指定できるぐらいには、セレクターの指定方法は覚えておいた方が後々のためです。

#実行画面
image.png

 ボタンを押すと内容が書き換わり、ブラウザのURLが変化します。そしてページ遷移が起こっていないことを確認するため、経過時間を表示しています。ボタンを何回か押した後、ブラウザの戻るボタンや進むボタンを押してみてください。ページ遷移せずに、必要な場所だけ書き換わるはずです。

#SEO対策
 実は今回の内容は、ブラウザの戻るボタンだけの問題ではありません。SEO対策でも必要になるのです。サーチエンジンはURLが同一だと、違う内容が表示されていたとしても、別々のデータとしてキャッシュしてくれません。当たり前といえば当たり前です。今回のようにパラメータに意味を持たせれば、違うページとしてキャッシュしてくれるのです。

 また、Googleで確認した結果、JavaScriptで動的に作成したページでも、きちんと内容を読み取ってキャッシュされました。ただしURLにパラメータを与えるのは必須条件です。

#まとめ
 ページ遷移しないWebシステムは、ページのルーティングがサーバサイドにある限り実現できません。有名どころのフレームワークは壊滅です。

 ページ遷移しないフレームワークを作るならば、クライアントサイドでルーティングさせる必要があります。その部分を作るのは、それほど難しいことではありません。結局の所、コントローラに相当する機能をクライアントに持っていくことになるので、距離ができてしまうサーバサイドとのデータのやりとりを、いかに簡潔に記述できるかが重要になります。

 そんなこんなで何年か後には、ページ遷移しないことを前提としたフレームワークが当たり前の世の中になっていて欲しいところです。

9
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?