使用Vue3實現(xiàn)倒計時器及倒計時任務(wù)的完整代碼
本內(nèi)容使用Vue3,以及element-plus輔助開發(fā)。
首先展示倒計時器的功能:
- 手動設(shè)置倒計時器的倒計時時間
- 開始倒計時按鈕
- 暫停倒計時按鈕
- 重新開始倒計時按鈕

其次展示倒計時任務(wù)管理界面功能:
創(chuàng)建倒計時任務(wù)選擇任務(wù)并進行倒計時刪除任務(wù)

一.倒計時器:
最后面會附有完整代碼,可直接CV。
1.html:
使用element-plus下拉框組件選擇設(shè)置的時分秒的時間,點擊確定按鈕就可以將設(shè)置的時間在formattedTime顯示,隨后使用操作按鈕進行對計時器的操作。
<el-card>
<h2>倒計時器</h2>
<!-- 倒計時時間選擇框 -->
<div>
<el-form inline>
<!-- 小時選擇器 -->
<el-form-item label="小時:">
<el-select v-model="selectedHours" :disabled="isRunning" placeholder="選擇小時" style="width: 100px;">
<el-option v-for="h in 24" :key="'h' + h" :label="h - 1" :value="h - 1"/>
</el-select>
</el-form-item>
<!-- 分鐘選擇器 -->
<el-form-item label="分鐘:">
<el-select v-model="selectedMinutes" :disabled="isRunning" placeholder="選擇分鐘" style="width: 100px;">
<el-option v-for="m in 60" :key="'m' + m" :label="m - 1" :value="m - 1"/>
</el-select>
</el-form-item>
<!-- 秒選擇器 -->
<el-form-item label="秒:">
<el-select v-model="selectedSeconds" :disabled="isRunning" placeholder="選擇秒" style="width: 100px;">
<el-option v-for="s in 60" :key="'s' + s" :label="s - 1" :value="s - 1"/>
</el-select>
</el-form-item>
</el-form>
<el-button type="info" @click="getTrue()">確定</el-button>
</div>
<!-- 倒計時顯示 -->
<div class="timer-display">
<h1>{{ formattedTime }}</h1>
</div>
<!-- 操作按鈕 -->
<div class="controls">
<!-- 倒計時器 -->
<el-button type="success" @click="startCountdown()" :disabled="isRunning">開始</el-button>
<el-button type="warning" @click="pauseCountdown()" :disabled="!isRunning">暫停</el-button>
<el-button type="primary" @click="restartCountdown()">重新開始</el-button>
<el-button type="info" @click="nextProcess()">下一階段</el-button>
</div>
</el-card>2.script:
(1)狀態(tài)變量:
// 選擇的倒計時初始值 const selectedHours = ref(0); const selectedMinutes = ref(0); const selectedSeconds = ref(0); // 當前剩余的倒計時時間,以秒為單位動態(tài)更新 const totalSeconds = ref(0); // 表示倒計時是否正在運行,用來防止重復(fù)啟動計時器 const isRunning = ref(false); // 存儲定時器的句柄,用于管理 setInterval let timer = null;
(2)格式化顯示時間:
// computed:這是一個計算屬性,動態(tài)計算剩余時間的格式化顯示。
const formattedTime = computed(() => {
const hours = Math.floor(totalSeconds.value / 3600);
const minutes = Math.floor((totalSeconds.value % 3600) / 60);
const seconds = totalSeconds.value % 60;
// 返回格式用于倒計時器的顯示 hh:mm:ss
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
});格式化邏輯:
- 小時:
Math.floor(totalSeconds.value / 3600),將總秒數(shù)除以3600得到小時數(shù)(向下取整)。 - 分鐘:取余后計算分鐘數(shù):
Math.floor((totalSeconds.value % 3600) / 60)。 - 秒數(shù):取余后直接取
totalSeconds.value % 60。 - 格式化:使用
padStart(2, '0')保證個位數(shù)前補0,顯示為兩位數(shù)。
(3)初始化倒計時:
// 將計算結(jié)果賦值給 totalSeconds,作為倒計時的起始值。
const initializeCountdown = () => {
totalSeconds.value = selectedHours.value * 3600 + selectedMinutes.value * 60 + selectedSeconds.value;
};(4)開始按鈕startCountdown -> 啟動倒計時器:
const startCountdown = () => {
if (totalSeconds.value === 0) {
initializeCountdown(); // 如果總秒數(shù)為0,重新初始化
}
// 通過 isRunning 確保倒計時只能啟動一次
if (!isRunning.value) {
isRunning.value = true;
// 使用 setInterval 每秒執(zhí)行一次回調(diào)
timer = setInterval(() => {
if (totalSeconds.value > 0) {
totalSeconds.value -= 1; // 每秒減1
} else {
// 調(diào)用 pauseCountdown 停止計時器
pauseCountdown();
}
}, 1000);
}
};(5)暫停按鈕pauseCountdown -> 暫停倒計時器:
const pauseCountdown = () => {
// 將 isRunning 設(shè)置為 false,標記倒計時暫停
isRunning.value = false;
// 如果計時器已存在(timer 不為 null),調(diào)用 clearInterval 停止計時器,并將 timer 置空
if (timer) {
clearInterval(timer);
timer = null;
}
};(6)重啟倒計時器restartCountdown -> 重新開始倒計時:
const restartCountdown = () => {
// 停止當前計時器
pauseCountdown();
// 重置 totalSeconds 為初始值
initializeCountdown();
// 重新啟動倒計時
startCountdown();
};(7)確定按鈕 -> 修改倒計時時間:
// 停止當前計時器,重新計算并設(shè)置倒計時總秒數(shù)
const getTrue = () => {
pauseCountdown();
initializeCountdown();
};(8)頁面卸載時清理計時器(onUnMounted):
// 當組件卸載時觸發(fā)
onUnmounted(() => {
// 清理計時器,防止內(nèi)存泄漏
if (timer) {
clearInterval(timer);
}
});3.css:
<style lang="css" scoped>
.countdown-timer {
text-align: center;
font-family: Arial, sans-serif;
}
.timer-display h1 {
font-size: 48px;
margin: 20px 0;
}
.controls button {
margin: 5px;
padding: 10px 20px;
font-size: 16px;
}
select {
margin: 5px;
padding: 5px;
}
</style>二.倒計時任務(wù)管理界面:
通過彈窗填寫任務(wù)名稱和時間(時、分、秒),并將任務(wù)提交到任務(wù)列表中。
1.html:
<el-card>
<!-- 倒計時時間選擇框 -->
<el-button type="primary" @click="addTaskDialog()">創(chuàng)建任務(wù)</el-button>
<!-- 任務(wù)隊列 -->
<h3>任務(wù)隊列</h3>
<el-table :data="timeTaskData" style="width: 100%" height="250">
<el-table-column prop="name" label="任務(wù)名稱" width="120" />
<el-table-column prop="time" label="倒計時間" width="120" />
<el-table-column label="操作" width="100">
<template #default="{ row }">
<el-button type="success" @click="setCountdownTime(row)" :icon="Check" circle />
<el-button type="danger" @click="deleteTimeTask(row)" :icon="Delete" circle />
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 任務(wù)創(chuàng)建彈窗 -->
<el-dialog v-model="taskDialogVisible" title="創(chuàng)建新任務(wù)" width="500" draggable>
<el-form>
<el-form-item label="任務(wù)名稱">
<el-input v-model="newTask.name" placeholder="請輸入任務(wù)名稱" />
</el-form-item>
<el-form-item label="小時">
<el-select v-model="newTask.hours" placeholder="選擇小時">
<el-option :key="'h0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="h in 24" :key="'h' + h" :label="h" :value="h" />
</el-select>
</el-form-item>
<el-form-item label="分鐘">
<el-select v-model="newTask.minutes" placeholder="選擇分鐘">
<el-option :key="'m0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="m in 60" :key="'m' + m" :label="m" :value="m" />
</el-select>
</el-form-item>
<el-form-item label="秒">
<el-select v-model="newTask.seconds" placeholder="選擇秒">
<el-option :key="'s0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="s in 60" :key="'s' + s" :label="s" :value="s" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="taskDialogVisible = false">取消</el-button>
<el-button type="primary" @click="addTimeTask()">創(chuàng)建任務(wù)</el-button>
</div>
</template>
</el-dialog>2.script:
// 用于控制彈窗的顯示和隱藏狀態(tài)
const taskDialogVisible = ref(false);
// 打開彈窗
const addTaskDialog = () =>{
taskDialogVisible.value = true;
console.log('彈窗狀態(tài):', taskDialogVisible.value); // 調(diào)試日志
}
// 用于綁定用戶輸入的任務(wù)數(shù)據(jù)
const newTask = reactive({
name: '', // 任務(wù)名稱
// 用戶輸入的時、分、秒,表示任務(wù)的時間
hours: '',
minutes: '',
seconds: ''
})
// 任務(wù)列表
const timeTaskData = ref([]);
const timeTask = reactive({
name: "",
time: null, // 任務(wù)時間,格式為 HH:mm:ss
roomGroup : ""
});
// 清空 timeTask 中的任務(wù)數(shù)據(jù)
const cleantimeRask = () =>{
timeTask.value = {
name: "",
time: null,
roomGroup : ""
};
}
const addTimeTask = async () =>{
taskDialogVisible.value = false;
// 使用用戶輸入的時、分、秒來設(shè)置時間
const hours = parseInt(newTask.hours) || 0;
const minutes = parseInt(newTask.minutes) || 0;
const seconds = parseInt(newTask.seconds) || 0;
// 將時間合并為 HH:mm:ss 格式
const timeString = `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
// 設(shè)置任務(wù)數(shù)據(jù)
timeTask.time = timeString; // 使用標準的 HH:mm:ss 格式
// 從 userStore 獲取當前用戶的分組
timeTask.roomGroup = userStore.user.roomGroup;
timeTask.name = newTask.name;
if (timeTask.name !== '' && timeTask.time !== '') {
await insertTimeTask(timeTask); // 插入任務(wù)(異步操作)
ElMessage.success("任務(wù)添加成功");
getTimeTaskByRGToShow(); // 更新任務(wù)列表
console.log(timeTaskData.value);
cleantimeRask(); // 清空當前任務(wù)數(shù)據(jù)
} else {
ElMessage.error("任務(wù)名稱或時間不能為空");
}
}
// 設(shè)置倒計時的時、分、秒
const setCountdownTime = (row) => {
let date;
if (row.time instanceof Date) {
date = row.time; // 如果是 Date 對象,直接賦值
} else if (typeof row.time === "string") {
const [hours, minutes, seconds] = row.time.split(":").map(Number); // 按 HH:mm:ss 分割
date = new Date(); // 使用當前日期
date.setHours(hours, minutes, seconds); // 設(shè)置時間
} else {
console.error("無效的時間格式");
return;
}
selectedHours.value = date.getHours(); // 獲取小時
selectedMinutes.value = date.getMinutes(); // 獲取分鐘
selectedSeconds.value = date.getSeconds(); // 獲取秒數(shù)
initializeCountdown(); // 更新總時間
};
// 刪除倒計時的任務(wù)
const deleteTimeTask = async (row) =>{
await deleteTimeTaskById(row.id);
ElMessage.success("任務(wù)刪除成功");
getTimeTaskByRGToShow();
console.log(timeTaskData.value);
};
// 根據(jù)組別獲取所有任務(wù)信息
const getTimeTaskByRGToShow = async () =>{
let roomGroup = userStore.user.roomGroup;
let result = await getTimeTaskByRG(roomGroup);
timeTaskData.value = result.data;
}
getTimeTaskByRGToShow();三.倒計時器完整代碼展示:
1.html:
<el-main style="background-color:darkgray">
<div>
<el-card>
<!-- 倒計時時間選擇框 -->
<el-button type="primary" @click="addTaskDialog()">創(chuàng)建任務(wù)</el-button>
<!-- 任務(wù)隊列 -->
<h3>任務(wù)隊列</h3>
<el-table :data="timeTaskData" style="width: 100%" height="250">
<el-table-column prop="name" label="任務(wù)名稱" width="120" />
<el-table-column prop="time" label="倒計時間" width="120" />
<el-table-column label="操作" width="100">
<template #default="{ row }">
<el-button type="success" @click="setCountdownTime(row)" :icon="Check" circle />
<el-button type="danger" @click="deleteTimeTask(row)" :icon="Delete" circle />
<!-- <el-button type="success" >開始倒計時</el-button> -->
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<div class="countdown-timer">
<el-card>
<h2>倒計時器</h2>
<!-- 倒計時時間選擇框 -->
<div>
<el-form inline>
<!-- 小時選擇器 -->
<el-form-item label="小時:">
<el-select v-model="selectedHours" :disabled="isRunning" placeholder="選擇小時" style="width: 100px;">
<el-option v-for="h in 24" :key="'h' + h" :label="h - 1" :value="h - 1"/>
</el-select>
</el-form-item>
<!-- 分鐘選擇器 -->
<el-form-item label="分鐘:">
<el-select v-model="selectedMinutes" :disabled="isRunning" placeholder="選擇分鐘" style="width: 100px;">
<el-option v-for="m in 60" :key="'m' + m" :label="m - 1" :value="m - 1"/>
</el-select>
</el-form-item>
<!-- 秒選擇器 -->
<el-form-item label="秒:">
<el-select v-model="selectedSeconds" :disabled="isRunning" placeholder="選擇秒" style="width: 100px;">
<el-option v-for="s in 60" :key="'s' + s" :label="s - 1" :value="s - 1"/>
</el-select>
</el-form-item>
</el-form>
<el-button type="info" @click="getTrue()">確定</el-button>
</div>
<!-- 倒計時顯示 -->
<div class="timer-display">
<h1>{{ formattedTime }}</h1>
</div>
<!-- 操作按鈕 -->
<div class="controls">
<!-- 倒計時器 -->
<el-button type="success" @click="startCountdown()" :disabled="isRunning">開始</el-button>
<el-button type="warning" @click="pauseCountdown()" :disabled="!isRunning">暫停</el-button>
<el-button type="primary" @click="restartCountdown()">重新開始</el-button>
<el-button type="info" @click="nextProcess()">下一階段</el-button>
</div>
</el-card>
</div>
</el-main>
<!-- 任務(wù)創(chuàng)建彈窗 -->
<el-dialog v-model="taskDialogVisible" title="創(chuàng)建新任務(wù)" width="500" draggable>
<el-form>
<el-form-item label="任務(wù)名稱">
<el-input v-model="newTask.name" placeholder="請輸入任務(wù)名稱" />
</el-form-item>
<el-form-item label="小時">
<el-select v-model="newTask.hours" placeholder="選擇小時">
<el-option :key="'h0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="h in 24" :key="'h' + h" :label="h" :value="h" />
</el-select>
</el-form-item>
<el-form-item label="分鐘">
<el-select v-model="newTask.minutes" placeholder="選擇分鐘">
<el-option :key="'m0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="m in 60" :key="'m' + m" :label="m" :value="m" />
</el-select>
</el-form-item>
<el-form-item label="秒">
<el-select v-model="newTask.seconds" placeholder="選擇秒">
<el-option :key="'s0'" :label="0" :value="0" /> <!-- 手動添加 0 -->
<el-option v-for="s in 60" :key="'s' + s" :label="s" :value="s" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="taskDialogVisible = false">取消</el-button>
<el-button type="primary" @click="addTimeTask()">創(chuàng)建任務(wù)</el-button>
</div>
</template>
</el-dialog>2.script:
<script setup>
import { reactive, ref, computed, onUnmounted } from 'vue';
import { Check,Delete,Star } from '@element-plus/icons-vue';
import { getCpByRG, insertByRG } from '@/api/competition';
import { getTimeTaskByRG,insertTimeTask,deleteTimeTaskById } from '@/api/timetask';
import { useUserStore } from '@/stores/user';
import { ElMessage } from 'element-plus';
const userStore = useUserStore();
// 彈窗組件
const taskDialogVisible = ref(false);
const addTaskDialog = () =>{
taskDialogVisible.value = true;
console.log('彈窗狀態(tài):', taskDialogVisible.value); // 調(diào)試日志
}
const newTask = reactive({
name: '',
hours: '',
minutes: '',
seconds: ''
})
const timeTaskData = ref([]);
const timeTask = reactive({
name: "",
time: null,
roomGroup : ""
});
const cleantimeRask = () =>{
timeTask.value = {
name: "",
time: null,
roomGroup : ""
};
}
const addTimeTask = async () =>{
taskDialogVisible.value = false;
// 用用戶輸入的時、分、秒來設(shè)置時間
const hours = parseInt(newTask.hours) || 0;
const minutes = parseInt(newTask.minutes) || 0;
const seconds = parseInt(newTask.seconds) || 0;
// 將時間合并為 HH:mm:ss 格式
const timeString = `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
// 設(shè)置任務(wù)數(shù)據(jù)
timeTask.time = timeString; // 使用標準的 HH:mm:ss 格式
timeTask.roomGroup = userStore.user.roomGroup;
timeTask.name = newTask.name;
if (timeTask.name !== '' && timeTask.time !== '') {
await insertTimeTask(timeTask);
ElMessage.success("任務(wù)添加成功");
getTimeTaskByRGToShow();
console.log(timeTaskData.value);
cleantimeRask();
} else {
ElMessage.error("任務(wù)名稱或時間不能為空");
}
}
// 設(shè)置倒計時的時、分、秒
const setCountdownTime = (row) => {
let date;
if (row.time instanceof Date) {
date = row.time; // 如果是 Date 對象,直接賦值
} else if (typeof row.time === "string") {
const [hours, minutes, seconds] = row.time.split(":").map(Number); // 按 HH:mm:ss 分割
date = new Date(); // 使用當前日期
date.setHours(hours, minutes, seconds); // 設(shè)置時間
} else {
console.error("無效的時間格式");
return;
}
selectedHours.value = date.getHours(); // 獲取小時
selectedMinutes.value = date.getMinutes(); // 獲取分鐘
selectedSeconds.value = date.getSeconds(); // 獲取秒數(shù)
initializeCountdown(); // 更新總時間
};
// 刪除倒計時的任務(wù)
const deleteTimeTask = async (row) =>{
await deleteTimeTaskById(row.id);
ElMessage.success("任務(wù)刪除成功");
getTimeTaskByRGToShow();
console.log(timeTaskData.value);
};
// 根據(jù)組別獲取所有任務(wù)信息
const getTimeTaskByRGToShow = async () =>{
let roomGroup = userStore.user.roomGroup;
let result = await getTimeTaskByRG(roomGroup);
timeTaskData.value = result.data;
}
getTimeTaskByRGToShow();
/
// 倒計時器
// 選擇的倒計時初始值
const selectedHours = ref(0);
const selectedMinutes = ref(0);
const selectedSeconds = ref(0);
// 當前倒計時時間(以秒為單位)
const totalSeconds = ref(0);
const isRunning = ref(false);
let timer = null;
// 格式化顯示的時間
const formattedTime = computed(() => {
const hours = Math.floor(totalSeconds.value / 3600);
const minutes = Math.floor((totalSeconds.value % 3600) / 60);
const seconds = totalSeconds.value % 60;
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
});
// 初始化倒計時
const initializeCountdown = () => {
totalSeconds.value = selectedHours.value * 3600 + selectedMinutes.value * 60 + selectedSeconds.value;
};
// 開始倒計時
const startCountdown = () => {
// 如果當前總秒數(shù)為 0,自動初始化倒計時
if (totalSeconds.value === 0) {
initializeCountdown();
}
if (!isRunning.value) {
isRunning.value = true;
playSound('start'); // 播放開始音效
timer = setInterval(() => {
if (totalSeconds.value > 0) {
totalSeconds.value -= 1;
} else {
pauseCountdown();
playSound('end'); // 倒計時結(jié)束時播放音效
}
}, 1000);
}
};
// 暫停倒計時
const pauseCountdown = () => {
isRunning.value = false;
playSound('pause'); // 播放暫停音效
if (timer) {
clearInterval(timer);
timer = null;
}
};
// 重新開始倒計時
const restartCountdown = () => {
pauseCountdown();
initializeCountdown();
playSound('reset'); // 播放重置音效
startCountdown();
};
// 確定修改倒計時時間
const getTrue = () => {
pauseCountdown();
initializeCountdown();
};
// 頁面卸載時清理計時器
onUnmounted(() => {
if (timer) {
clearInterval(timer);
}
});
</script>3.css:
<style lang="css" scoped>
.countdown-timer {
text-align: center;
font-family: Arial, sans-serif;
}
.timer-display h1 {
font-size: 48px;
margin: 20px 0;
}
.controls button {
margin: 5px;
padding: 10px 20px;
font-size: 16px;
}
select {
margin: 5px;
padding: 5px;
}
</style>到此這篇關(guān)于使用Vue3來實現(xiàn)一個倒計時器以及倒計時任務(wù)的文章就介紹到這了,更多相關(guān)vue3倒計時內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vite打包優(yōu)化之縮小打包體積實現(xiàn)詳解
這篇文章主要為大家介紹了使用Vite縮小打包體積如何實現(xiàn)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01

