【问题标题】:JSF2+AJAX: Keep Scrollbar position, plain mojarraJSF2+AJAX:保持滚动条位置,普通 mojarra
【发布时间】:2012-03-08 12:13:21
【问题描述】:

我在 JSF2 中有一个更复杂的 webapp(glassfish 3.1 上的 +EJB3.1 +JPA2),它只使用标准 (mojarra) JSF 组件并大量使用嵌套复合和 ajax 调用。

每当发生 ajax 调用时,我希望所有滚动条都保存并恢复它们的位置。

我尝试了不同的方法,但没有一个对我来说真的很好,所以我需要一些提示:

1) JavaScript:

添加一个 JavaScript,当滚动发生时(element.onScroll 必须由 javascript 设置,因为该属性在 XHTML4 中不可用)或发生 ajax 请求时(jsf.ajax.addOnEvent(保存位置))。 将滚动条的位置保存在隐藏的输入字段或 cookie 中。 当 ajax 响应发生时恢复它们 (jsf.ajax.addOnEvent(restorePositions))。

如果不使用 cookie,则相反:

-滚动位置必须在ajax-request发生之前存储在隐藏输入字段中,所以这里必须使用element.onScroll-attribute。不是很好,因为它会多次保存位置,尽管在每个 ajax 请求之前一次就足够了。

-所有隐藏的输入字段必须在 ajax-call 中传输。由于 JSF 站点使用多种形式,因此似乎无法将它们自动添加到所有 ajax 调用中。相反,每个元素都需要将隐藏的输入字段添加到执行属性中。

-每个可滚动元素都需要一个隐藏的输入字段。

如果使用 cookie,则相反:

-嗯,需要为网站启用 cookie。

一般情况下:

-JavaScript 代码必须知道或遍历所有具有滚动条的元素。

-如果组件被重新渲染并且需要 onScroll-attribute 集,则必须再次执行 JavaScript 代码。

2) JavaScript + 复合:

所以我想写一个复合scrollStateSave,它指向元素的JSF-id,它有滚动条。复合包含隐藏的输入字段(或 cookie)和 javascript 并处理所有内容,因此我只需要为每个元素添加一个复合“实例”,它具有滚动条。 javascript 利用闭包来处理一个站点上的多个元素。

反对:

-在 ajax 调用后重新渲染时不会执行组合中的 javascript。有一些解决方法,但对我来说它们看起来很难看。

3) Myfaces 有一个选项 AUTO_SCROLL:

它是如何工作的?它适用于非 myfaces-jsf-components 吗?

4) Tomahawk 提供 t:autoScroll-behaviour:

对我来说,使用标准 mojarra-jsf2-components 的 tomahawk-replacements 是可以的。但是 t:autoscroll 的文档提到了属性“事件”,而实现需要属性“值”。我应该在这个属性中添加什么来使 t:autoScrolll 工作?

【问题讨论】:

    标签: jsf-2


    【解决方案1】:

    好的,我完成了解决方案 2,它运行良好。为了给其他开发者一些帮助,为了得到提示,我的解决方案的哪些部分可能会更好,我将发布代码。

    复合/WebContent/resources/components/scrollbarStateSaver.xhtml:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:composite="http://java.sun.com/jsf/composite">
    
    <h:body>
    
    <composite:interface>
        <composite:attribute name="for"/>
    </composite:interface>
    
    <composite:implementation>
        <h:outputScript name="scrollbars.js" library="js"/>
        <script type="text/javascript">
            saveScrollbarPos("#{cc.attrs.for}");
        </script>
    </composite:implementation>
    </h:body>
    </html>
    

    Javascript /WebContent/resources/js/scrollbar.js:

    function saveScrollbarPos(id) {
    var scrollbarid = id;
    
    function savePos() {
        var scrollbar = document.getElementById(scrollbarid);
        document.cookie = scrollbarid+".scrolltop="+scrollbar.scrollTop+"; path=/";
    }
    
    function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
    }
    
    function restorePos() {
        var scrollbar = document.getElementById(scrollbarid);
        scrollbar.scrollTop = readCookie(scrollbarid+".scrolltop");
    }
    
    function onStatusChange(data) {
        var status = data.status;
        if (status == "begin") {
            savePos();
        }
        else {
            restorePos();
        }
    };
    
    var scrollbar = document.getElementById(scrollbarid);
    if (scrollbar != null) {
        jsf.ajax.addOnEvent(onStatusChange);
        jsf.ajax.addOnError(onStatusChange);
    }
    };
    

    xhtml小例子:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsf/composite/components">
    
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Title</title>
    </h:head>
    
    <h:body>
        <h:form id="form">
            <div id="panel" style="overflow:auto;">
                long content with ajax-calls in it
            </div>
            <c:scrollbarStateSaver for="panel"/>
    
            <h:panelGroup id="panel" style="overflow:auto;">
                long content with ajax-calls in it
            </h:panelGroup>
            <c:scrollbarStateSaver for="form:panel"/>
        </h:form>
    </h:body>
    </html>
    

    当然,composite可以通过#{cc.parent}和#{cc.clientId}本身增强来计算jsf-id,那么composite的for-attribute可以处理jsf-ids,如果composite插入到与 h:panelGroup 相同的级别。

    JavaScript 可能也可以更好地解决,但它实际上是我的第一个 javascript。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多