在Angular.js
和Socket.io
应用中,我希望在通过Socket.io
发送图片之前显示加载。我写这段代码:
当点击一个按钮时,这个代码会运行,首先我要运行startLoading
函数,之后我想发送图像:
$scope.startLoading(function(){
$scope.socket.emit('sendImg', {
data: $scope.newImg,
});
});
这是我的startLoading
函数:
$scope.startLoading = function (callback) {
//DO SOME STUFF LIKE ENABLING LOADING ANIMATION
$scope.animation =true; //binded to UI
$scope.errors = false; //binded to UI
callback(); //it seems this code runs before above lines
};
但似乎callback()
行在前两行之前运行,因此,我的加载在将图像发送到服务器后出现!为什么?我将回调线更改为这样的超时并且它工作正常,但这是一个很好的解决方案吗?我不这么认为!我需要为标准代码做些什么?
$scope.startLoading = function (callback) {
//DO SOME STUFF LIKE ENABLING LOADING ANIMATION
$scope.animation =true; //binded to UI
$scope.errors = false; //binded to UI
$timeout(function(){callback();}, 1000);
};
实际上,代码按顺序运行但是调用回调并发送图像冻结页面,因此,我的加载在冻结结束后出现。但我需要在冻结之前加载开始
答案 0 :(得分:1)
您的代码确实按顺序运行,但前两行不会立即更改UI。
当您为范围变量分配一些值时,它只是一个变量赋值。它不会触发任何事件。 Angular只会在以后评估绑定并查找更改时更新UI。所以这是发生的事情:
$scope.startLoading = function (callback) {
// Presumably this is called from some event from Angular,
// so all this is run in an $apply, in an Angular "context".
// But this is still "plain" javascript, so the next two lines
// are just plain variable assignments.
$scope.animation =true;
$scope.errors = false;
callback(); // This function does its thing, then returns
// When this function returns, Angular will evaluate all of its
// bindings, will find that the above values have changed,
// and will update the DOM.
};
有关详细信息,请参阅"与浏览器事件循环集成" dev guide中的部分。
您想要的是确保在回调运行之前更新DOM。我认为使用$timeout
对此没有任何不妥。
可能有更好/更好的方式,但我还没有找到它......
所以它会变成这样:
$scope.startLoading = function (callback) {
$scope.animation =true; // at this point, these are just
$scope.errors = false; // plain variable assignments
$timeout(callback); // schedule callback to run later
// After this returns, Angular will evaluate its bindings,
// and update the DOM, so if $scope.animation and $scope.errors
// are bound to something, they can trigger some visible change.
// callback will be called in the next $digest cycle, so _after_
// the DOM has been updated
};
(如果您只想在下一个" tick"中运行它,则无需为超时指定值。此外,无需包装回调,它可以直接传递给$timeout
。)
希望这有帮助!