一、实现效果
假如后端返了两个数据:
当前时间
的13
位时间戳currentTimestamp
、到期时间
的13
位时间戳expireTimestamp
,想实现“还有多久到期的时间”的倒计时,即:到期时间与当前时间之间的时间差以“天时分秒”
的形式进行倒计时,如下动图:
二、实现方式
第一步、封装方法——js
将时间戳转换成“天时分秒”
utils.js
:
1、写法一 ⭐️
/**
1、js获取 倒计时 天时分秒
通过时间戳的方式来
let d = parseInt(dec / 60 / 60 / 24); // 天
let h = parseInt(dec / 60 / 60 % 24); // 时
let m = parseInt(dec / 60 % 60); // 分
let s = parseInt(dec % 60); // 秒
2、参数分析:
@params {Num} inputTime: 需要转换成 天时分秒 的 13位时间戳
@params {Boolean} isPop: 便于实现两种返回结果:true -> `${d}天${h}小时${m}分${s}秒` ; false -> 包含天时分秒的finalDateObj对象
*/
export function timestampFormatter(inputTime, isPop = false) {
// 最终时间结果对象
const finalDateObj = {
d: null, // 天
h: null, // 小时
m: null, // 分钟
s: null, // 秒
}
// 剩余时间总的毫秒数 除以 1000 变为总秒数(时间戳为13位 需要除以1000,为10位 则不需要)
let dec = inputTime / 1000;
if (dec <= 0) {
dec = 0;
}
// 得到天 格式化成前缀加零的样式
let d = parseInt(dec / 60 / 60 / 24);
d = d < 10 ? '0' + d : d;
// 得到小时 格式化成前缀加零的样式
let h = parseInt(dec / 60 / 60 % 24);
h = h < 10 ? '0' + h : h;
// 得到分钟 格式化成前缀加零的样式
let m = parseInt(dec / 60 % 60);
m = m < 10 ? '0' + m : m;
// 得到秒 格式化成前缀加零的样式
let s = parseInt(dec % 60);
s = s < 10 ? '0' + s : s;
finalDateObj.d = d;
finalDateObj.h = h;
finalDateObj.m = m;
finalDateObj.s = s;
// 两种返回结果
return isPop ? `${d}天${h}小时${m}分${s}秒` : finalDateObj;
}
2、写法二 ⭐️
/**
1、js获取 倒计时 天时分秒
通过时间戳的方式来
let d = Math.trunc(dec / 3600 / 24); // 天
let h = Math.trunc(dec % (24 * 3600) / 3600); // 时
let m = Math.trunc(dec % 3600 / 60); // 分
let s = Math.trunc(dec % 3600 % 60); // 秒
2、参数分析:
@params {Num} inputTime: 需要转换成 天时分秒 的 13位时间戳
@params {Boolean} isPop: 便于实现两种返回结果:true -> `${d}天${h}小时${m}分${s}秒` ; false -> 包含天时分秒的finalDateObj对象
*/
export function timestampFormatter(inputTime, isPop = false) {
// 最终时间结果对象
const finalDateObj = {
d: null, // 天
h: null, // 小时
m: null, // 分钟
s: null, // 秒
}
// 剩余时间总的毫秒数 除以 1000 变为总秒数(时间戳为13位 需要除以1000,为10位 则不需要)
let dec = inputTime / 1000;
if (dec <= 0) {
dec = 0;
}
// 得到天 格式化成前缀加零的样式
let d = Math.trunc(dec / 3600 / 24);
d = d < 10 ? '0' + d : d;
// 得到小时 格式化成前缀加零的样式
let h = Math.trunc(dec % (24 * 3600) / 3600);
h = h < 10 ? '0' + h : h;
// 得到分钟 格式化成前缀加零的样式
let m = Math.trunc(dec % 3600 / 60);
m = m < 10 ? '0' + m : m;
// 得到秒 格式化成前缀加零的样式
let s = Math.trunc(dec % 3600 % 60);
s = s < 10 ? '0' + s : s;
finalDateObj.d = d;
finalDateObj.h = h;
finalDateObj.m = m;
finalDateObj.s = s;
// 两种返回结果
return isPop ? `${d}天${h}小时${m}分${s}秒` : finalDateObj;
}
第二步、实现“天时分秒”的倒计时
实现思路:⭐️
- 1、先在
state
里定义两个属性:
finalDate
——倒计时初始值(初始化为字符串 “00天00时00分00秒”),canMountDown
——判断是否开启定时器。- 2、初始化定时器
timer
为null
;- 3、定义一个方法
FunTimer
(里面写一个setInterval
定时器timer
,装实现倒计时的代码(我封装成了一个函数updateTime
)),- 4、在
componentDidMount
里进行判断:
- 若
canMountDown
为true
,就调用方法FunTimer
,并把canMountDown
置为false
;- 若
canMountDown
为false
,就把timer
定时器关了,并把canMountDown
置为true
;- 5、编写函数
updateTime
:【实现倒计时的代码】
- 第1步、获取到过期时间;
- 第2步、获取到当前时间的时间戳(后端返的值);
- 第2步、手动把获取到的当前时间 隔一秒加
1s
得到新的当前时间,赋值给store
里的当前时间的时间戳;- 第3步、 引入上面封装好的方法
timestampFormatter
(js
将时间戳转换成“天时分秒”),将到期时间与新的当前时间的差值传进去,获取到对应的“天时年分”,并赋值到state
里的finalDate
;- 第4步、将
state
里的finalDate
写到html
对应位置 就大功告成啦~- 6、在
componentWillUnmount
里关闭定时器
tasksDetails.jsx
:
import React,{Component} from 'react';
import { timestampFormatter } from '@src/utils/utils'; // 引入上面封装好的方法——`js`将时间戳转换成“天时分秒”
import store from '@src/utils/store'; // 引入store【store相关的是我项目接口相关的内容和公用方法,小萝卜儿们可根据实际情况处理】
class CountDown extends Component{
// 1、初始化state
state = {
canCountDown: true, // 判断是否开启定时器
finalDate: '00天00小时00分00秒', // 倒计时初始值
}
// 2、初始化定时器
timer = null;
// 自定义当前时间的时间戳
// currentTimestamp = null;
async componentDidMount() {
await store.getQueryTasks(); // 调用接口-获取到任务列表里的数据
// 初始化当前时间的时间戳(初始值取后端返滴数据: store?.currentTimestamp)【注意: currentTimestamp一定要记得*1转换成数值型哟】
// this.currentTimestamp = store?.currentTimestamp * 1;
this.handleCountDownLogic(); // 处理倒计时总逻辑【是否开启倒计时处理】
}
// 4、处理倒计时总逻辑【是否开启倒计时处理】
handleCountDownLogic = () => {
if (this.state.canCountDown) {
this.setState({ canCountDown: false })
this.FunTimer(); // 调用函数-倒计时
} else {
this.setState({ canCountDown: true })
clearInterval(this.timer); // 关闭定时器
}
}
// 6、在componentWillUnmount里关闭定时器
componentWillUnmount() {
clearInterval(this.timer); // 关闭定时器
}
// 3、封装函数-倒计时
FunTimer = () => {
this.timer = setInterval(() => {
// 想实现倒计时的代码就写在这里啦~【我单独封装了一个函数】
this.updateTime();
}, 1000)
}
// 5、更新时间
updateTime = () => {
const expireTimestamp = 1660970113000; // 到期时间【实际情况时 由后台返回,这儿写死只是做个测试】
const { currentTimestamp } = store; // 获取到后端返的当前时间的时间戳
/** 手动把获取到的当前时间 隔一秒加1s,并更新store里的当前时间的时间戳【注意: currentTimestamp一定要记得*1转换成数值型哟】*/
// this.currentTimestamp += 1000;
store.setCurrentTimestamp(currentTimestamp * 1 + 1000);
/** 计算得到需要倒计时的时间戳 */
// const countDownTimestamp = expireTimestamp * 1 - this.currentTimestamp * 1;
const countDownTimestamp = expireTimestamp * 1 - currentTimestamp * 1;
/** 调用上面封装的方法timestampFormatter,计算到倒计时的展示结果,并state赋值,方便html里进行展示 */
const result = timestampFormatter(countDownTimestamp, true);
this.setState({
finalDate: result,
})
/** 倒计时的时间戳小于0,则刷新任务列表数据、关闭定时器 */
if (countDownTimestamp < 0) {
console.log('倒计时小于0咯~');
clearInterval(this.timer); // 关闭定时器
this.timer = null; // 将定时器归置为null
// 根据自己需求进行操作
store.getQueryTasks(); // 刷新任务列表数据
}
}
render(){
return(
<div>
倒计时:{this.state.finalDate}
</div>
)
}
}
export default CountDown;
store/index.js
:【就是与接口相关滴代码,小萝卜儿们根据自己平时的思路来即可哦~】
import { makeAutoObservable } from 'mobx';
import API from '../api/index';
const store = makeAutoObservable({
/** 任务列表 */
tasksList: {},
/** 设置任务列表数据 */
setTasksList(data) {
this.tasksList = data;
},
/** 当前时间的时间戳 */
currentTimestamp: null,
/** 设置当前时间的时间戳 */
setCurrentTimestamp(data) {
this.currentTimestamp = data;
}
/** 查询任务列表 */
async getQueryTasks() {
const { data, success } = await API.queryTasks(); // 调用接口
if (data && success) {
this.setTasksList(data); // 设置任务列表数据
// currentTime: 当前时间的时间戳
const { currentTime } = data;
this.setCurrentTimestamp(currentTime);
}
},
});
export default store;