为什么Angular没有注意到这个变量的值已经改变了?

gre*_*600 1 javascript angularjs

我遇到了一个非常简单的Angular应用程序的问题.这是一个CodePen ; 相同的代码如下.

在这个程序,你点击一个按钮吃香蕉,并显示在页面上,你已经吃了香蕉的总数.每次点击后,应该有一秒钟的冷却时间才可以吃另一根香蕉.

为此,我做了以下事情:

  • $scope.cooling_down 是一个布尔值.

  • $scope.can_eat_banana是一个返回truefalse指示"吃香蕉"按钮是否可用的功能.基本上,如果$scope.cooling_down为false ,则返回true .

  • "吃香蕉"按钮有ng-disabled="!can_eat_banana()".

  • 当用户点击"只吃一根香蕉"按钮,我设置$scope.cooling_downtrue,并使用window.setTimeout()安排的回调来设置回false一秒钟后.

(你可能会问:为什么不摆脱$scope.can_eat_banana()完全,而只需使用ng-disabled="cooling_down"按钮?答:因为,随着游戏的发展,逻辑判断玩家可以吃一根香蕉是否会变得更加复杂,它似乎非常的混乱.把这个逻辑放在视图中.)

所以,当我运行这个测试用例时,会发生以下情况:

  1. 我加载页面.最初,该按钮已启用.

  2. 我点击"吃香蕉"按钮.正如所料,我的代码设置$scope.cooling_downtrue,并且按钮被禁用.到现在为止还挺好.

  3. 一秒钟后,我传入的回调window.setTimeout()开火了.(我console.log()在回调中有第一行确认它正在运行.)此回调设置$scope.cooling_downfalse.(您可以查看控制台以确认值已更新.)但是: Angular没有注意到值已更改.该按钮不会重新启用,并且{{cooling_down}}页面上的令牌仍然卡在上面true.

为什么?为什么Angular会在一次更改值时注意到(当true用户点击按钮后更改为),但第二次没有注意到(当回调触发并将其设置回时false)?

<!DOCTYPE html>

<html ng-app="game">

<head>
    <meta charset="utf-8">
    <title>Incredibly Stupid Banana Game</title>
</head>

<body ng-controller="GameController">

    <p>You have eaten {{bananas_eaten}} bananas.</p>

    <button type="button" ng-click="eat_banana()" ng-disabled="!can_eat_banana()">Eat a Banana</button>

    <p>[current value of cooling_down: {{cooling_down}}]</p>

    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
    <script>

        ( function() {

            var app = angular.module( "game", [] );

            app.controller( "GameController", [ "$scope", function( $scope ) {

                $scope.bananas_eaten = 0;
                $scope.cooling_down = false;

                $scope.eat_banana = function() {
                    $scope.bananas_eaten++;
                    $scope.cooling_down = true;
                    window.setTimeout( function() {
                        console.log( "setTimeout callback fired" );
                        $scope.cooling_down = false;
                        console.log( "Current value of cooling_down: " + $scope.cooling_down );
                    }, 1000 );
                };

                $scope.can_eat_banana = function() {
                    return !$scope.cooling_down;
                };

            } ] );

        }() );

    </script>

</body>

</html>
Run Code Online (Sandbox Code Playgroud)

Mal*_*lio 6

Angular在a之后不再运行其摘要循环window.setTimeout()(事实上​​,它甚至没有通知它).

$timeout()改用.