跳至主要內容

测试

Mr.Chen开发笔记React大约 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
}
上次编辑于: