import classNames from 'classnames' import PropTypes, { InferProps } from 'prop-types' import React from 'react' import { View } from '@tarojs/components' import { AtCountDownProps, AtCountdownState } from '../../../types/countdown' import AtCountdownItem from './item' import '../../style/components/countdown.scss' type TimeObject = { day: number hours: number minutes: number seconds: number } const toSeconds = ( day: number, hours: number, minutes: number, seconds: number ): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds export default class AtCountdown extends React.Component< AtCountDownProps, AtCountdownState > { public static defaultProps: AtCountDownProps public static propTypes: InferProps private seconds: number private timer: NodeJS.Timeout | number | undefined public constructor(props: AtCountDownProps) { super(props) const { day = 0, hours = 0, minutes = 0, seconds = 0 } = this.props this.seconds = toSeconds(day, hours, minutes, seconds) const { day: _day, hours: _hours, minutes: _minutes, seconds: _seconds } = this.calculateTime() this.state = { _day, _hours, _minutes, _seconds } } private setTimer(): void { if (!this.timer) this.countdonwn() } private clearTimer(): void { if (this.timer) { clearTimeout(this.timer as number) } } private calculateTime(): TimeObject { let [day, hours, minutes, seconds] = [0, 0, 0, 0] if (this.seconds > 0) { day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0 hours = Math.floor(this.seconds / (60 * 60)) - day * 24 minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60 seconds = Math.floor(this.seconds) - day * 24 * 60 * 60 - hours * 60 * 60 - minutes * 60 } return { day, hours, minutes, seconds } } private countdonwn(): void { const { day, hours, minutes, seconds } = this.calculateTime() this.setState({ _day: day, _hours: hours, _minutes: minutes, _seconds: seconds }) this.seconds-- if (this.seconds < 0) { this.clearTimer() this.props.onTimeUp && this.props.onTimeUp() return } this.timer = setTimeout(() => { this.countdonwn() }, 1000) } public UNSAFE_componentWillReceiveProps(nextProps: AtCountDownProps): void { if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return const { day, hours, minutes, seconds } = nextProps this.seconds = toSeconds(day!, hours!, minutes!, seconds!) this.clearTimer() this.setTimer() } public componentDidMount(): void { this.setTimer() } public componentWillUnmount(): void { this.clearTimer() } public componentDidHide(): void { this.clearTimer() } public componentDidShow(): void { this.setTimer() } public render(): JSX.Element { const { className, customStyle, format, isShowDay, isCard, isShowHour } = this.props const { _day, _hours, _minutes, _seconds } = this.state return ( {isShowDay && ( )} {isShowHour && ( )} ) } } AtCountdown.defaultProps = { customStyle: '', className: '', isCard: false, isShowDay: false, isShowHour: true, format: { day: '天', hours: '时', minutes: '分', seconds: '秒' }, day: 0, hours: 0, minutes: 0, seconds: 0 } AtCountdown.propTypes = { customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), className: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), isCard: PropTypes.bool, isShowDay: PropTypes.bool, isShowHour: PropTypes.bool, format: PropTypes.object, day: PropTypes.number, hours: PropTypes.number, minutes: PropTypes.number, seconds: PropTypes.number, onTimeUp: PropTypes.func }