Webデザインやガジェット、格安SIMの情報ブログ

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の内容やアニメーションを変えてみながら、自分好みのサイトを作ってみて下さい。

“WordPressでpjaxを使ってスムーズにページ遷移をしてみよう” への6件のフィードバック

  1. yoshida より:

    はじめまして!
    お世話になります。

    ためになる有用なサンプル感謝しております!

    今回、サイトにPjaxを組み込みたく
    (WordPressではないのですが)
    CMSに組み込んでいるところなのですが、
    pjaxによるページ遷移までは実装ができたのですが
    ローディング中の画像を出す箇所がうまくいかず・・

    記事内のサンプルを組み込もうとしているのですが
    表示されないのですがソース的に間違っている箇所がありますでしょうか。

    当方、スクリプトに関する知識に乏しく困り果てております。

    お教えいただけると大変助かります。

    【途中まで組み込んでいるスクリプト】

    $.pjax({
    area : ‘#pjaxContent, .pagetitle, .topicpath’,
    link : ‘a.pjax:not([target])’,
    callback : function() {
    $(‘#pjaxContent’).animate({
    left : 0,
    opacity : 1
    }, 100);
    },
    callbacks : {
    before : function() {

    $(‘#pjaxContent’).animate({
    left : -20,
    opacity : 0
    }, 100);
    },
    update : {
    complete : function() {
    $(“.content .extparams”).find(“.note”).hide().prev().addClass(‘hasnote’);
    }
    }
    },
    ajax: { timeout:2000 },
    wait : 120
    });

    【記事のサンプルを流し込んだもの】

    $.pjax({
    area : ‘#pjaxContent, .pagetitle, .topicpath’,
    link : ‘a.pjax:not([target])’,
    callback : function() {
    $(‘#pjaxContent’).animate({
    left : 0,
    opacity : 1
    }, 100);
    },
    callbacks : {
    before : function() {

    $(‘#pjaxContent’).animate({
    left : -20,
    opacity : 0
    }, 100);
    },
    update : {
    complete : function() {
    $(“.content .extparams”).find(“.note”).hide().prev().addClass(‘hasnote’);
    }
    }
    },
    ajax: { timeout:2000 },
    wait : 120
    });

    $(function() {
    // pjax読み込み中
    $(document).on(‘pjax:send’, function(e) {
    $(‘body’).addClass(‘loading’);
    $(‘#pjaxContent’).prepend(‘

    ‘);
    });

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

  2. yoshida より:

    すみません
    先ほどの件

    pjaxのバージョン違いが原因のようでした
    自己解決いたしましたので
    ご報告いたします。

    以上
    失礼いたします。

  3. tokumewi より:

    yoshidaさん

    はじめまして。お返事が遅れてしまって申し訳ございません。
    下記内容を自分も試して問題なかったのでこちらでも原因を探していたのですが、自己解決したようで良かったです。また何か有ればご遠慮無くコメント下さい!

  4. アシベ より:

    こんにちは、はじめまして。pjaxというのがあるのを最近知りました。なんでclassにpjaxって記述があるんだろうと疑問に思っていました。

    tokumewiさんに少しお尋ねしたいことがあるのですが、貴サイトのアイキャッチ部分にあるシェアボタンをクリックしたあとに各SNSボタンのオーバーレイが表示されますがクリックすると元にもどりますが、これも遷移でやっているものなのでしょうか?
    見ていてとてもいい仕様だなぁとおもったので気になりました。
    (カード型の写真部分に同じように使えればと)

  5. tokumewi より:

    アシベさん

    はじめまして。返信が遅れてしまい申し訳ございません。
    これはjQueryとCSSアニメーションを組み合わせて対応しています。

    ボタンを押すとアイキャッチとボタンを囲む.thumbというfigure属性に対して、step1,step2というclassを時間経過で順番に付与、step1のときはボタンが中央に寄るアニメーション、step2のときは中央から広がっていくアニメーションを発動させています。

    • アシベ より:

      お返事ありがとうございます。
       そうですか、JqueryとCSSアニメーションの組み合わせで表現されていたのですね。最近はマテリアルデザイン風の動きを加えたサイトをよく見かけますし、サイトの中にほんの少しだけこういった変化するアクションを加えておけば訪問者もおぉ~って思わず口にするかもしれませんね。(私がそうでした)
      これからも訪問させていただきます。更新を楽しみしていますね。

アシベ へ返信するコメントをキャンセル

writer : 鹿
このブログを管理している鹿。Webデザインとガジェットが好き。