manmanrai’s diary

新米フロントエンジニアの勉強記録ブログ

非同期通信ライブラリーpjax.js使い方、難しいところ

目的

スムーズにページ遷移するサイト(非同期通信をしながらURLを変更する)
(スーパーパフォーマンスの良いサイトを作ってみたかったです。)

使い方

使用JS:

ステップ:

  1. 静的なページを作る(html,css
  2. jsを読み込む
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="./js/jquery.pjax.js"></script>
<script src="./js/common.js"></script>

※ 番外編:jqueryのバージョンなかなか上げたくない理由は、スクロールアニメーション使いたいからです。

common.jsの中に

$.pjax({
    area : 'main',
    link : '.header__link, .header__logo'
});

それで

<a class="header__link" href="">
<a class="header__logo" href="">

クリックされた時、

<main>...</main>

の中身差し替えられます。同時にURLも変わります。
ページ遷移したように見えます。 (実際自分が使ってる時アニメーション付けてましたが、ここは本題ではないので、アニメーション関してのコード一切省略します。)

仕組み

[2017/04/21追記]

最初にアクセスしたページは全部読み込まれます。

f:id:manmanrai:20170421173429p:plain

そして、サイト内の遷移すると、別のページの指定のところを取ってくれます。

f:id:manmanrai:20170421173503p:plain

URLも書き替えてくれます。

f:id:manmanrai:20170421173522p:plain

そしたら、完全にページ遷移したように見えます。
index2.htmlから入る可能性もありますので、headerとfooterも用意する必要があります。

難しいところ

ネットで探してみたら、デモほぼ2ページしかなくて、「index.html」から「index2.html」飛ぶ、そして「index2.html」から「index.html」戻る、みたいな例しかありませんでした。

自分の案件を例として説明してみると、

まず、サイトマップこういう感じです。

┏トップページ
┣下層ページ
┣下層ページ
┣下層ページ
┣下層ページ
┗下層ページ

計6ページです。(下層って書いても実はディレクトリ階層は同じです。)

トップページと下層ページの差は何かって言うと、 構造的には
トップページはheader、[高、横幅100%使う背景画像、サイトコピー]、footer
下層ページはheader、[コンテンツ、ページトップに戻るボタン]、footer

ここで太文字にしたものは、ここ全部差し替えたいところです。

例えば最初に入ったページはトップページ、下層ページへのリンクをクリックしたら、[高、横幅100%使う背景画像、キャッチコピー][コンテンツ、ページトップに戻るボタン]これになります。

残したいheader、footerはそのままでいてほしいです。
これでうまく行けば良いのですが、、、そこで問題発生しました!!!

問題一

よく使うページトップに戻るボタンが機能しなくなったんです。

    $('a[href^=#]').click(function(){
        var speed = 'slow';
        var href = $(this).attr("href");
        var target = $(href == "#" || href == "" ? 'html' : href);
        var position = target.offset().top;
        $("html,body").animate({scrollTop:position},speed,'swing');
        target.delay(13000).click();
    });

pjaxのところちゃんと指定したaタグだけpjax使うんですが…
ここの「link」です。

$.pjax({
    area : 'main',
    link : '.header__link, .header__logo'
});

まあ、設定通りpjaxの切り替えはしてないのですけど、aタグ自体のリンク先飛ばしちゃいます。よくあるトップ戻るのリンク先は#なので、上に戻るじゃ戻ったんですが、パッてただリロードされた感じになります。

解決策

aタグ駄目だったら、そのページトップ戻るボタン自体をほかのタグで代用します。
普通にdivに変えました。(cssにもcursor指定しました。)

  $('.page__gotop').click(function(){
    var speed = 'fast';
    var target = $('html');
    var position = target.offset().top;
    $("html,body").animate({scrollTop:position},speed,'swing');
  });

もっと簡潔な書き方変えられますが、とりあえず大体こんな感じに変えました。 これでページトップ戻るボタンが普通に機能します。

※ ほかの問題を予想してみました。
ページ内のアンカーがスクロールアニメーション使えなくなるでしょう。。
[2017/04/21追記]
ページ内アンカーもaタグじゃなければ大丈夫だと思います。

問題二

問題一よりこちらの問題断然に大変だと思います。
それが読み込まされたもの存在しないものとして認識されてるんです。
jsで制御することができなくなったのです!

実は最初にpjax.jsについて何もわからない時、いっそう全部を読み込めば良いかなと思ったので、

$.pjax({
    area : 'body',
    link : '.header__link, .header__logo'
});

差し替えのareaをbodyにしたんです。
普通のページ遷移スピードどのぐらい違うか知りたいもありますし、どこまで読み込めば大丈夫なのか知りたかったんです。
そこで、headerの中のハンバーガーボタンが押せなくなりました。

メニューを開くのはjsの中で制御してますが、ハンバーガーボタン自体が存在しないことで、click functionも触れず、エラーも出てませんでした。

解決策

要素を外に出すようにしました。すべてJSで制御したいものを。
メニュー開くボタンも、ページトップに戻るボタンも、読み込みパーツから外しました。

トップページはheader、[高、横幅100%使う背景画像、キャッチコピー]、footer
下層ページはheader、[コンテンツ]、ページトップに戻るボタン、footer

それがそれで新しい問題が発生したのですが、いらないものを隠すことの方が簡単でした。

軽く説明すると、

トップページには上下左右幅いっぱい使うから、ページトップに戻るボタン設置する必要なかったので、でもトップから下層に行くと、ページトップに戻るボタンが読み込み範囲外なので、読み込まれてないです。
逆に言うと、入り口は下層なら、トップに行く時余計なページトップに戻るボタンがまだ残っています。

少し変わった解決策かもしれませんが、トップにもページトップに戻るボタンを設置しました。そして、クラス名を付けて、非表示にしました。
pjax.jsで読み込み完了した時に、実行するfunction設定できますので、そこでトップページだと分かったら、非表示クラスをつけるようにします。それ以外は非表示クラスを外すようにします。

さいごに

正直、このプラグインをこだわる必要があるのかなって、自分でも途中で何度も思ったのですが、隣のエンジニアが別案件で途中やめたって聞きましたので、今回こそ真相突き止めてあげたいなと思いました。

隣のエンジニアさん、ありがとうございます。

引き続き、頑張ります。

参考サイト

neganin.com

qiita.com