我可以停止计时器,当我点击暂停按钮时,但是当我再次点击播放时,有 2 个计时器正在播放并且它是错误的

I can stop the timer, when I click the pause button, but when I click play again, 2 timers are playing and it is buggy

我可以停止计时器,当我点击暂停按钮时,但是当我再次点击播放时,有 2 个计时器正在播放,而且它是错误的。它应该在暂停的地方恢复计时器。

let timerSelection = 'Work';
let startingMinutes = 25;
let startingSeconds = 0;
let timerRunning;
let stopTimer;
let playing = false;
let currentMinutes;
let currentSeconds;

//sets the correct timer duration
function setWork() {
    if (playing == false) {
        startingMinutes = 25;
        startingSeconds = 0;
        timerSelection = 'Work'
        document.querySelector("#minutes").innerHTML = '25';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setShortBreak() {
    if (playing == false) {
        startingMinutes = 5;
        startingSeconds = 0;
        timerSelection = 'ShortBreak'
        document.querySelector("#minutes").innerHTML = '05';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setLongBreak() {
    if (playing == false) {
        startingMinutes = 15;
        startingSeconds = 0;
        timerSelection = 'LongBreak'
        document.querySelector("#minutes").innerHTML = '15';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}


//play-button turns into pause button, when it's clicked
function playVisibility() {
    document.getElementById("play").style.visibility = "visible";
    document.getElementById("pause").style.visibility = "hidden";
}




//starts the timer
function timer() {

    document.getElementById("play").style.visibility = "hidden";
    document.getElementById("pause").style.visibility = "visible";

    
    playing = true;
    
    let time = startingMinutes * 60;

    setInterval(updateCoundtdown, 1000);
    time--;

    function updateCoundtdown() {
        if (playing) {
            let minutes = Math.floor(time / 60);
            let seconds = time % 60;

            seconds = seconds < 10 ? '0' + seconds : seconds;
            minutes = minutes < 10 ? '0' + minutes : minutes;

            currentMinutes = minutes;
            currentSeconds = seconds;

            document.querySelector("#minutes").innerHTML = minutes;
            document.querySelector("#seconds").innerHTML = seconds;
            time--;
            console.log(minutes + ':' + seconds);
        } else {
            console.log('Currently:   ' + currentMinutes + ':' + currentSeconds)
            return;
        }
    }
}
body {
    background-color: rgb(32, 32, 32);
}

#play {
    visibility: visible;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#play:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

#pause {
    visibility: hidden;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#pause:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

.play_img {
    height: 50px;
}

.pause_img {
    height: 50px;
}

.controls {
    position: absolute;
    left: calc(50% - 50px);
    top: 25em;
    height: 100px;
    width: 100px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#timer {
    position: absolute;
    left: calc(50% - 175px);
    top: 16em;
    height: 120px;
    width: 350px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#minutes {
    position: inherit;
    left: 10px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#seconds {
    position: inherit;
    left: 200px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#doppelpunkt {
    position: inherit;
    left: 160px;
    top: 1%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

.header {
    position: absolute;
    left: calc(50% - 250px);
    top: 5em;
    height: 70px;
    width: 500px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
    margin: 0 auto;
}


#work {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    width: 140px;
    height: 50px;
    position: inherit;
    left: calc(20% - 70px);
}


#work:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#work:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#short_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(50% - 70px);
}

#short_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#short_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#long_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(80% - 70px);
}

#long_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#long_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


button:hover {
    cursor: pointer;
    background-color: rgba(31, 31, 31, 0.527);
}

::selection {
    background: transparent;
}




@media (max-height: 520px) {
    .controls {
        top: 6.8em;
        left: calc(62.7% - 50px);
    }
    #timer {
        top: 8em;
        left: calc(46% - 175px)
    }
    .header {
        top: 1.5em;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Varela+Round&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="main.js"></script>

    <button id="timer">
        <div id="minutes">25</div> 
        <div id="seconds">00</div> 
        <div id="doppelpunkt"> : </div>
    </button>

    <header class="header">
        <button id="work" onclick="setWork()">Work</button>
        <button id="short_break" onclick="setShortBreak()">Short Break</button>
        <button id="long_break" onclick="setLongBreak()">Long Break</button>
    </header>
    <nav class="controls">
        <button id="play" onclick="timer();"><img class="play_img" src="play.png"></button>
        <button id="pause" onclick="playVisibility(); playing = false"><img class="pause_img" src="pause.png"></button>
    </nav>

</body>
</html>

每次您 运行 timer()(点击播放按钮),setInterval(updateCoundtdown, 1000); 会再次被调用,并且 updateCoundtdown() 每秒会被多次调用。

在开始新的间隔之前,您需要清除之前的间隔。

let updateCoundtdownIntervalHandle = null;
// ...
function playVisibility() {
    // on pause clear the interval.
    if (updateCoundtdownIntervalHandle !== null) {
        clearInterval(updateCoundtdownIntervalHandle);
        updateCoundtdownIntervalHandle = null;
    }
    // ...
}

function timer() {
    // ...
    // if old interval is still running for some reason, clear it
    if (updateCoundtdownIntervalHandle !== null) {
        clearInterval(updateCoundtdownIntervalHandle);
    }
    updateCoundtdownIntervalHandle = setInterval(updateCoundtdown, 1000);
    // ...
}

let timerSelection = 'Work';
let startingMinutes = 25;
let startingSeconds = 0;
let timerRunning;
let stopTimer;
let playing = false;
let currentMinutes;
let currentSeconds;
let updateCoundtdownIntervalHandle = null;

//sets the correct timer duration
function setWork() {
    if (playing == false) {
        startingMinutes = 25;
        startingSeconds = 0;
        timerSelection = 'Work'
        document.querySelector("#minutes").innerHTML = '25';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setShortBreak() {
    if (playing == false) {
        startingMinutes = 5;
        startingSeconds = 0;
        timerSelection = 'ShortBreak'
        document.querySelector("#minutes").innerHTML = '05';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setLongBreak() {
    if (playing == false) {
        startingMinutes = 15;
        startingSeconds = 0;
        timerSelection = 'LongBreak'
        document.querySelector("#minutes").innerHTML = '15';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}


//play-button turns into pause button, when it's clicked
function playVisibility() {
    clearInterval(updateCoundtdownIntervalHandle);
    document.getElementById("play").style.visibility = "visible";
    document.getElementById("pause").style.visibility = "hidden";
}




//starts the timer
function timer() {

    document.getElementById("play").style.visibility = "hidden";
    document.getElementById("pause").style.visibility = "visible";

    
    playing = true;
    
    let time = startingMinutes * 60;
    if (updateCoundtdownIntervalHandle !== null) {
        clearInterval(updateCoundtdownIntervalHandle);
    }
    updateCoundtdownIntervalHandle = setInterval(updateCoundtdown, 1000);
    time--;

    function updateCoundtdown() {
        if (playing) {
            let minutes = Math.floor(time / 60);
            let seconds = time % 60;

            seconds = seconds < 10 ? '0' + seconds : seconds;
            minutes = minutes < 10 ? '0' + minutes : minutes;

            currentMinutes = minutes;
            currentSeconds = seconds;

            document.querySelector("#minutes").innerHTML = minutes;
            document.querySelector("#seconds").innerHTML = seconds;
            time--;
            console.log(minutes + ':' + seconds);
        } else {
            console.log('Currently:   ' + currentMinutes + ':' + currentSeconds)
            return;
        }
    }
}
body {
    background-color: rgb(32, 32, 32);
}

#play {
    visibility: visible;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#play:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

#pause {
    visibility: hidden;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#pause:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

.play_img {
    height: 50px;
}

.pause_img {
    height: 50px;
}

.controls {
    position: absolute;
    left: calc(50% - 50px);
    top: 25em;
    height: 100px;
    width: 100px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#timer {
    position: absolute;
    left: calc(50% - 175px);
    top: 16em;
    height: 120px;
    width: 350px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#minutes {
    position: inherit;
    left: 10px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#seconds {
    position: inherit;
    left: 200px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#doppelpunkt {
    position: inherit;
    left: 160px;
    top: 1%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

.header {
    position: absolute;
    left: calc(50% - 250px);
    top: 5em;
    height: 70px;
    width: 500px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
    margin: 0 auto;
}


#work {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    width: 140px;
    height: 50px;
    position: inherit;
    left: calc(20% - 70px);
}


#work:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#work:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#short_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(50% - 70px);
}

#short_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#short_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#long_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(80% - 70px);
}

#long_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#long_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


button:hover {
    cursor: pointer;
    background-color: rgba(31, 31, 31, 0.527);
}

::selection {
    background: transparent;
}




@media (max-height: 520px) {
    .controls {
        top: 6.8em;
        left: calc(62.7% - 50px);
    }
    #timer {
        top: 8em;
        left: calc(46% - 175px)
    }
    .header {
        top: 1.5em;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Varela+Round&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="main.js"></script>

    <button id="timer">
        <div id="minutes">25</div> 
        <div id="seconds">00</div> 
        <div id="doppelpunkt"> : </div>
    </button>

    <header class="header">
        <button id="work" onclick="setWork()">Work</button>
        <button id="short_break" onclick="setShortBreak()">Short Break</button>
        <button id="long_break" onclick="setLongBreak()">Long Break</button>
    </header>
    <nav class="controls">
        <button id="play" onclick="timer();"><img class="play_img" src="play.png"></button>
        <button id="pause" onclick="playVisibility(); playing = false"><img class="pause_img" src="pause.png"></button>
    </nav>

</body>
</html>