ラック
Home > ブログ > 記事 > 2016年7月 > PJAXなるもの

PJAXなるもの

カテゴリ: ホームページ

PushState + AJAXでPJAX。

HTML5のHistory APIをもにょもにょしたりして、Ajaxでページ内を書き換えた場合でもブラウザの戻る・進むに対応したり色々恩恵が受けられるという技術、らしいです。

特徴

  • (AJAXで非同期に読み込むため)スムーズにページ遷移が行える
  • シームレス、かつエフェクトを付けることも可
  • コンテンツごとにURLが発行されるので、AJAXよりもSEO的に良い

などのメリットがあるようです。

IE10以下は対応していない、としていますが今更IE10以下って…という感じなので積極的に使っていきたいです。

参考サイトやデモなど

モノ自体はだいぶ前からあった模様。知らなかった…。

 

ということで自分でもテストをしてみました。falsandtru版(v2.42.0)で。jQueryは2.2.2でちゃんと動作しました。

で、下記のようなデモを作成。

index.phpおよびcontent.php


<?php
$httpheader = getallheaders();
if(array_key_exists('X-Pjax', $httpheader)) {
    if($httpheader['X-Pjax']) { // pjaxリクエストの場合の処理&コンテナ内のHTMLだけ出力
        include("./elements/index_content.html");
    }
    else { // pjaxリクエストじゃない場合の処理&全てのHTMLを出力
        include("./elements/index_all.php");
    }
}
else {
    include("./elements/index_all.php");
}
?>

上記はindex.php。content.phpはincludeしている「./elements/index_XXXXXX」の部分が「./elements/content_XXXXXX」になっているだけで同じです。

当然、elementフォルダの下に各ファイルが存在します。

 

index.js


$(function () {
    $.pjax({
        server: {
            header: true //リクエストヘッダに「X-Pjax」を付与
        },
        area: '#pjaxTest',
        link: 'a.pjax:not([target])',
        load: { head: 'meta, link', css: true, script: false },  // 再描画するエリアを選べる、インラインスクリプトを動作させない
		ajax: {
            timeout: 2000
        }, //タイムアウト2秒
        wait: 500 //フェードアニメーションエフェクト用、待ち時間0.5秒
    });
    //アニメーション用
    $(document).bind('pjax:fetch', function(){
		$('body').css('overflow', 'hidden');
		$('#pjaxTest').attr({'class': 'fadeOut'});
	});
	$(document).bind('pjax:render', function(){
		$('#pjaxTest').attr({'class': 'fadeIn'});
		$('body').css('overflow', '');
	});
});

pjaxをコールしている内容がこれ。

id=”pjaxTest”の中身を書き換えろ、というのが基本ですが参考サイトを基にフェードのエフェクトなど色々やっています。

中でも肝なのは「server: { header: true }」の記述。
コメントにある通り、このパラメータでリクエストヘッダに「X-Pjax」のキーを付与しており、そのリクエストヘッダの有無で上のphpの判定が動くので、これがないと通常の遷移と同じように全部読み込まれるパターンになります。

後はcssが異なったり、ブログなどではOGP用のmetaタグをページごとに切り替える必要があると思うのでその場合はmetaタグも書き換える、などを想定して上記のようなパラメータ設定に。

なお、jsは面倒くさいので今回は再読み込みさせないようにしました。

 

index_all.php(content_all.phpもid=”pjaxText”の中身や読み込むcssが異なるだけでほぼ同じ内容)


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="format-detection" content="telephone=no,address=no,email=no">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
	<title>PJAX Test (Top Page)</title>

	<!-- css -->
	<link href="./css/index.css" rel="stylesheet">

</head>
<body>
...

    <!-- main -->
    <main id="pjaxTest">
<?php
    include("./elements/index_content.html");
?>
    </main>
    <!-- /main -->

...

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="./js/jquery.pjax.min.js"></script>
<script src="./js/index.js"></script>
</body>
</html>

phpでリクエストヘッダにX-Pjaxがなかったり対応していなかったりした場合と判定されて読み込まれるphpはこれ。

中身としては普通のhtmlですが、id=”pjaxText”の中身はindex_content.htmlと同じなのに記述するのが嫌だったのでそこだけincludeして冗長さをなくしています。

(そのためだけにphpファイルにしているという)

 

index_content.html(content_content.htmlもid=”pjaxText”の中身や読み込むcssが異なるだけでほぼ同じ内容)


<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="format-detection" content="telephone=no,address=no,email=no">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
	<title>PJAX Test (Top Page)</title>

	<!-- css -->
	<link href="./css/index.css" rel="stylesheet">    

    <!-- main -->
    <main id="pjaxTest">
        <section class="container-fluid">
            <div class="row">
                <article class="col-xs-12">
                    <div class="page-header">
                        <h1>What's this page? <small>About page</small></h1>
                    </div>
                    <p>このページはPJAXのテストサイトのトップページです。</p>
                    <p>次のコンテンツは<a href="./content.php" class="pjax">こちら</a>。</p>
            </div>
        </section>
    </main>
    <!-- /main -->

で、肝心のコンテンツの中身がこれ。

基本的にはid=”pjaxTest”の中身を丸ごと記述しているだけですが、index.jsでcssやmetaタグも書き換えろ、と指定しているのでそのためにmetaやcssも入れています。

普通のhtmlからすれば明らかに記述量が短くて済み、リクエストヘッダにX-Pjaxのキーがあればこれしか読み込まなくて済むので確かに軽量化・高速化が捗りそうです。

 

嵌まったところ

さて、上記のテストを行う上で一点嵌まったところがありました。

それは、aタグをクリックして遷移すると、「最初はcontent.htmlの中身だけ読み込むが、直後になぜかもう一度X-PjaxがないGETリクエストが勝手に発行され、通常のページ遷移をしてしまう」という現象に遭遇したことです。

パケットキャプチャしたりだいぶ悩みましたが原因は至って単純で、「content.htmlの中にid=”pjaxTest”を付与したタグが記述されていなかった」ということ。


<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="format-detection" content="telephone=no,address=no,email=no">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
	<title>PJAX Test (Top Page)</title>

	<!-- css -->
	<link href="./css/index.css" rel="stylesheet">
    
        <section class="container-fluid">
            <div class="row">
                <article class="col-xs-12">
                    <div class="page-header">
                        <h1>What's this page? <small>About page</small></h1>
                    </div>
                    <p>このページはPJAXのテストサイトのトップページです。</p>
                    <p>次のコンテンツは<a href="./content.php" class="pjax">こちら</a>。</p>
            </div>
        </section>

中身としてはこんな状態でした。

てっきりid=”pjaxTest”のタグの中身だけを記述すれば良いのだと思っていたのですが、上記のようにタグ自体も必要だった、ということのようです。

pjaxで書き換えるタグがないと、「aタグからpjaxで書き換え→読み込んだコンテンツにキーとなるタグが存在しない→何らかの処理を経て通常遷移としてもう一度GETリクエストする」という挙動になるようです。

気付いてみればなんてことはなかったのですが、こんなところで嵌るとは…。

タグ: jQuery

 



関連する記事一覧