2024年前端最全手把手带你分解 Vue 倒计时组件,前端开发规范文档

本文详述了Vue倒计时组件的实现,包括如何处理时间更新、添加新功能,如传入到期时间和选择显示内容,以及解决浏览器后台时计时不准的问题。通过实例展示了使用setTimeout而非setInterval的优缺点,并提供了组件完整代码,帮助前端开发者提升技能。
摘要由CSDN通过智能技术生成

总结

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

7f872d3707c6f4db8414ecf148af6ef4.png

如果此时倒计时组件正在做活动一的倒计时,然后点击活动二,就要会马上传入新的time,这个时候就需要重新计时。当然,这里并不会重新计时,因为组件的mounted只会执行一次。也就是说this.countDown();只会执行一次,也就是说this.getTime(this.duration);只会执行一次,因此duration还是活动一的时间,怎么办呢?watch派上用场了。

我们来监听duration,如果发现duration变化,说明新的时间time传入组件,这时就要重新调用this.countDown()。

代码如下:

还剩{{day}}天{{hours}}:{{mins}}:{{seconds}}

好了,但是并没有解释上面提出的那个问题:为什么要有this.timer && clearTimeout(this.timer);这一句?

这样,假设现在页面显示的是活动一的时间,这时,执行到setTimeout,在一秒后就会把setTimeout里的回调函数放到任务队列中,注意是一秒后哦!这时,然而,在这一秒的开头,我们点击了活动二按钮,这时候的活动二的时间就会传入倒计时组件中,然后触发countDown(),也就调用this.getTime(this.duration);,然后执行到setTimeout,也会一秒后把回调函数放到任务队列中。

这时,任务队列中就会有两个setTimeout的回调函数了。等待一秒过去,两个回调函数相继执行,我们就会看到页面上的时间一下子背减了2,实际上是很快速地进行了两遍减1的操作。

这就是为什么要添加上this.timer && clearTimeout(this.timer);这一句的原因了。就是要把上一个setTimeout清除掉。

5. 使用 diffTime

当你认为这是一个完美的组件的时候,你想把这个组件用到项目上,假设你也确实用了,而且还上线了,确发现出现了个大问题:当页面打开的时候,倒计时开始了,时间是 还剩1天12:25:25,然后有人给你发微信,你马上切换到微信,回复消息后切回浏览器,发现倒计时时间却还是还剩1天12:25:25。你慌了:你写的代码出现bug了!

这是怎么回事?

出于节能的考虑, 部分浏览器在进入后台时(或者失去焦点时), 会将 setTimeout 等定时任务暂停 待用户回到浏览器时, 才会重新激活定时任务

说是暂停, 其实应该说是延迟, 1s 的任务延迟到 2s, 2s 的延迟到 5s, 实际情况因浏览器而异。

原来如此,看来不能每次都只是减1这么简单了(毕竟你把浏览器切到后台之后setTimeout就冷却了,等几秒后切回,然后执行setTimeout,只是减了一秒而已)。

所以我们需要改写一下getTime方法。

还剩{{day}}天{{hours}}:{{mins}}:{{seconds}}

可以看到,我们在三个位置添加了新的代码。

首先在data了添加了curTime这个变量,然后在执行countDown的时候给curTime赋值Date.now(),也就是当前的时刻,也就是显示在页面上的那个时刻。

然后看修改的第三处代码。可以看到是将-1改成了-diffTime

now 是 setTimeout的回调函数执行的时候的那个时刻。

因而 diffTime 则 表示 当前这个setTimeout的回调函数执行的时刻距离上 页面上的剩余时间上一次变化的时间段。其实也就是 当前这个setTimeout的回调函数执行的时刻距离上 一个setTimeout的回调函数执行的时刻时间段。

可能你还是不太能理解diffTime。举个例子:

你打开了这个倒计时页面,于是执行了countDown,也就是说要执行getTime这个方法了。也就是会马上执行下列的代码。

this.days = dd || 0;

this.hours = hh || 0;

this.mins = mm || 0;

this.seconds = ss || 0;

执行完这些代码页面上就会出现剩余时间。

this.curTime = Date.now(); 就记录下了此刻的时间点。

然后一秒后执行setTimeout里的回调函数:

const now = Date.now(); 记录当前这个setTimeout的回调函数执行的时间点。

const diffTime = Math.floor((now - this.curTime) / 1000); 记录当前这个setTimeout的回调函数执行的时间点距离页面上开始 渲染 剩余时间的 这一段时间。其实此时的diffTime就是=1。

然后this.curTime = now; 将curTime的值变成当前这个setTimeout的回调函数执行的时间点。

this.getTime(duration - diffTime); 其实就是this.getTime(duration - 1);

然后又执行getTime,就会重新执行下面的代码,有渲染了新的剩余时间。

this.days = dd || 0;

this.hours = hh || 0;

this.mins = mm || 0;

this.seconds = ss || 0;

然后一秒后又要执行setTmieout的回调函数,在这一秒还没结束的时候,我们将浏览器切到后台,此时setTimeout冷却了。等5秒后再切回。于是setTmieout的回调函数才得以执行。

这时const now = Date.now(); 记录当前这个setTimeout的回调函数执行的时间点。

而curTime是上一个setTimeout的回调函数执行的时间。

所以const diffTime = Math.floor((now - this.curTime) / 1000);实际上,diffTime的值就是5秒。

因而this.getTime(duration - diffTime); 其实就是this.getTime(duration - 5);

这样就完美解决了因为浏览器切到后台,导致剩余时间不变的问题。

6. 添加新功能:可以传入到期时间。

之前是只能传入剩余时间的,现在希望也支持传入到期时间。

只需要改动一下duration就好了。

computed: {

duration() {

if (this.end) {

let end = String(this.end).length >= 13 ? +this.end : +this.end * 1000;

end -= Date.now();

return end;

}

const time = this.isMiniSecond ? Math.round(+this.time / 1000) : Math.round(+this.time);

return time;

}

},

判断传入的end的长度是否大于13来判断是秒还是毫秒。轻松!

7. 添加新功能:可以选择要显示的内容,例如只显示秒,或者只显示小时。

只需要改动一下html:

<slot v-bind="{

d: days, h: hours, m: mins, s: seconds,

hh: 00${hours}.slice(-2),

mm: 00${mins}.slice(-2),

ss: 00${seconds}.slice(-2),

}">

很巧妙有没有,只需要用插槽,就把倒计时组件,也就是把子组件的值传递给父组件了。

看看父组件是怎么使用这个组件的。

{{timeObj.d}}天{{timeObj.hh}}小时{{timeObj.mm}}分钟{{timeObj.ss}}秒

看,如此巧妙又简单。

发现00${hours}.slice(-2) 这种写法也很值得学习。以前在获得到分钟的时候,要手动判断获得的分钟是两位数还是一位数,如果是一位数的话就要在前面手动补上0。就像下面的代码:

var StartMinute = startDate.getMinutes().toString().length >= 2 ? startDate.getMinutes() : ‘0’ + startDate.getHours();

00${hours}.slice(-2) 则不用判断,先补上0再说,然后再从后面往前截取两位。2019f26acbfc868510d2fd7c7b3628c7.png

到此。

一个完美的倒计时组件就完成了。759049a16e8c6cf5a83e97ca500b3982.png

关于Vue一些技巧,你还可以看看:Vue实战中的一些小魔法

三、学习总结


  1. 明白了setInterval的缺点以及用setTimeout代替setInterval。

  2. 学到了“+”,操作,不管三七二十一,将接口得到的长串数字转化为数字保平安。

  3. 利用clearTimeout来清除掉之前的计时器,以防止造成影响。

  4. 学会使用v-slot来子传父传值

  5. 学会一个倒计时组件,为了以后方便cv操作。把组件完整代码贴上:

<slot v-bind="{

d: days, h: hours, m: mins, s: seconds,

hh: 00${hours}.slice(-2),

mm: 00${mins}.slice(-2),

ss: 00${seconds}.slice(-2),

}">

你学到了什么,欢迎补充!!

总结

大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值