---
# System prepended metadata

title: 新手 JS 地下城- 2F 時鐘
tags: [JS地下城]

---

# 新手 JS 地下城- 2F 時鐘
###### tags: `JS地下城`


## 思路歷程

1. 指針該轉幾度？
    1. 時鐘有12小時、60分鐘、60秒
    2. 每次秒針動一格，360度/60秒=旋轉6度
    3. 每次分針動一格，也等於旋轉6度
    4. 時針因為只要動12格，每一格間距比較大，所以在分針走時候，時針也要微微的朝下一格前進，分針走一格=時針走360度/12格/60分=旋轉0.5度。

2. 時間跟指針的關聯性？
    如果說現在時間是 3 : 15 : 30 的話
    1. 時針的旋轉角度：
    ((360/12格)x 3小時) ＋ (0.5度 x 15分) =97.5度
    2. 分針的旋轉角度：
    15 x 6 = 90度
    3. 秒針的旋轉角度：
    30 x 6 = 180度
    
3. 取得現在時間的語法：`getDate()`
4. 取得現在時間之後，用`transform: rotate();`旋轉指針的角度
5. 每秒更新的語法：`setTimeout()` 或 `setInterval()`

## 過程
### 首先先取得現在的時間
`getDate()`這個語法我只在jQuery的套件中有看到，沒實際使用過，所以我先研究如何用`getDate()`取得我要的資料。

因為是時鐘，沒有需要顯示年月日，所以我所需要取得的資訊有：時、分、秒。

`getDate()`其實是JS Date的取值方法之一，撈出來的是日期，要用之前得要先定義一個變數為`new Date();`，之後才能從中間撈出你要的時間資料。
```javascript=
var now = new Date();
console.log(now.getDate());//回傳今天日期
```
而我需要取得的值分別為：
* 時：`getHours()`
* 分：`getMinutes()`
* 秒：`getSeconds()`

到此，這個程式架構已經明朗化，所以我打算先刻時鐘的外觀，再來把程式碼套進去驗證結果。

### 大概刻一下時鐘外觀
時鐘的主要架構有：外殼、刻度、時針、分針、秒針，這些都要靠`position: absolute;`去堆疊，而且為了要讓大家都置中，指針的部分又要用`transform: rotate();`去旋轉，所以我將置中的寫法，從我比較常用的

```css=
transform: translate(-50%,-50%);
top: 50%;
left: 50%;
```

改成

```css=
transform-origin: center;
top: 0;
left: 0;
```
### JS初步驗證(還不會每秒更新)
我把除了「刻度」之外的部分都刻好之後，就先跑去寫JS的部分，細刻這種事情，等到都確認邏輯沒問題之後再來修。

總之先把指針的DOM元素都抓起來
```javascript=
var hourPointer = document.querySelector('.hour');
var minutePointer = document.querySelector('.minute');
var secondPointer = document.querySelector('.second');
```
然後來測測看旋轉指針有沒有作用
```javascript=
hourPointer.style.transform = "rotate(7deg)";
```
再來測測看指針的角度能不能另外用變數帶入
```javascript=
var hourAngle = 10;
hourPointer.style.transform = `rotate(${angel}deg)`;
```

把「時間」跟「角度」的相互關係運算式，套用進去看看
```javascript=
var hourAngle = (now.getHours() * (360/12))+(now.getMinutes() * (360/12/60));
var minuteAngle = now.getMinutes() * (360/60);
var secondAngle = now.getSeconds() * (360/60);
hourPointer.style.transform = `rotate(${hourAngle}deg)`;
minutePointer.style.transform = `rotate(${minuteAngle}deg)`;
secondPointer.style.transform = `rotate(${secondAngle}deg)`;
```
看起來是沒有問題，只是在console的時候，我發現`getHours()`撈出來原來是24小時制呢。

不過不影響運算結果，我這邊就不特別轉成12小時制了。

### 讓時鐘動起來(每秒更新)
接下來就要進入到重頭戲了，`setTimeout()` 我比較常看到，雖然原理沒有很熟， `setInterval()`就沒看過了，我打算先研究一下這兩者的差別，再來看看我想要用哪種。

#### setTimeout()
網頁載入後或某個function執行後，過了指定秒數之後，執行一次
寫法如下：
```javascript=
setTimeout(function(){ 
    alert("Hello"); 
}, 3000);
// setTimeout( [ 要做什麼 ] , 秒數 );
```
#### setInterval()
網頁載入後或某個function執行後，每間隔指定秒數，執行
是一種會重複執行的語法
寫法如下：
```javascript=
setInterval(function(){ 
    alert("Hello"); 
}, 3000);
// setInterval( [ 要做什麼 ] , 秒數 );
```

看起來`setInterval()`比較符合我的需求

接下來把取得現在時間的功能打包成一個function
```javascript=
function nowTime() {
  hourPointer.style.transform = `rotate(${hourAngle}deg)`;
  minutePointer.style.transform = `rotate(${minuteAngle}deg)`;
  secondPointer.style.transform = `rotate(${secondAngle}deg)`;
}
```
然後用`setInterval()`每秒更新一次
```javascript=
setInterval(function () {
  nowTime();
}, 1000);
```

結果不會動？！Why~~

原來`var now = new Date();`抓到一次之後就丟著不管了，不會因為我每次撈取他都幫我再抓一次現在的時間，所以只好把整組都包進function中

## 最終程式碼如下：

```javascript=
function nowTime() {
  var now = new Date();
// console.log(now.getDate());
var hourPointer = document.querySelector(".hour");
var minutePointer = document.querySelector(".minute");
var secondPointer = document.querySelector(".second");
var hourAngle =
  now.getHours() * (360 / 12) + now.getMinutes() * (360 / 12 / 60);
var minuteAngle = now.getMinutes() * (360 / 60);
var secondAngle = now.getSeconds() * (360 / 60);
  hourPointer.style.transform = `rotate(${hourAngle}deg)`;
  minutePointer.style.transform = `rotate(${minuteAngle}deg)`;
  secondPointer.style.transform = `rotate(${secondAngle}deg)`;
}

setInterval(function () {
  nowTime();
}, 1000);

```

只是看起來要經過很多流程，好像有點蠢，也許未來有機會學得更深的時候，再來把他優化吧.....

## codepen

<iframe height="265" style="width: 100%;" scrolling="no" title="時鐘" src="https://codepen.io/joy-cheng/embed/YzNggmg?height=265&theme-id=dark&default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href='https://codepen.io/joy-cheng/pen/YzNggmg'>時鐘</a> by Joy Cheng
  (<a href='https://codepen.io/joy-cheng'>@joy-cheng</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>