反应计时器 svg 环没有正确递增
React timer svg ring not incrementing properly
我已经构建了一个 React 计时器并为其添加了一个 svg 环,以便它可以在 this 教程之后随着计时器中的递减进行动画处理,问题是,动画没有按我想要的那样移动它慢了大约 2 倍,我如何让它快 2 倍?乘以 2 似乎不起作用。
还有,为什么body背景变得有点奇怪,底部没有对齐?
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);
why is the body background become a bit weird and not aligned well at
the bottom
使用fixed
:
background: linear-gradient(
70deg,
rgb(19, 4, 54),
rgb(13, 2, 112),
rgb(73, 2, 70),
rgb(44, 10, 83)
) fixed;
我已经构建了一个 React 计时器并为其添加了一个 svg 环,以便它可以在 this 教程之后随着计时器中的递减进行动画处理,问题是,动画没有按我想要的那样移动它慢了大约 2 倍,我如何让它快 2 倍?乘以 2 似乎不起作用。 还有,为什么body背景变得有点奇怪,底部没有对齐?
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);
why is the body background become a bit weird and not aligned well at the bottom
使用fixed
:
background: linear-gradient(
70deg,
rgb(19, 4, 54),
rgb(13, 2, 112),
rgb(73, 2, 70),
rgb(44, 10, 83)
) fixed;