如何使用Vue创建一个生动的动画计时器倒计时
了解如何使用 Vue.js 轻松创建说明性和动画计时器倒计时

计时器应用程序无处不在,它们都有其独特的外观和设计。有些人选择简约设计,仅使用文本来指示剩余时间,而另一些人则尝试通过显示缓慢减小的饼形甚至定期播放音频来通知剩余时间,从而更加直观。
这是我们将在本文中构建的那种计时器:

它用长度、文字和颜色表示剩余时间,这使得它非常具有描述性。
我们将使用 Vue,所以设置您的项目,让我们开始吧!
创建定时器环
我们将从使用 svg 元素创建计时器环开始。它将包含一个circle元素,我们将使用它来创建计时器环。圆将绘制在svg容器的中心,半径为 45 像素。
src/components/AppTimer.vue
<模板>
<div classu003d"root">
<svg classu003d"svg" viewBoxu003d"0 0 100 100" xmlnsu003d"http://www.w3.org/2000/svg">
<g 类u003d"圆">
<circle classu003d"time-elapsed-path" cxu003d"50" cyu003d"50" ru003d"45" />
</g>
</svg>
</div>
</模板>
我们将circle元素包装在g元素中,以便我们能够将circle与将在本教程后面添加的其他元素组合在一起。
我们已经创建了基本的 HTML 标记,现在让我们添加将显示环的 CSS。
src/components/AppTimer.vue
...
<风格>
/* 设置容器的高度和宽度 */
。根 {
高度:300px;
宽度:300px;
位置:相对;
}/* 移除会隐藏时间标签的 SVG 样式 */
。圆圈 {
填写:无;
中风:无;
}/* 显示计时器进度的 SVG 路径 */
.time-elapsed-path {
笔画宽度:7px;
中风:#424242;
}
</style>
让我们在App.vue中注册AppTimer组件并显示它:
src/App.vue
<模板>
<应用定时器 />
</template><脚本>
从'./components/AppTimer.vue'导入AppTimer;导出默认{
名称:'应用程序',
成分: {
应用定时器,
},
};
</脚本>
这就是我们现在所拥有的。只是一个基本的戒指。让我们继续前进。

显示定时器标签
创建计时器环后要做的下一件事是显示指示剩余时间的标签。
src/components/AppTimer.vue
<模板>
<div classu003d"root">
...
<div classu003d"time-left-container">
<span classu003d"time-left-label">{{ timeLeftString }}</span>
</div>
</div>
</template><脚本>
导出默认 {
方法: {
padToTwo(数){
// 例如h -> 04
return String(num).padStart(2, '0');
},
},
计算:{
// 例如timeLeft of 100 -> '01:40'
timeLeftString() {
常量 timeLeft u003d this.timeLeft;
常量分钟 u003d Math.floor(timeLeft / 60);
常量秒 u003d timeLeft % 60;
返回 `${this.padToTwo(minutes)}:${this.padToTwo(seconds)}`;
},
剩下的时间() {
返回 this.limit - this.elapsed;
},
},
// 注册要从 App.vue 设置的 props
道具: {
已过:{
类型:数字,
要求:真,
},
限制: {
类型:数字,
要求:真,
},
},
};
</脚本>
...
AppTimer现在有两个道具。elapsed属性将用于设置经过的时间,而limit属性将指定总时间。
timeLeft()是一个计算属性,当elapsed发生变化时会自动更新。
timeLeftString()是另一个计算属性,它将返回一个MM:SS格式的字符串,指示剩余的计时器。每当timeLeft()更改时,它的值就会更新。
让我们将以下 CSS 添加到AppTimer.vue,它将设置标签样式并将其覆盖在计时器环的顶部:
src/components/AppTimer.vue
...
<风格>
...
.time-left-container {
/* 大小应与父容器大小相同 */
身高:继承;
宽度:继承; /* 将容器放在圆环的顶部 */
位置:绝对;
顶部:0; /* 垂直和水平居中内容(标签)*/
显示:弯曲;
对齐项目:居中;
证明内容:中心;
}.time-left-label {
字体大小:70px;
font-family: 'Segoe UI';
颜色:黑色;
}
</style>
让我们设置我们创建的AppTimer道具,来自App.vue:
src/App.vue
<模板>
<AppTimer :elapsedu003d"0" :limitu003d"10" />
</模板>
...
现在我们可以看到标签了。

开启定时器倒计时
如果计时器不能倒计时,它就没有用,让我们添加一些逻辑来启用此功能。
我们将使用状态变量 (timeElapsed) 来跟踪到目前为止以秒为单位的总时间。使用setInterval()方法,我们将每 1000 毫秒(1 秒)将该变量增加 1。我们还将使用clearInterval()方法确保在所有计时器结束后停止常规增量。
所有这些逻辑都将包含在startTimer()方法中。我们将在mounted()挂钩中调用startTimer(),以便在页面加载后立即开始倒计时。
src/App.vue
<模板>
<应用定时器
:elapsedu003d"timeElapsed"
:limitu003d"timeLimit"
/>
</template><脚本>
从'./components/AppTimer.vue'导入AppTimer;导出默认{
名称:'应用程序',
数据() {
返回 {
已用时间:0,
计时器间隔:未定义,
时间限制:10,
};
},
方法: {
开始计时器(){
this.timerInterval u003d setInterval(() u003d> {
// 当没有更多时间时停止计数
if (++this.time Elapsed u003du003du003d this.time 限制) {
clearInterval(this.timerInterval);
}
}, 1000);
},
},
// 立即启动定时器
挂载(){
this.startTimer();
},
成分: {
应用定时器,
},
};
</脚本>
现在我们有了一个功能定时器。

创建定时器进度环
现在我们需要添加一个将动画显示剩余时间的环。我们将为这枚戒指赋予独特的颜色,并将其放在灰色的戒指上。随着时间的流逝,它将动画显示越来越多的灰色环,直到没有时间剩余时只有灰色环可见。
我们将使用路径元素创建环,并使用 CSS 设置样式:
src/components/AppTimer.vue
<模板>
<div classu003d"root">
<svg
类u003d“svg”
视图框u003d"0 0 100 100"
xmlnsu003d"http://www.w3.org/2000/svg"
<g 类u003d"圆">
...
<路径
类u003d“时间左路径”
du003d"
中号 50, 50
米 -45, 0
45,45 0 1,0 90,0
45,45 0 1,0 -90,0
"
</路径>
</g>
</svg>
...
</div>
</template><脚本>
...
</script><样式>
...
.time-left-path {
/* 与原环厚度相同*/
笔画宽度:7px; /* 对路径结尾进行四舍五入 */
中风线帽:圆形; /* 确保动画从圆的顶部开始 */
变换:旋转(90度);
变换原点:中心; /* 一秒与倒数计时器的速度对齐 */
过渡:1s线性全部; /* 为环着色 */
中风:蓝色;
}.svg {
/* 翻转 svg 并使动画从左向右移动 */
变换:scaleX(-1);
}
</style>
所以现在这个蓝色的环覆盖了灰色的环。

为计时器进度环设置动画
为了使圆环动画,我们将使用path的stroke-dasharray属性。
以下是使用不同stroke-dasharray值时戒指的外观:

我们可以看到将stroke-dasharray设置为单个值会创建具有相同长度的短划线(蓝色弧线)和间隙(短划线之间的空间)的模式。stroke-dasharray添加尽可能多的破折号以填充路径的整个长度。
顾名思义,stroke-dasharray也可以取多个值。让我们看看当我们指定两个时会发生什么:

当指定两个值时,第一个值将确定破折号的长度,第二个值将确定间隙的长度。
我们可以使用此行为使蓝色路径可视化剩余时间。为此,首先让我们使用圆周长公式(2πr)计算蓝色路径所形成的圆的总长度:
全路径长度 u003d 2 x π x r u003d 2 x π x 45 u003d 282.6 ≈ 283
因此,为了显示路径的剩余时间,我们将指定两个值,第一个值将从283开始并逐渐减少到0,而第二个值将恒定在283。这确保了始终只有一个破折号和一个间隙,因为283与整个路径一样长。
以下是路径长度随着第一个值的变化而变化的方式:

让我们在我们的代码中实现它:
src/components/AppTimer.vue
<模板>
<div classu003d"root">
<svg
类u003d“svg”
视图框u003d"0 0 100 100"
xmlnsu003d"http://www.w3.org/2000/svg"
<g 类u003d"圆">
...
<路径
类u003d“时间左路径”
v-ifu003d"timeLeft > 0"
du003d"
中号 50, 50
米 -45, 0
45,45 0 1,0 90,0
45,45 0 1,0 -90,0
"
:styleu003d"{ strokeDasharray }"
</路径>
</g>
</svg>
...
</div>
</template><脚本>
导出默认 {
...
计算:{
...
strokeDasharray() {
常数半径 u003d 45;
const totalLength u003d 2 * Math.PI * 半径;
const timeFraction u003d this.timeLeft / this.limit;
const elapsedDash u003d Math.floor(timeFraction * totalLength);
返回 `${elapsedDash} ${totalLength}`;
},
},
...
};
</script><样式>
...
</style>
每当剩余时间发生变化时,我们使用计算属性 (strokeDasharray) 来计算stroke-dasharray属性的新值。
当没有剩余时间时,我们使用v-if完全停止显示蓝色环。
现在,蓝色圆环按照标签显示动画,以指示剩余时间。

但是有一个问题:如果你仔细观察,当计时器到零时,蓝色的环会突然消失。

发生这种情况是因为动画持续时间设置为一秒。当剩余时间的值设置为零时,仍然需要一秒钟才能将蓝色环实际设置为零。
为了解决这个问题,我们可以使用一个公式,每经过一秒,就会将环的长度减少一个额外的量(与动画分开)。让我们修改AppTimer.vue来做到这一点:
src/AppTimer.vue
<模板>
...
</template><脚本>
导出默认 {
...
计算:{
...
strokeDasharray() {
常数半径 u003d 45;
常量总计 u003d 2 * Math.PI * 半径;
const timeFraction u003d this.timeLeft / this.limit;
const adjTimeFraction u003d timeFraction - (1 - timeFraction) / this.limit;
const elapsedDash u003d Math.floor(adjTimeFraction * total);
返回 `${elapsedDash} ${total}`;
},
},
...
};
</script><样式>
...
</style>
现在蓝环在被v-if移除之前被缩小到最后:

创建背景
我们现在完成了计时器,所以我们需要在后台工作。我们将在App.vue中创建并设置它的样式:
src/App.vue
<模板>
<div classu003d"背景">
<div
类u003d“经过”
:styleu003d"{ 高度:'100%',背景颜色:'蓝色'}"
</div>
</div>
<应用定时器
:elapsedu003d"timeElapsed"
:limitu003d"timeLimit"
/>
</template><脚本>
...
</script><样式范围>
。背景 {
高度:100%;
位置:绝对;
顶部:0;
宽度:100%;
显示:弯曲;
弹性方向:列;
证明内容:结束;
背景颜色:黑色;
}.background .elapsed {
/* 对于高度动画 */
过渡:全 1 线性;
}
</style><风格>
html,
身体,
#应用程序 {
高度:100%;
边距:0;
}#app { /* 垂直和水平居中计时器 */
显示:弯曲;
证明内容:中心;
对齐项目:居中;位置:相对;
}
</style>
由于我们将背景颜色设置为蓝色,因此我们需要更改计时器环和计时器标签的颜色以使其保持可见。
我们将使用白色:
src/components/AppTimer.vue
...
<风格>
...
.time-left-label {
...
白颜色;
}.time-left-path {
...
/* 为环着色 */
中风:白色;
}
...
</style>
我们现在可以看到背景:

动画背景
背景很好,但它只是静态的。让我们添加一些代码来随着时间的推移对其高度进行动画处理。
src/App.vue
<模板>
<div classu003d"背景">
<div
类u003d“经过”
:styleu003d"{ 高度:背景高度,背景颜色:'蓝色'}"
v-ifu003d"timeLeft > 0"
</div>
</div>
<应用定时器
:elapsedu003d"timeElapsed"
:limitu003d"timeLimit"
/>
</template><脚本>
...
导出默认 {
...
计算:{
剩下的时间() {
返回 this.timeLimit - this.timeElapsed;
},
时间分数(){
返回 this.time Left / this.time 限制;
},
背景高度(){
const timeFraction u003d this.timeFraction; // 调整时间分数以防止剩余时间滞后
// 为 0,就像我们在剩余进度环中所做的那样
常量 adjTimeFraction u003d
timeFraction - (1 - timeFraction) / this.timeLimit;常量高度 u003d Math.floor(adjTimeFraction * 100);返回 `${height}%`;
},
},
...
};
</脚本>
...
现在我们有了一个背景动画,它作为剩余时间的另一个指标。

在特定时间点更改背景颜色
如果我们也可以使用颜色来指示剩余时间,那就太好了。
我们将使用thresholds数组定义背景颜色发生变化的特定时间点。在倒计时开始时,背景颜色将为蓝色。它将在总时间的 50% 时变为橙色,在总时间的 20% 时变为红色。
src/components/App.vue
...
<脚本>
...
导出默认 {
...
数据() {
返回 {
...
阈值:\ [
{
颜色:“蓝色”,
阈值:1,
},
{
颜色为橙色',
阈值:0.5,
},
{
红色',
阈值:0.2,
},
],
};
},
...
};
</脚本>
...
我们将使用reduce()方法从thresholds数组中获取当前时间的颜色。
src/components/App.vue
<模板>
<div classu003d"背景">
<div
类u003d“经过”
:styleu003d"{ 高度: backgroundHeight, backgroundColor }"
v-ifu003d"timeLeft > 0"
</div>
</div>
...
</template><脚本>
...
导出默认 {
...
计算:{
...
背景颜色() {
返回 this.thresholds.reduce(
(颜色,项目)u003d>
item.threshold >u003d this.timeFraction ? item.color : 颜色,
不明确的
);
},
},
...
};
</脚本>
...
我们完成了!我们有一个功能计时器,可以倒计时并以 4 种不同方式显示剩余时间。

探索这个应用程序的源代码
你可以在 GitHub 上查看这个小程序的完整源代码。
原文发表于:_codingbeautydev.com
JavaScript 所做的每一件疯狂的事
注册并立即免费获得这份引人入胜的指南,了解 JavaScript 的细微警告和鲜为人知的部分。

更多推荐

所有评论(0)