vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3动态倒计时

Vue3动态倒计时的代码实现

作者:码农研究僧

在使用Vue框架开发Web应用时,倒计时功能是一个常见的需求,它可以在一定时间内重复执行某些操作,比如防止用户重复提交表单、限制投票次数、实现验证码获取等功能,所以本文给大家介绍了Vue3动态倒计时的代码实现,需要的朋友可以参考下

1. Demo

给一版初始的Demo,在给一版实战中的Demo

基本知识点:

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与当前时间来动态更新表格的倒计时列

<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时间,也就是设定的未来时间
但是我要已过期,或者超过当前时间的 都显示 重新预约

那么只需要在超过当前时间或已过期的情况下显示“重新预约”

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

您可能感兴趣的文章:
阅读全文