likes
comments
collection

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

作者站长头像
站长
· 阅读数 15

前言

挂钟大家都知道吧,它通过时针、分针和秒针来表示时间,想当初小学刚开始教怎么看时钟的完全看不懂。今天带大家一步步实现一个类进度条时钟的效果,更直观的知晓当前的时间。

本文将会带大家学到以下知识点:

  1. 垂直水平居中方式
  2. gap 属性搭配 flex 布局 实现等边距
  3. Date 日期函数的使用及注意点
  4. CSS 变量的简单应用
  5. svgcircle 标签的用法
  6. stroke-dashoffset 属性和 stroke-dasharray 属性能够的用法

样式重置

首先老规矩,我们将 CSS 样式重置 ,方便各个浏览器统一展示效果。

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

背景调整

接下来通过添加 min-height: 100vh 属性,将 body 限制为 视口大小 且通过 overflow: hidden 来将 超出部分隐藏

body {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background-color: #2f363e;
}

这里为了将我们的时钟在屏幕中间展示,我们需要使用 flex 布局body 设置为 水平垂直居中 。同样的,小伙伴们还可以使用 light-heighttransform 等手段实现。

时间绘制

接下来我们要准备 4 个 div ,用来作为展示时间的容器。

<body>
    <div id="time">
        <div class="circle">
            <div id="hours">00</div>
        </div>
        <div class="circle">
            <div id="minutes">00</div>
        </div>
        <div class="circle">
            <div id="seconds">00</div>
        </div>
        <div class="ap">
            <div id="ampm">00</div>
        </div>
    </div>
</body>

然后给其宽高。

#time {
    display: flex;
    color: #fff;
}
#time .circle {
    position: relative;
    width: 150px;
    height: 150px;
}

细心的小伙伴一定注意到了这段 CSS 中有个比较特别的属性:gap。这有什么用呢?

我们来看看 MDN 对 gap 属性的描述:

CSS gap 属性是用来设置网格行与列之间的间隙(gutters),该属性是 row-gap 和 column-gap 的简写形式。

gap 属性它适用于 multi-column elements, flex containers, grid containers,也就是多列布局、弹性布局以及网格布局中(知识点++)。因此这里我们用 flex 布局 搭配 gap 是完全行得通的。

我们看看此时的效果如何:

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

我们发现最后一个用来表示上午下午的字体有点大,我们将其调小,同时通过 translateY 属性将该元素偏移 -20px(负数表示向上偏移,正数表示向下偏移),和时间做区分。

#time .ap {
    position: relative;
    font-size: 1em;
    transform: translateY(-20px);
}

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

这样美观了许多,主次分明。

动态时间

接下来我们要让时间变成实时的,因此我们要用到 Javascript 的 Date 函数了。

  1. 通过 getHours() 获取当前小时数。
  2. 通过 getMinutes() 获取当前分钟数。
  3. 通过 getSeconds() 获取当前秒钟数。

这里有个注意点,通过以上三个方法获取的时间值,都是不带前缀 0 的,并且是 number 类型。什么意思呢?

比如现在是下午的 14:07:04 ,通过 getMinutes() 获取的分钟数是 7 而不是 07,同理,通过 getSeconds()getHours() 获取的时间也是如此。

因此为了美观,我们需要手动给 10 以内 的时间值 补一个 0。具体怎么做呢?这里我用到了字符类型的 padStart 方法,它传递两个参数,分别是数字最后要填充到这个指定的位数,以及用来填充的字符。

为了将 7 变成 07,我们需要将 number 类型的 7 变为字符串类型的 '7',然后执行 '7'.padStart(2, 0)。

除此之外,对于 AM 以及 PM 的区分,我们通过判断 getHours() 的返回值是否大等于 12。如果大于则为 PM,否则是 AM。

处理完数据之后通过修改 innerHTML 的值来改变页面上展现的时间,同时通过 setInterval 来不断执行该操作,实现实时更新时间的效果。

<script>
    let hours = document.querySelector('#hours');
    let minutes = document.querySelector('#minutes');
    let seconds = document.querySelector('#seconds');
    let ampm = document.querySelector('#ampm');

    setInterval(() => {
        let h = `${new Date().getHours() % 12}`.padStart(2, 0);
        let m = `${new Date().getMinutes()}`.padStart(2, 0);
        let s = `${new Date().getSeconds()}`.padStart(2, 0);
        let am = h >= 12 ? 'PM' : 'AM';

        hours.innerHTML = h + '\n<div class="tip">HOURS</div>';
        minutes.innerHTML = m + '\n<div class="tip">MINUTES</div>';
        seconds.innerHTML = s + '\n<div class="tip">SECONDS</div>';
        ampm.innerHTML = am;
    }, 1000);
</script>

注意点小结:

  1. getHours、getMinutes 以及 getSeconds 返回 number 类型的值(不带前缀 0)
  2. padStart 是字符类型的方法,注意先将类型转为 string 再进行调用。

我们来看看效果:

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

画圆

接下来我们要对每个时间的容器都画一个圆的效果,这里我使用了 svg 标签。原因下文会提。

有的小伙伴可能对 svg 标签比较陌生,确实平时开发的时候用的比较少,实际上它和我们普通的标签差不多,而且也能用过 CSS 设置它的一些属性。

这里画圆我们需要用到 circle 标签,其中,cxcy 属性共同确定了一个圆心的位置,r 属性表示待绘制圆的半径。

<div id="time">
    <div class="circle" style="--clr: #ff2972">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
        </svg>
        <div id="hours">00</div>
    </div>
    <div class="circle" style="--clr: #fee800">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
        </svg>
        <div id="minutes">00</div>
    </div>
    <div class="circle" style="--clr: #04fc43">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
        </svg>
        <div id="seconds">00</div>
    </div>
</div>

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

可以看到默认情况下,circle 标签的背景色是黑色的,我们给它点样式。

#time .circle svg circle {
    width: 100%;
    height: 100%;
    fill: transparent;
    stroke: #191919;
    stroke-width: 4;
}

fill 属性表示当前填充 circle 标签应当用什么颜色(实际上就是背景色的意思)。

stroke 属性表示绘制一个边线(实际上就是边框)。

stroke-width 属性一般搭配 stroke 属性一起用,表示边线的宽度。

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

经过这么一手修改后已经有模有样了,但是别急,最麻烦的部分要来了。接下来我们要模拟时间进度条了。

模拟进度条

这里我们模拟进度条需要在每个 svg 标签下再添加一个 circle 标签。

<div id="time">
    <div class="circle" style="--clr: #ff2972">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
            <circle cx="70" cy="70" r="70" id="hh"></circle>
        </svg>
        <div id="hours">00</div>
    </div>
    <div class="circle" style="--clr: #fee800">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
            <circle cx="70" cy="70" r="70" id="mm"></circle>
        </svg>
        <div id="minutes">00</div>
    </div>
    <div class="circle" style="--clr: #04fc43">
        <svg>
            <circle cx="70" cy="70" r="70"></circle>
            <circle cx="70" cy="70" r="70" id="ss"></circle>
        </svg>
        <div id="seconds">00</div>
    </div>
</div>

同时,通过 CSS 变量给这个新增的 circle 标签各不相同的颜色。

#time .circle svg circle:nth-child(2) {
    stroke: var(--clr);
}

此时效果如下:

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

接下来我们要用到一个新的属性:stroke-dasharray

我们来看看 MDN 对 stroke-dasharray 属性的介绍:

属性 stroke-dasharray 可控制用来描边的点划线的图案范式。

是不是有点懵,我们看看下面这张动图:

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

这是 stroke-dasharray 属性值从 0 开始不断增加的效果。那我们就知道了,实际上这个属性就是控制点划线的长度用的。

那它和我们的进度条有什么关系呢?

不要急,要实现我们的进度条,还需要另一个属性:stroke-dashoffset

我们来看看 MDN 对 stroke-dashoffset 属性的介绍:

属性 stroke-dashoffset 指定了 dash 模式到路径开始的距离。

话不多说,上图:

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

这是 stroke-dashoffset 属性值从 0 开始不断增加的效果,是不是很像进度条在跑?

我们就是通过 Javascript 动态修改 stroke-dashoffset 来达到进度条跟着时间一起跑的效果!

let hh = document.querySelector('#hh');
let mm = document.querySelector('#mm');
let ss = document.querySelector('#ss');

setInterval(() => {
    ...
    hh.style.strokeDashoffset = 440 - (440 * h) / 12;
    mm.style.strokeDashoffset = 440 - (440 * m) / 60;
    ss.style.strokeDashoffset = 440 - (440 * s) / 60;
}, 1000);

⏰⏰ 手把手实现一个进度条时钟,麻麻再也不用担心我把时间看茬了!

Github 源码地址

juejin-demo/digital-clock-demo at main · catwatermelon/juejin-demo (github.com)

结束语

本文就到此结束了,希望大家共同努力,早日拿下 CSS 💪💪。

如果文中有不对的地方,或是大家有不同的见解,欢迎指出 🙏🙏。

如果大家觉得所有收获,欢迎一键三连💕💕。