在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
一、概述
记录时间 [2024-12-26]
本文讲述如何在 Vue3 项目中使用计时器组件。具体包括开发环境的配置,Vite+Vue 项目的创建,Element Plus 插件的使用,以及计时器组件的创建和使用。
想要直接实现计时器组件,查看文章的第四部分。
文末附有项目的测试代码,可以直接上手哦。
1. 计时器效果图
计时停止状态
计时启动状态
开发工具及文档
- Node.js - 下载地址;Node.js 安装和配置 - 参考文章
- VS Code - 下载地址;写前端代码的软件,直接安装即可。或者通过压缩包解压缩安装。
- Vue3 - 文档
- Vite - 文档
- Element Plus - 文档
二、创建 + 配置项目
Vite 是一种新型前端构建工具,意在提供开箱即用的配置,能够显著提升前端开发体验。
1. 创建
在 cmd 中,通过 Vite,构建一个 Vite + Vue 项目。
自行指定项目存放位置。
# 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
路径,就可以查看这个模板项目。
# 通过浏览器访问
Local: http://localhost:5173/# Ctrl + C 终止项目
3. 修改项目模板
使用 VS Code 打开项目 my-vue-app
,观察左边四个文件。
- 删除
HelloWorld.vue
,style.css
; - 再把
App.vue
,main.js
里面没用的代码注释掉。
就剩下一个基本框架,方便我们后续写内容。
修改 v3 创建模板(可选)
文件路径:C:\Users\user\.vscode\extensions\sdras.vue-vscode-snippets\snippets\vue.json
修改 vbase-3-setup
模板,后续创建 vue
组件时会用到。
"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 生效。
<script setup></script><template></template><style scoped></style>
4. 安装前端组件
安装组件
Element Plus 是基于 Vue 3,面向设计师和开发者的组件库。里面有一些基础的前端组件样式,如布局、按钮、输入框等,可用于简化开发。
通过 npm
安装 Element Plus:
可以用 cmd,也可以通过 VS Code 中的终端 Terminal 来执行项目。后续 Terminal 用的比较多。
# Ctrl + C 终止项目# 安装 Element Plus
npm install element-plus --save
会安装在项目的 node_modules
目录下。
导入组件
然后在 main.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. 测试
经过上面的修改,运行项目后,我们在浏览器中看到的是一个空白的页面。
npm install # 安装依赖
npm run dev # 执行运行
在 App.vue
中写点内容测试一下:
<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)
,这样中间的空间多一些。
<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 样式
<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
<script setup></script><template><h3>计时器组件 Timer.vue 导入到 App.vue 中</h3>
</template><style scoped></style>
将计时器组件导入到 App.vue
中
- 在
<script>
标签里导入; - 在
<template>
中应用。
<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 组件。
.box {width: 90%;border: 2px solid var(--el-border-color);border-radius: 0;padding: 30px;
}
在 <template>
中使用:
<div class="box"><Timer1 />
</div>
其他布局在 Timer.vue
中编写代码。
内边框 + 边框内的文字 + 三个按钮
- 使用 Element Plus 边框组件,在一行中循环显示 4 个小边框。
- 边框内的文字分两部分:显示时间;时间单位。
- 使用 Element Plus 按钮组件,设置 “开始”,“暂停”,“重置” 3 个按钮。
<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
,是正整数形式的标识符,可用于清除定时器。
参考用法(观察一下)
// 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
,定义变量。
<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
中更新累计耗时。
// 启动计时器
const startTimer = () => {// 如果已经在计时,直接返回if (isRunning.value) return;// 更新计时器的状态为 ture 正在计时isRunning.value = true;// 通过 id 启动定时器,累加耗时,从而相当于启动了计时器,1s = 1000ms,每 5ms 累加 5msintervalId = setInterval(() => {elapsedTime.value += 5;}, 5);
}
暂停计时器
编写方法 pauseTimer()
,用于暂停计时器。
- 更新计时器的启动状态为
false
; - 通过
id
清除定时器,暂停耗时的累加,从而相当于暂停了计时器。
// 暂停计时器
const pauseTimer = () => {// 更新计时器的状态为 false 暂停计时isRunning.value = false;// 通过 id 清除定时器,暂停耗时的累加,从而相当于暂停了计时器clearInterval(intervalId);
}
重置计时器
编写方法 resetTimer()
,用于重置计时器。
- 更新计时器的启动状态为
false
; - 通过
id
清除定时器,停止耗时的累加; - 将总耗时
elapsedTime
的值清空。 - 停止耗时的累加,且清空总耗时,相当于重置了计时器。
// 重置计时器
const resetTimer = () => {// 更新计时器的状态为 falseisRunning.value = false;// 通过 id 清除定时器,暂停耗时的累加clearInterval(intervalId);// 将已耗时设置为 0elapsedTime.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
:
// 时分秒分区显示
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>
标签中,使用插值表达式 {{}}
来完成页面内容的动态显示。
- 通过总耗时获取对应的 “时分秒”
<!-- i 用于循环遍历 -->
{{ formatTime(elapsedTime, time[i - 1]) }}
- 通过数组获取对应的时间单位
<!-- i 用于循环遍历 -->
{{ timeShow[i - 1] }}
- 绑定按钮点击事件和可点击状态
<!-- @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]
。
// 起始时间
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-model
与startTime
数组内容双向绑定,这样会将选中的起始时间保存到这个数组中。 - 使用
:disabled
绑定isRunning
的值,来决定下拉选项框是否被禁用。在计时器启动时,禁用;计时器停止时,不禁用。
再使用一个 “提交” 按钮,点击按钮,就执行 setStartTime()
方法。
- “提交” 按钮的点击事件绑定
setStartTime()
方法,将提交的startTime
换算成 “毫秒”,然后赋值给计时器的耗时elapsedTime
; - 由于使用了
ref
,DOM
会自动更新,也就是计时器上的时间会更新成所提交的起始时间。 - 使用
:disabled
绑定isRunning
的值,在计时器启动时,禁用 “提交” 按钮,不允许修改时间。
在 Timer.vue
的 <template>
标签中编写。
<!-- 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>
标签中编写。
.select-box {width: 100px;margin-right: 10px;
}
6. 设置运行时特效
在计时器启动时,计时器上显示的时间会发生变化。在此时,我们给计时器设计一个特别的 css
样式。
- 在计时器暂停 / 停止时,计时器上显示的时间不动,颜色是默认的;
- 在计时器启动时,计时器上显示的时间会发生变化,颜色也发生变化,变成海棠红色。
效果预览
计时器启动时的效果。
代码编写
在 Timer.vue
的 <template>
标签中修改代码。该效果是使用 v-if
来实现的。
<!-- 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
中,执行以下命令,即可运行此项目。
npm install # 安装依赖
npm run dev # 执行运行# 通过浏览器访问
Local: http://localhost:5173/# Ctrl + C 终止项目
六、完整测试代码
1. create
# 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 --savenpm install # 安装依赖
npm run dev # 执行运行# 通过浏览器访问
Local: http://localhost:5173/# Ctrl + C 终止项目
2. main.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
<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
<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 累加 5msintervalId = setInterval(() => {elapsedTime.value += 5;}, 5);
}// 暂停计时器
const pauseTimer = () => {// 更新计时器的状态为 false 暂停计时isRunning.value = false;// 通过 id 清除定时器,暂停耗时的累加,从而相当于暂停了计时器clearInterval(intervalId);
}// 重置计时器
const resetTimer = () => {// 更新计时器的状态为 falseisRunning.value = false;// 通过 id 清除定时器,暂停耗时的累加clearInterval(intervalId);// 将已耗时设置为 0elapsedTime.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
相关文章:
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
一、概述 记录时间 [2024-12-26] 本文讲述如何在 Vue3 项目中使用计时器组件。具体包括开发环境的配置,ViteVue 项目的创建,Element Plus 插件的使用,以及计时器组件的创建和使用。 想要直接实现计时器组件,查看文章的第四部分。…...
Redis单线程快的原因
基于内存操作:Redis将数据存储在内存中,使得数据的读写速度极快,这是其性能优势的主要原因。单线程避免上下文切换:在多线程环境下,CPU核数有限,线程上下文切换会带来性能损耗。Redis采用单线程,…...
基于SpringBoot的“在线BLOG网”的设计与实现(源码+数据库+文档+PPT)
基于SpringBoot的“在线BLOG网”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 在线BLOG网结构功能图 管理员登录功能界面 用户信息…...
重温设计模式--6、享元模式
文章目录 享元模式(Flyweight Pattern)概述享元模式的结构C 代码示例1应用场景C示例代码2 享元模式(Flyweight Pattern)概述 定义: 运用共享技术有效地支持大量细粒度的对象。 享元模式是一种结构型设计模式࿰…...
springboot-starter版本升级es版本问题
一、背景说明 版本漏洞处理,springboot版本升级,es版本暂不升级,但是pom引用中es版本一直为7.17.15高版本,不想显示声明版本,定位具体问题,最后还是重新定义了版本进行处理。 二、异常情况 这里看4.4.18是…...
嵌入式科普(25)Home Assistant米家集成意味着IOT的核心是智能设备
目录 一、概述 二、一张图说尽HA 三、HA的相关资料 四、米家集成划重点 五、总结 一、概述 小米Home Assistant 米家集成开源一周star近15k,迭代4个版本,12个贡献者 本文科普一下Home Assistant(简称HA)、米家集成ÿ…...
前端Python应用指南(四)Django实战:创建一个简单的博客系统
《写给前端的python应用指南》系列: (一)快速构建 Web 服务器 - Flask vs Node.js 对比(二)深入Flask:理解Flask的应用结构与模块化设计(三)Django vs Flask:哪种框架适…...
webrtc获取IceCandidate流程
在WebRTC(Web Real-Time Communication)中,ICECandidate是一个关键概念,它用于描述在建立点对点(P2P)连接时可以考虑的潜在通信端点。以下是关于WebRTC中ICECandidate的详细解释: 一、ICECandidate的定义 ICECandidate对象通常包含以下关键属性: foundation:用于唯一…...
快速入门Spring AI Alibaba
文章目录 前言一、环境准备二、获取API Key三、代码示例pomapplication.ymlcontroller 前言 Spring Cloud Alibaba AI 以 Spring AI 为基础,并在此基础上,基于 Spring AI 0.8.1 版本 API 完成同义系列大模型的接入实现阿里云同义系列大模型全面适配。 在…...
【mysql】MVCC及实现原理
【mysql】MVCC及实现原理 【一】介绍【1】什么是MVCC【2】什么是当前读和快照读【3】当前读,快照读和MVCC的关系【4】MVCC 能解决什么问题,好处(1)数据库并发场景有三种,分别为:(2)M…...
C++ —— 模板类与函数
C —— 模板类与函数 模板类可以用于函数的参数和返回值,有三种形式: 普通函数,参数和返回值是模板类的实例化版本。函数模板,参数和返回值是某种的模板类。函数模板,参数和返回值是任意类型(支持普通类和…...
【笔记】下载mysql5.7
MySQL5.7安装超详细步骤(保姆级教程)_mysql5.7下载安装-CSDN博客 下载与安装 初次登录以及改密码 MySQL 5.7 安装教程(全步骤图解教程)_mysql5.7的安装教程-CSDN博客...
让 AMD GPU 在大语言模型推理中崭露头角:机遇与挑战
在当今科技飞速发展的时代,大语言模型(LLM)的兴起彻底改变了人工智能领域的格局。从智能客服到文本生成,从知识问答到代码编写辅助,大语言模型的应用无处不在,深刻影响着我们的生活和工作。然而,…...
Linux运维常见命令
vi/vim快捷键使用 1)拷贝当前行 yy ,拷贝当前行向下的5行 5yy,并粘贴(输入p)。 2)删除当前行 dd ,删除当前行向下的5行5dd 3)在文件中查找某个单词 [命令行下 /关键字,回车查找 ,输入n就是查找下一个 ] 4)设置文件的行号&…...
前端真实面试题自用
一、写在前面 笔者,经过计算机学硕考研的失败后,想谋求一份前端工作实在是太难了。一方面,确实曾经学习过的东西很久没有拾起,另一方面,对于前端面经还是记忆不深刻,特地写此贴记录笔者在真实前端面试中遇…...
人工智能与云计算的结合:如何释放数据的无限潜力?
引言:数据时代的契机 在当今数字化社会,数据已成为推动经济与技术发展的核心资源,被誉为“21世纪的石油”。从个人消费行为到企业运营决策,再到城市管理与国家治理,每个环节都在生成和积累海量数据。然而,数…...
初始 ShellJS:一个 Node.js 命令行工具集合
一. 前言 Node.js 丰富的生态能赋予我们更强的能力,对于前端工程师来说,使用 Node.js 来编写复杂的 npm script 具有明显的 2 个优势:首先,编写简单的工具脚本对前端工程师来说额外的学习成本很低甚至可以忽略不计,其…...
benchmarksql5.0 测试工具如何在达梦上能够跑起来?
(1)添加驱动程序文件: lib文件夹下创建一个dm文件夹,并在dm文件夹下放置达梦数据库的驱动程序:DmJdbcDriver8.jar (2)引用驱动程序文件所在目录: 在文件benchmarksql-5.0/run/funcs.sh中的function setCP()函数中; 也就是在文件…...
amazon广告授权
amazon授权资料地址 Amazon Advertising Advanced Tools Center postman地址:Amazon Advertising Advanced Tools Center...
设计模式与游戏完美开发(2)
更多内容可以浏览本人博客:https://azureblog.cn/ 😊 该文章主体内容来自《设计模式与游戏完美开发》—蔡升达 第二篇 基础系统 第四章 游戏主要类——外观模式(Facade) 一、游戏子功能的整合 一个游戏程序常常由内部数个不同的…...
WebRTC服务质量(10)- Pacer机制(02) RoundRobinPacketQueue
WebRTC服务质量(01)- Qos概述 WebRTC服务质量(02)- RTP协议 WebRTC服务质量(03)- RTCP协议 WebRTC服务质量(04)- 重传机制(01) RTX NACK概述 WebRTC服务质量(…...
VSCode调试
目录 C/C远程本地调试插件配置参考 C/C远程本地调试 测试源码:https://github.com/jrhee17/ssl-study 插件 Remote - SSH C/C 配置 .vscode/launch.json {"version": "0.2.0","configurations": [{"name": "afte…...
【ES6复习笔记】解构赋值(2)
介绍 解构赋值是一种非常方便的语法,可以让我们更简洁地从数组和对象中提取值,并且可以应用于很多实际开发场景中。 1. 数组的解构赋值 数组的解构赋值是按照一定模式从数组中提取值,然后对变量进行赋值。下面是一个例子: con…...
01 - 初识 Spring
初识Spring 企业级应用 企业级应用是指那些为商业组织、⼤型企业而创建并部署的解决⽅案及应用。这些⼤型的企业级应用结构复 杂、涉及的外部资源众多,事务密集,数据规模⼤,用户数量多,有较强的安全性考虑和较⾼的性能要求。 …...
重装荣耀X14笔记本电脑踩坑记
这几天趁着有国补搞了台荣耀 X14笔记本电脑。到手后第一件事情对我来说当然是要重装成Windows 11 LTSC版。所以按以往的经验做了个USB启动安装盘,但发现上电后按F12能进入启动设备选择,可是USB分类下没有任何设备。重启按F2进入设置界面,关闭…...
华为管理变革之道:奋斗文化与活力
目录 企业文化是什么? 为什么活下去是华为的文化? 活下来,是华为公司的最低纲领,也是华为公司的最高纲领! 资源终会枯竭,唯有文化才能生生不息 企业文化之一:以客户为中心 企业文化之二&a…...
代码随想录算法训练营第十五天-二叉树-110.平衡二叉树
所谓平衡二叉树是指任意子树的高度差不超过1目前所学习的有关二叉树的问题,都是基于二叉树的遍历顺序来实现的 #include <iostream> #include <sstream> #define LEN 10009struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(): val(0…...
各种网站(学习资源、常用工具及其他,持续更新中~)
欢迎围观笔者的个人博客~ 也欢迎通过RSS网址https://kangaroogao.github.io/atom.xml进行订阅~ 大学指南 上海交通大学生存手册中国科学技术大学人工智能与数据科学学院本科进阶指南USTC不完全入学指南大学生活质量指北科研论 信息搜集 AI信息搜集USTC飞跃网站计算机保研 技…...
【gunicorn -k gevent 参数gevent说明,主要CPU密集和I/O密集型】
CPU 密集型和I/O 密集型是两种不同的计算任务类别,它们的性能瓶颈来源不同: 1. CPU 密集型 定义 CPU 密集型任务是指主要消耗 CPU 计算资源 的任务。这类任务需要大量的计算操作,而很少涉及 I/O 操作(如网络或磁盘的读写&#x…...
快速理解24种设计模式
简单工厂模式 建立产品接口类,规定好要实现方法。 建立工厂类,根据传入的参数,实例化所需的类,实例化的类必须实现指定的产品类接口 创建型 单例模式Singleton 保证一个类只有一个实例,并提供一个访问他它的全局…...
5G -- 5G网络架构
5G组网场景 从4G到5G的网络演进: 1、UE -> 4G基站 -> 4G核心网 * 部署初中期,利用存量网络,引入5G基站,4G与5G基站并存 2、UE -> (4G基站、5G基站) -> 4G核心网 * 部署中后期,引入5G核心网&am…...
硬件开发笔记(三十二):TPS54331电源设计(五):原理图BOM表导出、元器件封装核对
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/144753092 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...
UE5 崩溃问题汇总!!!
Using bundled DotNet SDK version: 6.0.302 ERROR: UnrealBuildTool.dll not found in "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" 在你遇到这种极奇崩溃的BUG ,难以解决的时候。 尝试了N种方法,都不行的解决方法。…...
美国站群服务器如何帮助实现有效的多域名管理?
国站群服务器以其丰富的IP资源、高性能硬件和灵活的配置选项,成为多域名管理的理想选择。特别是在需要针对不同域名实现SEO优化、业务分离或多站点运营的场景中,美国站群服务器提供了高效且实用的解决方案。以下是如何利用美国站群服务器实现有效的多域名…...
VMware的三种网络模式——在NAT模式下开放接口为局域网内其他主机提供服务
众所周知 VMware 有三种常用的网络通讯模式,分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式),它们各有不同的用法。 Bridged 桥接模式是与主机…...
【漏洞复现】灵当CRM datapdf.php 任意文件读取漏洞
免责声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删除。本次测试仅供学习使用,如若非法他用,与平台和本文作…...
MySql详细教程-从入门到进阶(超实用)
基础篇 通用语法及分类 DDL: 数据定义语言,用来定义数据库对象(数据库、表、字段)DML: 数据操作语言,用来对数据库表中的数据进行增删改DQL: 数据查询语言,用来查询数据库中表的记录DCL: 数据控制语言,用…...
【C语言练习(17)—输出杨辉三角形】
C语言练习(17) 文章目录 C语言练习(17)前言题目题目解析整体代码 前言 杨辉三角形的输出可以分三步,第一步构建一个三角形、第二步根据规律将三角形内容填写、第三步将三角形以等腰的形式输出 题目 请输出一个十行的…...
服务器压力测试怎么做
在部署任何Web应用程序或服务之前,进行服务器压力测试(也称为负载测试)是确保系统能够处理预期用户流量的关键步骤。通过模拟大量并发请求,可以评估服务器的性能、稳定性和响应时间,识别潜在瓶颈,并优化资源…...
深度学习中的正则化
深度学习中的正则化(regularization)旨在防止过拟合并提高模型对未知数据的泛化能力。正则化是一种通过在给定的训练集上适当地拟合函数并避免过度拟合来减少误差的技术。 通过对模型参数添加约束,正则化鼓励模型学习更简单、更稳健的模式,从而降低其对噪…...
深入了解 React:从入门到高级应用
深入了解 React:从入门到高级应用 React 是由 Facebook 开发并维护的一个开源 JavaScript 库,用于构建用户界面。自2013年发布以来,React 在前端开发领域迅速崛起,成为最受欢迎的 UI 构建工具之一。无论是小型的单页应用…...
华为云环境下LVS/DR架构的故障诊断优化
本文作者:刘涛 文章目录 前言1.LVS/DR集群的问题2.华为云环境3.问题排查3.1 检查LVS/DR模式配置3.1.1 RS服务器3.1.2 DS服务器 3.2 继续分析抓包结果3.2.1 调整tcpdump抓包过滤条件3.2.2 client向集群VIP发包3.2.3 DS服务器arp消息 3.3 查看丢包3.3.1 监控DS和RS服…...
Effective C++ 条款 22:将成员变量声明为 private
文章目录 条款 22:将成员变量声明为 private核心思想示例代码注意事项结论 条款 22:将成员变量声明为 private 核心思想 成员变量的封装性 将成员变量声明为 private 是面向对象设计的重要原则,有助于保持封装性。 为何使用 private&#x…...
ShardingSphere(分库分表)
ShardingSphere 高性能架构模式 读写分离架构: 基本原理是将数据库读写操作分散到不同的节点上,主库负责处理事务性的增删改操作,从库负责处理查询操作。避免由数据更新导致的行锁,来提升性能。 一主一从:可以将查…...
Visual Studio Code(VS Code)配置C/C++环境
一、Visual Studio Code安装 Visual Studio Code,下文中简称为VS Code的详细安装方法请参考VSCode安装教程(超详细)-CSDN博客 二、MinGW编译器下载与配置 1、MinGW介绍 MinGW(Minimalist GNU for Windows)是一款用于Windows 平台的轻…...
使用 OpenCV 在图像中添加文字
在图像处理任务中,我们经常需要将文本添加到图像中。OpenCV 提供了 cv2.putText() 函数,可以很方便地在图像上绘制文本,支持多种字体、颜色、大小和位置等参数。 本文将详细介绍如何使用 OpenCV 在图像中添加文字,介绍 cv2.putTe…...
高校网络安全_网络安全之道
需要对学校的网络进行安全防护,主要有这么几个痛点: 传统本地化产品难以及时更新情报库,应对新型攻击。 近年来,黑客和黑产团伙攻击手 段呈现多样化实战化,除传统僵木蠕外,各类新型、复杂甚至未知威胁高发…...
『大模型笔记』评估大型语言模型的指标:ELO评分,BLEU,困惑度和交叉熵介绍以及举例解释
评估大型语言模型的指标:ELO评分,BLEU,困惑度和交叉熵介绍以及举例解释 文章目录 一. ELO Rating大模型的elo得分如何理解1. Elo评分的基本原理2. 示例说明3. 大模型中的Elo得分总结3个模型之间如何比较计算,给出示例进行解释1. 基本原理扩展到三方2. 示例计算第一场: A A…...
kafka的配置
server.properties server.properties模板 # broker id,多个broker服务器的话,每个broker id必须不同 broker.id1# kafka broker所在节点的 hostnamehostname10.1.1.1.3:9092# 处理网络请求的线程数 num.network.threads 8# 执行磁盘IO的线程数 num.io…...
Linux下Java通过JNI调用C++
以下为Demo流程 1.创建Java文件 public class HelloWord {// 声明本地方法public native void sayHello();static {// 加载本地库System.loadLibrary("hello");}public static void main(String[] args) {new HelloWord().sayHello();} } 2.编译生成.h头文件 在H…...