angularjs短信验证码及秒倒计时

  工作H5开发需要做短信验证码及秒倒计时,如果是用纯JS做好像还比较容易,但用angularJS做还是一些坑,特此记录一下,有如下几种实现方式。

一.setTimeout方式实现

<html>
<head>
	<title>AngularJs倒计时</title>
</head>
<body>
	<div ng-controller="registerCtrl">
		<div>
			<div>
				<label>验证码:</label>
				<input ng-model='verifCode' ng-disabled="verifCodeDisabled" placeholder="请输入验证码"></input>
				<button ng-bind="timing" ng-click="reacQuire()"></button>
			</div>
		</div>
		
		<div class="btn-group">
			<button ng-click="submitBtn()" ng-disabled="submitBtnDisabled">提交</button>
		</div>
	</div>
	<script src="jquery-1.8.3.js"></script>
	<script src="angular1.2.9.js"></script>
	<script src="index.js"></script>
</body>
</html>

index.js

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

app.controller('registerCtrl', function($scope,$interval){
   	let countDown = 10;
	$scope.timing = countDown + "s";
	
	$scope.verifCode = '';
	$scope.verifCodeDisabled = false;
	$scope.submitBtnDisabled = false;
	
	function settime() {
		if(countDown > 0) {
			setTimeout(function() {settime(countDown--); $scope.$apply();}, 1000);
			$scope.timing = countDown + 's';
		}else {
			$scope.timing = "重新获取";
			$scope.verifCodeDisabled = true;
			$scope.submitBtnDisabled = true;
		}
	}
	
	settime();
	
	$scope.reacQuire = function() {
		if(countDown <= 0) {
			countDown = 10;
			$scope.timing = countDown + "s";
			settime();
            $scope.verifCodeDisabled = false;
			$scope.submitBtnDisabled = false;
		}
	};
	
	$scope.submitBtn = function() {
		if(!$scope.verifCode) {
			alert('请输入验证码');
			return;
		}
		alert('提交成功');
	};
});

angular.element(document).ready(function() {   
	angular.bootstrap(document,['myModule']);  
});

运行效果:


  当倒计到0,输入框和“提交”按钮变灰,倒计时按钮变成“重新获取”,如下所示:


  在这里的实现在,必须注意settime函数中的$scope.$apply();在这里,如果没有$scope.$apply();则倒计时,只会倒计一次,虽然JS确实在一秒一秒的减少,但由于异步(延迟)的存在,当开始执行回调函数的时候,angularJS自身controller中的脏值检测已经结束,无法检测到回调函数导致数据的变化,导致页面无法正常倒计时间。同样,如果在settime函数级别加上$scope.$apply();效果确实可以,但F12可以看到angularJS报错$apply already in progress。详见:理解和解决angularJS报错$apply already in progress

 

二.修改网上查看的实现方式,也能达到目的

<html>
<head>
	<title>AngularJs倒计时</title>
</head>
<body>
	<div ng-controller="registerCtrl">
		<a href="javascript:" ng-click="sendphonecode(reg_phone)" ng-class="paraclass" ng-bind="paracont">获取验证码</a>  
	</div>
	<script src="jquery-1.8.3.js"></script>
	<script src="angular1.2.9.js"></script>
	<script src="app.js"></script>
</body>
</html>

app.js

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

app.controller('registerCtrl', function($scope, $interval) {
	
    $scope.paracont = "获取验证码";  
    $scope.paraclass = "but_null";  
    $scope.paraevent = true;
   
    var second = 10, timePromise = undefined;  
   
    function interval(){  
	  if(second<=0){  
		$interval.cancel(timePromise);  
		timePromise = undefined;  
		
		$scope.paracont = "重发验证码";  
		$scope.paraclass = "but_null";  
		$scope.paraevent = true;  
	  }else{  
		$scope.paracont = second + "秒后可重发";  
		$scope.paraclass = "not but_null";  
		second--;
	  }  
    }
	
	timePromise = $interval(interval, 1000, 100); //表示每一秒执行一次,执行100次
    
	$scope.sendphonecode = function() {
		if(second <= 0) {
			second = 10;
			timePromise = $interval(interval, 1000, 100); //表示每一秒执行一次,执行100次
		}
	};
});

angular.element(document).ready(function() {   
	angular.bootstrap(document,['myModule']);  
});

运行效果:

 

三.用$interval实现

<html>
<head>
	<title>AngularJs倒计时</title>
</head>
<body>
	<div ng-controller="registerCtrl">
		<div>
			<div>
				<label>验证码:</label>
				<input ng-model='verifCode' ng-disabled="verifCodeDisabled" placeholder="请输入验证码"></input>
				<button ng-bind="timing" ng-click="reacQuire()"></button>
			</div>
		</div>
		
		<div class="btn-group">
			<button ng-click="submitBtn()" ng-disabled="submitBtnDisabled">提交</button>
		</div>
	</div>
	<script src="jquery-1.8.3.js"></script>
	<script src="angular1.2.9.js"></script>
	<script src="index02.js"></script>
</body>
</html>

index02.js

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

app.controller('registerCtrl', function($scope,$interval){
   	let countDown = 10;
	$scope.timing = countDown + "s";
	
	$scope.verifCode = '';
	$scope.verifCodeDisabled = false;
	$scope.submitBtnDisabled = false;
	
	var time = $interval(interval, 1000);
	
	function interval() {
		countDown--;
		$scope.timing = countDown + "s";
		if(countDown <= 0) {
			$interval.cancel(time);
			$scope.timing = "重新获取";
			$scope.verifCodeDisabled = true;
			$scope.submitBtnDisabled = true;
		}
	}
	
	$scope.reacQuire = function() {
		if(countDown <= 0) {
			countDown = 10;
			$scope.timing = countDown + "s";
			time = $interval(interval, 1000);
			$scope.verifCodeDisabled = false;
			$scope.submitBtnDisabled = false;
		}
	};
	
	$scope.submitBtn = function() {
		if(!$scope.verifCode) {
			alert('请输入验证码');
			return;
		}
		alert('提交成功');
	};
});

angular.element(document).ready(function() {   
	angular.bootstrap(document,['myModule']);  
});

运行效果同方法一。

 

四.指令方式

<html>
<head>
	<title>AngularJs倒计时</title>
</head>
<body>
	<div ng-controller="registerCtrl">
		 <timer-button show-timer="initTime" timeout="timeoutValue">获取验证码</timer-button>
	</div>
	<script src="jquery-1.8.3.js"></script>
	<script src="angular1.2.9.js"></script>
	<script src="index03.js"></script>
</body>
</html>

index03.js

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

app.controller('registerCtrl', function($scope, $interval){
   	$scope.initTime = false;
	$scope.timeoutValue = 10000;
});

app.directive('timerButton', function($timeout, $interval){
    return {
        restrict: 'AE',
        scope: {
            showTimer: '=',
            timeout: '='
        },
        link: function(scope, element, attrs){
            scope.timer = false;
            scope.timerCount = scope.timeout / 1000;
            scope.text = "获取验证码";

            scope.onClick = function(){
                scope.showTimer = true;
                scope.timer = true;
                scope.text = 's';
                var counter = $interval(function(){
					if(scope.timerCount > 0) {
						scope.timerCount = scope.timerCount - 1;
					}else {
						scope.timerCount = '';
					}
                }, 1000);

                $timeout(function(){
                    scope.text = "重新获取";
                    scope.timer = false;
                    $interval.cancel(counter);
                    scope.showTimer = false;
                    scope.timerCount = scope.timeout / 1000;
                }, scope.timeout);
            }
        },
        template: '<button ng-click="onClick()" class="button button-calm xgmm-btn" ng-disabled="timer"><span ng-show="showTimer">{{ timerCount }}</span>{{text}}</button>'
    };
});

angular.element(document).ready(function() {   
	angular.bootstrap(document,['myModule']);  
});

运行效果:

  刚打开页面,显示”获取验证码“按钮

  点击”获取验证码“按钮,进行秒倒计时

  倒计到0时,显示”重新获取“,此时,可点击“重新获取”按钮重新进行倒计时。

 

五.AngularJs $interval 和 $timeout

1.$interval

  window.setInterval的Angular包装形式。Fn是每次延迟时间后被执行的函数。

  间隔函数的返回值是一个承诺。这个承诺将在每个间隔刻度被通知,并且到达规定迭代次数后被取消,如果迭代次数未定义,则无限制的执行。通知的值将是运行的迭代次数。取消一个间隔,调用$intreval.cancel(promise)。

  备注:当你执行完这项服务后应该把它销毁。特别是当controller或者directive元素被销毁时而$interval未被销毁。你应该考虑到在适当的时候取消interval事件。

使用:$interval(fn,delay,[count],[invokeApply],[Pass]);

  fn:一个将被反复执行的函数。

  delay:每次调用的间隔毫秒数值。

  count:循环次数的数值,如果没设置,则无限制循环。

  invokeApply:如果设置为false,则避开脏值检查,否则将调用$apply。

  Pass:函数的附加参数。

方法:cancel(promise);

  取消与承诺相关联的任务。

  promise:$interval函数的返回值。

使用代码:

(function () {
    angular.module("Demo", [])
    .controller("testCtrl",["$interval",testCtrl]);
    function testCtrl($interval){
      var toDo = function () {
          console.log("Hello World");
      };
      $interval(toDo, 3000, 10);
    };
  }());

2.$timeout

  window.setTimeout的Angular包装形式。Fn函数包装成一个try/catch块,代表$exceptionHandler服务里的任何异常。

  timeout函数的返回值是一个promise,当到达设置的超时时间时,这个承诺将被解决,并执行timeout函数。

  需要取消timeout,需要调用$timeout.cancel(promise);

使用: $timeout(fn,[delay],[invokeApply]);

  fn:一个将被延迟执行的函数。

  delay:延迟的时间(毫秒)。

  invokeApply:如果设置为false,则跳过脏值检测,否则将调用$apply。

方法:cancel(promise);

  取消与承诺相关联的任务。这个的结果是,承诺将被以摒弃方式来解决。

  promise:$timeout函数返回的承诺。

使用代码:

(function () {
    angular.module("Demo", [])
    .controller("testCtrl",["$timeout",testCtrl]);
    function testCtrl($timeout){
      var toDo = function () {
          console.log("Hello World");
      };
      $timeout(toDo,5000)
    };
  }());

  大致使用方法可以和原生js的setInterval和setTimeout那样使用,一些使用小技巧可以用在浏览器单线程的事件执行方面。

猜你喜欢

转载自bijian1013.iteye.com/blog/2391958