在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)

一、概述

记录时间 [2024-12-26]

本文讲述如何在 Vue3 项目中使用计时器组件。具体包括开发环境的配置,Vite+Vue 项目的创建,Element Plus 插件的使用,以及计时器组件的创建和使用。

想要直接实现计时器组件,查看文章的第四部分。

文末附有项目的测试代码,可以直接上手哦。

1. 计时器效果图

计时停止状态

计时启动状态

开发工具及文档

二、创建 + 配置项目

Vite 是一种新型前端构建工具,意在提供开箱即用的配置,能够显著提升前端开发体验。

1. 创建

在 cmd 中,通过 Vite,构建一个 Vite + Vue 项目。

自行指定项目存放位置。

shell 复制代码
# check npm, 检查 npm 版本
npm -v

# 7.0 以上版本使用该语句
npm create vite@latest my-vue-app

# choose vue + js
# 选择创建 Vue 项目,使用 JavaScript 语言

# 执行以下命令即可运行该模板项目
cd my-vue-app	# 跳转到项目路径
npm install		# 安装依赖
npm run dev		# 执行运行

2. 项目预览

通过浏览器,访问对应的 http 路径,就可以查看这个模板项目。

shell 复制代码
# 通过浏览器访问
Local:   http://localhost:5173/

# Ctrl + C 终止项目

3. 修改项目模板

使用 VS Code 打开项目 my-vue-app,观察左边四个文件。

  • 删除 HelloWorld.vuestyle.css
  • 再把 App.vuemain.js 里面没用的代码注释掉。

就剩下一个基本框架,方便我们后续写内容。

修改 v3 创建模板(可选)

文件路径:C:\Users\user\.vscode\extensions\sdras.vue-vscode-snippets\snippets\vue.json

修改 vbase-3-setup 模板,后续创建 vue 组件时会用到。

json 复制代码
  "Vue Single File Component Setup Composition API": {
    "prefix": "vbase-3-setup",
    "body": [
	  "<script setup>",
      "",
      "</script>",
      "",
      "<template>",
      "",
      "</template>",
      "",
      "<style scoped>",
      "",
      "</style>"
    ],
    "description": "Base for Vue File Setup Composition API"
  },

修改后,vbase-3-setup 模板效果如下,输入 v3 即可使用。

重启 VS Code 生效。

html 复制代码
<script setup>

</script>

<template>

</template>

<style scoped>

</style>

4. 安装前端组件

安装组件

Element Plus 是基于 Vue 3,面向设计师和开发者的组件库。里面有一些基础的前端组件样式,如布局、按钮、输入框等,可用于简化开发。

通过 npm 安装 Element Plus:

可以用 cmd,也可以通过 VS Code 中的终端 Terminal 来执行项目。后续 Terminal 用的比较多。

shell 复制代码
# Ctrl + C 终止项目

# 安装 Element Plus
npm install element-plus --save

会安装在项目的 node_modules 目录下。

导入组件

然后在 main.js 中导入组件。

js 复制代码
import { createApp } from 'vue'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

三、整体布局

1. 测试

经过上面的修改,运行项目后,我们在浏览器中看到的是一个空白的页面。

shell 复制代码
npm install		# 安装依赖
npm run dev		# 执行运行

App.vue 中写点内容测试一下:

html 复制代码
<script setup>
</script>

<template>
  <h3>test</h3>
</template>

<style scoped></style>

保存修改后的文件,然后刷新浏览器的页面。就可以观察到更新后的内容。

2. 栅格布局

使用 Element Plus,通过基础的 24 分栏,迅速简便地创建布局。

挑选一个左中右 3 分的布局。

App.vue 中实现这个效果。

HTML 显示

此时布局中,"左中右" 分布为 8:8:8(24),也就是均分,我们可以手动调整为 6:12:6(24),这样中间的空间多一些。

html 复制代码
<template>
  <el-row>

    <!-- left -->

    <el-col :span="8">
      <div class="grid-content ep-bg-purple" />
      <h1>left</h1>
    </el-col>

    <!-- center -->

    <el-col :span="8">
      <div class="grid-content ep-bg-purple-light" />
      <h1>center</h1>
      <h1>计时器组件</h1>
    </el-col>

    <!-- right -->

    <el-col :span="8">
      <div class="grid-content ep-bg-purple" />
      <h1>right</h1>
    </el-col>
  </el-row>
</template>

CSS 样式

css 复制代码
<style scoped>
h1 {
  text-align: center;
}

.el-row {
  margin-bottom: 20px;
}

.el-row:last-child {
  margin-bottom: 0;
}

.el-col {
  border-radius: 4px;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}
</style>

3. 效果预览

在浏览器中呈现的效果如下图所示。

四、计时器组件

1. 创建 + 导入组件

Vue 组件的创建位置一般在项目的 my-vue-app\src\components 目录下。

在该目录下,创建计时器组件 Timer.vue

html 复制代码
<script setup>

</script>

<template>
    <h3>计时器组件 Timer.vue 导入到 App.vue 中</h3>
</template>

<style scoped></style>

将计时器组件导入到 App.vue

  • <script> 标签里导入;
  • <template> 中应用。
html 复制代码
<script setup>
import Timer from './components/Timer.vue'
</script>

<template>
	<!-- template 里面有其他代码的,Timer 放到对应位置即可 -->
	<!-- 放到 center 布局里 -->
	<Timer />
</template>

2. 计时器的布局

先在网页上绘制计时器的静态布局,就是先画出一个样子来。

  • 内 / 外边框,按钮,使用 Element Plus 组件;
  • "时分秒" 显示 2 位数,"毫秒" 显示 3 位数;
  • 各种文字调整成合适大小。

效果预览

代码编写

外边框

外边框在 App.vue 中实现,在 <style> 中编写一个 css 样式,使用 Element Plus 组件。

css 复制代码
.box {
  width: 90%;
  border: 2px solid var(--el-border-color);
  border-radius: 0;
  padding: 30px;
}

<template> 中使用:

html 复制代码
<div class="box">
	<Timer1 />
</div>

其他布局在 Timer.vue 中编写代码。


内边框 + 边框内的文字 + 三个按钮

  • 使用 Element Plus 边框组件,在一行中循环显示 4 个小边框。
  • 边框内的文字分两部分:显示时间;时间单位。
  • 使用 Element Plus 按钮组件,设置 "开始","暂停","重置" 3 个按钮。
html 复制代码
<template>
    <h1>计时器</h1>

    <!-- display: inline; 让 div 在同一行 -->
    <!-- 循环显示 4 个小边框 -->
    <div v-for="i in 4" style="display: inline;">
        <div class="radius" :style="{
            borderRadius: 'small'
                ? `var(--el-border-radius-small)`
                : '',
        }">
            <div class="show-size">
                00
                <span style="font-size: 20px;">小时</span>
                
                <!-- 通过总耗时获取对应的时分秒 -->
                <!-- {{ formatTime(elapsedTime, time[i - 1]) }} -->

                <!-- 通过数组获取对应的时间单位 -->
                <!-- <span style="font-size: 20px;">{{ timeShow[i - 1] }}</span> -->
            </div>
        </div>
    </div>

    <!-- 框 和 button 使用 element-plus -->

    <div style="margin-top: 120px;">
        <el-button type="primary">开始</el-button>
        <el-button type="info">暂停</el-button>
        <el-button>重置</el-button>
    </div>
</template>

<style scoped>
.show-size {
    font-size: 2em;
    margin: 10px 0;
    text-align: center;
}

.radius {
    height: 60px;
    width: 20%;
    border: 1px solid var(--el-border-color);
    border-radius: 0;
    float: left;
}
</style>

3. 计时器的初步逻辑

接下来在 Timer.vue 中实现计时器的初步逻辑:

  • 使用定时器函数累计耗时,确定时间概念(时分秒)。
  • 能通过网页与计时器组件进行交互。
  • 点击启动 ,计时器开始工作;点击暂停 ,计时器暂停工作;点击重置,计时器重置。

定时器函数

setInterval() 是 JavaScript 中的一个定时器函数,用于按照指定的时间间隔 (以毫秒为单位)重复执行一段代码或函数。它会持续调用指定的函数,直到 clearInterval() 被调用或者页面被卸载。

setInterval() 会返回一个 intervalID,是正整数形式的标识符,可用于清除定时器

参考用法(观察一下)

js 复制代码
// intervalID: id
let intervalID = null;

// 通过 id 启动定时器
// func: 每次定时器到期时要调用的函数或要执行的代码
// delay: 两次调用之间的时间间隔, 以毫秒为单位, 1s = 1000ms
intervalID = setInterval({func}, delay);

// 通过 id 清除定时器
clearInterval(intervalId);

定时器:规定一段时间,每隔一段时间完成一个动作,比如执行一段代码;

计时器:统计累计消耗的时间。

定义变量

Timer.vue 中实现这个逻辑:

  • elapsedTime:累计耗时(以毫秒为单位);
  • intervalId:定时器的 ID
  • setInterval():启动定时器;
  • clearInterval():清除定时器。
  • isRunning:判断计时器是否启动的标志。(计时器和定时器同启同停)

当你在模板中使用了一个 ref,然后改变了这个 ref 的值时,Vue 会自动检测到这个变化,并且相应地更新 DOM。

<script> 标签中导入 ref,定义变量。

html 复制代码
<script setup>
import { ref } from 'vue';

// 计时器的启动状态 false 暂停计时;ture 正在计时
const isRunning = ref(false);

// 计时器的耗时(以毫秒为单位)
const elapsedTime = ref(0);

// 定时器的 id,用于调用定时器的函数,如 setInterval,clearInterval
let intervalId = null;

// 循环获取数组的内容, 配合小边框使用, 用来渲染页面内容
const time = [
    'hours', 'minutes', 'seconds', 'millis'
];

const timeShow = [
    '小时', '分钟', '秒', '毫秒'
];
</script>

启动计时器

编写方法 startTimer(),用于启动计时器。

  • 判断计时器的启动状态,如果已经在计时,直接返回;
  • 更新计时器的启动状态为 ture
  • 通过 id 启动定时器,累加耗时,从而相当于启动了计时器,每隔 5ms 在 elapsedTime 中更新累计耗时。
js 复制代码
// 启动计时器
const startTimer = () => {
    // 如果已经在计时,直接返回
    if (isRunning.value) return;

    // 更新计时器的状态为 ture 正在计时
    isRunning.value = true;

    // 通过 id 启动定时器,累加耗时,从而相当于启动了计时器,1s = 1000ms,每 5ms 累加 5ms
    intervalId = setInterval(() => {
        elapsedTime.value += 5;
    }, 5);
}

暂停计时器

编写方法 pauseTimer(),用于暂停计时器。

  • 更新计时器的启动状态为 false
  • 通过 id 清除定时器,暂停耗时的累加,从而相当于暂停了计时器。
js 复制代码
// 暂停计时器
const pauseTimer = () => {
    // 更新计时器的状态为 false 暂停计时
    isRunning.value = false;

    // 通过 id 清除定时器,暂停耗时的累加,从而相当于暂停了计时器
    clearInterval(intervalId);
}

重置计时器

编写方法 resetTimer(),用于重置计时器。

  • 更新计时器的启动状态为 false
  • 通过 id 清除定时器,停止耗时的累加;
  • 将总耗时 elapsedTime 的值清空。
  • 停止耗时的累加,且清空总耗时,相当于重置了计时器。
js 复制代码
// 重置计时器
const resetTimer = () => {
    // 更新计时器的状态为 false
    isRunning.value = false;

    // 通过 id 清除定时器,暂停耗时的累加
    clearInterval(intervalId);

    // 将已耗时设置为 0
    elapsedTime.value = 0;

    // 重置起始时间
    // for (let i = 0; i < 4; i++) {
    //     startTime.value[i] = 0;
    // }
}

耗时换算

我们通过 elapsedTime 累加耗时,它是以毫秒为单位的,我们要实现 "时,分,秒,毫秒" 分区显示。

需要通过简单的数学计算,来完成耗时换算。
1 s = 1000 m s 1 m i n = 60 s = ( 60 × 1000 ) m s 1 h = 60 m i n = ( 60 × 60 ) s = ( 60 × 60 × 1000 ) m s 1 s = 1000 ms \\ 1 min = 60 s = (60×1000) ms \\ 1 h = 60 min = (60×60) s = (60×60×1000) ms 1s=1000ms1min=60s=(60×1000)ms1h=60min=(60×60)s=(60×60×1000)ms

倒过来计算,通过毫秒换算成 "时,分,秒,毫秒" 显示。

注意:程序中整数做除法,会直接省略小数点后面的数值(3739220/1000 = 3739)
e g : t o t a l T i m e = 3739220 m s s h o w : m i l l i s = t o t a l T i m e % 1000 = 3739220 % 1000 = 220 m s s h o w : s e c o n d s = ( t o t a l T i m e / 1000 ) % 60 = 19 s s h o w : m i n u t e s = ( t o t a l T i m e / ( 1000 ∗ 60 ) ) % 60 = 2 m i n s h o w : h o u r s = ( t o t a l T i m e / ( 1000 ∗ 60 ∗ 60 ) ) % 24 = 1 h e n d S h o w : 1 h : 2 m i n : 19 s : 220 m s eg: totalTime = 3739220 ms \\ show: millis = totalTime \% 1000 = 3739220 \% 1000 = 220ms \\ show: seconds = (totalTime / 1000) \% 60 = 19s \\ show: minutes = (totalTime / (1000 * 60)) \% 60 = 2min \\ show: hours = (totalTime / (1000 * 60 * 60)) \% 24 = 1h \\ endShow:1h:2min:19s:220ms eg:totalTime=3739220msshow:millis=totalTime%1000=3739220%1000=220msshow:seconds=(totalTime/1000)%60=19sshow:minutes=(totalTime/(1000∗60))%60=2minshow:hours=(totalTime/(1000∗60∗60))%24=1hendShow:1h:2min:19s:220ms

在代码中编写耗时换算函数 formatTime

js 复制代码
// 时分秒分区显示
const formatTime = (milliseconds, timeString) => {
    const millis = Math.floor(milliseconds % 1000);
    const seconds = Math.floor((milliseconds / 1000) % 60);
    const minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
    const hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);

    // 配合数组 time 使用,确定获取的是 millis/seconds/minutes/hours 其中一部分
    // String(obj).padStart(3, '0') 格式化数据的显示,毫秒 3 位,其他 2 位
    
    if (timeString == 'millis') {
        return `${String(millis).padStart(3, '0')}`;
    } else if (timeString == 'seconds') {
        return `${String(seconds).padStart(2, '0')}`;
    } else if (timeString == 'minutes') {
        return `${String(minutes).padStart(2, '0')}`;
    } else if (timeString == 'hours') {
        return `${String(hours).padStart(2, '0')}`;
    }

}

4. 更新页面渲染

动态显示

Timer.vue<template> 标签中,使用插值表达式 {``{}} 来完成页面内容的动态显示。

  • 通过总耗时获取对应的 "时分秒"
html 复制代码
<!-- i 用于循环遍历 -->
{{ formatTime(elapsedTime, time[i - 1]) }}
  • 通过数组获取对应的时间单位
html 复制代码
<!-- i 用于循环遍历 -->
{{ timeShow[i - 1] }}
  • 绑定按钮点击事件可点击状态
html 复制代码
<!-- @click="startTimer", 点击按钮触发 startTimer() 方法 -->
<!-- :disabled="isRunning", 根据 isRunning 的值确定按钮是否被禁用, true 禁用, false 不禁用 -->

<el-button @click="startTimer" :disabled="isRunning" type="primary">开始</el-button>

<!-- 另外两个按钮同理 -->

<el-button @click="pauseTimer" :disabled="!isRunning" type="info">暂停</el-button>
<el-button @click="resetTimer">重置</el-button>

效果预览

点击启动 ,计时器开始工作;点击暂停 ,计时器暂停工作;点击重置,计时器重置。

计时器不动时,"暂停" 按钮不可点击;计时器运行时,"开始" 按钮不可点击。

(按钮被禁用时,颜色会变浅一些)


接下来开始优化计时器,增加设置起始时间功能,同时设置运行时特效。


5. 设置起始时间

效果预览

在计时器的下方,可以设置计时器的起始时间。

需要达到的效果:按照 "时分秒" 的格式设置起始时间,点击 "提交" 按钮后,上方计时器显示的起始时间,就是我们提交的时间。

逻辑实现

Timer.vue<script> 标签中编写逻辑代码。

  • startTime:存放 "时分秒" 格式的初始时间 的数组,默认为 [0, 0, 0, 0]
  • setStartTime():将提交的 startTime 换算成 "毫秒",然后赋值给计时器的耗时 elapsedTime
  • 重置计时器的同时,将 startTime 的值重置为 [0, 0, 0, 0]
js 复制代码
// 起始时间
const startTime = ref([0, 0, 0, 0]);

// 设置起始时间,换算成毫秒,赋值给计时器的耗时
const setStartTime = () => {
    elapsedTime.value = (((startTime.value[1] * 60) + startTime.value[2]) * 60 + startTime.value[3]) * 1000;
}

// 重置计时器
const resetTimer = () => {
    // other codes...

    // 重置起始时间
    for (let i = 0; i < 4; i++) {
        startTime.value[i] = 0;
    }
}

样式设计

使用 Element Plus 组件,挑选 3 个下拉选项框,分别对应选择的 "时分秒"。

  • 在下拉选项框中,使用 v-modelstartTime 数组内容双向绑定,这样会将选中的起始时间保存到这个数组中。
  • 使用 :disabled 绑定 isRunning 的值,来决定下拉选项框是否被禁用。在计时器启动时,禁用;计时器停止时,不禁用。

再使用一个 "提交" 按钮,点击按钮,就执行 setStartTime() 方法。

  • "提交" 按钮的点击事件绑定 setStartTime() 方法,将提交的 startTime 换算成 "毫秒",然后赋值给计时器的耗时 elapsedTime
  • 由于使用了 refDOM 会自动更新,也就是计时器上的时间会更新成所提交的起始时间。
  • 使用 :disabled 绑定 isRunning 的值,在计时器启动时,禁用 "提交" 按钮,不允许修改时间。

Timer.vue<template> 标签中编写。

html 复制代码
<!-- set Start Time -->

<h3>设置起始时间</h3>

<div v-for="i in 3" style="display: inline;">
    <el-select v-model="startTime[i]" :disabled="isRunning" placeholder="Select" class="select-box">
        <el-option v-for="item in 60" :key="item - 1" :label="`${item - 1} ${timeShow[i - 1]}`" :value="item - 1" />
    </el-select>

</div>

<!-- 计时器启动时不允许修改时间 -->

<el-button type="success" @click="setStartTime" :disabled="isRunning">提交</el-button>

给下拉选项框设置一个 css 样式,在 Timer.vue<style> 标签中编写。

css 复制代码
.select-box {
    width: 100px;
    margin-right: 10px;
}

6. 设置运行时特效

在计时器启动时,计时器上显示的时间会发生变化。在此时,我们给计时器设计一个特别的 css 样式。

  • 在计时器暂停 / 停止时,计时器上显示的时间不动,颜色是默认的;
  • 在计时器启动时,计时器上显示的时间会发生变化,颜色也发生变化,变成海棠红色。

效果预览

计时器启动时的效果。

代码编写

Timer.vue<template> 标签中修改代码。该效果是使用 v-if 来实现的。

html 复制代码
<!-- set running css v-if -->

<div class="show-size">

    <span v-if="isRunning" style="color:#db5a6b;">

        <!-- 通过总耗时获取对应的时分秒 -->
        {{ formatTime(elapsedTime, time[i - 1]) }}

        <!-- 通过数组获取对应的时间单位 -->
        <span style="font-size: 20px;">{{ timeShow[i - 1] }}</span>
    </span>

    <span v-else>
        {{ formatTime(elapsedTime, time[i - 1]) }}
        <span style="font-size: 20px;">{{ timeShow[i - 1] }}</span>
    </span>

</div>

五、运行项目

至此,在 Vue3 项目中使用计时器组件 就成功实现了,点击 VS Code 左上角的 Terminal -> New Terminal,转到 powershell 中,执行以下命令,即可运行此项目。

shell 复制代码
npm install		# 安装依赖
npm run dev		# 执行运行

# 通过浏览器访问
Local:   http://localhost:5173/

# Ctrl + C 终止项目

六、完整测试代码

1. create

shell 复制代码
# check npm
npm -v

# npm 7+, 创建 Vite+Vue3 项目
npm create vite@latest my-vue-app

# choose vue + js
# 选择创建 Vue 项目,使用 JavaScript 语言

# 跳转到项目路径
cd my-vue-app

# 安装 element-plus
npm install element-plus --save

npm install		# 安装依赖
npm run dev		# 执行运行

# 通过浏览器访问
Local:   http://localhost:5173/

# Ctrl + C 终止项目

2. main.js

js 复制代码
import { createApp } from 'vue'

// 引入 element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

3. App.vue

html 复制代码
<script setup>
import Timer from './components/Timer.vue'
</script>

<template>
  <el-row>

    <!-- left -->

    <el-col :span="6">
      <div class="grid-content ep-bg-purple" />
    </el-col>

    <!-- center -->

    <el-col :span="12">
      <div class="grid-content ep-bg-purple-light" />

      <div class="box">
        <Timer />
      </div>

    </el-col>

    <!-- right -->

    <el-col :span="6">
      <div class="grid-content ep-bg-purple" />
    </el-col>
  </el-row>
</template>

<style scoped>
h1 {
  text-align: center;
}

.box {
  width: 90%;
  border: 2px solid var(--el-border-color);
  border-radius: 0;
  padding: 30px;
}

.el-row {
  margin-bottom: 20px;
}

.el-row:last-child {
  margin-bottom: 0;
}

.el-col {
  border-radius: 4px;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}
</style>

4. Timer.vue

html 复制代码
<script setup>
import { ref } from 'vue';

// 计时器的启动状态 false 暂停计时;ture 正在计时
const isRunning = ref(false);

// 计时器的耗时(以毫秒为单位)
const elapsedTime = ref(0);

// 定时器的 id,用于调用定时器的函数,如 setInterval,clearInterval
let intervalId = null;

// 循环获取数组的内容, 配合小边框使用, 用来渲染页面内容
const time = [
    'hours', 'minutes', 'seconds', 'millis'
];

const timeShow = [
    '小时', '分钟', '秒', '毫秒'
];

// 起始时间
const startTime = ref([0, 0, 0, 0]);

// 设置起始时间,换算成毫秒,赋值给计时器的耗时
const setStartTime = () => {
    elapsedTime.value = (((startTime.value[1] * 60) + startTime.value[2]) * 60 + startTime.value[3]) * 1000;
}

// 时分秒分区显示
const formatTime = (milliseconds, timeString) => {
    const millis = Math.floor(milliseconds % 1000);
    const seconds = Math.floor((milliseconds / 1000) % 60);
    const minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
    const hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);

    // 配合数组 time 使用,确定获取的是 millis/seconds/minutes/hours 其中一部分
    // String(obj).padStart(3, '0') 格式化数据的显示,毫秒 3 位,其他 2 位

    if (timeString == 'millis') {
        return `${String(millis).padStart(3, '0')}`;
    } else if (timeString == 'seconds') {
        return `${String(seconds).padStart(2, '0')}`;
    } else if (timeString == 'minutes') {
        return `${String(minutes).padStart(2, '0')}`;
    } else if (timeString == 'hours') {
        return `${String(hours).padStart(2, '0')}`;
    }

}

// 启动计时器
const startTimer = () => {
    // 如果已经在计时,直接返回
    if (isRunning.value) return;

    // 更新计时器的状态为 ture 正在计时
    isRunning.value = true;

    // 通过 id 启动定时器,累加耗时,从而相当于启动了计时器,1s = 1000ms,每 5ms 累加 5ms
    intervalId = setInterval(() => {
        elapsedTime.value += 5;
    }, 5);
}

// 暂停计时器
const pauseTimer = () => {
    // 更新计时器的状态为 false 暂停计时
    isRunning.value = false;

    // 通过 id 清除定时器,暂停耗时的累加,从而相当于暂停了计时器
    clearInterval(intervalId);
}

// 重置计时器
const resetTimer = () => {
    // 更新计时器的状态为 false
    isRunning.value = false;

    // 通过 id 清除定时器,暂停耗时的累加
    clearInterval(intervalId);

    // 将已耗时设置为 0
    elapsedTime.value = 0;

    // 重置起始时间
    for (let i = 0; i < 4; i++) {
        startTime.value[i] = 0;
    }
}

</script>

<template>
    <h1>计时器</h1>

    <!-- display: inline; 让 div 在同一行 -->
    <!-- 循环取数 -->
    <div v-for="i in 4" style="display: inline;">
        <div class="radius" :style="{
            borderRadius: 'small'
                ? `var(--el-border-radius-small)`
                : '',
        }">

            <!-- set running css v-if -->

            <div class="show-size">

                <span v-if="isRunning" style="color:#db5a6b;">

                    <!-- 通过总耗时获取对应的时分秒 -->
                    {{ formatTime(elapsedTime, time[i - 1]) }}

                    <!-- 通过数组获取对应的时间单位 -->
                    <span style="font-size: 20px;">{{ timeShow[i - 1] }}</span>
                </span>

                <span v-else>
                    {{ formatTime(elapsedTime, time[i - 1]) }}
                    <span style="font-size: 20px;">{{ timeShow[i - 1] }}</span>
                </span>

            </div>
        </div>
    </div>

    <!-- 框 和 button 使用 element-plus -->

    <div style="margin-top: 120px;">

        <!-- @click 绑定按钮点击事件;:disabled 绑定按钮是否可以点击 -->

        <el-button @click="startTimer" :disabled="isRunning" type="primary">开始</el-button>
        <el-button @click="pauseTimer" :disabled="!isRunning" type="info">暂停</el-button>
        <el-button @click="resetTimer">重置</el-button>
    </div>

    <!-- set Start Time -->

    <h3>设置起始时间</h3>

    <div v-for="i in 3" style="display: inline;">
        <el-select v-model="startTime[i]" :disabled="isRunning" placeholder="Select" class="select-box">
            <el-option v-for="item in 60" :key="item - 1" :label="`${item - 1} ${timeShow[i - 1]}`" :value="item - 1" />
        </el-select>

    </div>

    <!-- 计时器启动时不允许修改时间 -->

    <el-button type="success" @click="setStartTime" :disabled="isRunning">提交</el-button>
</template>

<style scoped>
.show-size {
    font-size: 2em;
    margin: 10px 0;
    text-align: center;
}

.radius {
    height: 60px;
    width: 20%;
    border: 1px solid var(--el-border-color);
    border-radius: 0;
    float: left;
}

.select-box {
    width: 100px;
    margin-right: 10px;
}
</style>

参考资料

Vue3 文档:https://cn.vuejs.org/guide/introduction.html

Vite 文档:https://vitejs.cn/vite3-cn/guide/#scaffolding-your-first-vite-project

Element-plus 文档:https://element-plus.org/zh-CN/component/overview.html

色彩工具:https://tool.lu/index.php/color/palette.html?id=2

VS Code 官网:https://code.visualstudio.com/

Node.js 官网:https://nodejs.org/zh-cn/download/prebuilt-binaries

参考文章 - Node.js 安装和配置:https://blog.csdn.net/Sareur_1879/article/details/144729321

相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax