前回まででフォロワーを出してみましたが、なんかいまいちスピードが上がらないので、今回はGithubのコミットログを貼り付けて、主に説明したいところまで端折ります。
- フォロワーとフォローしている人を取得する関数を修正して1つに
- the_contentにかけていたフックの関数をそのまま利用し、Ajaxで返す
- それぞれのフォロワーリストにボタンを表示
- ボタンにはユーザーIDを渡せるよう変更(指定しなければ現在の投稿の作者IDを利用)
わからないことがあったら、Githubのコミットログにコメントを残してもらえると答えられます。(※ Githubは行ごとにコメント残せるんですよ)
工夫したポイントを説明すると、Ajaxの部分ですかね。
Ajaxを実装する場合、「JSONを取得して云々かんぬん」という説明があるのですが、jsRenderとか、そういうJSテンプレートを使った実装していない限り、JSONで画面を作るのってめんどくさいんですよね。PHP側とJS側両方で似たような描画用関数を実装することになったりして。
WordPressでサイトを作っている場合、わざわざJSONで画面を作るようなWebアプリ的な作り方をしないと思うので、Ajax経由で渡すデータの利用方法が「DOMの操作」なのであれば、HTMLをサーバで作って、それをそのまま渡してしまった方がよいです。
Ruby on Railsの開発者であるDHHがブログでそんなこと(Server-generated JavaScript Responses)を書いていたので、それのしょぼい版ですね。
今回は「これ以上フォロワーが存在しない」という場合、pタグを渡すようにしていて、pタグが挿入された瞬間に「もっと読み込む」ボタンは消えるということをCSS上でやっています。
p.no-follower{
& + a.fs-more-btn{
display: none;
}
}
で、こうなります。下にある「もっと見る」ボタンを押すとそれより古いフォロワーが読み込まれて……

あれー!!

フォローチェックのイベントを改善する
ページを表示した時点でフォロワーを取得できる機能を以前作りましたが、今回起きている事態は「フォローしているかチェック」機能がAjaxレスポンスでは働かないのが原因ですね。
これを避けるために次のような実装をしましょう。
- まず、「ボタンが画面に表示された」というイベント
rendered.freundschaftを監視し、まだアップデートされていないボタン(=クラスがfs-disabledのまま)をアップデートする - 「ログインしている/していない」は1回目のチェックでわかるので、1回しか確認しないようにする
- イベントが発生するのは、画面の表示(DOMREADY)とAjaxの更新の2回
ちなみに、rendered.freundschaftという書き方はjQueryにおけるイベントの名前空間ですね。clickイベントなんかはよく使いますが、このイベントの監視をやめたいなと思っても、他のJSがclickイベントを監視しているかもしれないんじゃないですか。そういうとき、click.takahashi.fumikiとかで登録しておけば、他のイベントリスナーをそのままに、自分のだけ削除できるんですね。
では、これを以前書いたfollower.jsに実装しましょう。
(function ($) {
'use strict';
// いろんなイベントを渡って使う変数を記録
var nonce = '',
loggedIn;
// documentオブジェクトを監視
$(document).on('rendered.freundschaft', function(){
var $btns = $('.fs-disabled'), // disabledが未確認のボタンをこの時点で取得
authorIds = [];
// ログインしていないことをすでに確認済みだったら、
// ログインボタンに変更
if( false === loggedIn ){
$btns.removeClass('fs-disabled').addClass('fs-login');
}
// ボタン全部の投稿者IDを取得して、ログイン判定
$btns.each(function(index, btn){
authorIds.push($(btn).attr('data-author-id'));
});
// 投稿者IDがあればAjax
if( authorIds.length ){
$.post(FreundschaftFollow.endpoint, {
action: FreundschaftFollow.actions.fs_status,
author_ids: authorIds
}).done(function(result){
if( result.logged_in ){
// ログインしているので、ユーザーに応じたボタンを出力
for( var prop in result.users ){
if( result.users.hasOwnProperty(prop) ){
var userId = prop.replace(/user_/, '');
if( result.users[prop] ){
// フォローしている
$('.fs-btn[data-author-id=' + userId + ']').removeClass('fs-disabled').addClass('fs-following');
}else{
// フォローしていない
$('.fs-btn[data-author-id=' + userId + ']').removeClass('fs-disabled').addClass('fs-follow');
}
}
}
// nonceを保存
nonce = result.nonce;
}else{
// ログインしていないので、
// ボタンをログインに
$btns.removeClass('fs-disabled').addClass('fs-login');
// ログインチェックを記録
loggedIn = false;
}
}).fail(function(xhr, status, message){
alert(message);
});
}
});
// DOMREADYでイベント発行
$(window).ready(function(){
$(document).trigger('rendered.freundschaft');
});
$(document).on('click', '.fs-btn', function(e){
// ここは変更なしなので中略
});
// フォロワーをもっと読み込むボタン
$(document).on('click', '.fs-more-btn', function(e){
e.preventDefault();
var $btn = $(this),
endpoint = $btn.attr('href') + '&offset=' + $btn.attr('data-offset');
// 読み込み中は何もしない
if( !$btn.hasClass('loading') ){
// 読み込み中に変更
$btn.addClass('loading');
$.get(endpoint).done(function(result){
// HTMLを挿入
$btn.before(result.html);
// オフセットを更新
$btn.attr('data-offset', result.offset);
// ボタンの更新イベント
$(document).trigger('rendered.freundschaft');
}).fail(function(xhr, status, error){
alert(error);
}).always(function(){
// 読み込み中を解除
$btn.removeClass('loading');
});
}
});
})(jQuery);
変わったところだけハイライトしようかと思いましたが、大変なのでGithubのコミットdiffを見てください。こんだけコード量が多くなってくると、githubの方が見やすいですね……。

まとめ
- Ajaxでどんどん読み込んだ
- Ajaxで返すJSONにHTMLぶっこんじゃいなよ!
- DOMREADY以外でも画面を更新した
さて、というわけで、色々とやってきましたが、他の細部を(フォロワー数が出てない)とか、そいういう問題もありつつ、本来の目的は$wpdbに詳しくなることなので、次回以降、細部の調整をしつつ、メッセージ機能の仕様を固めてみましょう。
シングルページWebアプリケーション ―Node.js、MongoDBを活用したJavaScript SPA
価格¥4,199
順位667,745位
著Michael S. Mikowski, Josh C. Powell
監訳佐藤 直生
翻訳木下 哲也
発行オライリージャパン
発売日2014 年 5 月 24 日
