测试
大约 2 分钟约 476 字
倒计时
import PropTypes from 'prop-types'
import moment from 'moment'
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
countdown: 0,
list: []
}
this.timer = null
}
static propTypes = {
style: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
itemStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
itemTextStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
itemPartStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
startTime: PropTypes.any,
endTime: PropTypes.any,
onEnd: PropTypes.func
}
static defaultProps = {
startTime: this.timestamp(new Date(), true),
endTime: moment(new Date()).add(30, 'minutes').valueOf()
}
/**
* 生成时间戳
* @param {*} date 时间
* @param {*} ms 是否毫秒级
*/
timestamp(date, ms = false) {
let times = moment()
if (date) {
times = moment(date)
}
let stamp = times.unix()
if (ms) {
// 毫秒级时间戳
stamp = times.valueOf()
}
return date
}
componentDidMount() {
this.initPage()
}
componentWillUnmount() {
this.clearTimer()
}
initPage() {
const {
startTime = this.timestamp(new Date(), true),
endTime = moment(new Date()).add(30, 'minutes').valueOf()
} = this.props
const seconds = this.dateDiff(startTime, endTime, 'seconds') || 0
this.formatList(seconds, () => {
this.countdownTime()
})
}
clearTimer() {
this.timer && clearInterval(this.timer)
this.timer = null
this.setState({ countdown: 0 })
}
countdownTime() {
const { onEnd } = this.props
if (this.timer) {
return false
}
this.timer = setInterval(() => {
let { countdown } = this.state
if (countdown > 0) {
countdown--
this.formatList(countdown)
} else {
onEnd && onEnd()
this.clearTimer()
}
}, 1000)
}
/**
* 时间差
* @param {*} start 开始时间
* @param {*} end 结束时间
* @param {*} key 差值单位 y Q M w d h m s ms
* years quarters months weeks days hours minutes seconds milliseconds
* @returns
*/
dateDiff(start, end, key) {
key = key || 'ms'
return moment(end).diff(moment(start), key)
}
// 毫秒转时间
millToDate(x, format, key) {
key = key || 'ms'
let tmpTime = moment.duration(x, key)
if (!format) {
format = 'HH小时mm分钟'
}
let str = format.replace('YYYY', tmpTime.years())
str = str.replace(/MM/g, ('00' + tmpTime.months()).slice(-2))
str = str.replace(/DD/g, ('00' + tmpTime.days()).slice(-2))
str = str.replace(/HH/g, ('00' + tmpTime.hours()).slice(-2))
str = str.replace(/mm/g, ('00' + tmpTime.minutes()).slice(-2))
str = str.replace(/ss/g, ('00' + tmpTime.seconds()).slice(-2))
return str
}
formatList(seconds, cb) {
// 天数
let days = this.millToDate(seconds, 'DD', 'seconds')
days = Number(days)
// 时分秒
const duration = this.millToDate(seconds, 'HH:mm:ss', 'seconds')
let list = duration.split([':'])
if (days > 0) {
const hours = days * 24 + Number(list[0])
list[0] = hours > 99 ? 99 : hours
}
this.setState(
{
countdown: seconds,
list
},
() => {
cb && cb()
}
)
}
renderItem(item, index) {
const { itemStyle, itemTextStyle, itemPartStyle } = this.props
const { list } = this.state
return (
<div key={`${index}`} className="listItem">
<div style={[styles.listItemCon, itemStyle]}>
<span className="listItemConText" style={itemTextStyle}>
{item}
</span>
</div>
{list.length !== index + 1 ? (
<span className="listItemPart itemPartStyle">:</span>
) : null}
</div>
)
}
render() {
const { list } = this.state
const timerList = list.map((v, i) => {
return this.renderItem(v, i)
})
return <div className="container">{timerList}</div>
}
}
.container,
.listItem {
display: flex;
}
.listItemCon {
min-width: 18px;
min-height: 18px;
border-radius: 5;
background-color: #000;
justify-content: center;
}
.listItemConText {
font-size: 12px;
font-weight: bold;
color: #fff;
}
.listItemPart {
margin: 0 3px;
font-size: 14px;
color: #000;
}
{
"jsLib": [
"https://cdn.jsdelivr.net/npm/moment@2.30.1/moment.min.js",
"https://cdn.jsdelivr.net/npm/prop-types@15.8.1/prop-types.min.js"
],
"codepenLayout": "top",
"codepen": false,
"jsfiddle": false
}