html - 反应计时器 svg 环没有正确增加
问题描述
我已经构建了一个反应计时器并将其添加了一个 svg 环,以便在本教程之后它会随着计时器的递减而动画,问题是,动画不会像我想要的那样移动,大约慢 2 倍,如何我要让它快 2 倍吗?乘以 2 似乎不起作用。另外,为什么身体背景变得有点奇怪,底部没有对齐?
html:
<html>
<head>
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
<div id="lmfao">
</div>
</body>
</html>
CSS:
body {
background: linear-gradient(70deg, rgb(19, 4, 54), rgb(13, 2, 112),
rgb(73, 2, 70), rgb(44, 10, 83));
display: flex;
justify-content: center;
align-items: center;
}
.wrap {
display: flex;
}
.wrap2 {
display: flex;
justify-content: center;
}
button {
background: none;
border: none;
outline: none;
}
#break {
margin-right: 10vw;
}
button:hover {
transform: scale(1.5);
}
.left-positioned:hover {
position: relative;
right: 6px;
}
.right-positioned:hover {
position: relative;
left: 6px;
}
i {
font-size: 2em;
}
span {
font-size: 2em;
}
#timer-label {
margin-right: 0px;
}
#time-left {
font-size: 3rem;
}
#start_stop {
margin-left: 10px;
}
svg {
position: relative;
top: 50px;
transform: rotate(180deg);
width: 350px;
height: 350px;
}
circle {
cx: 50%;
cy: 50%;
r: 150px;
fill: none;
stroke-width: 10px;
}
#path {
transform: rotate(90deg);
transform-origin: center;
transition-property: stroke-dasharray;
transition-duration: 1s;
transition-timing-function: linear;
stroke-linecap: round;
}
#timeriii {
position: absolute;
bottom: 30vh;
right: 47vw;
}
JS:
import * as React from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
var timer_is_paused = true;
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
minutes: this.props.s_mins,
mStr: this.props.s_mins < 10 ? "0" + this.props.s_mins.toString() :
this.props.s_mins.toString(),
seconds: -1,
sStr: "00",
onBreak: false,
class: "fas fa-play",
strke: "green",
strke_len: "942 942"
}
this.totalTime = this.state.minutes * 60;
this.timeLeft = this.totalTime - 1;
this.invertedTotal = 1 / this.totalTime;
this.reactInterval;
this.start_timer = this.start_timer.bind(this);
this.play_pause = this.play_pause.bind(this);
this.reset = this.reset.bind(this);
}
start_timer() {
var strke_res = Math.ceil(this.timeLeft * 942/ this.totalTime);
if(timer_is_paused) clearInterval(this.reactInterval);
else if(this.state.seconds < 10) {
if(this.state.seconds === -1) {
if(this.state.minutes === 0) {
this.setState(state => ({
minutes: state.onBreak ? this.props.s_mins : this.props.b_mins,
mStr: state.onBreak ? this.props.s_mins < 10 ? "0" + this.props.s_mins : this.props.s_mins
: this.props.b_mins < 10 ? "0" + this.props.b_mins: this.props.b_mins,
seconds: -1,
sStr: "00",
onBreak: !state.onBreak,
strke: "green",
strke_len: "942 942"
}));
this.totalTime = this.state.minutes * 60;
this.timeLeft = this.totalTime - 1;
this.invertedTotal = 1 / this.totalTime;
}
else this.setState(state => ({
minutes: state.minutes - 1,
mStr: state.minutes > 10 ? state.minutes - 1 : "0" + (state.minutes-1).toString(),
seconds: 58,
sStr: "59",
strke_len: strke_res + " 942"
}));
}
else this.setState(state => ({
seconds: state.seconds - 1,
sStr: "0" + state.seconds.toString(),
strke_len: strke_res + " 942"
}));
}
else {
this.setState(state => ({
seconds: state.seconds - 1,
sStr: state.seconds.toString(),
strke_len: strke_res + " 942"
}));
}
this.timeLeft--;
}
play_pause() {
if (timer_is_paused) {
this.setState({ class: "fas fa-pause"});
timer_is_paused = false;
this.reactInterval = setInterval(this.start_timer, 1000);
}
else {
this.setState({class: "fas fa-play"});
timer_is_paused = true;
clearInterval(this.reactInterval);
}
}
reset() {
clearInterval(this.reactInterval);
this.setState({
minutes: this.props.s_mins,
mStr: this.props.s_mins < 10 ? "0" + this.props.s_mins.toString() :
this.props.s_mins.toString(),
seconds: -1,
sStr: "00",
onBreak: false,
class: "fas fa-play",
strke: "green",
strke_len: "942 942"
});
timer_is_paused = true;
this.totalTime = this.state.minutes * 60;
this.invertedTotal = 1 / this.totalTime;
this.timeLeft = this.totalTime - 1;
}
componentDidUpdate(prevProps) {
if(this.props.s_mins !== prevProps.s_mins) {
this.setState({
minutes: this.props.s_mins,
mStr: this.props.s_mins < 10 ? "0" + this.props.s_mins.toString() :
this.props.s_mins.toString()
});
this.totalTime = this.state.minutes * 60;
this.timeLeft = this.totalTime - 1;
this.invertedTotal = 1 / this.totalTime;
}
}
render() {
return <div><svg>
<circle stroke= "grey" />
<circle id="path" stroke={this.state.strke}
stroke-dasharray={this.state.strke_len}/>
</svg>
<div id="timeriii">
<span id="timer-label">{this.state.onBreak ? "Break" : "Session"}</span><br />
<span id="time-left">{this.state.mStr}:{this.state.sStr}</span><br />
<button id="start_stop" onClick={this.play_pause} class="left-positioned">
<i class={this.state.class}></i>
</button>
<button id="reset" onClick={this.reset} class="right-positioned"><i class="fas fa-undo" /></button>
</div>
</div>
}
}
//this part isn't important for the question, the can't be an issue here
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
session_length: 25,
break_length: 5,
}
this.ses_inc = this.ses_inc.bind(this);
this.ses_dec = this.ses_dec.bind(this);
this.bre_inc = this.bre_inc.bind(this);
this.bre_dec = this.bre_dec.bind(this);
}
ses_inc() {
var len = this.state.session_length;
if (len < 60 && timer_is_paused)
this.setState({session_length: len + 1});
}
ses_dec() {
var len = this.state.session_length;
if (len > 1 && timer_is_paused)
this.setState({session_length: len - 1});
}
bre_inc() {
var len = this.state.break_length;
if (len < 60 && timer_is_paused)
this.setState({break_length: len + 1});
}
bre_dec() {
var len = this.state.break_length;
if (len > 1 && timer_is_paused)
this.setState({break_length: len - 1});
}
reset() {
this.setState({
session_length: 25, break_length: 5
})
}
render() {
return <div id="clock">
<div class="wrap">
<div id="break">
<h2 id="break-label">Break Length</h2>
<button id="break-decrement" onClick={this.bre_dec} class="left-positioned">
<i class="fas fa-arrow-down"></i>
</button>
<span id="break-length">
{this.state.break_length}
</span>
<button id="break-increment" onClick={this.bre_inc} class="right-positioned">
<i class="fas fa-arrow-up"></i>
</button>
</div>
<div id="session">
<h2 id="session-label">
Session Length</h2>
<button id="session-decrement"
onClick={this.ses_dec} class="left-positioned">
<i class="fas fa-arrow-down"></i>
</button>
<span id="session-length">
{this.state.session_length}
</span>
<button id="session-increment" onClick={this.ses_inc} class="right-positioned">
<i class="fas fa-arrow-up"></i>
</button>
</div>
</div>
<div class="wrap2">
<Timer s_mins={this.state.session_length} b_mins = {this.state.break_length}/>
</div>
</div>
}
}
var body = document.getElementById("lmfao");
ReactDOM.render(<Clock /> , body)
解决方案
它没有按您期望的方式工作,因为interval
时间不精确。您需要使用当前时间并跟踪时差(毫秒):
例子:
在运行间隔函数之前保存开始时间:
this.setState({
startTime: Date.now() //--> save start time
});
获取以秒为单位的时差,并使用差值代替-1
:
const currenTime = Date.now();
const difference = Math.floor((currenTime - this.state.startTime) / 1000);
为什么body背景变得有点奇怪,底部没有对齐
使用fixed
:
background: linear-gradient(
70deg,
rgb(19, 4, 54),
rgb(13, 2, 112),
rgb(73, 2, 70),
rgb(44, 10, 83)
) fixed;
推荐阅读
- linux - 仅通过特定路径获取唯一文件名
- php - php file() 进入 foreach - 致命错误:无法中断/继续 1 级
- regex - 正则表达式匹配 ASCII 符号/数字
- r - 使用 randomForest 进行分类的代码格式
- matlab - MATLAB 中的滤波器扫描效果
- syntax - OCaml 匹配简写
- objective-c - 使用 UIScrollView 缩放方法如何在 Apple AVCam 示例项目中保存缩放的视频记录?
- performance - pingdom 工具无法识别的图像
- linux - macOS 与 Linux 上的回溯信息不同
- java - IllegalStateException:不在 FX 应用程序线程上;currentThread = JavaFX-Launcher