通过Primefaces,Waypoint和Masonry在JSF中实现无限滚动

时间:2014-01-11 16:30:51

标签: jsf-2 primefaces jquery-masonry jquery-waypoints primefaces-extensions

我试图在jQuery Waypoint和Masonry API的帮助下使用Primefaces实现无限滚动。

这是我到目前为止所做的:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions">
<f:view>
    <h:head>
        <h:outputScript library="primefaces" name="jquery/jquery.js" />
        <h:outputScript name="js/global.js"/>
        <h:outputScript name="js/masonry.pkgd.js"/>
        <h:outputScript name="js/imagesloaded.pkgd.js"/>
        <h:outputStylesheet name="css/global.css" />                
        <title>Gallery</title>      
    </h:head>
    <h:body>
        <h:form prependId="false">      
            <h:panelGroup id="galleryPanel" layout="block">
                <p:outputPanel autoUpdate="true">
                    <h:panelGroup layout="block" styleClass="galleryContainer">
                        <ui:repeat id="gallery" value="#{galleryController.images}"  var="image">
                            <h:panelGroup layout="block" styleClass="item">
                                <h:graphicImage library="images" name="demo/#{image}.jpg" />
                            </h:panelGroup>                 
                        </ui:repeat>
                    </h:panelGroup>                                     
                </p:outputPanel>                
                <pe:waypoint id="waypoint" widgetVar="waypointWidget" offset="function(){return $.waypoints('viewportHeight') - $(this).outerHeight()}">
                    <pe:javascript event="reached" execute="handleLoadStart(ext);"/>  
                </pe:waypoint>
                <h:outputScript target="body">
                    var layout = function(){
                        var container = $('.galleryContainer');
                        $(container).imagesLoaded(function(){
                            $(container).masonry({
                                itemSelector : '.item',
                                columnWidth : 240
                            });
                        });
                    };

                    var handleLoadStart = function(ext) {
                        if (ext.direction == "down") { 
                            PF('waypointWidget').remove();                          
                            moreMedia();
                        }
                    };

                    var handleLoadStop = function(){
                        layout();
                        PF('waypointWidget').register();                         
                    };                  

                    $(document).ready(function(){
                        layout();
                    });
                </h:outputScript>               
                <p:remoteCommand name="moreMedia" update="gallery" actionListener="#{galleryController.loadMore}" oncomplete="handleLoadStop()"/>
            </h:panelGroup>
        </h:form>
    </h:body>
</f:view>
</html>

Managed Bean是:

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

@ManagedBean(name="galleryController")
@ViewScoped
public class GalleryController implements Serializable {

    private static final long serialVersionUID = 563439107531288284L;

    private List<String> images;

    @PostConstruct
    public void initialize() {
        images = new ArrayList<>();     
        IntStream.range(1, 16).forEach(i->images.add(new String("image" + i)));     
    }

    public void loadMore(ActionEvent event){
        IntStream.range(1, 16).forEach(i->images.add(new String("image" + i))); 
    }

    public List<String> getImages() {
        return images;
    }

    public void setImages(List<String> images) {
        this.images = images;
    }    
}

部分有效,因为它有问题。

主要问题是,当我将新图像添加到现有图像列表时,ui:repeat将完全呈现。我不想这样做。因为通过这种方式,现有图像也会被加载。像FF或Chome这样的现代浏览器会缓存图像,所以它对他们来说不是问题,但在IE浏览器中,我可以在网络控制台中看到它正在发送GET来获取这些图像。从性能角度来看,已经加载的图像不应该被提取,只有新添加的图像。

但我不知道如何在JSF中创建它!

另外,作为副作用,砌体没有按预期工作。每当onComplete p:remoteCommand触发layout()方法时,滚动条就会设置为顶部。从功能的角度来看,它应该保持在Waypoint触发下一次加载的位置。

任何建议都会非常有用。

3 个答案:

答案 0 :(得分:0)

PrimeFaces Extensions有pe:fluidGrid顺便说一下基于Masonry。检查展示http://primeext.mooo.com:8080/primeext-showcase/views/fluidGrid.jsf

答案 1 :(得分:0)

初始加载后,您不再更新ui:repeat。使用临时数据存储(如h:inputHidden)来保存由托管返回和格式化的数据,然后使用JavaScript将数据从h:inputHidden移动到Masonry。在Masonry中使用以下内容附加数据:

$container.masonry( "appended", html, true );    

其中html是h:inputHidden

的数据

如果您需要,可以访问以下博客了解详情。它不使用PrimeFaces也不使用WayPoints,但是如何更新Masonry与想要做的类似。

http://kahimyang.info/kauswagan/code-blogs/1699/how-to-use-and-append-data-to-masonry-in-responsive-jquerymobile-with-jsf-2-and-ajax

答案 2 :(得分:0)

假设您需要使用一个无限列表

<ul>
   <li>item 1</li>
   <li>item 2</li>
   <li>...</li>
</ul>

这个想法是创建一个名为list.xhml的复合组件,例如带有属性索引。 例如,该组件可以加载10个元素的页面。 滚动时,使用JQuery ajax加载该组件并将其添加到dom。