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动态倒计时的资料请关注脚本之家其它相关文章!

相关文章

  • vue中使用vue-print.js实现多页打印

    vue中使用vue-print.js实现多页打印

    这篇文章主要介绍了vue中使用vue-print.js实现多页打印,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 关于vue的element-ui web端引入高德地图并获取经纬度

    关于vue的element-ui web端引入高德地图并获取经纬度

    这篇文章主要介绍了关于vue的element-ui web端引入高德地图并获取经纬度,高德地图首先要去申请key和密钥,文中提供了部分实现代码和解决思路,感兴趣的朋友可以学习一下
    2023-04-04
  • vue项目中使用window的onresize事件方式

    vue项目中使用window的onresize事件方式

    这篇文章主要介绍了vue项目中使用window的onresize事件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • vue ElementUI实现异步加载树

    vue ElementUI实现异步加载树

    这篇文章主要为大家详细介绍了vue ElementUI实现异步加载树,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • vue 实现websocket发送消息并实时接收消息

    vue 实现websocket发送消息并实时接收消息

    这篇文章主要介绍了vue 实现websocket发送消息并实时接收消息,项目结合vue脚手架和websocket来搭建,本文给大家分享实例代码,需要的朋友可以参考下
    2019-12-12
  • Vue实现Dialog封装

    Vue实现Dialog封装

    在写业务的时候很常见的一个场景就是需要在不同的页面调用同一个表单,常用的交互就是把表单以弹窗的形式展示,本文主要介绍了Vue实现Dialog封装,感兴趣的可以了解一下
    2021-07-07
  • 原生echart和vue-echart的使用详解

    原生echart和vue-echart的使用详解

    这篇文章主要为大家详细介绍了原生echart和vue-echart的使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • vue使用Element的Tree树形控件实现拖动改变节点顺序方式

    vue使用Element的Tree树形控件实现拖动改变节点顺序方式

    这篇文章主要介绍了vue使用Element的Tree树形控件实现拖动改变节点顺序方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Vue+Video.js实现视频抽帧并返回抽帧图片Base64

    Vue+Video.js实现视频抽帧并返回抽帧图片Base64

    这篇文章主要为大家详细介绍了Vue如何利用Video.js实现视频抽帧并返回抽帧图片Base64,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2024-01-01
  • 56个实用的JavaScript 工具函数助你提升开发效率

    56个实用的JavaScript 工具函数助你提升开发效率

    今天来看看JavaScript中的一些实用的工具函数,希望能帮助你提高开发效率!需要的朋友可以参考下面文章的具体内容
    2021-10-10

最新评论