angularJS倒计时器按递减顺序

时间:2017-09-01 11:35:27

标签: javascript html angularjs timer countdowntimer



var app = angular.module('quizApp', []);

app.directive('timer', function($timeout, $compile) {
  return {
    restrict: 'E',
    replace: false,
    scope: {
      interval: '=interval',
      startTimeAttr: '=startTime',
      countdownattr: '=countdown'
    },
    controller: function($scope, $element) {
      if ($element.html().trim().length === 0) {
        $element.append($compile('<span>{{millis}}</span>')($scope));
      }

      $scope.startTime = null;
      $scope.timeoutId = null;
      $scope.countdown = $scope.countdownattr && parseInt($scope.countdownattr, 10) > 0 ? parseInt($scope.countdownattr, 10) : undefined;
      $scope.isRunning = false;

      $scope.$on('timer-start', function() {
        $scope.start();
      });

      $scope.$on('timer-resume', function() {
        $scope.resume();
      });

      $scope.$on('timer-stop', function() {
        $scope.stop();
      });

      function resetTimeout() {
        if ($scope.timeoutId) {
          clearTimeout($scope.timeoutId);
        }
      }

      $scope.start = $element[0].start = function() {
        $scope.startTime = $scope.startTimeAttr ? new Date($scope.startTimeAttr) : new Date();
        resetTimeout();
        tick();
      };

      $scope.resume = $element[0].resume = function() {
        resetTimeout();
        $scope.startTime = new Date() - ($scope.stoppedTime - $scope.startTime);
        tick();
      };

      $scope.stop = $element[0].stop = function() {
        $scope.stoppedTime = new Date();
        resetTimeout();
        $scope.timeoutId = null;
      };

      $element.bind('$destroy', function() {
        resetTimeout();
      });

      var tick = function() {
        if ($scope.countdown > 0) {
          $scope.countdown--;
        } else if ($scope.countdown <= 0) {
          $scope.stop();
        }

        $scope.millis = new Date() - $scope.startTime;

        if ($scope.countdown > 0) {
          $scope.millis = $scope.countdown * 1000
        }

        $scope.seconds = Math.floor(($scope.millis / 1000) % 60);
        $scope.minutes = Math.floor((($scope.millis / (1000 * 60)) % 60));
        $scope.hours = Math.floor((($scope.millis / (1000 * 60 * 60)) % 24));
        $scope.days = Math.floor((($scope.millis / (1000 * 60 * 60)) / 24));

        //We are not using $timeout for a reason. Please read here - https://github.com/siddii/angular-timer/pull/5

        console.log($scope.seconds)
        $scope.timeoutId = setTimeout(function() {
          tick();
          $scope.$apply();
        }, $scope.interval);

        $scope.$emit('timer-tick', {
          timeoutId: $scope.timeoutId,
          millis: $scope.millis
        });
      };

      $scope.start();
    }
  };
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="quizApp">
  <timer interval="1000">Time ends in : {{hours}} hours, {{minutes}} minutes, {{seconds}} seconds</timer>
</div>
&#13;
&#13;
&#13;

我有这个计时器指令并且遇到了下面列出的一些问题。无法解决这个问题。任何帮助将不胜感激。

1)小时,分钟和秒未在标记中更新。

2)计时器按升序排列。我希望它按递减顺序排列。

我在我的测验应用中使用此计时器。所以,让我们说总时间是1小时54分00秒。在开始测验计时器应该开始减少秒,然后是几分钟,然后是几小时。当它变为0时,我应该收到警报。

提前谢谢。

1 个答案:

答案 0 :(得分:0)

我看到的一些问题

  1. 您的指令范围中定义了两个非可选属性,但它们未在计时器指令HTML中传入。
  2. 未填充HTML值的原因是这些值与指令范围无关。在将这些属性传递给指令时,您已设置了隔离范围。如果它们与指令绑定,我会将它们添加为模板。
  3. 无法定义计时器的启动位置。这是传递变量的好选择。
  4. 使用控制器功能代替链接link vs. controller
  5. 我不确定毫秒代码在做什么,所以我只是把它显示在柜台上,如果它存在的话。随意制作,但你想要它。
  6. 我不确定$ emit正在做什么,但我假设其他一些代码正在使用它。如果没有,你可以删除它。
  7. 从超时切换到使用间隔,因为它创建了大量的超时,但从未停止过它们。例如,每个循环都会产生一个新的timeoutId,所以如果你试图阻止它,它就会停止最新的循环。
  8. var app = angular.module('app', []);
    
    app.directive('timer', function($timeout, $compile) {
      return {
    restrict: 'E',
    scope: {
      interval: '=', //don't need to write word again, if property name matches HTML attribute name
      startTimeAttr: '=?startTime', //a question mark makes it optional
      countdownAttr: '=?countdown' //what unit?
    },
    template: '<div><p>'+
      '<p>Time ends in : {{ hours }} hour<span data-ng-show="hours > 1">s</span>, ' +
      '{{ minutes }} minutes, ' +
      '{{ seconds }} seconds ' +
      '<span data-ng-if="millis">, milliseconds: {{millis}}</span></p>' +
    
      '<p>Interval ID: {{ intervalId  }}<br>' +
      'Start Time: {{ startTime | date:"mediumTime" }}<br>' +
      'Stopped Time: {{ stoppedTime || "Not stopped" }}</p>' +
      '</p>' +
      '<button data-ng-click="resume()" data-ng-disabled="!stoppedTime">Resume</button>' +
      '<button data-ng-click="stop()" data-ng-disabled="stoppedTime">Stop</button>',
    
    link: function (scope, elem, attrs) {
    
      //Properties
      scope.startTime = scope.startTimeAttr ? new Date(scope.startTimeAttr) : new Date();
      var countdown = (scope.countdownAttr && parseInt(scope.countdownAttr, 10) > 0) ? parseInt(scope.countdownAttr, 10) : 60; //defaults to 60 seconds
      
      function tick () {
        
        //How many milliseconds have passed: current time - start time
        scope.millis = new Date() - scope.startTime;
        
        if (countdown > 0) {
          scope.millis = countdown * 1000;
          countdown--;
        } else if (countdown <= 0) {
          scope.stop();
          console.log('Your time is up!');
        }
    
        scope.seconds = Math.floor((scope.millis / 1000) % 60);
        scope.minutes = Math.floor(((scope.millis / (1000 * 60)) % 60));
        scope.hours = Math.floor(((scope.millis / (1000 * 60 * 60)) % 24));
        scope.days = Math.floor(((scope.millis / (1000 * 60 * 60)) / 24));
    
        //is this necessary? is there another piece of unposted code using this?
        scope.$emit('timer-tick', {
          intervalId: scope.intervalId,
          millis: scope.millis
        });
        
        scope.$apply();
        
      }
      
      function resetInterval () {
        if (scope.intervalId) {
          clearInterval(scope.intervalId);
          scope.intervalId = null;
        }        
      }
      
      scope.stop = function () {
        scope.stoppedTime = new Date();
        resetInterval();
      }
      
      //if not used anywhere, make it a regular function so you don't pollute the scope
      function start () {
        resetInterval();
        scope.intervalId = setInterval(tick, scope.interval);           
      }
      
      scope.resume = function () {
        scope.stoppedTime = null;
        scope.startTime = new Date() - (scope.stoppedTime - scope.startTime);
        start();
      }
      
      start(); //start timer automatically
      
      //Watches
      scope.$on('time-start', function () {
        start();
      });
      
      scope.$on('timer-resume', function() {
        scope.resume();
      });
      
      scope.$on('timer-stop', function() {
        scope.stop();
      });
      
      //Cleanup
      elem.on('$destroy', function () {
        resetInterval();
      });
      
    }
      };
    });
    <!DOCTYPE html>
    <html data-ng-app="app">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    </head>
    <body>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
    
     <timer interval="1000" countdown="61"></timer>
     
    </body>
    </html>

    或正在使用JSBin here