使用keepScrollPosition和navigateBack进行转换

时间:2013-04-22 18:50:38

标签: durandal

我们正在使用Durandal进行SPA应用,并且在我看来,它是常见的用例。我们有两个页面:一个页面是实体列表(带有过滤器,排序,虚拟滚动),另一个页面是实体的详细预览。因此,用户在列表页面上并设置过滤器并显示结果列表。滚动一点点后,用户会注意到他/她想要查看详细信息的实体。因此,单击正确的链接用户将导航到详细信息预览页面。

在预览页面上“完成工作”后,用户单击后退按钮(在应用程序本身或浏览器中),他/她回到列表页面上。但是,默认的“入口”转换将页面滚动到顶部而不是用户按下预览的列表上的位置。因此,为了“阅读”列表,用户必须在按下预览之前向下滚动他/她。

所以我开始创建新的转换,对于某些页面(如列表搜索页面)保持滚动位置,其他页面(如预览或编辑页面)在转换完成时滚动到顶部。然而这很容易做到,当我注意到当我点击navigateBack'按钮'时预览页面上有奇怪的行为时,我感到很惊讶。我已经很久了,经过调查我发现windows.history.back早先完成了转换,这导致预览页面在按下后退按钮时自动滚动到上一个(列表)页面的位置。这种滚动对用户界面产生了非常不愉快的影响,没有提到它对我的过渡来说是“彻头彻尾的灾难”。

在这种情况下,我有什么想法或建议?

以下是过渡代码。就这个问题而言,这只是一个尚未完成的工作副本。

define(['../system'], function (system) {
var fadeOutDuration = 100;

var scrollPositions = new Array();

var getScrollObjectFor = function (node) {
    var elemObjs = scrollPositions.filter(function (ele) {
        return ele.element === node;
    });
    if (elemObjs.length > 0)
        return elemObjs[0];
    else
        return null;
};

var addScrollPositionFor = function (node) {
    var elemObj = getScrollObjectFor(node);
    if (elemObj) {
        elemObj.scrollPosition = $(document).scrollTop();
    }
    else {
        scrollPositions.push({element: node, scrollPosition: $(document).scrollTop()});
    }
};

var scrollTransition = function (parent, newChild, settings) {
    return system.defer(function (dfd) {
        function endTransition() {
            dfd.resolve();
        }

        function scrollIfNeeded() {
            var elemObj = getScrollObjectFor(newChild);
            if (elemObj)
            {
                $(document).scrollTop(elemObj.scrollPosition);
            }
            else {
                $(document).scrollTop(0);
            }
        }

        if (!newChild) {


            if (settings.activeView) {
                addScrollPositionFor(settings.activeView);
                $(settings.activeView).fadeOut(fadeOutDuration, function () {
                    if (!settings.cacheViews) {
                        ko.virtualElements.emptyNode(parent);
                    }
                    endTransition();
                });
            } else {
                if (!settings.cacheViews) {
                    ko.virtualElements.emptyNode(parent);
                }
                endTransition();
            }
        } else {
            var $previousView = $(settings.activeView);
            var duration = settings.duration || 500;
            var fadeOnly = !!settings.fadeOnly;

            function startTransition() {

                if (settings.cacheViews) {
                    if (settings.composingNewView) {
                        ko.virtualElements.prepend(parent, newChild);
                    }
                } else {
                    ko.virtualElements.emptyNode(parent);
                    ko.virtualElements.prepend(parent, newChild);
                }

                var startValues = {
                    marginLeft: fadeOnly ? '0' : '20px',
                    marginRight: fadeOnly ? '0' : '-20px',
                    opacity: 0,
                    display: 'block'
                };

                var endValues = {
                    marginRight: 0,
                    marginLeft: 0,
                    opacity: 1
                };

                $(newChild).css(startValues);
                var animateOptions = {
                    duration: duration, 
                    easing : 'swing', 
                    complete: endTransition,
                    done: scrollIfNeeded
                };

                $(newChild).animate(endValues, animateOptions);
            }

            if ($previousView.length) {
                addScrollPositionFor(settings.activeView);
                $previousView.fadeOut(fadeOutDuration, startTransition);
            } else {
                startTransition();
            }
        }
    }).promise();
};

return scrollTransition;

});

1 个答案:

答案 0 :(得分:0)

更简单的方法是在模块停用时存储滚动位置并恢复viewAttached上的滚动。

您可以将这些职位存储在某个全局app变量中:

app.scrollPositions = app.scrollPositions || {};
 app.scrollPositions [system.getModuleId(this)] = theCurrentScrollPosition;