简体   繁体   English

除非我使用$ timeout,否则AngularJs不能在指令中进行动画处理

[英]AngularJs animating in directive doesn't work unless i use $timeout

I can't figure out why the following animation doesn't work as it should: 我不知道为什么以下动画无法正常工作:

app.directive('openMenu', ['$animate', '$timeout', function($animate, $timeout) {
    return {
        link: function(scope, elem) {
            elem.bind('click', function() {

                if(elem.is(':animated'))
                    return;

                $timeout(function() {
                    $animate.addClass(elem, 'see');
                }, 0);

            });
        }
    }
}]);

And in this one the animation doesn't work at all (and class is not added either): 而且在这一动画中根本不起作用(也没有添加类):

app.directive('openMenu', ['$animate', function($animate) {
    return {
        link: function(scope, elem) {
            elem.bind('click', function() {

                if(elem.is(':animated'))
                    return;

                $animate.addClass(elem, 'see');

            });
        }
    }
}]);

In the second code snippet I only removed $timeout , which is 0, I tried to use self-firing functions to check - animating works only when I am using timeouts. 在第二个代码片段中,我仅删除了$timeout ,它是0,我尝试使用自触发函数进行检查-仅当我使用超时时,动画才有效。 Can someone explain me why? 有人可以解释我为什么吗?

middle {
    margin-left: 0;
}
middle.see {
    margin-left: 270px;
}
.middle.see-add {
    -webkit-transition: margin-left 300ms;
    -moz-transition: margin-left 300ms;
    -ms-transition: margin-left 300ms;
    -o-transition: margin-left 300ms;
    transition: margin-left 300ms;
    margin-left: 0;
}
.middle.see-add.see-add-active {
    margin-left: 270px;
}

Here is the markup: 这是标记:

<div class="middle" open-menu></div>

Since your directive uses jQuery and jQuery modify the DOM, we need to tell angular about it. 由于您的指令使用jQuery且jQuery修改了DOM,因此我们需要对它进行介绍。 To do so, you need to do $scope.$apply but you would run into the error : "digest already in progress". 为此,您需要执行$ scope。$ apply,但是会遇到错误:“消化已在进行中”。

The code executed inside the $timeout guarantee that your code will be safely executed on the next digest cycle. 在$ timeout内部执行的代码保证了您的代码将在下一个摘要周期安全地执行。

0 is the default value, you don't even need to specify it. 默认值为0,甚至不需要指定它。 You could simply write : 您可以简单地写:

 $timeout(function() {
    $animate.addClass(elem, 'see');
 });

The $timeout service is simply a convenient service equivalent to : $ timeout服务只是一个便捷的服务,等效于:

var timeout = setInterval(function(){
    // do stuff
    $scope.$apply();
}, 0); 

You can find extensive information about the digest mechanism in the official documentation : https://docs.angularjs.org/error/$rootScope/inprog 您可以在官方文档中找到有关摘要机制的大量信息: https : //docs.angularjs.org/error/$rootScope/inprog

Your problem is that you happen to be out of the Angular life-cycle. 您的问题是您碰巧不在Angular生命周期内。 You are using .bind so Angular will not be notified whenever something has changed. 您使用的是.bind因此只要发生更改,Angular都不会收到通知。 The $timeout works because it's a one of the wrappers to notify Angular about an outside change. $timeout之所以有效,是因为它是将外部更改通知Angular的包装器之一。 You could also use $apply . 您也可以使用$apply Both, the $timeout and $apply take a callback which will be executed. $timeout$apply都将执行一个回调。 After the callback is finished Angular starts a digest beginning at the rootScope . 回调完成后,Angular从rootScope开始开始digest Now every binding will be updated and everything should work properly. 现在,每个绑定都将更新,并且所有内容都应正常运行。

scope.$apply(function() {
    $animate.addClass(elem, 'see');
});

I think it's because elem.bind('click') is a jQuery function, which is running outside of the angular digest phase. 我认为这是因为elem.bind('click')是一个jQuery函数,它在角度摘要阶段之外运行。

Probably this would work as well instead of using $timeout : 也许这也可以使用$timeout代替:

scope.$apply(function() {
     $animate.addClass(elem, 'see');
})'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM