冬言響 / 日記

アメコミとか映画とか音楽とか猫とか単車とか自転車とか革とか銀とかジーンズとかブーツとか今日喰ったものとか。

RSS2.0

jQuery で Ajax を利用して「もっと読む」

ウチのサイトはトップページに日記の最新 5 件ぶんを降順に表示して、その下に以前は過去ログの月別ページへのリンクを置いていたのだけど、これはサイドバー領域にあった方が収まりが良いなあと思うようになったのでそっちに移動した。古い記事が読みたい場合はそっちから過去ログを辿って頂ければよろしい。

とはいえ、なんかの弾みでふらっとウチのサイトに来たひとがトップページを上から順に眺めていって一番下まで来てもう少し以前の記事も読みたいなとか思ったときに自然に辿れるリンクがあった方がよろしいという気もするので、本文の一番最後にこんなものをこさえてみた。

<div id="readmore">
<p><a href="/?page=2">もっと読む</a></p>
</div>

リンク先は 2 ページ目ということでトップページと概ね同じ仕様でありながら最新記事から数えて 6 件目から 10 件目が表示される。その次は 3 ページ目で 11 件目から 15 件目、4 ページ目は 16 件目から 20 件目…以下略

で、ここからが本題。ただ単にフツーにリンクアンカーでページ辿っていくだけの原始的なアレならなんでもないのだけど、なんか最近のお洒落なブログなんかだとアンカーなりボタンなりをクリックしたらページ全体を読み込むんではなくて続きぶんだけを読み込んで下に追加して表示したりとか、クリックするまでもなくページ最下部までスクロールしたら自動的に続きが表示されるような仕組みがあったりするじゃないですか。なんでも Ajax とゆう仕組みを利用するとそれが出来るそうで、しかも jQuery だとそれが楽に使えると。

やってみよう。

というわけで色々調べてどうにかでっち上げてみた。

$("#readmore a").click(function() {
    $(this).text("読込中…");
    var intPage = parseInt($(this).attr("href").replace(/\/\?page=([0-9]+)$/, "$1"));
    $.ajax({
        type: "POST",
        url: "readmore.php",
        data: "page=" + intPage,
        cache: false,
        success: function(strHtml) {
            $("#readmore").before(strHtml);
            $("#readmore a").text("もっと読む")
                            .attr("href", "/?page=" + (intPage + 1));
            }
        });
    return false;
    });

「もっと読む」リンクをクリックしたらまずアンカー文字列を「読込中…」に変更。フツーはなんかぐるぐる回る GIF アニメなんかを使うんだろうけど面倒くさかったのでとりあえず文字だけで。

次に href 属性値から次に表示すべきページ番号「2」を取得。正規表現でぶった切っただけだと文字列型なので parseInt() で整数型に変換。

$.ajax() メソッドで Ajax リクエストを実行してページ番号を readmore.php に渡す。readmore.php はそのページに当たるぶんのログをデータベースから引っ張ってきて <article>?</article> のフツーに本文に表示するときの形で出力する。readmore.php は実際のものと同一ではないけど概ね以下のような具合。

<?php
if(preg_match("/^[0-9]+$/", $_GET["page"]) {
    $intPage = (int)$_GET["page];
    $re = mysql_query("SELECT subject, body FROM log ORDER BY datetime DESC LIMIT " . (($intPage - 1) * 5) . ", 5");
    while($aryRe = mysql_fetch_array($re)) {
        echo("<article>\n");
        echo("<h1>" . $aryRe["subject"] . "</h1>\n");
        echo($aryRe["body"]);
        echo("</article>\n");
        }
    }

出力された内容は strHtml に格納されているので「もっと読む」リンクがある div の手前に追加。「読込中…」を「もっと読む」に戻し、href 属性値をその次のページのものに書き換え。

最後に return false; で a 要素本来の挙動を停止して終了。

ローディング表示の仕組みとかとりあえずこれで動くから良いかとか思ってたら世間的には ajaxStart() とか ajaxStop() を使うもんぽいのだけど動いてるから良いよね。そのうちそっちも試す。

概ね意図通りに動いてくれるんだけどこれで読み込まれた部分には以前に書いた blockquote の引用元表示とかが適用されない。最初にページが読み込まれたときに処理されるから、と思う。どうしたら良いか今はまだ判らんけどそのうちどうにかする。