勇者如龙 发表于 2024-11-26 01:21:43

使用Vue3实现倒计时器及倒计时任务的完整代码

本内容使用Vue3,以及element-plus辅助开发。首先展示倒计时器的功能:
<ul><li>手动设置倒计时器的倒计时时间</li><li>开始倒计时按钮</li><li>暂停倒计时按钮</li><li>重新开始倒计时按钮</li></ul>
 其次展示倒计时任务管理界面功能:创建倒计时任务选择任务并进行倒计时删除任务

一.倒计时器:

最后面会附有完整代码,可直接CV。 


1.html:

使用element-plus下拉框组件选择设置的时分秒的时间,点击确定按钮就可以将设置的时间在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)状态变量:
// 选择的倒计时初始值
const selectedHours = ref(0);
const selectedMinutes = ref(0);
const selectedSeconds = ref(0);
// 当前剩余的倒计时时间,以秒为单位动态更新
const totalSeconds = ref(0);
// 表示倒计时是否正在运行,用来防止重复启动计时器
const isRunning = ref(false);
// 存储定时器的句柄,用于管理 setInterval
let timer = null;(2)格式化显示时间:
// computed:这是一个计算属性,动态计算剩余时间的格式化显示。
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')}`;
});<strong>格式化逻辑</strong>:

[*]小时:Math.floor(totalSeconds.value / 3600),将总秒数除以3600得到小时数(向下取整)。
[*]分钟:取余后计算分钟数:Math.floor((totalSeconds.value % 3600) / 60)。
[*]秒数:取余后直接取 totalSeconds.value % 60。
[*]格式化:使用 padStart(2, '0') 保证个位数前补 0,显示为两位数。
(3)初始化倒计时:
// 将计算结果赋值给 totalSeconds,作为倒计时的起始值。
const initializeCountdown = () => {
    totalSeconds.value = selectedHours.value * 3600 + selectedMinutes.value * 60 + selectedSeconds.value;
};(4)开始按钮startCountdown -> 启动倒计时器:
const startCountdown = () => {
    if (totalSeconds.value === 0) {
      initializeCountdown(); // 如果总秒数为0,重新初始化
    }
    // 通过 isRunning 确保倒计时只能启动一次
    if (!isRunning.value) {
      isRunning.value = true;
      // 使用 setInterval 每秒执行一次回调
      timer = setInterval(() => {
            if (totalSeconds.value > 0) {
                totalSeconds.value -= 1; // 每秒减1
            } else {
                // 调用 pauseCountdown 停止计时器
                pauseCountdown();
            }
      }, 1000);
    }
};(5)暂停按钮pauseCountdown -> 暂停倒计时器:
const pauseCountdown = () => {
    // 将 isRunning 设置为 false,标记倒计时暂停
    isRunning.value = false;
    // 如果计时器已存在(timer 不为 null),调用 clearInterval 停止计时器,并将 timer 置空
    if (timer) {
      clearInterval(timer);
      timer = null;
    }
};(6)重启倒计时器restartCountdown -> 重新开始倒计时:
const restartCountdown = () => {
    // 停止当前计时器
    pauseCountdown();
    // 重置 totalSeconds 为初始值
    initializeCountdown();
    // 重新启动倒计时
    startCountdown();
};(7)确定按钮 -> 修改倒计时时间:
// 停止当前计时器,重新计算并设置倒计时总秒数
const getTrue = () => {
    pauseCountdown();
    initializeCountdown();
};(8)页面卸载时清理计时器(onUnMounted):
// 当组件卸载时触发
onUnmounted(() => {
    // 清理计时器,防止内存泄漏
    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>
二.倒计时任务管理界面:

通过弹窗填写任务名称和时间(时、分、秒),并将任务提交到任务列表中。 1.html:

<el-card>
    <!-- 倒计时时间选择框 -->
    <el-button type="primary" @click="addTaskDialog()">创建任务</el-button>
    <!-- 任务队列 -->
    <h3>任务队列</h3>
    <el-table :data="timeTaskData" style="width: 100%" height="250">
      <el-table-column prop="name" label="任务名称" 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>
<!-- 任务创建弹窗 -->
<el-dialog v-model="taskDialogVisible" title="创建新任务" width="500" draggable>
    <el-form>
      <el-form-item label="任务名称">
            <el-input v-model="newTask.name" placeholder="请输入任务名称" />
      </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()">创建任务</el-button>
      </div>
    </template>
</el-dialog>

2.script:

// 用于控制弹窗的显示和隐藏状态
const taskDialogVisible = ref(false);
// 打开弹窗
const addTaskDialog = () =>{
    taskDialogVisible.value = true;
    console.log('弹窗状态:', taskDialogVisible.value); // 调试日志
}
// 用于绑定用户输入的任务数据
const newTask = reactive({
    name: '', // 任务名称
    // 用户输入的时、分、秒,表示任务的时间
    hours: '',
    minutes: '',
    seconds: ''
})
// 任务列表
const timeTaskData = ref([]);
const timeTask = reactive({
    name: "",
    time: null, // 任务时间,格式为 HH:mm:ss
    roomGroup : ""
});
// 清空 timeTask 中的任务数据
const cleantimeRask = () =>{
    timeTask.value = {
      name: "",
      time: null,
      roomGroup : ""
    };
}
const addTimeTask = async () =>{
    taskDialogVisible.value = false;
    // 使用用户输入的时、分、秒来设置时间
    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")}`;
    // 设置任务数据
    timeTask.time = timeString; // 使用标准的 HH:mm:ss 格式
    // 从 userStore 获取当前用户的分组
    timeTask.roomGroup = userStore.user.roomGroup;
    timeTask.name = newTask.name;
    if (timeTask.name !== '' && timeTask.time !== '') {
      await insertTimeTask(timeTask); // 插入任务(异步操作)
      ElMessage.success("任务添加成功");
      getTimeTaskByRGToShow(); // 更新任务列表
      console.log(timeTaskData.value);
      cleantimeRask(); // 清空当前任务数据
    } else {
      ElMessage.error("任务名称或时间不能为空");
    }
}
// 设置倒计时的时、分、秒
const setCountdownTime = (row) => {
    let date;
    if (row.time instanceof Date) {
      date = row.time; // 如果是 Date 对象,直接赋值
    } else if (typeof row.time === "string") {
      const = row.time.split(":").map(Number); // 按 HH:mm:ss 分割
      date = new Date(); // 使用当前日期
      date.setHours(hours, minutes, seconds); // 设置时间
    } else {
      console.error("无效的时间格式");
      return;
    }
    selectedHours.value = date.getHours();      // 获取小时
    selectedMinutes.value = date.getMinutes();// 获取分钟
    selectedSeconds.value = date.getSeconds();// 获取秒数
    initializeCountdown(); // 更新总时间
};
// 删除倒计时的任务
const deleteTimeTask = async (row) =>{
    await deleteTimeTaskById(row.id);
    ElMessage.success("任务删除成功");
    getTimeTaskByRGToShow();
    console.log(timeTaskData.value);
};
// 根据组别获取所有任务信息
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()">创建任务</el-button>
            <!-- 任务队列 -->
            <h3>任务队列</h3>
            <el-table :data="timeTaskData" style="width: 100%" height="250">
                <el-table-column prop="name" label="任务名称" 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>
<!-- 任务创建弹窗 -->
<el-dialog v-model="taskDialogVisible" title="创建新任务" width="500" draggable>
    <el-form>
      <el-form-item label="任务名称">
            <el-input v-model="newTask.name" placeholder="请输入任务名称" />
      </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()">创建任务</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('弹窗状态:', taskDialogVisible.value); // 调试日志
}
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;
    // 用用户输入的时、分、秒来设置时间
    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")}`;
    // 设置任务数据
    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("任务添加成功");
      getTimeTaskByRGToShow();
      console.log(timeTaskData.value);
      cleantimeRask();
    } else {
      ElMessage.error("任务名称或时间不能为空");
    }
}
// 设置倒计时的时、分、秒
const setCountdownTime = (row) => {
    let date;
    if (row.time instanceof Date) {
      date = row.time; // 如果是 Date 对象,直接赋值
    } else if (typeof row.time === "string") {
      const = row.time.split(":").map(Number); // 按 HH:mm:ss 分割
      date = new Date(); // 使用当前日期
      date.setHours(hours, minutes, seconds); // 设置时间
    } else {
      console.error("无效的时间格式");
      return;
    }
    selectedHours.value = date.getHours();      // 获取小时
    selectedMinutes.value = date.getMinutes();// 获取分钟
    selectedSeconds.value = date.getSeconds();// 获取秒数
    initializeCountdown(); // 更新总时间
};
// 删除倒计时的任务
const deleteTimeTask = async (row) =>{
    await deleteTimeTaskById(row.id);
    ElMessage.success("任务删除成功");
    getTimeTaskByRGToShow();
    console.log(timeTaskData.value);
};
// 根据组别获取所有任务信息
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 = () => {
    // 如果当前总秒数为 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'); // 倒计时结束时播放音效
            }
      }, 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>到此这篇关于使用Vue3来实现一个倒计时器以及倒计时任务的文章就介绍到这了,更多相关vue3倒计时内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/javascript/331244l91.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 使用Vue3实现倒计时器及倒计时任务的完整代码