Vue.js 倒计时组件:暂停、继续、页面切换自动控制
<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>
原文地址: https://www.cveoy.top/t/topic/mtcb 著作权归作者所有。请勿转载和采集!