## 进化的倒计时
栏目: JavaScript · 发布时间: 5年前
内容简介:最近接到产品的需求,需要在系统的订单模块-未付费列表上增加一列倒计时显示,订单到期后系统会自动关闭订单,作为开发人员的我其实是拒绝的,但是你还是得做吧,除非哪一天我中了彩票,我就可以理直气壮的拒绝了(~~~收),回到主题,下面开始我的倒计时进化之旅(期待^^^)我们项目使用的vue,在我开始真正的写业务逻辑前,我会封装一下需要用到的工具函数,没办法呀,要有全局观嘛(墨镜+大金链子.png)身为web前端的我们,首先都不用带脑子想的,我肯定首选
最近接到产品的需求,需要在系统的订单模块-未付费列表上增加一列倒计时显示,订单到期后系统会自动关闭订单,作为开发人员的我其实是拒绝的,但是你还是得做吧,除非哪一天我中了彩票,我就可以理直气壮的拒绝了(~~~收),回到主题,下面开始我的倒计时进化之旅(期待^^^)
工具函数
我们项目使用的vue,在我开始真正的写业务逻辑前,我会封装一下需要用到的 工具 函数,没办法呀,要有全局观嘛(墨镜+大金链子.png)
// src/utils/index.js /** * 将时间戳转换成时分秒,例如08:14:20 * @param {number} ms 时间戳 * */ formatTimeStamp(ms) { let hours = parseInt(ms / (1000 * 60 * 60)), minutes = parseInt((ms % (1000 * 60 * 60)) / (1000 * 60)), seconds = parseInt((ms % (1000 * 60)) / 1000); hours = hours < 10 ? '0' + hours : hours; minutes = minutes < 10 ? '0' + minutes : minutes; seconds = seconds < 10 ? '0' + seconds : seconds; return `${hours}:${minutes}:${seconds}` }, 复制代码
小试牛刀的第一版倒计时
身为web前端的我们,首先都不用带脑子想的,我肯定首选 setInterval
的,开始撸代码呀:
destroyed() { window.clearInterval(this.timer); }, methods: { /* 获取未付费订单列表数据 */ fetchData() { this.listLoading = true; getList("/order_not_pay", query).then(res => { this.orderList = res.data.data; this.page.total = res.data.total; this.listLoading = false; if (this.list.length === 0) { // 没有数据 return; } // 开始倒计时 this.countDown(); }); }, /* 倒计时 */ countDown() { this.timer = setInterval(this.updateTime, 1000); }, /* 更新时间 */ updateTime() { let DAYS = 259200000, // 订单3天后过期 endSeconds = 0, endTime = 0; this.orderList.forEach((item, index) => { endSeconds = +new Date(item.created_at) + DAYS - +new Date(); if (endSeconds <= 0) { // 时间到 Vue.set(item, "endTime", "已逾期"); } else { endTime = formatTimeStamp(endSeconds); Vue.set(item, "endTime", endTime); } }); } } 复制代码
由于是项目中的部分代码,其中一些变量没有详细写出来,大致思路就是拿到列表数据后,启用setInterval定时器,每次循环一遍orderList,根据订单创建时间(created_at)加上3天减去当前时间,得到剩余时间,转换格式,我在组件卸载钩子函数中销毁定时器,注意要用windows,之前用this调用就是不起作用,哈哈哈,this指向的是Vue啦。欧拉,提交代码,告诉测试妹子可以测一下了,等待中(应该是没有bug的吧,渍渍...)。
循序渐进的第二版倒计时
没有bug是不可能滴,公司请你来干嘛,不就是写bug的嘛,惭愧惭愧。过了没多久,噩耗传来,测试妹子给我发消息说,你的定时器有问题哦,3天的话倒计时应该从72:00:00开始吧,你的是从72:02:00开始的。哦,世上竟有如此荒唐之事,待我一探究竟再给你答复,我第一个想到的是是不是服务器时间不准,因为之前我在测试服下单的时间就比正确的时间快两分钟,然后我就找到跟我对接的后端,问一下他是不是服务端时间不准哦,后端熟练的打开了终端,敲了几行我不是很懂的命令,最终显示的北京时间是正确的。咦,不科学,我脱口而出,为了寻找真相,我去到测试妹子旁边让她复现一下bug,在她操作的过程中,我把目光锁定在她屏幕右下角的时间栏,对比了一下我的手机时间,嗨呀,难怪,原来是她的电脑慢了两分钟,找到问题的根源后,回到座位,思考如何解决。 的确我计算取了本地时间,但我们不能保证用户电脑的时间都是准确的,为此我想到让后端返回当前时间,与本地时间取差值,每次减去这个差值即可。除了这个问题,我还发现了,列表的计时器偶尔会发生卡顿,与是查了一下setInteval和setTimeout相关资料,推荐做法是用setTimeout模拟setInterval,开始撸代码:
destroyed() { window.clearTimeout(this.timer); }, methods: { /* 获取未付费订单列表数据 */ fetchData() { this.listLoading = true; getList("/order_not_pay", query).then(res => { this.orderList = res.data.data; this.page.total = res.data.total; this.listLoading = false; if (this.list.length === 0) { // 没有数据 return; } // 开始倒计时 this.countDown(); }); }, /* 倒计时 */ countDown() { this.timer = setTimeout(this.updateTime, 1000); }, /* 更新时间 */ updateTime() { let DAYS = 259200000, // 订单3天后过期 endSeconds = 0, endTime = 0, // 计算服务器与本地的时间差 diffTime = +new Date(this.orderList[0].now_time) - +new Date(); this.orderList.forEach((item, index) => { endSeconds = +new Date(item.created_at) + DAYS - +new Date() - diffTime; if (endSeconds <= 0) { // 时间到 Vue.set(item, "endTime", "已逾期"); } else { endTime = formatTimeStamp(endSeconds); Vue.set(item, "endTime", endTime); } }); this.timer = setTimeout(this.updateTime, 1000); } } 复制代码
相对稳定的第三版倒计时
后来了解到了window.requestAnimationFrame(callback) api,一般用于css动画制作,根据屏幕的刷新频率执行回调函数,一般是1秒钟执行60此,相比用setTimeout而言,效率更高,当然存在兼容问题,目前方案是浏览器支持使用window.requestAnimationFrame,否则采用setTimeout,要使用window.requestAnimationFrame,需要先解决模拟一秒钟执行回调函数,开始撸代码:
data() { timer: null, lastTime: 0, // 记录上一次的时间戳 options: { diffTime: 0, // 服务端与本地时间差值 days: 259200000, // 订单3天后过期 endSeconds: 0, endTime: 0 } }, destroyed() { window.clearTimeout(this.timer); }, methods: { /* 获取未付费订单列表数据 */ fetchData() { this.listLoading = true; getList("/order_not_pay", query).then(res => { this.orderList = res.data.data; this.page.total = res.data.total; this.listLoading = false; if (this.list.length === 0) { // 没有数据 return; } // 计算服务器与本地的时间差 this.options.diffTime = +new Date(this.list[0].now_time) - +new Date(); // 当使用requestAnimationFrame时,记录上一次时间戳 this.lastTime = Date.now(); // 开始倒计时 this.countDown(); }); }, /* 倒计时 */ countDown() { if (window.requestAnimationFrame) { // 浏览器支持requestAnimationFrame window.requestAnimationFrame(this.animationCb); } else { // 用setTimeout兼容 this.timer = setTimeout(this.setTimeoutCb, 1000); } }, /* setTimeout调函数 */ setTimeoutCb() { this.updateTime(); this.timer = setTimeout(this.setTimeoutCb, 1000); }, /* requestAnimationFrame回调函数 */ animationCb() { if (Date.now() - this.lastTime >= 1000) { this.updateTime(); this.lastTime = Date.now(); } window.requestAnimationFrame(this.animationCb); }, /* 更新时间 */ updateTime() { this.list.forEach((item, index) => { if (item.status == 20) { this.options.endSeconds = +new Date(item.created_at) + this.options.days - +new Date() - this.options.diffTime; if (this.options.endSeconds <= 0) { // 时间到 Vue.set(item, "endTime", "已逾期"); } else { this.options.endTime = utils.formatTimeStamp( this.options.endSeconds); Vue.set(item, "endTime", this.options.endTime); } } }); } } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- JavaScript异步进化史
- 革命与进化:全同态加密
- BackSwap银行木马进化分析
- Dridex的进化史
- ThreadLocal 的进化:TransmittableThreadLocal
- ThreadLocal 的进化:InheritableThreadLocal
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。