#11. Color theme switcher + Clock(原生JS版)

#11. 白天/夜间模式切换+时钟显示

这次作品的灵感是来自这个dribbble
CodePen:
https://codepen.io/zyrxdkoz/pen/dyRWKZM

实作逻辑

clock部分

  1. 在一个div当中切出时针、分针、秒针、中心位置(包含外圈和圆心)。
  2. 运用trasform rotate方法转动上时钟元件。
  3. 运用date API取出所有时间单位,带入2.的css属性来渲染

色彩模式切换

  1. 在root建立css变数
  2. 运用dom api在中加上class选择器'dark',看是否要套用dark mode的css变数。

让我们来看程序码(值得特别注意的地方会加上备注):

Html部分

<!DOCTYPE html>
// 会在html加上dark选择器
<html lang="en">
  <head>
    // 略
  </head>
  <body>

    <button class="toggle">Dark mode</button>

    <div class="clock-container">
    // 就跟真正的时钟一样有不同的元件。
      <div class="clock">
        <div class="needle hour"></div>
        <div class="needle minute"></div>
        <div class="needle second"></div>
        <div class="center-point"></div>
      </div>

      <div class="time"></div>
      <div class="date"></div>
    </div>

    <script src="script.js"></script>
  </body>
</html>

CSS部分 (节录部分)


:root {
  --primary-color: #000;
  --secondary-color: #fff;
}

html {
  transition: all 0.5s ease-in;
}

html.dark {
  --primary-color: #fff;
  --secondary-color: #333;
  background-color: #111;
  color: var(--primary-color);
}

.clock-container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}

.clock {
  position: relative;
  width: 200px;
  height: 200px;
}

.needle {
  background-color: var(--primary-color);
  position: absolute;
  top: 50%;
  left: 50%;
  height: 65px;
  width: 3px;
  // 设定元素变化的原点:底部中间位置
  transform-origin: bottom center;
  transition: all 0.5s ease-in;
}
// 运用trasform属性控制指针的定位和旋转行为
.needle.hour {
  transform: translate(-50%, -100%) rotate(0deg);
}

.needle.minute {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
}

.needle.second {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
  background-color: #e74c3c;
}

// 指针中心
.center-point {
  background-color: #e74c3c;
  width: 10px;
  height: 10px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

// 用伪元素做出时钟的中心部件(会依照色彩模式变换颜色)
.center-point::after {
  content: '';
  background-color: var(--primary-color);
  width: 5px;
  height: 5px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

Javascript部分

const hourEl = document.querySelector('.hour')
const minuteEl = document.querySelector('.minute')
const secondEl = document.querySelector('.second')
const timeEl = document.querySelector('.time')
const dateEl = document.querySelector('.date')
const toggle = document.querySelector('.toggle')

const days = [
  'Sunday',
  // 略
]
const months = [
  'Jan',
  // 略
  'Dec',
]

// 白天/夜晚模式切换,单纯用classList的remove、add来实现
toggle.addEventListener('click', (e) => {
  const html = document.querySelector('html')
  if (html.classList.contains('dark')) {
    html.classList.remove('dark')
    e.target.innerHTML = 'Dark mode'
  } else {
    html.classList.add('dark')
    e.target.innerHTML = 'Light mode'
  }
})

// 这个函式可以在一个范围内划定要跑的阶数。
const scale = (num, in_min, in_max, out_min, out_max) => {
  return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}

function setTime() {
  // 用new运算子建立一个Date物件,
  const time = new Date()
  const month = time.getMonth()
  const day = time.getDay()
  const date = time.getDate()
  const hours = time.getHours()
  // 让小时单位为12小时制
  const hoursForClock = hours >= 13 ? hours % 12 : hours
  const minutes = time.getMinutes()
  const seconds = time.getSeconds()
  // 显示PM或AM
  const ampm = hours >= 12 ? 'PM' : 'AM'
  
  // 以下时针、分针、秒针都带入scale函式来rotate。
  hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    hoursForClock, // 参考的数值
    0,  // 参考数值的变化范围(最小)
    12, // 参考数值的变化范围(最大)
    0, // 输出数值的变化范围(最小)
    360 // 输出数值的变化范围(最大)
  )}deg)`
  
  minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    minutes,
    0,
    60,
    0,
    360
  )}deg)`
  
  secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    seconds,
    0,
    60,
    0,
    360
  )}deg)`

  // 让分钟单位的显示为十进位,1 => 01
  timeEl.innerHTML = `${hoursForClock}:${
    minutes < 10 ? `0${minutes}` : minutes
  } ${ampm}`
  
  dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}

setTime()

// 每一秒钟执行一次setTime函式,启动时钟。
setInterval(setTime, 1000)


<<:  10. 解释 AJAX 的工作原理(XMLHttpRequest)

>>:  每个人都该学的30个Python技巧|技巧 12:终止回圈咒语—break及continue(字幕、衬乐、练习)

Day_06 无线转有线

了解完套件更新的地方後,再回来玩其他的网路架构。依照day04的架构,严格说来树梅派wifi连上的其...

【没钱买ps,PyQt自己写】Day 3 - 用 pyinstaller 将 python 程序打包,把每天的成果分享给你的亲朋好友

看完这篇文章你会得到的成果图 因为 PyQt5 要学的东西太多, 我们先来学打包 python 好了...

C# 入门之正则表达式匹配并替换

好久没有更新了,最近比较忙,不过今天遇到一个很有意思的问题,就过来记录一下。 通过正则表达式匹配文本...

qrcode 的 generate和decode(python)

generate: import qrcode import argparse def make_q...

Day 21:工作术

前言 工作术不只是工作上,还有自己想做的事情,目的都是在一样的时间内做更多事情,且挤出更多时间。 聪...