Vue3动态倒计时的代码实现
作者:码农研究僧
在使用Vue框架开发Web应用时,倒计时功能是一个常见的需求,它可以在一定时间内重复执行某些操作,比如防止用户重复提交表单、限制投票次数、实现验证码获取等功能,所以本文给大家介绍了Vue3动态倒计时的代码实现,需要的朋友可以参考下
1. Demo
给一版初始的Demo,在给一版实战中的Demo
基本知识点:
- Vue 3 的响应式原理:Vue 3 使用 reactive 和 ref 创建响应式数据,数据的变化会自动触发视图更新
- setup 函数:Vue 3 引入了 Composition API,其中的 setup 函数是组件逻辑的入口
- watch 侦听器:用于侦听响应式数据的变化,在倒计时场景中可以用于监听时间的变化
- 生命周期钩子:如 onMounted 和 onUnmounted 用于在组件挂载和销毁时启动和清理倒计时
- setInterval 和 clearInterval:用于每隔一段时间执行倒计时任务
Demo:
<template>
<div>
<table>
<thead>
<tr>
<th>任务名称</th>
<th>剩余时间</th>
</tr>
</thead>
<tbody>
<tr v-for="task in tasks" :key="task.id">
<td>{{ task.name }}</td>
<td>{{ task.remainingTime }} 秒</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup>
import { reactive, onMounted, onUnmounted } from 'vue';
const tasks = reactive([
{ id: 1, name: '任务A', remainingTime: 60 },
{ id: 2, name: '任务B', remainingTime: 120 },
{ id: 3, name: '任务C', remainingTime: 180 },
]);
let intervalId;
onMounted(() => {
intervalId = setInterval(() => {
tasks.forEach(task => {
if (task.remainingTime > 0) {
task.remainingTime -= 1;
}
});
}, 1000);
});
onUnmounted(() => {
clearInterval(intervalId);
});
</script>
2. 实战Demo
本身倒计时的某一列时间是固定的,那就不需要通过后端来获取动态数据,只需要基于appointmentEndTime和当前时间来计算倒计时。对于超过当前时间的数据,可以直接显示“已结束”或其他提示
以下是基于Vue 3的倒计时实现方式,重点是如何根据appointmentEndTime与当前时间来动态更新表格的倒计时列
- appointmentEndTime 固定:你可以直接在表格数据中使用固定的时间戳。
- 倒计时逻辑:通过setInterval每秒更新一次倒计时,但如果appointmentEndTime已经过期,就不再更新。
- 无须请求后端:无需额外API请求,直接使用appointmentEndTime进行计算
<template>
<div>
<el-table :data="tableData" style="width: 100%">
<!-- 审核时间列 -->
<el-table-column
label="审核时间"
align="center"
prop="appointmentReviewTime"
:formatter="dateFormatter"
width="170px"
/>
<!-- 还柜时间列 -->
<el-table-column
label="还柜时间"
align="center"
prop="appointmentEndTime"
:formatter="dateFormatter"
width="170px"
/>
<!-- 倒计时列 -->
<el-table-column label="倒计时" align="center" width="170px">
<template #default="scope">
<span>{{ formatCountdown(scope.row.appointmentEndTime) }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
export default {
setup() {
// 表格数据,appointmentEndTime 是固定的时间
const tableData = ref([
{
appointmentReviewTime: '2024-09-20 12:00:00',
appointmentEndTime: '2024-09-20 14:00:00' // 固定时间
},
{
appointmentReviewTime: '2024-09-21 15:00:00',
appointmentEndTime: '2024-09-21 17:00:00' // 固定时间
}
]);
// 倒计时格式化函数
const formatCountdown = (endTime) => {
const now = new Date().getTime();
const endTimestamp = new Date(endTime).getTime();
const remainingTime = endTimestamp - now;
// 如果已过期,返回 "已结束"
if (remainingTime <= 0) {
return '已结束';
}
const hours = Math.floor(remainingTime / (1000 * 60 * 60));
const minutes = Math.floor((remainingTime % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
return `${hours}小时 ${minutes}分钟 ${seconds}秒`;
};
// 使用 setInterval 动态更新倒计时
const intervalId = ref(null);
onMounted(() => {
intervalId.value = setInterval(() => {
// 强制触发视图更新
tableData.value = [...tableData.value];
}, 1000);
});
// 清除计时器
onBeforeUnmount(() => {
clearInterval(intervalId.value);
});
return {
tableData,
formatCountdown
};
}
};
</script>

如果不会出现自动更新视图的,需要排查下浏览器的终端是否会有输出异常
实战中的Bug:(错误信息 queryParams.value is not iterable 表示在某处尝试遍历或解构了queryParams,但是它不是可迭代的对象,确保queryParams是一个对象或数组,不能将非迭代对象进行迭代操作)

3. 拓展Demo
appointmentEndTime这个是timestamp时间,也就是设定的未来时间
但是我要已过期,或者超过当前时间的 都显示 重新预约
那么只需要在超过当前时间或已过期的情况下显示“重新预约”
- 修改 formatCountdown 函数:
在 formatCountdown 函数中添加一个返回值,用于标记该时间是否已经过期
const formatCountdown = (endTime) => {
const now = new Date().getTime();
const endTimestamp = new Date(endTime).getTime();
const remainingTime = endTimestamp - now;
// 如果已过期,返回 "已过期" 并标记为需要重新预约
if (remainingTime <= 0) {
return { text: '已过期', isExpired: true };
}
const hours = Math.floor(remainingTime / (1000 * 60 * 60));
const minutes = Math.floor((remainingTime % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
// 分时秒的格式化
return { text: `${hours}小时 ${minutes}分钟 ${seconds}秒`, isExpired: false };
};
- 修改模板逻辑:
使用 formatCountdown 函数的返回值来判断是否显示 “重新预约”
<el-table-column label="还柜剩余时间" align="center" width="155px">
<template #default="scope">
<span>{{ formatCountdown(scope.row.appointmentEndTime).text }}</span>
</template>
</el-table-column>
<el-button
link
type="primary"
@click="showRejectionReason(scope.row.id)"
v-if="scope.row.appointmentEndTime !== null && formatCountdown(scope.row.appointmentEndTime).isExpired"
v-hasPermi="['dangerous:appointment-commission:query']"
>
重新预约
</el-button>

为了在等于当前时间点的时候触发后端请求
可以修改倒计时的函数如下:
// 倒计时格式化函数
const formatCountdown = (endTime,id) => {
const now = new Date().getTime();
const endTimestamp = new Date(endTime).getTime();
const remainingTime = endTimestamp - now;
// 设置一个容忍时间范围(例如,1秒)
const tolerance = 1000; // 1秒
// 当时间接近到达时,发送请求到后端更新状态
if (remainingTime <= tolerance && remainingTime > 0) {
console.log(1); // 确保能够输出
}
// 如果已过期,返回 "已过期" 并标记为需要重新预约
if (remainingTime < 0) {
return { text: '已过期', isExpired: true };
}
const hours = Math.floor(remainingTime / (1000 * 60 * 60));
const minutes = Math.floor((remainingTime % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
// 分时秒的格式化
return { text: `${hours}小时 ${minutes}分钟 ${seconds}秒`, isExpired: false };
};
以上的函数需要注意的点如下:
由于时间的精确性和计算方式,remainingTime 很少会正好等于 0。即使时间点非常接近,由于毫秒级的差异,可能导致 remainingTime 不完全等于 0
以上就是Vue3动态倒计时的代码实现的详细内容,更多关于Vue3动态倒计时的资料请关注脚本之家其它相关文章!
