首先大致说一下需求:大概就是要实现下面的效果,秒杀分为三个阶段: 预热中,抢购中,已结束。
预热中的展示效果又分为两种:当距离秒杀开始超过24小时的时候显示秒杀什么时候开始;当距离秒杀开始时间少于24小时的时候,开始倒计时。
抢购中的展示效果也分为两种:当距离秒杀结束超过24小时的时候显示秒杀什么时候结束;当距离秒杀结束时间少于24小时的时候,开始倒计时。
结束就展示已经结束。
基于imvc的实现:
1. 首先在control.js中我们通过从后台取得的活动开始时间effectTime,活动结束时间expireTime,以及当前服务器时间serviceDateTime,这三个时间来界定秒杀的状态seckillStatus(三种),当然还需要从接口获取当前产品是不是秒杀产品isSeckillProduct,然后吧=把effectTime,expireTime,seckillStatus,isSeckillProduct的值更新到state中。
2. 然后就是具体组件内部的渲染了,参考PC的SenKill.js组件,因为需要计时以及在24之内和之外的不同展示,这里组件内部state需要设计6个相关变量:
this.state = {
currentHours: '',
currentMinutes: '',
currentSeconds: '',
countTimer: null, //计时器
isShowPreheatTime: false, //控制预热中的两种展示
isShowPurchaseTime: false, //控制抢购中的两种展示
}
我们在render()中渲染代码,这里为了模块化,可以把秒杀模块在细化为一个子模块,然后就是根据上面state不同的值进行渲染了
3.所以重点是怎么控制这些状态,注意这里有关计时的,可以写在componentDidMount() 中,简单来说,就是接受父组件传来的秒杀开始,结束,状态信息,然后在预热中的时候,判断秒杀开始时间和当时时间(我觉得这里应该使用服务器时间)间隔,间隔大于24小时,不计时,只显示活动什么时候开始,间隔小于24小时,开始计时。同理,抢购中也是如此。
componentDidMount() {
const { seckillEffectTime, seckillExpireTime, seckillStatus } = this.props.state
let countTimer = null
let isShowPreheatTime = true
let isShowPurchaseTime = true
if (seckillStatus === '抢购中') {
let difftime = formatTimeInterval(dateTimeConvert(new Date(), seckillExpireTime)
if (parseInt(difftime.hours) > 24) {
isShowPurchaseTime = false
} else {
countTimer = setInterval(() => this.countDown(seckillExpireTime), 1000)
}
}
if (seckillStatus === '预热中') {
let difftime = formatTimeInterval(seckillEffectTime, dateTimeConvert(new Date()))
if (parseInt(difftime.hours) > 24) {
isShowPreheatTime = false
} else {
countTimer = setInterval(() => this.countDown(seckillEffectTime), 1000)
}
}
this.setState({
isShowPreheatTime: isShowPreheatTime,
isShowPurchaseTime: isShowPurchaseTime,
countTimer: countTimer,
})
}
4.然后就是计时函数了,抢购中,如果从现在到结束时间间隔小于24小时,就需要一直计时,
countTimer = setInterval(() => this.countDown(seckillExpireTime), 1000)
countDown(time) {
let countTime = formatTimeInterval(time, dateTimeConvert(new Date()))
this.setState({
currentHours: countTime.hours,
currentMinutes: countTime.minutes,
currentSeconds: countTime.seconds,
})
}
这里思考下conutTimer有问题没??看过之后发现缺少临界情况,当countTime=0的时候,是不是应该有所调整呢,当在预热期countTime=0那么就要进入抢购中,如果在抢购中,countTime=0,就要进入结束,所以需要增加临界情况:
一定要注意各种临界情况!!!!!
countDown(time) {
const { countTimer } = this.state
let { seckillEffectTime, seckillExpireTime, seckillStatus } = this.props.state
const { handleChangeSeckillStatus } = this.props.handlers
let countTime = formatTimeInterval(time, dateTimeConvert(new Date()))
if (countTime.hours === '00' && countTime.minutes === '00' && countTime.seconds === '00') {
clearInterval(countTimer)
if (seckillStatus === '预热中') {
handleChangeSeckillStatus('抢购中')
let countTimer = null
let isShowPreheatTime = true
let isShowPurchaseTime = true
let difftime = formatTimeInterval(new Date(), seckillExpireTime)
if (parseInt(difftime.hours) > 24) {
isShowPurchaseTime = false
} else {
countTimer = setInterval(() => this.countDown(seckillExpireTime, 1000)
}
this.setState({
isShowPreheatTime: isShowPreheatTime,
isShowPurchaseTime: isShowPurchaseTime,
countTimer: countTimer,
})
}
if (seckillStatus === '抢购中') {
handleChangeSeckillStatus('已结束')
}
return null
} else {
this.setState({
currentHours: countTime.hours,
currentMinutes: countTime.minutes,
currentSeconds: countTime.seconds,
})
}
}
5.最后完成时候,移除计时器
componentWillUnmount() {
clearInterval(this.state.countTimer)
}