我们通常在做秒杀活动时,会有活动开始或者活动结束倒计时
而在活动列表中,需要做统一处理
以下为做的关于倒计时的组件~
primaryColor可忽略,是关于倒计时时间的主题色
startTime活动开始时间
endTime活动结束时间
refresh方法为其中一个倒计时结束后,页面的重新渲染方法,经常是重新请求列表接口,方法自定义
组件文件
import React, { Component, CSSProperties } from 'react';
import { View } from '@tarojs/components';
import { isFunction } from 'lodash-es';
import { hexToRgba, iosTimeStringFomat } from '@/application/utils/format';
import './index.scss';
interface PaymentRewardCountdownProps {
primaryColor: string;
startTime: string;
endTime: string;
refresh(): void;
}
interface PaymentRewardCountdownState {
timeRemaining: TimeRemaining | null;
}
interface TimeRemaining {
type: 'start' | 'end' | 'ended';
value: number;
}
export default class PaymentRewardCountdown extends Component<
PaymentRewardCountdownProps,
PaymentRewardCountdownState
> {
constructor(props: PaymentRewardCountdownProps) {
super(props);
this.state = {
timeRemaining: null
};
}
componentDidMount(): void {
const { startTime, endTime, refresh } = this.props;
const iosStartTime = iosTimeStringFomat(startTime);
const iosEndTime = iosTimeStringFomat(endTime);
this.timer = setInterval(() => {
const now = new Date();
const start = new Date(iosStartTime);
const end = new Date(iosTimeStringFomat(iosEndTime));
if (now < start) {
const diff = start.getTime() - now.getTime();
this.setState({ timeRemaining: { type: 'start', value: diff } });
} else if (now < end) {
const diff = end.getTime() - now.getTime();
this.setState({ timeRemaining: { type: 'end', value: diff } });
} else {
this.setState({ timeRemaining: { type: 'ended', value: 0 } });
clearInterval(this.timer);
if (isFunction(refresh)) {
refresh();
}
}
}, 1000);
}
componentWillUnmount() {
if (this.timer) {
clearInterval(this.timer);
}
}
private timer: NodeJS.Timeout;
private renderCountdown = () => {
const { primaryColor } = this.props;
const { timeRemaining } = this.state;
if (!timeRemaining) {
return null;
}
const numberStyle: CSSProperties = {
color: primaryColor,
background: `${hexToRgba(primaryColor, 0.5)}`
};
const timeInfo = formatSeconds(timeRemaining.value / 1000);
return (
<View className={classes.right}>
<View className={classes.prefix}>
{timeRemaining.type === 'start' ? '距离开始' : '距离结束:'}:
</View>
<View className={classes.number} style={numberStyle}>
{timeInfo.days}
</View>
<View className={classes.symbol}>天</View>
<View className={classes.number} style={numberStyle}>
{timeInfo.hours}
</View>
<View className={classes.symbol}>时</View>
<View className={classes.number} style={numberStyle}>
{timeInfo.minutes}
</View>
<View className={classes.symbol}>分</View>
<View className={classes.number} style={numberStyle}>
{timeInfo.seconds}
</View>
<View className={classes.symbol}>秒</View>
</View>
);
};
render() {
return <View className={prefix}>{this.renderCountdown()}</View>;
}
}
const prefix = 'payment-reward-countdown';
const classes = {
right: `${prefix}__right`,
prefix: `${prefix}__right__prefix`,
number: `${prefix}__right__number`,
symbol: `${prefix}__right__symbol`
};
interface DataInfo {
days: number;
hours: string;
minutes: string;
seconds: string;
}
function addLeadingZero(num: number): string {
if (num < 10) {
return `0${num}`;
}
return num.toString();
}
function formatSeconds(time: number): DataInfo {
const days = Math.floor(time / (3600 * 24));
const hours = addLeadingZero(Math.floor((time % (3600 * 24)) / 3600));
const minutes = addLeadingZero(Math.floor((time % 3600) / 60));
const seconds = addLeadingZero(Math.floor(time % 60));
return {
days,
hours,
minutes,
seconds
};
}
样式文件
.payment-reward-countdown {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
&__right {
height: 32px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
&__prefix {
font-size: $font-size-mini;
}
&__number {
padding: 0 6px;
height: 32px;
font-weight: 500;
font-size: 22px;
color: #FF3B30;
line-height: 32px;
text-align: center;
background: rgba(255,59,48,0.05);
border-radius: 4px;
}
&__symbol {
padding: 0 6px;
color: #666666;
line-height: 28px;
text-align: center;
font-size: 20px;
font-weight: bold;
}
}
}
在数组的item文件中,直接调用时间组件
<PaymentRewardCountdown
startTime={market.startTime}
endTime={market.endTime}
refresh={this.refresh}
primaryColor={primaryColor}
/>
示例图