关于在Vue中写倒计时,可参考大佬写的:juejin.cn/post/703840…
为什么要用setTimeout来模拟setInterval的行为?
定时器指定的时间间隔,表示的是何时将定时器的代码添加到消息队列,而不是何时执行代码。所以真正何时执行代码的时间是不能保证的,取决于何时被主线程的事件循环取到,并执行。
也就是说,每个setTimeout产生的任务会直接push到任务队列中;而setInterval在每次把任务push到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中) 。
1.发送验证码后60秒倒计时
我们可以采用setTimeout配合侦听属性来实现获取验证码之后的60秒倒计时:
data(){
return{
...
// 获取验证码按钮是否禁用
getCodeBtn:false,
// n秒倒计时
time:0,
// 定时器
timer:null
...
}
},
watch:{
time(){ // 监视time如果变化就调用-1函数
this.countDown(this.time)
}
},
methods: {
//获取验证码
async getCode(){
...
try {
await this.$store.dispatch('getCode',mobile) // 让仓库派发getCode发送请求
this.getCodeBtn = !this.getCodeBtn // 禁用按钮
this.time = 60 // 设置定时时间
this.countDown(this.time) // 调用倒计时函数
} catch (error) {
this.$message.error(`${error}`)
}
...
},
// 时间-1
countDown(time){ // 传入时间
if(time <= 0) { // <=0 时完成计时,解禁按钮,清除定时器
this.getCodeBtn = !this.getCodeBtn
clearTimeout(this.timer)
return
}
this.timer = setTimeout(()=>{
this.time = time - 1 // 每次调用对this.time进行-1并重新赋值,触发watch
},1000)
},
...
效果如下:
2.未支付订单的30分钟倒计时
当然,我们也可以不采用watch属性进行监视,直接用定时器,配合递归调用的方式,实现倒计时,具体操作如下:
在对应的订单页面中,order.vue:
...
data() {
return {
// 剩余分钟
m:'',
// 剩余秒钟
s:'',
...
};
},
computed:{
...mapState({
order: state => state.trade.orderInfo // 订单详情
}),
},
methods: {
// 30分钟倒计时
countdown () {
let end = new Date(this.order.createTime).getTime();// createTime是后台返的数据,代表创建订单的那一个时刻的毫秒数
let now = new Date().getTime(); // 获取当前时间的毫秒数
let minus = now - end; // 现在和下单时刻的毫秒差
let m_30 = 30 * 60 * 1000; // 30分钟毫秒数
let differ = m_30 - minus; // 时间差
let m = parseInt(differ / 1000 / 60 % 60); // 求出分钟数
let s = parseInt(differ / 1000 % 60); // 求出秒数
this.m = m > 9 ? m : '0' + m;
this.s = s > 9 ? s : '0' + s;
let _this = this; // 注意保存this
if(m >= 0 && s >= 0) {
if(m == 0 && s == 0) {
// 倒计时,派发action结束关闭订单
this.$store.dispatch('reqOrderInfo',this.$route.params.orderId);
return;
}
setTimeout(function () {
_this.countdown(); // 还没结束就递归调用
}, 1000)
}
},
...
},
mounted(){
// 派发获取订单详情
this.$store.dispatch('reqOrderInfo',this.$route.params.orderId).then(()=>{
this.countdown();
})
},
...
效果如下: