文章目录
  1. 1. 常规实现方式
  2. 2. 改进之后实现方式
    1. 2.1. 优化

相信很多app里都会有获取手机验证码的按钮,验证码获取成功后这个按钮会进入60秒倒计时状态,倒计时期间按钮是不可点击的,在前端起到限制了用户获取成功后频繁请求重复获取的作用。

常规实现方式

在H5页面里我们最容易想到常规的实现方式如下(这里提供的代码只是最基本的能说明问题用来演示用的Demo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
var timer = null; // 定时器
var count = 60; // 倒计时秒数
function getVerifyCode() {
var target = event.target;
target.disabled = 'disabled';
timer = setInterval(setSecondNum,1000);
function setSecondNum() {
count--;
if (count>0) {
target.innerHTML = count + '秒';
} else {
clearInterval(timer);
target.innerHTML = '发送验证码';
target.disabled = false;
count = 60;
}
}
}
</script>

如果是PC网页端这种写法能满足基本需求,在安卓手机上也没多大问题,因为安卓的应用在后台可以继续运行,倒计时会继续走着,但在苹果手机上就不行了,当获取验证码成功后,按钮倒计时开始后,如果这时打开其它应用当前app进入后台运行,进入后台的app就会被系统挂起,倒计时就会停止在一个值比如56秒处,当重新打开这个应用,倒计时会接着上次的值继续执行55…,其实也可以让应用进入后台依然运行着,但为了一个倒计时按钮不值当的,我们可以改进一下上面的常规写法来解决这个问题

改进之后实现方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
var timer = null; // 定时器
var count = 60; // 倒计时秒数
function getVerifyCode() {
var startTime = new Date().getTime(); // 获取点击按钮时的初始时间
var target = event.target;
target.disabled = 'disabled';
timer = setInterval(setSecondNum,1000);
function setSecondNum() {
var endTime = new Date().getTime(); // 定时器每次调用该方法获取系统最新时间
var betweenSeconds = parseInt((endTime - startTime)/1000); // 计算出每次调用和初次点击之间间隔的秒数
count = 60 - betweenSeconds; // 按钮上显示的倒计时数字用总的倒计时秒数减去两次之间间隔的秒数
if (count>0) {
target.innerHTML = count + '秒';
} else {
clearInterval(timer);
target.innerHTML = '发送验证码';
target.disabled = false;
count = 60;
}
}
}
</script>

改进之后在真机上测了一下确实解决了上述问题,但仔细观察还发现一个小瑕疵,倒计时过程中偶尔会出现秒数跳跃的问题,意思就是有时偶尔会出现38秒直接跳到36秒的情况,仔细看了一下改进之后的实现方式,发现问题出现在计算两次间隔秒数时使用的是parseInt方法导致的

优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
var timer = null; // 定时器
var count = 60; // 倒计时秒数
function getVerifyCode() {
var startTime = new Date().getTime(); // 获取点击按钮时的初始时间
var target = event.target;
target.disabled = 'disabled';
timer = setInterval(setSecondNum,1000);
function setSecondNum() {
var endTime = new Date().getTime(); // 定时器每次调用该方法获取系统最新时间
var betweenSeconds = Math.round((endTime - startTime)/1000); // 计算出每次调用和初次点击之间间隔的秒数
count = 60 - betweenSeconds; // 按钮上显示的倒计时数字用总的倒计时秒数减去两次之间间隔的秒数
if (count>0) {
target.innerHTML = count + '秒';
} else {
clearInterval(timer);
target.innerHTML = '发送验证码';
target.disabled = false;
count = 60;
}
}
}
</script>

最终将parseInt替换为Math.round方法,问题解决。

文章目录
  1. 1. 常规实现方式
  2. 2. 改进之后实现方式
    1. 2.1. 优化