0%

JavaScript-CSS-with-Js-Clock-02

02 - JavaScript CSS with Js Clock

這次做這個作品的時間相對01 Drum Kit 快上許多,不是因為花了更多時間,
而是寫程式的能力真的是累積的,超級有感QQ,
從上一篇跳出error 都不知道是什麼問題,到處google要google什麼,

到現在可以直接google自己要的東西,真的是差非常多,
雖然還是有很多東西還是要先google他可能是什麼,
像是readme **關於語法** 提到的IIFE 只會執行一次,一開始根本不曉得是什麼原理,
就只能google為什麼function裡面的function只會執行一次 想當然的當然什麼東西都查不到XD,
就只能去看看有沒有別人寫過一樣的東西,他們用了什麼方法成功執行程式,
看看自己跟別人不一樣的地方在哪裡,
慢慢一段一段改,終於找到原因是什麼,就可以好好google了~
過程真的很花時間,但這次全部自己刻畫面,自己寫html終於不是模仿別人怎麼寫的了,
所以用故意用不一樣的圖片,讓他真的是自己生出來的孩子,
當秒針好好前進的時候,真的有一種說不出的感動,無法闔上的嘴角相信初學者自己做一次也可以體驗到的,


做完這個作品的時候剛好是星期五的下班後。
大家都下班了自己留下來試試看,終於完成後看到還有一個加班的前端工程師,
就去關心他一下,順便讓前輩指引一下我的人生道路,

1
2
3
4
5
6
問著: 你是怎麼變成這麼強的工程師?
: 哪裡強,我超廢 只懂一點點JS, CSS也爛到不行,會架構而已。
: 怎麼可能,我覺得你們每一個人都超強的。
: 他說上班就是這樣,做一堆垃圾的事情,差不多都是重複的,你來做個一個月你也可以學會,但不好玩就是了,你現在的能力來面試我們前端啊,一定可以的!
: 不過我還是建議你去當後端拉,比較好玩一點,錢也比較多。
: 原來我在他的眼裡已經是一個可以通過面試的人,也可能是他人太善良,所以安慰我的話。

我說著: 我覺得所有東西都要好好學的很扎實, css要懂一些很炫的animation ,html要可以在腦中就直覺得刻出來, JS要很精通

1
2
: 但你沒有時間啊,沒有時間什麼都學會,沒有時間什麼都精通,該是時間決定一下自己要的方向了,想想自己要點的技能樹。
: 我真的要好好想一想,總不可能一直用比別人多一倍的時間去努力吧,這樣的人生好像也真的只剩下技能了。

最近真的面臨到一些問題,覺得自己好像花太多時間在練習這些基礎能力上,
雖然還是有好好的運動,但真的跟還是大學生的時候差了很多,
半夜也是會覺得有點孤單,
剛好在做這次的作品的時候感冒了,開始省思自己到底要的是什麼,
是不是在別人眼裡的我還是一個剛畢業的24歲小鬼,
看不清自己的人生方向,到處詢問前輩的意見,
一點主見都沒有,

主題

用JS與CSS搭配製作一個實時的時鐘效果。

步驟

Step1. 製作時針、分針、秒針

利用classhand樣式來表現出時分秒針的樣式

Step2. 設定定時器

利用 setInterval(setDate, 1000);每秒取得當前時間

Step3. 利用當前時間來取得對應角度

將每秒取得的時間在setData裡面取出,並計算出對應角度
再透過element.style.tranform來變更CSS效果,產生位移的感覺。

Javascript語法&備註

let & const

對於ES6新增的區域變數宣告與常數宣告
我知道的是const需要的是一開始就指定值,且不可再被指定
但在之前的經驗裡,function內我還是會放let來做變數的宣告,
實際上若該值不會再被變動,應該是用const做宣告比較好的。

Date()

取得時間的函數,一定要搭配new來使用new Date()
date.getSeconds():取得當前秒
date.getMinutes():取得當前分鐘
date.getHours():取得當前小時
setDate(date):設置當前時間對應的每個月的幾號(1-31),返回改變後時間(毫秒)。
setFullYear(year):設置四位年份。
setHours(hour):設置小時(0-23)。
setMilliseconds():設置毫秒(0-999)。
setMinutes(min):設置分鐘(0-59)。
setMonth(month):設置月份(0-11)。
setSeconds(sec):設置秒(0-59)。
setTime(milliseconds):設置毫秒時間。


有了這些應該可以做出所有跟時間有關的功能了。

setInterval()

定時器,有兩個參數setInterval(callback, time)
第一個是要執行的function,第二個是時間(毫秒)

關於語法

一開始我用IIFE來攥寫setInterval(callback, time) 但發現他只會執行一次
Ex:

1
2
3
4
5
6
7
8
9
10
11
12
13
(function(){
function setClock(){
const aaa = new Date()
}
setInterval(setClock(), 1000)
})
```javascript
發現這樣不行
所以將`setInterval(setClock(), 1000)` 改寫成一個function()
EX:
```javascript
function (setInterval(){
setClock()}, 1000)

這樣就可以解決問題了
但還是覺得不用IIFE 程式碼看起來更漂亮直覺一點

CSS語法&備註

transform-origin

變形的軸心,預設為物件的中心點,
在這個範例中,設定為100%(right)可以使其從時鐘面的中心點開始旋轉。

transform:rotate()

旋轉物件,數值後方要加上角度deg
可超過360度,正值為順時針轉,負值為逆時針旋轉。

transition-timing-function: cubic-bezier()

設定動畫轉場所依據的貝茲曲線,可以透過chrome的開發者工具來進行可視化調整。
由於原作有使用故補充w3schools

參閱:MDN-transform

探索

轉了個角度,調了點指針

為了要讓指針從12點方向(0點)開始計算,
作者將指針.hand都加上了rotate(90deg)來轉,
並在計算時間的function內最終結果也都+90,
我是改成將每一根只真額外寫.hand-second, .hand-mintue, .hand-hour
這樣在計算時就不用+90,可以用最大360來做計算了。

再用上述的transform-origin :bottom 將指針都定位在最上方
這樣就可以像一個正常的運轉的時鐘了 ~~

transform:rotate的彈跳問題

作者最後有提到一個小問題,若指針在354度切到0度時,
會使指針往前彈回去,這是因為有使用transtion,在角度做切換時會加上的動畫效果,
354→0度會認為是往前,而非轉一圈回到起點,所以動畫先往前轉到0。
為了避免這個反彈的怪現象,我加上了一個function來處理角度

1
2
3
4
5
6
7
8
function setRotate(deg) {
if (deg === 0) {
document.querySelector('.hand').style.transition = 'all 0s';
} else {
document.querySelector('.hand').style.transition = 'all 0.05s';
}
return `rotate(${deg}deg)`;
}

當計算角度為0時,把動畫效果關閉,這樣就可以避免了!

因為整個東西都是自己想出來的所以沒有遇到這個問題QQ
附上原作的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>JavaScript30 - 02 - JS and CSS Clock | Gua's Note</title>
<script src="ga.js"></script>
</head>

<body>
<style>
.GuaHsu-header {
background-color: #333;
text-align: center;
padding: 10px;
color: #7ff3cb;
font-size: 20px;
font-weight: 100;
}
.GuaHsu-header span{
margin: 0 5px;
}
.GuaHsu-header a{
text-decoration: none;
color: unset;
}
</style>
<div class="GuaHsu-header">
<span><a href="https://guahsu.io/categories/JavaScript30/" target="_blank">JavaScript30 心得</a></span>
<span>|</span>
<span><a href="https://github.com/guahsu/JavaScript30" target="_blank">GitHub</a></span>
</div>

<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>


<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 */
transform: rotate(90deg);
/*add*/
}

.hand {
width: 50%;
background: black;
position: absolute;
top: 50%;
transform-origin: 100%;
transform: rotate(90deg);
transition: all 0.05s;
transition-timing-function: cubic-bezier(0.35, 2.65, 1, 1);
border-radius: 50%;
/*add*/
}
/*add*/

.second-hand {
height: 2px;
background: #c11f1f;
}

.min-hand {
height: 4px;
width: 45%;
margin-left: 5%;
background: black;
}

.hour-hand {
height: 6px;
width: 35%;
margin-left: 15%;
background: black;
}
</style>

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

function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const mins = now.getMinutes();
const hour = now.getHours();
let secondsDegress = ((seconds / 60) * 360);
secondHand.style.transform = setRotate(secondsDegress);

let minsDegress = ((mins / 60) * 360);
minHand.style.transform = setRotate(minsDegress);

let hourDegress = ((hour / 12) * 360) + ((mins / 12 / 60) * 360);
hourHand.style.transform = setRotate(hourDegress);
}

//GuaHsu 若傳入角度為0,則不顯示動畫效果避免354~0的rotate反彈跳
function setRotate(deg) {
if (deg === 0) {
document.querySelector('.hand').style.transition = 'all 0s';
} else {
document.querySelector('.hand').style.transition = 'all 0.05s';
}
return `rotate(${deg}deg)`;
}

setInterval(setDate, 1000);

</script>
</body>

</html>

[DEMO]