あけましておめでとうございます。2014年も開発を中心に、自分なりにコツコツと頑張っていこうと思います(^^)
冬休み、やっと少しまとまった時間が取れたので、今さらながらにJavaScriptやjQueryを触っています。
半分遊びですが、今後もWeb系の開発が続くと思うので無駄にはならないだろうと(^^;
あと自分で遊びのWebシステムを作ろうと思っていて(多分Java EE7ベース)、「こんなことやりたい」といったイメージの具体化を少しずつしています。
無限スクロール
で、今やりたいことの1つに無限スクロールがあります。
TwitterやFacebookで画面下にスクロールするとデータが読み込まれるアレです。
最近、動画サービスのHuluに入ったのですが、画像で同じようなことがされていました。
別にJSFにこだわるわけではないのですが、JSFだとどんな風に実現するんだ?と気になって(^^;
イメージとしては以下のようにパネルのコンポーネントが並んでいる画面で下にスクロールすると新しいパネルが表示されていく、というそんな様な画面です。
jQueryだと
jQueryのプラグインだと色々あるみたいです(^^;以下サイトでまとまってました。
jQueryを触り始めて思ったのですが、プラグインがたくさんありすぎて、どれがマッチするのか探すの結構大変そうな気が…(^^;時間があると楽しいの間違いないですが、納期ある仕事だと悩ましそうな。
JSFだと
JSFでも普通にjQueryのプラグインとうまく組み合わせて作ることもできそうです。
実際、以下のサイトはそんな感じでした。
ただ、この例ではPrimeFacesのremoteCommandコンポーネント(クライアントサイドのJSから管理対象ビーン(Backing Bean)のメソッドを呼ぶためのコンポ)を使っているので純粋にjQueryだけでとは言えないのですが(^^;
PrimeFaces ExtensionsのWaypointコンポ
PrimeFacesのデモを何気にみていたら、Extensionsに無限スクロールのサンプルがあって、コンポーネントもありました。(なぜ上記のサンプルではPrimeFaces使ってるのにこれを使わないかは不明です…)
Waypointコンポーネント
http://fractalsoft.net/primeext-showcase-mojarra/views/waypoint.jsf
中身はjQueryのWaypointプラグインを利用してると思われます(サンプルのコード的にも)
で、これを使って簡単に最初のイメージのものを作ってみました。
画面表示時こんな感じでパネルがワラワラと並んでます。
スクロールして画面の最下端に触れるとイベントが発火して「すたーと」ダイアログ表示とともに追加のパネルデータを読み込みます(読み込む前の時点では以下図のようにパネル50まで存在)。
パネルの読み込み完了のイベントで「えんど」ダイアログが表示されます。
パネルがちゃんと増えてるー。
そして再度スクロールして画面下に到達すると同じことの繰り返しです。
500個くらいまでいってみた(^^;
無限スクロールできた(^^)
コード
管理対象ビーン(Backing Bean)に画面に表示されるパネルの元データとしてListを定義します。この例ではサンプルを簡単にするためStringにしています。
初期表示時に文字列を50個、リストに入れます。またリストに文字列を追加するメソッドも定義しておきます。
package jp.co.hoge.pfsample.ext.waypoint;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import lombok.Getter;
import lombok.Setter;
@Named(value = "wayPointPanelBean")
@ViewScoped
public class WayPointPanelBean implements Serializable{
@Getter @Setter
private List<String> strList;
private int strListMax = 0;
@PostConstruct
public void init(){
strList = new ArrayList<>();
for(int i = 1; i <= 50; i++){
strList.add(Integer.toString(i));
}
}
public void loadMorePanel(){
strListMax = strList.size();
for(int i = strListMax + 1; i <= strListMax + 10; i++){
strList.add(Integer.toString(i));
}
}
}
画面側は以下のような感じで、少しややこしい感じです。
<?xml version='1.0' encoding='UTF-8' ?>
<html lang="ja"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
<h:head>
<title>Waypoint</title>
</h:head>
<h:body>
<h:form prependId="true">
<p:dataGrid id="dgPanel" var="pnl" value="#{wayPointPanelBean.strList}">
<p:panel id="pnl" header="#{pnl}">Name:hogehoge#{pnl}</p:panel>
</p:dataGrid>
<p:remoteCommand id="remote" name="loadMore" update="dgPanel" process="@this"
actionListener="#{wayPointPanelBean.loadMorePanel()}"
oncomplete="handleLoadEnd();">
</p:remoteCommand>
<pe:waypoint id="way" offset="function(){return $.waypoints('viewportHeight') - $(this).outerHeight()}" widgetVar="widgetWay">
<pe:javascript event="reached" execute="handleLoadStart(ext);" />
</pe:waypoint>
<script type="text/javascript">
function handleLoadStart(ext){
if(ext.direction === "down"){
alert("すたーと");
PF('widgetWay').remove();
loadMore();
}
}
function handleLoadEnd(){
alert("えんど");
PF('widgetWay').register();
}
</script>
</h:form>
</h:body>
</html>
流れ的には
- waypointコンポを定義してスクロールで検知する対象を決めます
- 1の条件を満たした場合にキックするJavaScriptをjavascriptコンポで紐づけます
- 2で呼び出されるJavaScriptの処理を定義します
- 3の中で管理対象ビーン(Backing Bean)のメソッドを呼ぶためにremoteCommandコンポを定義してactionListenerでメソッドを紐づけます
こんな感じです。1では通常、for属性でコンポのIDを指定するか、入れ子にwaypointを定義します。上記ではどちらの定義でもないのですが、forがnullの場合は親に対するものとなるため、上記例はFormが対象となります
JavaScriptの中でwaypointを外したり付けたりしてるのは、データを増やしたタイミングで再度イベント実行されて無限ループされるのを防ぐためです。
offsetが最初いまいちイメージできなくてマゴマゴしたのですが、以下jQuery Waypointsのドキュメントやサンプルが参考になりました。
$.waypoints('viewportHeight')はざっくり言うと内部で表示されている縦幅なんですね。
http://imakewebthings.com/jquery-waypoints/#docs
わかりにくかったので図にしてみました。
上記のwaypointはfor属性でコンポーネント指定していないので、親であるformが指定されています。なので、formのoffsetがマイナス画面でみえない分=最下端となってます。
慣れるとわりと自由に使えそう…かな(^^;
環境
- Windows 8 Pro 64bit
- JDK8
- NetBeans 7.4
- GlassFish 4.0
- PrimeFaces 4.0
- PrimeFaces Extensions 1.1.0