calc-oa-lib
Version:
calc oa library
308 lines (271 loc) • 8.11 kB
JSX
import PropTypes from "prop-types";
import React from "react";
import $calc from "../../utils/common";
import styleObj from "./index.module.scss";
export default class CalcCountDown extends React.Component {
//#region 属性 & 构造函数
// 属性类型校验
static propTypes = {
lv: PropTypes.number,
customClass: PropTypes.string,
beforeStartText: PropTypes.string,
afterStartText: PropTypes.string,
// 倒计时时间间隔, 单位s
interval: PropTypes.number,
// 是否自动启动倒计时
isAutoRunFirst: PropTypes.bool,
// 是否执行启动事件当自动启动倒计时的时候
isExeStartEventWhenAutoRunFirst: PropTypes.bool,
// 启动后执行的事件
onStartEvent: PropTypes.func,
// 每帧需要执行的事件
// 假设显示器刷新频次为60HZ, 则一帧执行时间为1/60*1000 = 16.7ms
onIntervalEvent: PropTypes.func,
onFinishEvent: PropTypes.func,
};
// 属性默认值
static defaultProps = {
lv: 7,
customClass: "custom-calc-count-down",
beforeStartText: "Send Code",
afterStartText: "Resend in {interval}",
interval: 180,
isAutoRunFirst: false,
isExeStartEventWhenAutoRunFirst: false,
onStartEvent: () => {
console.log(`onStartEvent`);
},
onIntervalEvent: (subTime) => {
console.log(`onIntervalEvent`, subTime);
},
onFinishEvent: () => {
console.log(`onFinishEvent`);
},
};
constructor(props) {
super(props);
this.state = {
interval: this.props.interval,
isCounting: false,
};
}
#data = {
rafID: null,
startTime: null,
stopTime: null,
subTime: null,
};
//#endregion
//#region 属性
// 显示文本
get showingText() {
const _self = this;
const { beforeStartText, afterStartText } = _self.props;
const { interval, isCounting } = _self.state;
let text = "";
if (!isCounting) {
text = beforeStartText;
} else {
text = afterStartText.replace("{interval}", interval);
}
return text;
}
//#endregion
//#region hooks
render() {
const _self = this;
const { lv, customClass } = _self.props;
const { isCounting } = _self.state;
return (
<div className={`${styleObj["calc-count-down-scoped"]}`}>
<div className={`calc-count-down ${customClass}`}>
<div
className={`label-btn ${isCounting ? "isCounting" : ""}`}
onClick={(e) => {
_self.#startCountDownEvent(true);
}}
>
{_self.showingText}
</div>
</div>
</div>
);
}
componentDidMount() {
const _self = this;
// 任务初始化
_self.initTask(() => {});
// console.log(`componentDidMount`);
}
shouldComponentUpdate(nextProps, nextState) {
const _self = this;
const removeProps = ["children"];
const nextPropsClone = $calc.tool.deepClone(nextProps, removeProps);
const curPropsClone = $calc.tool.deepClone(_self.props, removeProps);
const nextStateClone = $calc.tool.deepClone(nextState, removeProps);
const curnextStateClone = $calc.tool.deepClone(_self.state, removeProps);
const needRender =
JSON.stringify(nextPropsClone) != JSON.stringify(curPropsClone) ||
JSON.stringify(nextStateClone) != JSON.stringify(curnextStateClone);
// console.log("calc-count-down shouldComponentUpdate...", needRender);
if (needRender) {
return true;
}
return false;
}
componentDidUpdate(prevProps, prevState) {}
componentWillUnmount() {}
//#endregion
//#region methods
//任务初始化
//callBack: 回调函数
initTask(callBack) {
const _self = this;
// // 1>重置时间间隔
// _self.#resetInterval(callBack);
const { isAutoRunFirst, isExeStartEventWhenAutoRunFirst = false } =
_self.props;
// console.log(
// `initTask-isAutoRunFirst`,
// isAutoRunFirst,
// `initTask-isExeStartEventWhenAutoRunFirst`,
// isExeStartEventWhenAutoRunFirst
// );
isAutoRunFirst &&
_self.#startCountDownEvent(isExeStartEventWhenAutoRunFirst);
callBack && callBack();
}
//重置时间间隔
//callBack: 回调函数
#resetInterval(callBack) {
const _self = this;
const { interval } = _self.props;
_self.setState(
{
interval,
},
() => {
callBack && callBack();
}
);
}
// 启动倒计时事件
// isExeStartEventWhenAutoRunFirst: 是否执行启动事件当自动启动倒计时的时候
#startCountDownEvent(isExeStartEvent = true) {
const _self = this;
// console.log(`startCountDownEvent-isExeStartEvent`, isExeStartEvent);
_self.#start(isExeStartEvent);
}
// 启动倒计时
// isExeStartEvent: 是否执行启动事件, 默认true
#start(isExeStartEvent = true) {
const _self = this;
// console.log(`start-isExeStartEvent`, isExeStartEvent);
const { isCounting } = _self.state;
const { interval, onStartEvent } = _self.props;
// 若已经启动, 则返回
if (isCounting) {
return false;
}
_self.setState(
{
isCounting: true,
},
() => {}
);
_self.#data.startTime = performance.now();
// const that = this;
_self.#data.rafID = requestAnimationFrame((timestamp) => {
_self.#step(timestamp);
});
// 执行启动事件
isExeStartEvent && onStartEvent && onStartEvent();
}
// 每帧需要执行的动作
#step(timestamp) {
const _self = this;
// console.log(timestamp);
const { interval, onIntervalEvent, onFinishEvent } = _self.props;
const { startTime } = _self.#data;
_self.#data.subTime = timestamp - startTime;
// 设置state.interval
_self.#formatInterval(_self.#data.subTime);
// 执行间隔事件
onIntervalEvent && onIntervalEvent(_self.#data.subTime);
// 倒计时和时间到, 停止计数
if (Math.floor(_self.#data.subTime / 1000) >= interval) {
_self.#finish();
return true;
}
// 继续执行下一帧动作
_self.#data.rafID = requestAnimationFrame((timestamp) => {
_self.#step(timestamp);
});
}
// 格式化显示的间隔值
#formatInterval(subTime) {
const _self = this;
const { interval } = _self.props;
subTime = $calc.tool.isNullOrEmpty(subTime) ? 0 : subTime;
_self.setState(
{
interval: interval - Math.floor(subTime / 1000),
},
() => {}
);
}
// 执行完毕
#finish() {
const _self = this;
const { interval, onFinishEvent } = _self.props;
_self.#pause();
// 重置属性
_self.#data.rafID = null;
_self.#data.startTime = null;
_self.#data.stopTime = null;
_self.#data.subTime = null;
// 重置间隔时间
_self.#resetInterval();
// 执行完成事件
onFinishEvent && onFinishEvent();
}
// 暂停
#pause() {
const _self = this;
const { isCounting } = _self.state;
const { rafID } = _self.#data;
// 若已经停止计数, 则pass
if (!isCounting) {
return;
}
_self.setState(
{
isCounting: false,
},
() => {}
);
_self.#data.stopTime = performance.now();
rafID && cancelAnimationFrame(rafID);
}
// 继续
#continue() {
const _self = this;
const { isCounting } = _self.state;
let { startTime, stopTime } = _self.#data;
// 若已经在计数, 则pass
if (isCounting) {
return;
}
_self.setState(
{
isCounting: true,
},
() => {}
);
_self.#data.startTime = startTime + performance.now() - stopTime;
_self.#data.rafID = requestAnimationFrame((timestamp) => {
_self.#step(timestamp);
});
}
//#endregion
}