WordPressでpjaxを使ってスムーズにページ遷移をしてみよう

以前ブログのテーマをマテリアルデザインにリニューアルしたとき、pjaxを導入したとお伝えしましたが、肝心の解説をするのを忘れていました。今回は簡単なデモと解説でpjaxを実際に触れてみるまでをご紹介したいと思います。

スポンサードリンク

pjaxとは

PJAX

リニューアル告知の時にも少し触れましたが、おさらいを兼ねてもう少し詳しくご紹介します。

pjaxとはajaxとpushStateを組み合わせた技術です。Ajaxで非同期にコンテンツを入れ替え、HTML5から導入されたHistory APIを使ってブラウザにURLの履歴を追加できます。

これを使えばコンテンツ部分だけを読み込んで通信量を削減&読み込み速度が向上されます。ページを遷移にアニメーションなどを追加してカッコいいページが作れちゃいます。

対応ブラウザは以下のとおり。非対応ブラウザであっても通常のリンクとして遷移するので問題ありません。

Can I use... Support tables for HTML5  CSS3  etc

デモ・ダウンロード

百聞は一見にシカず。とりあえずデモを見て動きを確認しましょう。ボタンを押すとふわっとアニメーションしながらページ遷移します、2ページ目をリロードするとcssが読み込まれていないことが分かります。

解説

とりあえずソースを全部載せて部分ごとに解説していきます。

HTML

index.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>pjaxテストページ 1ページ目</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" type="text/css" href="css/reset.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="js/jquery.pjax.js"></script>
<script src="js/script.js"></script>
</head>
<body>
	
<header>
	<h1>pjaxテストページ</h1>
</header>

<div id="contents">

	<section>
		<h2>ページ1</h2>
		<p>ボタンを押すとページ2に遷移します。pjaxを使えば更新する部分のみを読み込んで再描画できるので、通信量の削減にも繋がります。ページ遷移のエフェクトを追加したりローディングアニメーションを追加したりと何でも出来そうな気がするので、試してみてください。</p>
		
		<div class="btn">
			<p><a href="index2.html">ページ2へ移動する <i class="fa fa-chevron-circle-right"></i></a></p>
		<!-- /.btn --></div>
	</section>

<!-- /#contents --></div>

<footer>
	<p>&copy; Creator Clip.</p>
</footer>

</body>
</html>

index2.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>pjaxテストページ 2ページ目</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>

<div id="contents">

	<section>
		<h2>ページ2</h2>
		<p>2ページ目に移動しました。ページをリロードするとcssが読み込まれていないことが分かります。</p>
		
		<div class="btn">
			<p><a href="index.html">ページ1へ戻る <i class="fa fa-chevron-circle-right"></i></a></p>
		<!-- /.btn --></div>
	</section>

<!-- /#contents --></div>

</body>
</html>

jQuery


$(function(){
	
	// pjax遷移用class付与
	function addPjaxClass() {
		selectorArr = [
			'.btn a'
		        // ,'.hogehoge'
		        // ,'.hogehoge'
		];
		for(i=0; i<selectorArr.length; i++) {
			$(selectorArr[i]).each(function() {
				$(this).addClass('pjax');
			});
		}
	}
	addPjaxClass();
	
	// pjax遷移開始
	var nextUrl = '';
	$(document).on('click', '.pjax', function(e) {
	    e.preventDefault(); // デフォルトの動作を中止
		
		// 遷移先のURLを取得
		nextUrl = $(this).attr('href');

		//まずは切り替える部分を透明に
	    $('#contents').animate({opacity:0}, 300, function(){
	        $.pjax({//エフェクトが終わったらPjaxイベント
	            url: nextUrl,
	            container: '#contents', // 入れ替える部分
	            fragment: '#contents', // 入れ替え先
	            timeout: 20000,
	        });
	    });
	});
	 
	//Pjaxイベントが終わったときの動作
	$(document).on('pjax:end', function() {
		addPjaxClass();
	    $('#contents').stop().animate({opacity:1}, 300);
	});
	
	// タイムアウト時
	$(document).on('pjax:timeout', function() {
		location.href = nextUrl;
		$('#contents').animate({opacity:1}, 300);
	});
			
});

詳細の解説

HTMLでは特に変わったことはせず、11~13行目で必要なjsファイルを読み込んでいます。CSSは装飾用なのでお好みに応じてカスタマイズしてください。


<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="js/jquery.pjax.js"></script>
<script src="js/script.js"></script>

jQueryでpjaxの遷移を指定しており、最小限のコードで実現するにはこのようになります。.pjaxというclassが付いたリンクは全てpjaxを使用して遷移するようにしています。


$(function(){
    // pjax遷移開始
    var nextUrl = '';
    $(document).on('click', '.pjax', function(e) {
        e.preventDefault(); // デフォルトの動作を中止
         
        // 遷移先のURLを取得
        nextUrl = $(this).attr('href');
 
        //まずは切り替える部分を透明に
        $('#contents').animate({opacity:0}, 300, function(){
            $.pjax({//エフェクトが終わったらPjaxイベント
                url: nextUrl, //リクエストするURL
                container: '#contents', // 入れ替える部分
                fragment: '#contents', // 入れ替え先
                timeout: 20000,
            });
        });
    });
      
    //Pjaxイベントが終わったときの動作
    $(document).on('pjax:end', function() {
        $('#contents').stop().animate({opacity:1}, 300);
    });
});

pjaxが発動したら遷移先のURLを取得し、コンテンツ部分をフェードアウトしてコンテンツ部分を読み込みます。containerが入れ替える部分、fragmentが入れ替え先となっているので、基本的に同じセレクタを指定します。

pjaxで読み込みが完了したらpjax:end内に書かれているコードが実行されます。ここでは非表示にしていたコンテンツ部分をフェードインで表示させています。

これだけでも動作しますが、ページのリンク全てに入れるのは面倒だし、別窓リンクをクリックすると読み込み先が見つからなくなるので少し改良します。


$(function(){
    // pjax遷移用class付与
    function addPjaxClass() {
        selectorArr = [
            '.btn a'
        // ,'.hogehoge'
        // ,'.hogehoge'
        ];
        for(i=0; i<selectorArr.length; i++) {
            $(selectorArr[i]).each(function() {
                $(this).addClass('pjax');
            });
        }
    }
    addPjaxClass();

    //Pjaxイベントが終わったときの動作
    $(document).on('pjax:end', function() {
        addPjaxClass();
        $('#contents').stop().animate({opacity:1}, 300);
    });
});

まずはpjax遷移用のclassを配列を使って指定します。addPjaxClass()という関数を作り、selectorArrという配列に指定するセレクタを列挙します。複数指定するときはカンマで区切って並べます。

ページの読み込みが完了したら、再びaddPjaxClass()を発動してclassを付与することで複数のリンクをpjax遷移にすることが可能です。

WordPressに対応させるには

ここまでは静的なHTMLを読み込んだ時の方法で、WordPressに実装するにはもう一工夫必要です。現状は入れ替える部分をソースコード全体から探して置き換えているだけなので無駄な読み込みが発生しています。

WordPressならheader.phpsidebar.phpなどのファイルに分かれているので、pjaxでリクエストがあったときはコンテンツ部分だけを返すことで削減できます。


<?php
    //http-requestヘッダに_pjaxがあるか判別
    $pjax = !($_GET['_pjax']);
    
    //X-PJAXが無かったら通常の読み込みと判断してサイトのヘッダも読み込む
    if ($pjax) {
        get_header();
    }
?>

<div id="contents">
~省略~
<!-- / #contents --></div>

<?php if ($pjax) { get_sidebar(); } // サイドバーも同様 ?>

注意点

pjaxを使うとインラインで書かれたもの以外は初回のみ実行されるので、SNSボタンやスライダーなどのjsは動かなくなってしまいます。

この問題を解決するには、関数を作りページ読み込み後に発動したり、コンテンツ部分に直接インラインでCSSやjsを書いて実行すると動くようになります。参考までに、当ブログで現在使っているコードをご紹介します。


$(function() {	
	/* -------------------------------------------------------
		pjaxページ遷移
	--------------------------------------------------------*/
	//Pjaxイベントが終わったときの動作
	$(document).on('pjax:end', function() {

	    // コンテンツを表示
	    $('#entry #entryInner').stop().animate({opacity:1}, 300);
		
		// Google Analytics
		var location = window.location.pathname + window.location.search;
		ga('send', 'pageview', location);	
  	
		// その他もろもろを再描画
		navigation();
		shareBtnAnim();
		tableData();
		rippleEffect();
		removeZoom();
		ttlSmall();
		contactForm();
		SyntaxHighlighter.autoloader( // SyntaxHighlighterプラグイン
			"bash                      /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushBash.js"
			,"css                      /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushCss.js"
			,"php                      /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushPhp.js"
			,"diff                     /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushDiff.js"
			,"html xml xhtml           /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushXml.js"
			,"js jscript javascript    /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushJScript.js"
			,"perl pl                  /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushPerl.js"
			,"plain                    /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushPlain.js"
			,"python py                /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushPython.js"
			,"sql                      /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushSql.js"
			,"tt tt2                   /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushTT2.js"
			,"yaml yml                 /wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/scripts/shBrushYAML.js"
		);
		SyntaxHighlighter.all();
	});
});

それぞれを関数にまとめ、pjaxでコンテンツ部分を読み込んだら上から順番に実行しています。サイドバーにある目次などはページごとに実行したいので、single.phpのコンテンツ部分に直接インラインでjQueryを書いています。

また、ページのタイトルはfragmentに設定した箇所にdata-title属性があると自動的にタイトルを置き換えてくれます。

現状ではパンくずリストやAdsenseがリロードしないかぎり更新されないので、何か解決策が無いか模索中です…。(いい方法があれば教えて下さい!)

ローディングアニメーションを付ける

WordPressで使用すると読み込むファイルが重いのでページが真っ白になる時間が長くなります。リンクをクリックしても中々表示されないとユーザーは不安になり離脱率が高まってしまいます。そこでSVGを使ってローディングアニメーションを実装しています。

See the Pen LVoQMW by tokumewi (@tokumewi) on CodePen.

pjaxで読込中に実行するpjax:sendを使ってローディングアイコンをコンテンツ部分に挿入しています。読み込みが終われば非表示にすれば簡易的なローディングアニメーションの完成です。


$(function() {
	// pjax読み込み中
	$(document).on('pjax:send', function(e) {
		$('body').addClass('loading');
		$('#entry').prepend('\
		<div class="loader">\
			<svg class="circular">\
				<circle class="path" w cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"></circle>\
			</svg>\
		<!-- /.loader --></div>');
	});

	//Pjaxイベントが終わったときの動作
	$(document).on('pjax:end', function() {
		// ローディングアイコンを消す
		$('body').removeClass('loading');
		$('.loader').fadeOut(200);	
	});
});

まとめ

今回このpjaxを導入したのはこの記事がきっかけです。

元々そういう技術があることすら知らず、ググってみて少しずつ使い方を勉強していきました。WEB制作の新しい技術は「習うより慣れろ」です。今回導入にあたって沢山のサイトを参考にさせていただきました。

ページ遷移に一工夫するだけでカッコいい印象になるかと思います。pjaxの内容やアニメーションを変えてみながら、自分好みのサイトを作ってみて下さい。

鹿
writer : 鹿
このブログを管理している鹿。Webデザインとガジェットが好き。
  • Feedly(RSS)で
    ブログを購読してみる
    購読する
  • Push7(プッシュ通知)で
    ブログを購読する
    購読する