JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用课程,课程主打 No Frameworks
、No Compilers
、No Libraries
、No Boilerplate
在30天的30部教学影片里,建立30个JavaScript的有趣小东西。
另外,Wes Bos 也很无私地在 Github 上公开了所有 JS 30 课程的程序码,有兴趣的话可以去 fork 或下载。
透过 JavaScript 的 Date 物件分别取得"时"、"分"、"秒"并计算出在圆上的相对应角度,最後搭配 CSS 的 transform
和 transition
属性,制作出一个简易的时钟。
由最外层的"clock"部分包住内层的"clock-face"和其内部的"时针"、"分针"、"秒针",形成一个完整的巢状结构。
<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>
首先,将物件 transform
的基准点,更改为最右端。接着,将所有指针都预先固定在12点钟方向。最後,透过 transition
属性还有 transition-timing-function
属性,分别调整 CSS animation 效果变化速度和做出指针移动时的弹跳效果。
.hand {
width: 50%;
height: 6px;
background: black;
position: absolute;
top: 50%;
/*以下是影片中教学的部分*/
transform-origin: 100%; /*改变 transform 的 x-axis*/
transform: rotate(90deg); /*初始位置从12点钟出发*/
transition: all 0.05s; /*调整 CSS animation 变动的速度*/
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}
transform
预设是以物件中心作为平移、旋转、缩放、倾斜时的基准点。详细内容见此
transition timing function
,可用来定义转场发生的时间曲线,以四个参数的贝兹曲线代表。详细内容见此
首先,分别取得代表"时针"、"分针"、"秒针"的标签。
/*JS*/
const secondHand = document.querySelector('.second-hand');
const minsHand = document.querySelector('.min-hand')
const hourHand = document.querySelector('.hour-hand')
建立 Date
物件,取得"时"、"分"、"秒"的资料,以此算出所应旋转的角度(注意,角度必须加上早先设定的90度,才会是正确的),之後分别调整 CSS 的 transform
属性。
最後用 setInterval()
方法,设定每1000毫秒(1秒)就执行 setDate()
方法一次,藉此动态改变 rotate
的值。
(时针、分针、秒针的原理都一样,只是在角度计算上有所差异)
/*JS*/
function setDate(){
const now = new Date();
/*时针、分针、秒针的原理都一样*/
const seconds = now.getSeconds();
const secondsDegrees = ((seconds/60)*360) + 90;/*旋转的角度要加上预设的90度*/
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
}
setInterval(setDate,1000)
分别设定完"时针"、"分针"、"秒针"後,setDate()
方法如下。
/*JS*/
function setDate(){
const now = new Date();
/*时针、分针、秒针的原理都一样*/
const seconds = now.getSeconds()
const secondsDegrees = ((seconds/60)*360) + 90;/*旋转的角度要加上预设的90度*/
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
const minsDegrees = ((mins/60)*360) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hours = now.getHours();
const hoursDegrees = ((hours/12)*360) + 90;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}
以上都完成後,一个简单的时钟就出现了。但仔细一看就会发现指针在某个时间点会突然倒转一圈。
举"秒针"为例,在59秒~0秒之间,数值上的角度会从444度变为90度(分针也是如此),整整倒转354度接近一圈,这就解释了为什麽指针会有突然倒转的现象。
而我们可以分别记录时针和分针所走的圈数,并将原来计算出的度数加上360度*圈数,解决指针倒转的问题。
用 if 判断到 0 秒(分)时,就将圈数加1。
var secRound = 0; /*纪录秒针所走圈数*/
var minRound = 0; /*纪录秒针所走圈数*/
function setDate(){
const now = new Date();
/*时针、分针、秒针的原理都一样*/
const seconds = now.getSeconds()
if(seconds == 0){/*避免回弹*/
secRound += 1;
}
const secondsDegrees = ((seconds/60)*360) + 360*secRound + 90;/*旋转的角度要加上预设的90度*/
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
if(mins == 0){/*避免回弹*/
minRound += 1;
}
const minsDegrees = ((mins/60)*360) + 360*minRound + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hours = now.getHours();
const hoursDegrees = ((hours/12)*360) + 90;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
}
最後的最後,我们还可以让指针的位置更加精准。一般而言,秒针每走一格,分针应该跟着移动一点,同理时针也是如此。
对分针而言移动每过一分钟移动6度,我们可以用 (秒数/60)*6,算出实际上每过一秒钟,分针应该要跟着移动多少度。
对时针而言移动每过一小时移动30度,我们可以用 (分钟数/60)*30,算出实际上每过一分钟,时针应该要跟着移动多少度。
const mins = now.getMinutes();
if(mins == 0){/*避免回弹*/
minRound += 1;
}
const minsDegrees = ((mins/60)*360) + 360*minRound + ((seconds/60)*6) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hours = now.getHours();
const hoursDegrees = ((hours/12)*360) + ((mins/60)*30) + 90;
hourHand.style.transform = `rotate(${hoursDegrees}deg)`;
rotate(${hoursDegrees}deg)
是 ES6 Template literals
的写法。
详细介绍 Template literals
<<: Day 1 - JavaScript 的变数与基本资料型态
曾就「资讯本身的破坏」和「资讯或资讯系统获取或使用中断」进行了辩论。然而,FISMA和FIPS 19...
前言 将这 30 天的资料做成目录,并简单说明内容,方便查找 纪录一下 系列目录 HTML 与 CS...
linebot 结合网路爬虫 讲解完网路爬虫的实际应用後,接下来将他跟 Line chatbot 进...
Youtube 影片 : 影片介绍如何使用 dotnet cli 打包 .net 开发程序,建立单一...
在前面元件以及生命周期的章节中我们提过 render() 这个方法,而且有特别指出它是在 Clas...