react倒计时组件

回到文章>>

COPYHTML

<div id="app"></div>

COPYCSS

.item { display: flex; }

COPYJAVASCRIPT

const { Component, useState } = React; class CountDown extends Component { timer = null; state = { status: "pending", endTime: 0, progress: 0, }; // 开始倒计时 start() { this.execute("onStart"); this.setState({ status: "running" }); const { diff, format } = this.props; const running = () => { const now = Date.now(); const progress = Math.max(this.state.endTime - now, 0); let _progress = ""; if (typeof format === "string") { _progress = this.formatTime(progress, format); } else if (typeof format === "function") { _progress = format.call(null, progress); } this.setState({ progress: _progress }); this.execute("onStep", _progress); if (progress === 0) { this.stop(); } return progress; }; if (diff && diff >= 17) { this.timer = setInterval(() => { running(); }, diff); } else { const requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; setTimeout(() => { (function loop() { const progress = running(); if (progress > 0) { requestAnimFrame(loop); } })(); }, 0); } } // 停止倒计时 stop() { clearInterval(this.timer); this.setState({ status: "ended" }); this.execute("onEnd"); } componentDidMount() { const { endTime, total } = this.props; if (!endTime && !total) { // 至少需要一个参数 console.error(`endTime and total need least one`); } else { const now = Date.now(); let _endTime = 0; if (!endTime) { _endTime = now + (total || 0); } else { _endTime = endTime; } this.setState({ endTime: _endTime }); this.start(); } } formatTime(timestamp, format = "dd hh:mm:ss.ii") { const dateFormat = { "d+": Math.floor(timestamp / 1000 / 60 / 60 / 24), // 天 "h+": Math.floor((timestamp / 1000 / 60 / 60) % 24), // 时 "m+": Math.floor((timestamp / 1000 / 60) % 60), // 分 "s+": Math.floor((timestamp / 1000) % 60), // 秒 "i+": timestamp % 1000, // 毫秒 }; for (let key in dateFormat) { if (new RegExp("(" + key + ")").test(format)) { format = format.replace(RegExp.$1, () => { const regLen = RegExp.$1.length; if (/i+/.test(RegExp.$1)) { return (dateFormat[key] + "000").substr(0, regLen); } return regLen === 1 ? dateFormat[key] : ("00" + dateFormat[key]).substr(("" + dateFormat[key]).length); }); } } return format; } // 触发props中传过来的回调 execute(fn, ...params) { const func = this.props[fn]; if (typeof func === "function") { func(...params); } } render() { return <p>{this.state.progress}</p>; } } const SelfFormatCount = () => { const [ended, setEnded] = useState(false); // 倒计时是否结束的标识 return ( <div> <CountDown total={5000} format={(timestamp) => { return (timestamp / 1000).toFixed(3); }} onEnd={() => setEnded(true)} /> {ended && <p style={{ color: "#f00" }}>已结束</p>} </div> ); }; ReactDOM.render( <div> <div class="item"> <p>10秒钟的倒计时:</p> <CountDown total={10000} format={"mm:ss.iii"} /> </div> <div class="item"> <p>自定义格式的10秒钟的倒计时:</p> <SelfFormatCount /> </div> <div class="item"> <p>距离早晨8点的倒计时:</p> <CountDown endTime={new Date().setHours(8, 0, 0, 0)} format={"hh小时mm分ss秒"} /> </div> <div class="item"> <p>距离中午12点30分的倒计时:</p> <CountDown endTime={new Date().setHours(12, 30, 0, 0)} format={"hh小时mm分ss秒"} /> </div> <div class="item"> <p>距离今晚24点的倒计时:</p> <CountDown endTime={new Date().setHours(24, 0, 0, 0)} format={"hh小时mm分ss秒"} /> </div> </div>, document.getElementById("app") );
新窗口打开