有问题暂停setInterval然后继续

时间:2015-10-21 19:24:55

标签: javascript html

我遇到了一个我正在构建的计时器时钟的问题。一切顺利但总之这就是它的作用:

  1. 用户可以设置他/她想要学习或做任何活动的时间
  2. 用户按下开始
  3. 开始按钮变为“停止”按钮
  4. 计时器从用户选择的时间开始倒计时
  5. 一旦定时器点击0,时钟停止,按钮变回“开始”,一切都重置为0:00
  6. 注意

    用户点击开始按钮或开始按钮后,如果能够通知用户,设备将振动。

    问题

    我遇到的问题是,当时钟正在运行并且用户按下“停止学习”按钮时,时钟停止,是的,这很好但是当他/她再次按下按钮时(现在应该是“开始” “按钮因为它基本上暂停了”,然后时钟花费了给定的时间并从用户给出的时间开始计时,而不是继续直到0:00。

    我查看了一些文章并且我使用了变量并在布尔状态之间切换并检查时钟是否正在运行。

    isRunning = !isRunning
    

    我见过一些人说我应该使用:

    clearInterval(name);
    

    这不起作用,因为我不想清除时钟状态或者我做错了。

    代码

    可以在此处找到指向小提琴的链接:https://jsfiddle.net/ToreanJoel/c75vLf8b/

    HTML

    <br/>
    <div class="timer" id="startingTimer">
        <p class="title" id="state">Break</p>
        <p id="time">00:00</p><span ng-style="{'height':fillHeight, 'background':fillColor }" class="fill" style="height: 0.933333%; background: rgb(153, 204, 0);"></span>
    
    </div>
    <br/>
    <div class="session" id="toggleSessionStart">
        <div class="timer control startingTimercontroller" id="startingTimercontroller">
            <p class="title controlTitle" id="StartTimer">Start Study</p>
        </div>
        <!--<div class="timer control startingPauseTimercontroller" id="startingPauseTimercontroller">
            <p class="title controlTitle" id="StartPauseTimer">Start Break</p>
        </div>--></div>
    <br/>
    <header>
        <div class="session">
            <div class="sessionCtrl">
                <p>session length</p>
                <input type="number" class="time" id="valueTimerSession" value="10">
            </div>
            <!--<div class="breakCtrl">
                <p>break length</p>
                <input type="number" class="time" id="valueTimerBreak" value="5"> 
           </div>--></div>
    </header>
    

    CSS

    body {
        background: #333333;
        color: #fff;
    }
    #time {
        font-size: 90px;
        position: relative;
        top: -40px;
    }
    @media (max-width: 500px) {
        #time {
            font-size: 90px;
            position: relative;
            top: -80px;
        }
    }
    .plus {
        background-color: #333333;
        color: #fff;
        border: none;
        cursor: pointer;
        font-size: 2em;
        outline: none;
    }
    .time {
        font-size: 2.5em;
        padding-left: 10px;
        padding-right: 10px;
        width: 100%;
    }
    .minus {
        background-color: #333333;
        color: #fff;
        border: none;
        cursor: pointer;
        font-size: 2em;
        outline: none;
    }
    header {
        display: flex;
        justify-content: center;
        text-align: center;
        margin: 0 auto;
        color: #fff;
        text-transform: uppercase;
        padding: 20px;
    }
    .session .breakCtrl, .session .sessionCtrl {
        display: inline;
        padding-left: 30px;
        padding-right: 30px;
    }
    .session {
        font-size: .8em;
        display: flex;
    }
    .timer {
        margin: 0 auto;
        text-align: center;
        width: 300px;
        height: 300px;
        font-size: 4em;
        border: 2px solid #99CC00;
        border-radius: 50%;
        cursor: pointer;
        position: relative;
        z-index: 20;
        overflow: hidden;
    }
    .control {
        margin: 0 auto;
        text-align: center;
        width: 120px;
        height: 120px;
        font-size: 4em;
        border: 2px solid #99CC00;
        border-radius: 50%;
        cursor: pointer;
        position: relative;
        z-index: 20;
        overflow: hidden;
        font-family: sans-serif;
    }
    .startingTimercontroller {
        background: #37B703 !important;
        border: 2px solid #fff;
    }
    .startingPauseTimercontroller {
        background: #B70000 !important;
        border: 2px solid #fff;
    }
    .title {
        margin: 45px;
        margin-bottom: -30px;
    }
    .controlTitle {
        font-size: 28px;
        position: relative;
        top: 25px;
        margin: 0;
    }
    .heading {
        text-align: center;
        font-size: 50px;
        text-transform: uppercase;
        font-family: sans-serif;
    }
    

    JS

    //event Listener
    var clickStart = document.getElementById("toggleSessionStart");
    
    //pauseing the clock
    var clockRunning = false;
    var clicked = false;
    
    //getting the user value ammount to study and break for
    var valueTimerSession = parseInt(document.getElementById('valueTimerSession').value);
    
    
    function pomodoro(studyTime) {
        this.studyTime = studyTime;
        this.seconds = 59;
        this.timerDOM = document.getElementById("time");
        this.state = document.getElementById("state");
        this.toggleSessionStart = document.getElementById('toggleSessionStart');
    }
    
    pomodoro.prototype.startStudyTicker = function () {
        var thisStudyTicker = this;
        var seconds = this.seconds - 1;
        var DOM = this.timerDOM;
        var minutes = this.studyTime - 1;
        var loopingSeconds = seconds;
        var state = this.state;
        var toggleSessionStart = this.toggleSessionStart;
    
        if (clicked && clockRunning) {
            console.log('We are runnung');
            window.ticker = setInterval(function () {
                //save the minutes to global variable
                window.minSaved = minutes;
                window.secSaved = loopingSeconds;
    
                console.log("The time saved is " + window.minSaved + ":" + window.secSaved);
    
                console.log(minutes + ":" + loopingSeconds);
                var tick = loopingSeconds--;
                if (loopingSeconds >= 0) {
    
                    tick;
                    DOM.innerHTML = minutes.toString() + ":" + (loopingSeconds < 10 ? '0' + loopingSeconds.toString() : loopingSeconds.toString());
    
                } else {
                    if (minutes > 0) {
                        minutes--;
                        loopingSeconds = seconds;
                        tick;
                        DOM.innerHTML = minutes.toString() + ":" + (loopingSeconds < 10 ? '0' + loopingSeconds.toString() : loopingSeconds.toString());
                    }
                    if (minutes <= 0) {
                        //vibrate - Timer is Done
                        window.navigator.vibrate(300);
                        console.log('im finished');
                        clearInterval(ticker);
                    }
                }
            }, 1000);
        } else {
            if (!clicked && !clockRunning) {
                clearInterval(ticker);
            }
        }
    
    }
    
    pomodoro.prototype.stopStudyTicker = function () {
        var thisStudyTickerStop = this;
        console.log('We are paused');
    
        clearInterval(ticker);
        thisStudyTickerStop.startStudyTicker();
    }
    
    //get the session title
    var sessionTitle = document.getElementById('state');
    
    //the DOM toggle
    function toggleDOM(chosenTime) {
        if (clicked && clockRunning) {
            //started the session - the Title
            sessionTitle.innerHTML = "Session";
            clickStart.innerHTML =
                '<div class="timer control startingPauseTimercontroller" id="startingPauseTimercontroller"><p class="title controlTitle" id="StartTimer">Stop Study</p></div>';
    
            //vibrate
            window.navigator.vibrate(300);
    
            //prototype execution
            var startStudy = new pomodoro(chosenTime);
            startStudy.startStudyTicker();
        } else {
            sessionTitle.innerHTML = "Break";
            clickStart.innerHTML =
                '<div class="timer control startingTimercontroller" id="startingTimercontroller"><p class="title controlTitle" id="StartTimer">Start Study</p></div>';
    
            //vibrate
            window.navigator.vibrate([100, 100, 100]);
    
            //prototype execution
            var stopStudy = new pomodoro();
            stopStudy.stopStudyTicker();
        }
    }
    
    clickStart.addEventListener('click', function () {
        //user clicked and the clock starts
        clicked = !clicked;
        clockRunning = !clockRunning;
    
        //valueTimerBreak = parseInt(document.getElementById('valueTimerBreak').value);
        valueTimerSession = parseInt(document.getElementById('valueTimerSession').value);
    
        //the Toggle
        toggleDOM(valueTimerSession);
    
    });
    

    我正在查看堆栈溢出的一些事情,但没有什么似乎有帮助,因为我没有尝试使用多个按钮暂停或播放,但使用一个切换其状态和标记和布局可以在jsFiddle上看到( https://jsfiddle.net/ToreanJoel/c75vLf8b/)。

    我正在使用Prototypal Pattern并且我还没有使用它,但我会再次讨论所有内容,只是为了重构代码以便使用它。

    提前致谢

2 个答案:

答案 0 :(得分:2)

我并没有真正理解你的代码,但是我自己做了,基本上如果你点击一个按钮并且秒没有存储在变量中 - 存储它们,否则只是继续循环。我想你会理解我的代码,只需用我的。

替换你的javascript
var clickStart = document.getElementById("toggleSessionStart");

var pomodoro = function() {
    this.inProgress = false;
    this.studyTime = null;
    this.timerInstance = null;
    this.timerDOM = document.getElementById("time");
    this.stateElement = document.getElementById("state");
    this.toggleSessionStart = document.getElementById('toggleSessionStart');
}

pomodoro.prototype = {
    start: function() {
        var parent = this;

        if(this.studyTime === null) this.studyTime = parseInt(document.getElementById('valueTimerSession').value, 10) * 60;

        this.timerInstance = setInterval(function() {
            parent.studyTime--;

            if(parent.studyTime < 1) parent.destroy();
            else parent.updateTime();
        }, 1000);

        return this;
    },
    pause: function() {
        clearInterval(this.timerInstance);
        this.timerInstance = null;

        return this;
    },
    destroy: function() {
        this.pause();
        this.studyTime = null;
        this.toogleState(false);
        this.timerDOM.innerHTML = '00:00';
        return this;
    },
    updateTime: function() {
        var totalSec = this.studyTime,
              minutes = Math.floor(totalSec / 60),
              seconds = totalSec % 60;

        this.timerDOM.innerHTML = (minutes < 10 ? "0" + minutes : minutes) + ":" + (seconds  < 10 ? "0" + seconds : seconds);
        return this;
    },
    toogleState: function(state) {
        this.inProgress = (typeof state !== 'undefined') ? state : !this.inProgress;

        if(this.inProgress) {
            this.stateElement.innerHTML = "Session";
            clickStart.innerHTML = '<div class="timer control startingPauseTimercontroller" id="startingPauseTimercontroller"><p class="title controlTitle" id="StartTimer">Stop Study</p></div>';
            this.start();
        }
        else {
            this.stateElement.innerHTML = "Break";
            clickStart.innerHTML = '<div class="timer control startingTimercontroller" id="startingTimercontroller"><p class="title controlTitle" id="StartTimer">Start Study</p></div>';
            this.pause();
        }

        window.navigator.vibrate(300);

        return this;
    }
};

var pomodoroInstance = new pomodoro();

clickStart.addEventListener('click', function () {
    pomodoroInstance.toogleState();
});

顺便说一句。有一个问题,你不能手动停止计时器,所以如果用户想要设置不同的时间,他将不得不重新加载页面。您可以添加一个小按钮,该按钮将触发destroy()方法。

答案 1 :(得分:0)

我宁愿在一个单独的类中实现时钟的逻辑,毕竟时钟不需要任何时间,我们的api将包括启动/停止/暂停计时器的方法< / p>

gui然后创建一个时钟实例,每当你点击开始/停止按钮时我们只需要调用控制定时器的魔术时钟方法,注意时钟没有一个方法来渲染自己,它& #39;最好让另一个类ClockGUI的类具有内部实例Clock,这个新类只调用Clock实例的方法来更新计时器并更新gui

&#13;
&#13;
function Clock (time) {
  this.timeLeft = time
  this.paused = false
}

Clock.prototype.start = function () {
  this.raf = requestAnimationFrame(
    this._loop.bind(this)
  )
}

Clock.prototype.stop = function () {
  cancelRequestAnimationFrame(this.raf)
}

Clock.prototype.togglePause = function () {
  this.paused = !this.paused
}

Clock.prototype._update = function (t) {
  if (!this.paused) {
    this.timeLeft -= t
    if (this.timeLeft <= 0) {
      this.stop()
    }
  }
}

Clock.prototype._loop = function () {
  this.raf = requestAnimationFrame(this._loop.bind(this))
  var now = Date.now()
  var delta = now - (this.prev || now)
  this._update(delta)
  this.prev = now
}


// game
var timeLeft = document.querySelector('#time-left')
var input = document.querySelector('input')
var button = document.querySelector('button')
var started = false
var clock
button.addEventListener('click', function () {
  button.innerText = button.innerText === 'start' ? 'pause' : 'start'

  if (!started) {
    started = true
    clock = new Clock(input.value * 1000 * 60)
    clock.start()
    
    input.disabled = true
    
    return
  }
  
  // toggle the state of the clock
  clock.togglePause()
})

function render () {
  requestAnimationFrame(render)
  // render only if a clock was created
  if (clock) {
    var time = Math.floor(clock.timeLeft / 1000)
    var minutes = Math.floor(time / 60)
    var seconds = time % 60
    var ms = clock.timeLeft % 1000
    timeLeft.innerHTML = minutes + ':' + seconds + ':' + ms
  }
}

requestAnimationFrame(render)
&#13;
<div>
  Time left: <span id="time-left"></span>
</div>

<button> start </button>
  
<input type="number" value="10">
&#13;
&#13;
&#13;

由于您已经看到时钟不受setInterval控制,而是被requestAnimationFrame控制,因此固定1000毫秒间隔的问题是您想要的暂停行为:

  • 暂停:只需致电clearInterval
  • 开始:计算剩下多少时间不是一秒的一部分,例如timeLeft % 1000,在剩下的那段时间设置超时,然后再次调用设置间隔

您可以使用频率较低的setInterval,例如10毫秒,但是不能保证该功能只需要10毫秒,而可以接近 10毫秒,因此您仍然可以需要计算setInterval函数的两次调用之间经过的时间,在上面的示例中,这是在Clock.prototype._loop上完成的