react倒计时组件 天 时 分 秒

效果如图

 

倒计时组件CountDown/index.js

/**
 * 直播未开播倒计时组件
 * @autor sjq
 */

import React, { useState, useEffect, useRef } from 'react'
import classNames from 'classnames/bind'
import { CheckTime } from '@/utils/countDown'
import style from './index.styl'

const cx = classNames.bind(style)

export const MobileCountDown = (props) => {
  const { countParams } = props
  const { day, hour, minute, seconds, leftTime } = countParams
  // 初始的值
  const [timeObj, setTimeObj] = useState({
    d: day,
    h: hour,
    m: minute,
    s: seconds,
  })

  const latestCount = useRef(timeObj)
  const [over, setOver] = useState(false)

  useEffect(() => {
    // console.log('==更新的时间', timeObj)
    latestCount.current = timeObj // 每次更新时间保存
  })
  // 模拟时钟
  const countDownTime = () => {
    if (over || leftTime < 0) return
    const latestTimeObj = latestCount.current
    const isDhms =
      latestTimeObj.d === 0 &&
      latestTimeObj.h === 0 &&
      latestTimeObj.m === 0 &&
      latestTimeObj.s === 0
    const isHms =
      latestTimeObj.h === 0 && latestTimeObj.m === 0 && latestTimeObj.s === 0
    const isMs = latestTimeObj.m === 0 && latestTimeObj.s === 0
    const isS = latestTimeObj.s === 0

    if (isDhms) setOver(true)
    else if (isHms)
      setTimeObj((obj) => {
        let { d } = obj
        return {
          d: d - 1,
          h: 23,
          m: 59,
          s: 59,
        }
      })
    else if (isMs)
      setTimeObj((obj) => {
        let { d, h } = obj
        return {
          d,
          h: h - 1,
          m: 59,
          s: 59,
        }
      })
    else if (isS)
      setTimeObj((obj) => {
        let { d, h, m } = obj
        return {
          d,
          h,
          m: m - 1,
          s: 59,
        }
      })
    else
      setTimeObj((obj) => {
        let { d, h, m, s } = obj
        return {
          d,
          h,
          m,
          s: s - 1,
        }
      })
  }

  useEffect(() => {
    let timeCard = setInterval(countDownTime, 1000)
    return () => {
      clearInterval(timeCard)
    }
  })
  
  return (
    <>
      { !over && (
        <div className={`${cx('count-down')}`}>
          <div className={cx('count-down-contain')}>
            <div className={cx('count-down-text')}>距直播开始</div>
            <div className={cx('count-down-card')}>
              <div className={cx('count-down-diamond count-down-hour')}>
                {CheckTime(timeObj.d)}
              </div>
              <div className={cx('count-down-semi count-down-semicolon')}></div>
              <div className={cx('count-down-diamond count-down-hour')}>
                {CheckTime(timeObj.h)}
              </div>
              <div className={cx('count-down-semi count-down-semicolon')}></div>
              <div className={cx('count-down-diamond count-down-minute')}>
                {CheckTime(timeObj.m)}
              </div>
              <div className={cx('count-down-semi count-down-semicolon')}></div>
              <div className={cx('count-down-diamond count-down-second')}>
                {CheckTime(timeObj.s)}
              </div>
              <div className={cx('count-down-semi count-down-semicolon')}></div>
            </div>
          </div>
        </div>
      )}
    </>
  )
}

父组件

 ....
import { initTime } from '@/utils/countDown'
....
const MPlayer = (props) => {
  const [countPlayStatus, setCountPlayStatus] = useState('')
  const [timeParams, setTimeParams] = useState({})
  useEffect(() => {
    const { server_time, content } = courseContent || {}
    if (courseContent&&server_time&&content) {
      const { start_time, status } = content[0] || {}
// 重点可以看一下这一块 传入的开始和结束时间 const initCount
= initTime({ type: 's', startTime: start_time, serverTime: server_time, }) setCountPlayStatus(status) setTimeParams(initCount)
} }, [])
return ( <div className={cx( isTransverse && type === 'rtc' ? 'player-transverse-wrapper' : 'player-wrapper' )} > {/* 未开播的时候显示倒计时 未开播而且没有流的时候 显示倒计时 前面的很多逻辑. demo的时候可去掉,只显示组件即可*/} {countPlayStatus=== NO_START && liveStatus !== RUNNING && liveStatus !== FINISHED && timeParams.leftTime > 0 && ( <MobileCountDown countParams={timeParams} /> )} </div> ) } .....
const mapStateToProps = (state) => ({
isTransverse: state.system.isTransverse,
liveMsgTract: state.im.liveMsgTract
})
....
export default filterComp(Player, connect(mapStateToProps)(MPlayer))
.......

关于倒计时提取的方法utils/countDown.js

/**
 * 倒计时公用方法抽取
 * @author sjq
*/
// 向下取整
export function ChangeNumFloor(num) {
  return Math.floor(num)
}
// 后端获取字段转为天:小时:分钟:秒
export function initTime({ type = 'ms', startTime = 0, serverTime = 0 } = {}) {
  const now = type === 's' ? Number(serverTime) * 1000 : serverTime // 1641564283   后端传过来的字段是s这里做了一下兼容如果是ms也支持
  const getStartTime = startTime.replace(/-/g, '/') // 预设开课时间  后端字段接口里面取字段时间格式 "2022-01-14 09:00:00" 转换成2022/01/14 09:00:00 否则手机时间无效时间
  const endDate = new Date(getStartTime)
  const end = endDate.getTime()
  const leftTime = end - now
  const day = ChangeNumFloor(leftTime / 1000 / 60 / 60 / 24)
  const hour = ChangeNumFloor((leftTime / 1000 / 60 / 60) % 24)
  const minute = ChangeNumFloor((leftTime / 1000 / 60) % 60)
  const seconds = ChangeNumFloor((leftTime / 1000) % 60)
  return {
    day,
    hour,
    minute,
    seconds,
    leftTime,
  }
}
// 天:小时:分钟:秒 单个数字需要补0
export function CheckTime(i) {
  return i.toString().padStart(2, '0')
}

 

--------------有问题或者更优方案欢迎留言讨论------------------

 

posted @ 2022-02-17 15:05  pikachuWorld  阅读(555)  评论(0编辑  收藏  举报