<template>
  <div class='countdown'>
    <div class='input-container'>
      <label for='time-input'>倒计时时间(分钟):</label>
      <input type='number' id='time-input' v-model='time' min='1' max='1440' />
    </div>
    <div class='button-container'>
      <div class='start-button' :class='{ disabled: isCounting }' @click='startCountdown'>开始</div>
      <div class='pause-button' :class='{ disabled: !isCounting }' @click='pauseCountdown'>{{ pauseButtonText }}</div>
      <div class='reset-button' :class='{ disabled: isCounting }' @click='resetCountdown'>重置</div>
    </div>
    <div class='time-display'>{{ displayTime }}</div>
  </div>
</template>
<script>
export default {
  name: 'EffectiveLearning',
  data() {
    return {
      time: 0,
      isCounting: false,
      countdownInterval: null,
      pauseButtonText: '暂停',
      startTime: null,
      elapsedTime: 0,
      visibilityChangeHandler: null,
    };
  },
  computed: {
    displayTime() {
      const remainingTime = this.time * 60 - this.elapsedTime;
      const minutes = Math.floor(remainingTime / 60);
      const seconds = remainingTime % 60;
      return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    },
  },
  methods: {
    startCountdown() {
      if (this.time === 0 || this.isCounting) {
        return;
      }
      this.isCounting = true;
      this.startTime = Date.now() - this.elapsedTime * 1000;
      this.countdownInterval = setInterval(() => {
        this.elapsedTime = Math.floor((Date.now() - this.startTime) / 1000);
        if (this.elapsedTime >= this.time * 60) {
          this.pauseCountdown();
        }
      }, 1000);
      this.visibilityChangeHandler = () => {
        if (document.visibilityState === 'hidden') {
          this.pauseCountdown();
        } else if (document.visibilityState === 'visible' && this.isCounting) {
          this.startCountdown();
        }
      };
      document.addEventListener('visibilitychange', this.visibilityChangeHandler);
    },
    pauseCountdown() {
      if (!this.isCounting) {
        return;
      }
      clearInterval(this.countdownInterval);
      this.countdownInterval = null;
      this.isCounting = false;
      this.pauseButtonText = '继续';
    },
    resetCountdown() {
      if (this.isCounting) {
        return;
      }
      this.time = 0;
      this.elapsedTime = 0;
      this.pauseButtonText = '暂停';
    },
  },
  watch: {
    time() {
      if (!this.isCounting) {
        this.elapsedTime = 0;
      }
    },
  },
  beforeUnmount() {
    document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
  },
  created() {
    window.addEventListener('focus', this.startCountdown);
    window.addEventListener('blur', this.pauseCountdown);
  },
  beforeUnmount() {
    window.removeEventListener('focus', this.startCountdown);
    window.removeEventListener('blur', this.pauseCountdown);
    document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
  },
};
</script>
<style>
.countdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.input-container {
  margin-bottom: 20px;
}

.button-container {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

.start-button,
.pause-button,
.reset-button {
  display: inline-block;
  padding: 10px 20px;
  margin: 0 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.start-button.disabled,
.reset-button.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.pause-button.disabled {
  border-color: #ccc;
  color: #ccc;
  cursor: not-allowed;
}

.time-display {
  font-size: 48px;
}
</style>
Vue.js 倒计时组件:暂停、继续、页面切换自动控制

原文地址: https://www.cveoy.top/t/topic/mtcb 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录