多个Elments的SetInterval(Vanilla JavaScript)

发布于 2025-02-07 22:23:58 字数 5257 浏览 3 评论 0原文

我已经使用Vanilla JavaScript创建了一个时间跟踪器;但是,当您有多个活动时,开始按钮功能无法正常工作。如果您有一个以上的活动DIV,则计时器与最后一个DIV同时启动,而第一个Divs Play按钮开始了最后一个Div。您能否查看我的newplay EventListener来确定我的方法是不正确的吗? (我是否错过了绑定,此,事件或E?

JavaScript:

let date = new Date().toLocaleDateString('en-us', { weekday:"long", year:"numeric", month:"short", day:"numeric"});
let showDate = document.getElementById("insert-date");
showDate.innerText=date;



//Get number of activity buttons for loop to add event listener to each
const btnLength = document.querySelectorAll(".opt-btn").length;

//Will append new div's here
const mainDiv = document.getElementById("activities");

//Add event listeners to each activity button & captures the buttonValue(activity name)
 for (let i = 0; i < btnLength; i++){
document.querySelectorAll(".opt-btn")[i].addEventListener("click", function() {
    const buttonValue = this.value;
    addActivity(buttonValue);
});
   

    //Onclick event creates the div, i, p , play, stop, timer text and appends to the main div
function addActivity(buttonValue){
 
 
        const newDiv = document.createElement('div');
     newDiv.classList.add("activity");

     const newP = document.createElement('p');
     newP.innerText = buttonValue;
     newP.classList.add("act-p");
     newDiv.appendChild(newP);

     const newPlay =document.createElement('i');
     newPlay.classList.add("fa-solid");
     newPlay.classList.add("fa-play");
     let activityInterval;
     newPlay.addEventListener('click', () => {
     activityInterval = setInterval(() => {
            elapsedSeconds++
            updateTimerValue()
          }, 1000)
        })
       newDiv.appendChild(newPlay);

    const newStop =document.createElement('i');
    newStop.classList.add("fa-solid");
    newStop.classList.add("fa-circle-stop");
    newStop.addEventListener("click", clearInterval(activityInterval));
    newDiv.appendChild(newStop);

    newElapsedTime = document.createElement('p');
    newElapsedTime.classList.add("elapsedTime-Text");
    newElapsedTime.innerText = "00:00:00";
    newDiv.appendChild(newElapsedTime);

          mainDiv.appendChild(newDiv);

    let elapsedSeconds = 0;
    updateTimerValue()


    function updateTimerValue() {
        // Count the seconds, minutes and hours, convert to strings and pad the strings with leading 0's
        const seconds = String(elapsedSeconds % 60).padStart(2, '0')
        const minutes = String(parseInt(elapsedSeconds / 60 % 60)).padStart(2, '0')
        const hours = String(parseInt(elapsedSeconds / 60 / 60)).padStart(2, '0')
    
        // Use string interpolation for formatting the timer string
        newElapsedTime.innerText = `${hours}:${minutes}:${seconds}`
      }

    }

 }
  

html:

<section class="option-sec">
<div class = "container">
    <div class = "row">
        <div class ="col col-md-2">
<button class = "opt-btn" value="BATHROOM"><img src ="/images/bathroom.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="COMMUTE"><img src ="/images/commute.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="WORK"><img src ="/images/desk.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="ENT"><img src ="/images/ent.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FAMILY"><img src ="/images/family.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FITNESS"><img src ="/images/gym.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEAL"><img src ="/images/meal.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEDITATE"><img src ="/images/meditate.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="RELIGION"><img src ="/images/pray.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SHOPPING"><img src ="/images/shopping.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SLEEP"><img src ="/images/sleep.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="STUDY"><img src ="/images/study.png" class="option"></button>
</div>
        </div>
    </div>
</section>
<!--End Of Option Buttons-->
<section class="date-area">
    <h1 class="date-hdr">CURRENT DATE: </h1>
    <h2  class="date-hdr" id="insert-date"></h2>
</section>   

<div class ="activity-container">
    <div id="activities" class="activity-list"></div>
</div>

I have created a time tracker with vanilla Javascript; however, the start button functionality is not working correctly when you have more than one activity. If you have more than one activity div, the timer starts at the same time as the last div and the first divs play button starts the last div. Can you please look at my newPlay eventListener to determine how my approach was incorrect? (Am I missing a bind, this, event, or e?

JAVASCRIPT:

let date = new Date().toLocaleDateString('en-us', { weekday:"long", year:"numeric", month:"short", day:"numeric"});
let showDate = document.getElementById("insert-date");
showDate.innerText=date;



//Get number of activity buttons for loop to add event listener to each
const btnLength = document.querySelectorAll(".opt-btn").length;

//Will append new div's here
const mainDiv = document.getElementById("activities");

//Add event listeners to each activity button & captures the buttonValue(activity name)
 for (let i = 0; i < btnLength; i++){
document.querySelectorAll(".opt-btn")[i].addEventListener("click", function() {
    const buttonValue = this.value;
    addActivity(buttonValue);
});
   

    //Onclick event creates the div, i, p , play, stop, timer text and appends to the main div
function addActivity(buttonValue){
 
 
        const newDiv = document.createElement('div');
     newDiv.classList.add("activity");

     const newP = document.createElement('p');
     newP.innerText = buttonValue;
     newP.classList.add("act-p");
     newDiv.appendChild(newP);

     const newPlay =document.createElement('i');
     newPlay.classList.add("fa-solid");
     newPlay.classList.add("fa-play");
     let activityInterval;
     newPlay.addEventListener('click', () => {
     activityInterval = setInterval(() => {
            elapsedSeconds++
            updateTimerValue()
          }, 1000)
        })
       newDiv.appendChild(newPlay);

    const newStop =document.createElement('i');
    newStop.classList.add("fa-solid");
    newStop.classList.add("fa-circle-stop");
    newStop.addEventListener("click", clearInterval(activityInterval));
    newDiv.appendChild(newStop);

    newElapsedTime = document.createElement('p');
    newElapsedTime.classList.add("elapsedTime-Text");
    newElapsedTime.innerText = "00:00:00";
    newDiv.appendChild(newElapsedTime);

          mainDiv.appendChild(newDiv);

    let elapsedSeconds = 0;
    updateTimerValue()


    function updateTimerValue() {
        // Count the seconds, minutes and hours, convert to strings and pad the strings with leading 0's
        const seconds = String(elapsedSeconds % 60).padStart(2, '0')
        const minutes = String(parseInt(elapsedSeconds / 60 % 60)).padStart(2, '0')
        const hours = String(parseInt(elapsedSeconds / 60 / 60)).padStart(2, '0')
    
        // Use string interpolation for formatting the timer string
        newElapsedTime.innerText = `${hours}:${minutes}:${seconds}`
      }

    }

 }
  

HTML:

<section class="option-sec">
<div class = "container">
    <div class = "row">
        <div class ="col col-md-2">
<button class = "opt-btn" value="BATHROOM"><img src ="/images/bathroom.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="COMMUTE"><img src ="/images/commute.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="WORK"><img src ="/images/desk.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="ENT"><img src ="/images/ent.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FAMILY"><img src ="/images/family.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FITNESS"><img src ="/images/gym.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEAL"><img src ="/images/meal.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEDITATE"><img src ="/images/meditate.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="RELIGION"><img src ="/images/pray.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SHOPPING"><img src ="/images/shopping.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SLEEP"><img src ="/images/sleep.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="STUDY"><img src ="/images/study.png" class="option"></button>
</div>
        </div>
    </div>
</section>
<!--End Of Option Buttons-->
<section class="date-area">
    <h1 class="date-hdr">CURRENT DATE: </h1>
    <h2  class="date-hdr" id="insert-date"></h2>
</section>   

<div class ="activity-container">
    <div id="activities" class="activity-list"></div>
</div>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏夜暖风 2025-02-14 22:23:58

tldr;

使用前声明变量。


严格模式本来会产生一个本来会产生一个,将脚本写入使用newelapsedtime在使用之前尚未声明的时间错误。

sloppy模式>没有声明会导致任何活动的“播放”点击处理程序创建或覆盖共享的全局对象属性window.newelapsedtime而不会生成错误。

在处理程序的执行上下文中声明变量,该变量将活动添加到Maindiv似乎可以求解彼此干扰的活动点击。

解决方案的示例不会实现停止(或暂停和恢复),如果play &lt; i&gt;元素多次单击相同的活动:

"use strict";
let date = new Date().toLocaleDateString('en-us', { weekday:"long", year:"numeric", month:"short", day:"numeric"});
let showDate = document.getElementById("insert-date");
showDate.innerText=date;

// debug: show value in buttons instead of images

Array.from(document.querySelectorAll(".opt-btn")).forEach(
    button=>button.innerHTML = button.value
);

//Get number of activity buttons for loop to add event listener to each
const btnLength = document.querySelectorAll(".opt-btn").length;

//Will append new div's here
const mainDiv = document.getElementById("activities");

//Add event listeners to each activity button & captures the buttonValue(activity name)
 for (let i = 0; i < btnLength; i++){
document.querySelectorAll(".opt-btn")[i].addEventListener("click", function() {
    const buttonValue = this.value;
    addActivity(buttonValue);
});
   
//Onclick event creates the div, i, p , play, stop, timer text and appends to the main div

function addActivity(buttonValue){
     const newDiv = document.createElement('div');
     newDiv.classList.add("activity");

     const newP = document.createElement('p');
     newP.innerText = buttonValue;
     newP.classList.add("act-p");
     newDiv.appendChild(newP);

     const newPlay =document.createElement('i');

     newPlay.classList.add("fa-solid");
     newPlay.classList.add("fa-play");
     let activityInterval;
     newPlay.addEventListener('click', () => {

     // what to do if newPlay clicked twice?
     if( activityInterval) {
        throw Error("no code support for clicking play multiple times for same activity");
     }
 
     activityInterval = setInterval(() => {
            elapsedSeconds++
            updateTimerValue()
          }, 1000)
        })
       newDiv.appendChild(newPlay);

    const newStop =document.createElement('i');
    newStop.classList.add("fa-solid");
    newStop.classList.add("fa-circle-stop");
    newStop.addEventListener("click", clearInterval(activityInterval));
    newDiv.appendChild(newStop);

    // declare newElapsedTime variable befor use:
    const newElapsedTime = document.createElement('p');

    newElapsedTime.classList.add("elapsedTime-Text");
    newElapsedTime.innerText = "00:00:00";
    newDiv.appendChild(newElapsedTime);

    mainDiv.appendChild(newDiv);

    let elapsedSeconds = 0;
    updateTimerValue()


    function updateTimerValue() {
        // Count the seconds, minutes and hours, convert to strings and pad the strings with leading 0's
        const seconds = String(elapsedSeconds % 60).padStart(2, '0')
        const minutes = String(parseInt(elapsedSeconds / 60 % 60)).padStart(2, '0')
        const hours = String(parseInt(elapsedSeconds / 60 / 60)).padStart(2, '0')
    
        // Use string interpolation for formatting the timer string
        newElapsedTime.innerText = `${hours}:${minutes}:${seconds}`
      }

    }

 }
button {
  text-align: center;
  min-width: 8rem;
}
.fa-play:after {
   content: "[play]"
}
<section class="option-sec">
<div class = "container">
    <div class = "row">
        <div class ="col col-md-2">
<button class = "opt-btn" value="BATHROOM"><img src ="/images/bathroom.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="COMMUTE"><img src ="/images/commute.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="WORK"><img src ="/images/desk.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="ENT"><img src ="/images/ent.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FAMILY"><img src ="/images/family.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FITNESS"><img src ="/images/gym.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEAL"><img src ="/images/meal.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEDITATE"><img src ="/images/meditate.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="RELIGION"><img src ="/images/pray.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SHOPPING"><img src ="/images/shopping.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SLEEP"><img src ="/images/sleep.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="STUDY"><img src ="/images/study.png" class="option"></button>
</div>
        </div>
    </div>
</section>
<!--End Of Option Buttons-->
<section class="date-area">
    <h1 class="date-hdr">CURRENT DATE: </h1>
    <h2  class="date-hdr" id="insert-date"></h2>
</section>   

<div class ="activity-container">
    <div id="activities" class="activity-list"></div>
</div>

我完全建议以严格的模式编写代码,并因此解决编译器所产生的任何错误。

TLDR;

Declare variables before use.


Writing the script in strict mode would have generate a compile time error that newElapsedTime has not been declared before use.

In sloppy mode however, assignment to newElapsedTime without declaration causes any activity's "play" click handler to create or overwrite the value of a shared global object property window.newElapsedTime with no error generated.

Declaring the variable in the execution context of the handler which added the activity to mainDiv seems to solve activity clicks interfering with each other.

This example of a solution does not implement stop (or pause and resume) and logs an error if the play <i> element is clicked multiple times for the same activity:

"use strict";
let date = new Date().toLocaleDateString('en-us', { weekday:"long", year:"numeric", month:"short", day:"numeric"});
let showDate = document.getElementById("insert-date");
showDate.innerText=date;

// debug: show value in buttons instead of images

Array.from(document.querySelectorAll(".opt-btn")).forEach(
    button=>button.innerHTML = button.value
);

//Get number of activity buttons for loop to add event listener to each
const btnLength = document.querySelectorAll(".opt-btn").length;

//Will append new div's here
const mainDiv = document.getElementById("activities");

//Add event listeners to each activity button & captures the buttonValue(activity name)
 for (let i = 0; i < btnLength; i++){
document.querySelectorAll(".opt-btn")[i].addEventListener("click", function() {
    const buttonValue = this.value;
    addActivity(buttonValue);
});
   
//Onclick event creates the div, i, p , play, stop, timer text and appends to the main div

function addActivity(buttonValue){
     const newDiv = document.createElement('div');
     newDiv.classList.add("activity");

     const newP = document.createElement('p');
     newP.innerText = buttonValue;
     newP.classList.add("act-p");
     newDiv.appendChild(newP);

     const newPlay =document.createElement('i');

     newPlay.classList.add("fa-solid");
     newPlay.classList.add("fa-play");
     let activityInterval;
     newPlay.addEventListener('click', () => {

     // what to do if newPlay clicked twice?
     if( activityInterval) {
        throw Error("no code support for clicking play multiple times for same activity");
     }
 
     activityInterval = setInterval(() => {
            elapsedSeconds++
            updateTimerValue()
          }, 1000)
        })
       newDiv.appendChild(newPlay);

    const newStop =document.createElement('i');
    newStop.classList.add("fa-solid");
    newStop.classList.add("fa-circle-stop");
    newStop.addEventListener("click", clearInterval(activityInterval));
    newDiv.appendChild(newStop);

    // declare newElapsedTime variable befor use:
    const newElapsedTime = document.createElement('p');

    newElapsedTime.classList.add("elapsedTime-Text");
    newElapsedTime.innerText = "00:00:00";
    newDiv.appendChild(newElapsedTime);

    mainDiv.appendChild(newDiv);

    let elapsedSeconds = 0;
    updateTimerValue()


    function updateTimerValue() {
        // Count the seconds, minutes and hours, convert to strings and pad the strings with leading 0's
        const seconds = String(elapsedSeconds % 60).padStart(2, '0')
        const minutes = String(parseInt(elapsedSeconds / 60 % 60)).padStart(2, '0')
        const hours = String(parseInt(elapsedSeconds / 60 / 60)).padStart(2, '0')
    
        // Use string interpolation for formatting the timer string
        newElapsedTime.innerText = `${hours}:${minutes}:${seconds}`
      }

    }

 }
button {
  text-align: center;
  min-width: 8rem;
}
.fa-play:after {
   content: "[play]"
}
<section class="option-sec">
<div class = "container">
    <div class = "row">
        <div class ="col col-md-2">
<button class = "opt-btn" value="BATHROOM"><img src ="/images/bathroom.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="COMMUTE"><img src ="/images/commute.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="WORK"><img src ="/images/desk.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="ENT"><img src ="/images/ent.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FAMILY"><img src ="/images/family.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="FITNESS"><img src ="/images/gym.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEAL"><img src ="/images/meal.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="MEDITATE"><img src ="/images/meditate.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="RELIGION"><img src ="/images/pray.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SHOPPING"><img src ="/images/shopping.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="SLEEP"><img src ="/images/sleep.png" class="option"></button>
</div>
<div class ="col col-md-2">
    <button class = "opt-btn" value="STUDY"><img src ="/images/study.png" class="option"></button>
</div>
        </div>
    </div>
</section>
<!--End Of Option Buttons-->
<section class="date-area">
    <h1 class="date-hdr">CURRENT DATE: </h1>
    <h2  class="date-hdr" id="insert-date"></h2>
</section>   

<div class ="activity-container">
    <div id="activities" class="activity-list"></div>
</div>

I thoroughly recommend writing code in strict mode and resolving any errors generated by the compiler because of it.

为你拒绝所有暧昧 2025-02-14 22:23:58

问题可能是在此行中:

activityInterval = setInterval(() => {
        elapsedSeconds++
        updateTimerValue()
      }, 1000)
    })

每次您调用addactivity(),您最终会重新定义activity Interval to to The Interval to The Interval to The Interval Tem the Instrain创建的活动。因此,在stoptimer()中,您只需停止最新计时器。

相反,Activity Interval需要是本地变量。首先在事件处理程序之外进行delcare,然后在stoptimer()中编写箭头函数回调:

local声明:

let activityInterval;
newPlay.addEventListener("click", () => {
  activityInterval = setInterval(() => {
    elapsedSeconds++;
    updateTimerValue();
  }, 1000);

callback: callback:

newStop.addEventListener("click", () => clearInterval(activityInterval));

这也是一个codesandbox: https://codesandbox.io/s/zealy-jepealy-jepsen-7gc4fn?gc4fn?file=/src/index/index.file=/src/index。 JS:1100-1286
(我没有图像,“日期”只是一个占位符)

The issue likely is with this line:

activityInterval = setInterval(() => {
        elapsedSeconds++
        updateTimerValue()
      }, 1000)
    })

Each time you call addActivity(), you end up redefining activityInterval to the interval specific to the most recent activity created. Therefore, in stopTimer(), you only stop the most recent timer.

Instead, activityInterval needs to be a local variable. Delcare it outside the event handler first, and write a arrow function callback in stopTimer():

local declaration:

let activityInterval;
newPlay.addEventListener("click", () => {
  activityInterval = setInterval(() => {
    elapsedSeconds++;
    updateTimerValue();
  }, 1000);

callback:

newStop.addEventListener("click", () => clearInterval(activityInterval));

Here's a codesandbox too: https://codesandbox.io/s/zealous-jepsen-7gc4fn?file=/src/index.js:1100-1286
(I didn't have the images, and "date" is just a placeholder)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文