首页 > 解决方案 > 反应计时器 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)

笔链接:https ://codepen.io/harel_avv/pen/RwGQEXy

标签: htmlcssreactjssvgtimer

解决方案


它没有按您期望的方式工作,因为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;

推荐阅读