Day02 - JavaScript + CSS Clock

简介:

Day02 - JavaScript + CSS Clock

作者:©liyuechun
简介:JavaScript30Wes Bos 推出的一个 30 天挑战。项目免费提供了 30 个视频教程、30 个挑战的起始文档和 30 个挑战解决方案源代码。目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用。现在你看到的是这系列指南的第 2 篇。完整指南在 从零到壹全栈部落

简介

第二天的练习是用JS+CSS模拟时钟效果。

效果如下:

clock

实现以上模拟时钟的效果,大致思路和解决方案如下:

  • 分别获取到当前时间的时、分、秒。
  • 通过时分秒对一圈360度,进行映射,确定每一个指针所需旋转的角度。
  • 通过CSS的transform:rotate(deg),来实时的调整指针在键盘中的位置。

页面布局

  <div class="clock">
    <div class="clock-face">
      <div class="hand hour-hand"></div>
      <div class="hand min-hand"></div>
      <div class="hand second-hand"></div>
    </div>
  </div>

CSS样式

  <style>
    html {
      background: #018DED url(http://unsplash.it/1500/1000?image=881&blur=50);
      background-size: cover;
      font-family: 'helvetica neue';
      text-align: center;
      font-size: 10px;
    }

    body {
      margin: 0;
      font-size: 2rem;
      display: flex;
      flex: 1;
      min-height: 100vh;
      align-items: center;
    }

    .clock {
      width: 30rem;
      height: 30rem;
      border: 20px solid white;
      border-radius: 50%;
      margin: 50px auto;
      position: relative;
      padding: 2rem;
      box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1),
      inset 0 0 0 3px #EFEFEF,
      inset 0 0 10px black,
      0 0 10px rgba(0, 0, 0, 0.2);
    }

    .clock-face {
      position: relative;
      width: 100%;
      height: 100%;
      transform: translateY(-3px);
      /* account for the height of the clock hands */
    }

    .hand {
      width: 50%;
      height: 6px;
      background: black;
      position: absolute;
      top: 50%;
      transform-origin: 100%;
      transform: rotate(90deg);
      transition: all 0.05s;
      transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
    }
  </style>

涉及到的特性:

  • transform-origin

调整指针的初始位置以及旋转的轴点:transform-oragin

transform-origin: 100%; //初始化使三个指针全部指向12时
  • transform: rotate()

设置旋转角度

  • transition
transition: all 0.05s;//设置动画时间为0.05秒
  • transition-timing-function: cubic-bezier(x, x, x, x)

设置 transition-time-function 的值,以实现秒针“滴答滴答”的效果。此外注意 transform 中的 rotate (旋转)属性由角度来控制,可以试着在页面上修改这个参数来查看效果。

JS代码

  <script>
    const secondHand = document.querySelector('.second-hand');
    const minsHand = document.querySelector('.min-hand');
    const hourHand = document.querySelector('.hour-hand');

    function setDate() {
      const now = new Date();

      const seconds = now.getSeconds();
      const secondsDegrees = ((seconds / 60) * 360) + 90;
      secondHand.style.transform = `rotate(${secondsDegrees}deg)`;

      const mins = now.getMinutes();
      const minsDegrees = ((mins / 60) * 360) + ((seconds / 60) * 6) + 90;
      minsHand.style.transform = `rotate(${minsDegrees}deg)`;

      const hour = now.getHours();
      const hourDegrees = ((hour / 12) * 360) + ((mins / 60) * 30) + 90;
      hourHand.style.transform = `rotate(${hourDegrees}deg)`;
    }

    setInterval(setDate, 1000);

    setDate();
  </script>
  • 获取秒针、分钟、小时节点
    const secondHand = document.querySelector('.second-hand');
    const minsHand = document.querySelector('.min-hand');
    const hourHand = document.querySelector('.hour-hand');
  • 获取当前时间秒、分、小时
const now = new Date();
const seconds = now.getSeconds();
const mins = now.getMinutes();
const hour = now.getHours();
  • 计算秒、分、小时角度
const secondsDegrees = ((seconds / 60) * 360) + 90;
const minsDegrees = ((mins / 60) * 360) + ((seconds / 60) * 6) + 90;
const hourDegrees = ((hour / 12) * 360) + ((mins / 60) * 30) + 90;
  • 根据角度设置样式
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
  • 设置定时器,每秒调用一次setDate函数
setInterval(setDate, 1000);

延伸思考

此处存在一个小瑕疵,当秒针旋转一圈之后回到初始位置,开始第二圈旋转,角度值的变化时 444° → 90° → 96° .... 这个过程中,指针会先逆时针从 444° 旋转至 90°,再继续我们期望的顺时针旋转,由于秒针变换时间只有 0.05s,所以呈现的效果就是秒针闪了一下,如果想要观察细节,可以将 .second 设为 transition: all 1s,效果如下所示:

要解决这个问题,目前找到了两种解决办法:

  • 第一种
  <script>
    const secHand = document.querySelector('.second-hand');
    const minHand = document.querySelector('.min-hand');
    const hourHand = document.querySelector('.hour-hand');

    function setDate() {
      const date = new Date();

      const second = date.getSeconds();
      const secondDeg = (90 + (second / 60) * 360);

      const min = date.getMinutes();
      const minDeg = (90 + (min / 60) * 360);

      const hour = date.getHours();
      const hourDeg = (90 + (hour / 12) * 360 + (min / 12 / 60) * 360); // 加入分钟所占的时间,使时针可以缓慢地移动


      //解决指针跳顿问题【第一种方法】
      //在发生跳顿的角度值处,将 CSS 的 `transition` 属性去掉
      if (secondDeg === 90) {
        secHand.style.transition = 'all 0s';
      } else {
        secHand.style.transition = 'all 0.05s';
      }

      if (minDeg === 90) {
        minHand.style.transition = 'all 0s';
      } else {
        minHand.style.transition = 'all 0.1s';
      }


      secHand.style.transform = `rotate(${ secondDeg }deg)`;
      minHand.style.transform = `rotate(${ minDeg }deg)`;
      hourHand.style.transform = `rotate(${ hourDeg }deg)`;

    }

    setInterval(setDate, 1000);

    setDate();
  </script>
  • 第二种
  <script>
    const secondHand = document.querySelector('.second-hand');
    const minsHand = document.querySelector('.min-hand');
    const hourHand = document.querySelector('.hour-hand');

    let secondDeg = 0;
    let minDeg = 0;
    let hourDeg = 0;

    function initDate() {
      const date = new Date();
      const second = date.getSeconds();
      secondDeg = 90 + (second / 60) * 360;
      const min = date.getMinutes();
      minDeg = 90 + (min / 60) * 360 + ((second / 60) / 60) * 360;
      const hour = date.getHours();
      hourDeg = 90 + (hour / 12) * 360 + ((min / 60) / 12) * 360 + (((second / 60) / 60) / 12) * 360;
    }

    function updateDate() {
      secondDeg += (1 / 60) * 360;
      minDeg += ((1 / 60) / 60) * 360;
      hourDeg += (((1 / 60) / 60) / 12);

      secondHand.style.transform = `rotate(${ secondDeg }deg)`;
      minsHand.style.transform = `rotate(${ minDeg }deg)`;
      hourHand.style.transform = `rotate(${ hourDeg }deg)`;
    }

    initDate();
    setInterval(updateDate, 1000);
  </script>

既然引发问题的是角度的大小变化,那就可以对这个值进行处理。此前的代码中,每秒都会重新 new 一个 Date 对象,用来计算角度值,但如果让这个角度值一直保持增长,也就不会出现逆时针回旋的问题了。

CSS代码优化

.clock-face:after {
  width: 0.2rem;
  height: 0.2rem;
  left: 50%;
  top: 50%;
  position: absolute;
  display: block;
  content: '';
  background-color: #a8c5d1;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1), 0 0 10px rgba(0, 0, 0, 0.2);
  transform: translate(-50%, -50%);
  /*transition: all .05s;*/
}


.second-hand {
  height: 2px;
  margin-top: -1px;
  border-bottom-left-radius: 100%;
  border-top-left-radius: 100%;
  transition: all .05s;
  background-color: red;
}

.hour-hand {
  background-color: yellow;
}

优化后效果:

源码下载

Github Source Code

春哥简介

简介: 资深讲师,全栈工程师;区块链、高可用架构技术爱好者。
个人博客:http://liyuechun.org
新浪微博:黎跃春-追时间的人
github:http://github.com/liyuechun

技术交流

  • 区块链技术交流QQ群:348924182
  • 「区块链部落」官方公众号

相关文章
|
2月前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
14天前
纸屑飘落生日蛋糕场景js+css3动画特效
纸屑飘落生日蛋糕CSS3动画特效是一款js+css3制作的全屏纸屑飘落,生日蛋糕点亮庆祝动画特效。
32 3
|
1月前
|
JavaScript 前端开发
CSS3 动画和 JavaScript 动画的性能比较
具体的性能表现还会受到许多因素的影响,如动画的复杂程度、浏览器的性能、设备的硬件条件等。在实际应用中,需要根据具体情况选择合适的动画技术。
|
1月前
|
前端开发 JavaScript
如何在 JavaScript 中访问和修改 CSS 变量?
【10月更文挑战第28天】通过以上方法,可以在JavaScript中灵活地访问和修改CSS变量,从而实现根据用户交互、页面状态等动态地改变页面样式,为网页添加更多的交互性和动态效果。在实际应用中,可以根据具体的需求和场景选择合适的方法来操作CSS变量。
|
1月前
|
缓存 前端开发 JavaScript
优化CSS和JavaScript加载
优化CSS和JavaScript加载
|
1月前
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
|
1月前
|
缓存 前端开发 JavaScript
优化CSS和JavaScript加载
Next.js和Nuxt.js在优化CSS和JavaScript加载方面提供了多种策略和工具。Next.js通过代码拆分、图片优化和特定的CSS/JavaScript优化措施提升性能;Nuxt.js则通过代码分割、懒加载、预渲染静态页面、Webpack配置和服务端缓存来实现优化。两者均能有效提高应用性能。
|
1月前
|
前端开发 JavaScript
用HTML CSS JS打造企业级官网 —— 源码直接可用
必看!用HTML+CSS+JS打造企业级官网-源码直接可用,文章代码仅用于学习,禁止用于商业
126 1
|
1月前
|
前端开发 JavaScript 安全
HTML+CSS+JS密码灯登录表单
通过结合使用HTML、CSS和JavaScript,我们创建了一个带有密码强度指示器的登录表单。这不仅提高了用户体验,还帮助用户创建更安全的密码。希望本文的详细介绍和代码示例能帮助您在实际项目中实现类似功能,提升网站的安全性和用户友好性。
46 3
|
1月前
|
前端开发 JavaScript UED
如何使用 JavaScript 动态修改 CSS 变量的值?
【10月更文挑战第28天】使用JavaScript动态修改CSS变量的值可以为页面带来更丰富的交互效果和动态样式变化,根据不同的应用场景和需求,可以选择合适的方法来实现CSS变量的动态修改,从而提高页面的灵活性和用户体验。
下一篇
DataWorks