You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在计时器对应的HTMLDivElement存在时执行操作?

跟踪Timer元素存活状态的解决方案

问题背景

自定义了一个Timer类,会返回用于倒计时至0的HTMLDivElement,代码示例及使用方式如下:

/*
Example:

Create timer
let timer = new Timer('div', 'timer', timeForGame).render(); 

Timer fires event when clock id down to 0
timer.addEventListener('countDown', () => { console.log("Timer is out") })
*/
export default class Timer extends Component{
    protected time: number;
    protected event: CustomEvent;
    constructor(tagName: string, className: string, time: number) {
        super(tagName, className);
        this.time = time;
        this.event = new CustomEvent("countDown")
    }

    startTimer(){
        let countdown = this.time * 1000;
        this.container.textContent = String(countdown / 1000);
        const countingDown = () => {
            console.log(countdown / 1000, " seconds");
            countdown -= 1000;
            this.container.textContent = String(countdown / 1000);
            if (countdown === 0){ 
                this.container.dispatchEvent(this.event);
                clearInterval(Timer) 
            }
        }
        const Timer = setInterval(countingDown, 1000);
    }

    render() {
        this.container.innerHTML = String(this.time);
        this.startTimer();
        return this.container;
    }
}

尝试用以下代码跟踪元素存活状态但未生效:

while(document.querySelector('.timer') !== null){
  setTimeout(() => {
    console.log('i exist')
  }, 0);
}

问题原因

你写的while循环是同步死循环,JavaScript是单线程模型,这个循环会持续占用主线程,导致setTimeout的回调永远无法执行,页面也会直接卡死。而且循环是同步执行的,不会主动重新查询DOM状态,即使元素被移除,循环也不会停止。

解决方案

方法1:复用现有countDown事件(跟踪逻辑存活状态)

如果你的"存活状态"指的是倒计时未结束,直接复用Timer类已有的countDown事件即可,不需要额外轮询:

let timer = new Timer('div', 'timer', timeForGame).render(); 
// 监听倒计时结束事件,此时Timer逻辑上不再"存活"
timer.addEventListener('countDown', () => {
  console.log('Timer 倒计时结束');
});

方法2:用MutationObserver跟踪DOM中的物理存活状态

如果需要跟踪元素是否被从DOM中移除(物理上的存活状态),使用浏览器原生的MutationObserver监听DOM变化:

// 创建Timer实例并添加到DOM
let timer = new Timer('div', 'timer', 5).render();
document.body.appendChild(timer);

// 创建MutationObserver实例
const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    // 检查本次变更中是否包含被移除的Timer元素
    const isTimerRemoved = Array.from(mutation.removedNodes).includes(timer);
    if (isTimerRemoved) {
      console.log('Timer元素已从DOM中移除');
      observer.disconnect(); // 完成跟踪后停止监听,节省资源
    }
  });
});

// 配置监听选项:监听body及其子树的子节点变化
observer.observe(document.body, { childList: true, subtree: true });

方法3:扩展Timer类,新增自定义移除事件(可选)

如果需要更灵活的控制权,可以在Timer类内部集成监听逻辑,新增元素移除时的自定义事件:

export default class Timer extends Component{
    protected time: number;
    protected countDownEvent: CustomEvent;
    protected removedEvent: CustomEvent;

    constructor(tagName: string, className: string, time: number) {
        super(tagName, className);
        this.time = time;
        this.countDownEvent = new CustomEvent("countDown");
        this.removedEvent = new CustomEvent("timerRemoved");

        // 监听元素是否被移除出DOM
        const elementObserver = new MutationObserver(() => {
            if (!document.contains(this.container)) {
                this.container.dispatchEvent(this.removedEvent);
                elementObserver.disconnect();
            }
        });
        elementObserver.observe(document.body, { childList: true, subtree: true });
    }

    startTimer(){
        let countdown = this.time * 1000;
        this.container.textContent = String(countdown / 1000);
        const countingDown = () => {
            console.log(countdown / 1000, " seconds");
            countdown -= 1000;
            this.container.textContent = String(countdown / 1000);
            if (countdown === 0){ 
                this.container.dispatchEvent(this.countDownEvent);
                clearInterval(timerInterval) 
            }
        }
        const timerInterval = setInterval(countingDown, 1000);
    }

    render() {
        this.container.innerHTML = String(this.time);
        this.startTimer();
        return this.container;
    }
}

// 使用方式
let timer = new Timer('div', 'timer', 5).render();
document.body.appendChild(timer);
timer.addEventListener('timerRemoved', () => {
  console.log('Timer元素已被移除');
});

内容的提问来源于stack exchange,提问作者Danyil Derkach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:15:40