我们将 Durandal 用于我们的 SPA 应用程序,在我看来,这是一个常见的用例。我们有两个页面:一个页面是实体列表(带有过滤器、排序、虚拟滚动),另一个是实体的详细预览。因此,用户在列表页面上并设置了一个过滤器,结果列表就出来了。向下滚动一点后,用户会注意到一个他/她想查看详细信息的实体。因此,单击适当的链接用户将导航到详细信息预览页面。
在预览页面上的“工作完成”后,用户单击返回按钮(在应用程序本身或浏览器中),他/她回到列表页面。但是,默认的“入口”转换会将页面滚动到顶部,而不是滚动到列表中用户按下预览的位置。因此,为了“阅读”列表,用户必须在按下预览之前向下滚动他/她所在的位置。
所以我开始创建新的过渡,它将为某些页面(如列表搜索页面)保持滚动位置,而对于其他页面(如预览或编辑页面)在过渡完成时滚动到顶部。这很容易做到,然而,当我注意到当我点击navigateBack'按钮'时预览页面上有奇怪的行为时,我感到很惊讶。我已经长话短说,经过调查,我发现 windows.history.back 更早完成,然后进行转换,这导致预览页面在按下后退按钮时自动向下滚动到上一个(列表)页面的位置。这种滚动对 UI 产生了非常不愉快的影响,更不用说这对我的过渡来说是“彻底的灾难”。
有什么想法或建议在这种情况下我能做什么?
这是转换的代码。就我遇到这个问题而言,它只是一个尚未完成的工作副本。
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;
});