Vue3动态倒计时的代码实现

 更新时间:2024年09月24日 09:44:54   作者:码农研究僧  
在使用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动态倒计时的资料请关注脚本之家其它相关文章!

相关文章

  • vue3+ts+vite+electron搭建桌面应用的过程

    vue3+ts+vite+electron搭建桌面应用的过程

    这篇文章主要介绍了vue3+ts+vite+electron搭建桌面应用的过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • 详解vue移动端日期选择组件

    详解vue移动端日期选择组件

    小编给大家整理了关于vue移动端日期选择组件的知识点总结,希望能够给读者带来帮助,一起学习参考下。
    2018-02-02
  • 使用webpack手动搭建vue项目的步骤

    使用webpack手动搭建vue项目的步骤

    这篇文章主要介绍了从零使用webpack手动搭建vue项目的步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • vue-cli3.0 特性解读

    vue-cli3.0 特性解读

    这篇文章主要介绍了vue-cli3.0 特性解读,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • 详解Vue如何自定义hooks(组合式)函数

    详解Vue如何自定义hooks(组合式)函数

    这篇文章主要为大家详细介绍了在Vue中如何实现自定义hooks(组合式)函数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • 详解vue路由

    详解vue路由

    这篇文章主要介绍了vue路由的相关资料,文中讲解非常细致,帮助大家更好的理解和学习vue路由知识,感兴趣的朋友可以了解下
    2020-08-08
  • Vue项目通过network的ip地址访问注意事项及说明

    Vue项目通过network的ip地址访问注意事项及说明

    这篇文章主要介绍了Vue项目通过network的ip地址访问注意事项及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue实现滑动到底部加载更多效果

    vue实现滑动到底部加载更多效果

    这篇文章主要为大家详细介绍了vue实现滑动到底部加载更多效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • 解决element-ui的el-select选择器的@blur事件失效的坑

    解决element-ui的el-select选择器的@blur事件失效的坑

    这篇文章主要介绍了解决element-ui的el-select选择器的@blur事件失效的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue2和el-input无法修改和写入并且不报错的解决方案

    vue2和el-input无法修改和写入并且不报错的解决方案

    这篇文章主要介绍了vue2和el-input无法修改和写入并且不报错的解决方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-07-07

最新评论