是否可以使用$timeout
承诺使scrollTo
可链接,如下所示?如果没有,我如何编写scrollTo作为一个承诺,以便我可以使用then回调?
HTML:
<div ng-click=toTop()>click me</div>
JS:
app.controller('MainCtrl', function($scope, $timeout) {
$scope.toTop = function() {
var bodyEl = angular.element(document.querySelector('#body'));
scrollTo_(bodyEl[0], 0, 500);
};
function scrollTo_(element, to, duration) {
if (duration <= 0) {
$timeout.cancel(forward);
console.log('yoyo');
return forward;
}
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
var forward = $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
scrollTo_(element, to, duration - 10);
}, 10, false);
}
});
答案 0 :(得分:1)
这就是我如何完成递归承诺:
function scrollTo_(element, to, duration) {
if(duration<=0) return Promise.resolve();
var difference = to - element.scrollTop,
perTick = difference / duration * 10;
return $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
}, 10, false).then(function(){
duration -= 10;
return scrollTo_(element, to, duration)
});
}
修改强>
如果你想在两者之间停止超时,我猜你可以这样做:
var scrollTopTimeoutFlag = true, scrollTopTimeout;
function scrollTo_(element, to, duration) {
if(duration<=0 || !scrollTopTimeoutFlag){
if(scrollTopTimeout) return $timeout.cancel(scrollTopTimeout);
return $q.when(); // $q.when == Promise.resolve
}
var difference = to - element.scrollTop,
perTick = difference / duration * 10;
scrollTopTimeout = $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
}, 10, false);
return scrollTopTimeout.then(function(){
duration -= 10;
return scrollTo_(element, to, duration)
});
}
答案 1 :(得分:1)
很难解释“使用$ timeout承诺使scrollTo
可链接,如下所示”,因为scrollTo
不可链接。因此,让我们假设scrollTo_()
通过让它返回一个$ q的承诺而成为“可以”。
有了这个假设,似乎合理的是返回的承诺应该在完成滚动时解决,或者如果滚动在完成之前停止(通过另一个var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, $q) {
var stopSignal = false;
$scope.toTop = function() {
var element = angular.element(document.querySelector('#body'))[0];
stopSignal = true; // stop previous.
scrollTo_(0, 500).then(function() { // Yay, scrollTo_() is thenable!
console.log('scroll complete');
}, function() {
console.log('scroll stopped');
});
function scrollTo_(to, duration) {
var startTime = null,
startPos = element.scrollTop,
dfrd = $q.defer();
function step(timestamp) {
if(stopSignal) {
// This block kills an animation that's in progress.
// It doesn't affect freshly initiated animations.
stopSignal = false; // reset the `stopSignal` flag.
dfrd.reject(); // reject the deferred, to indicate non-completion
return; // prevent further animation by returning early and killing the recursion.
}
if (!startTime) {
stopSignal = false;
startTime = timestamp;
}
var progress = timestamp - startTime;
if (progress < duration) {
element.scrollTop = startPos + (to - startPos) * progress / duration; // linear movement w.r.t. time, though not necessarily at regular intervals.
window.requestAnimationFrame(step); // recurse
} else {
element.scrollTop = to; // ensure final position is accurate
dfrd.resolve();
}
}
// This is horribly messy but necessary(?) for the stop signal to take effect.
window.requestAnimationFrame(function() {
stopSignal = false;
window.requestAnimationFrame(step);
});
return dfrd.promise;
}
};
});
调用)则拒绝。
这里是:
{{1}}
bind_param() 双击以查看滚动效果在另一个启动之前停止。
正如您所看到的,通过丢弃$ timeout和
可以避免10ms的timout引起的间隔不久之后,每个人都应该以这种方式编写浏览器动画。