如何使用原生技術寫一個倒數計時時鐘

Mike617發表於2018-09-04

apple_time

A countdown clock

心血來潮,想做一個蘋果釋出會的倒數計時

訪問地址

frontend.wang

備用地址

barnett617.github.io/apple_time

Fork me on github

github.com/barnett617/…

前言

本網站基於github pages服務進行展示

過程

步驟如下:

  1. 首先,網頁標題來個標誌性的蘋果圖示

如何為網站新增圖示:

在<head>標籤中新增<link rel="shortcut icon" href="favicon.ico">,其會從專案根目錄找favicon.ico檔案

rel表示將要引用的資源型別,href表示指向資源的URL, <link rel="shortcut icon" href="favicon.ico">中 rel="shortcut icon"是一種固定寫法,不寫或錯寫會導致圖示無法正常顯示。

  1. 主體佈局

背景

如果要背景鋪滿螢幕,來一個漸變色要怎麼做呢

首先,為什麼要用漸變,因為好看啊

其次,為什麼漸變不用PS做的圖片,因為CSS3提供了gradients屬性,通過CSS實現其實漸變是由瀏覽器生成的,可以減少下載的事件和寬頻的使用

既然漸變是瀏覽器生成的,就會涉及到不同瀏覽器的支援問題(Safari、Opera、Firefox等)

另外,漸變的方式分為兩種:線性漸變(Linear Gradients)徑向漸變(Radial Gradients),顧名思義,線性漸變是從一個起點沿著一個方向從一種顏色漸變成另一種顏色,而徑向漸變是從一個起點沿著一個角度漸變

線性:linear-gradient

徑向:radial-gradient

其引數對於不同的瀏覽器有著不同的寫法,但基本都是在配置漸變方向和漸變首末的顏色

從上到下(預設)

background: -webkit-linear-gradient(red, blue); /* Safari 5.1 - 6.0 */
background: -o-linear-gradient(red, blue); /* Opera 11.1 - 12.0 */
background: -moz-linear-gradient(red, blue); /* Firefox 3.6 - 15 */
background: linear-gradient(red, blue); /* 標準的語法 */
複製程式碼

從左到右

background: -webkit-linear-gradient(left, red , blue); /* Safari 5.1 - 6.0 */
background: -o-linear-gradient(right, red, blue); /* Opera 11.1 - 12.0 */
background: -moz-linear-gradient(right, red, blue); /* Firefox 3.6 - 15 */
background: linear-gradient(to right, red , blue); /* 標準的語法 */
複製程式碼

左上角到右下角

background: -webkit-linear-gradient(left top, red , blue); /* Safari 5.1 - 6.0 */
background: -o-linear-gradient(bottom right, red, blue); /* Opera 11.1 - 12.0 */
background: -moz-linear-gradient(bottom right, red, blue); /* Firefox 3.6 - 15 */
background: linear-gradient(to bottom right, red , blue); /* 標準的語法 */
複製程式碼

注意:Internet Explorer 9 及之前的版本不支援漸變

上面的是指定方向,也可以指定角度,如下:

background-image: linear-gradient(to top, #7A88FF, #7AFFAF);
/* 等價 */
background-image:linear-gradient(0deg, #7A88FF, #7AFFAF);
複製程式碼

角度指的是過渡在哪個方向截止,瀏覽器會繪製一條經過元素中心點的假想線。指定的角度就是這條線的角度,同時還指明過度在哪裡結束

0deg 表示元素的頂邊 to top
90deg 表示元素的右邊 to right
180deg 表示元素的底邊 to bottom
270deg 表示元素的左邊 to left

角度解釋圖

如果仍然無法理解角度如何用,這裡有一個線上演示

除此,透明度(transparent)使用

CSS3 漸變也支援透明度(transparent),可用於建立減弱變淡的效果。

可使用 rgba() 函式來定義顏色結點。rgba() 函式中的最後一個引數可以是從 0 到 1 的值,它定義了顏色的透明度:0 表示完全透明,1 表示完全不透明。

如下為從左側完全透明的紅色到右側完全不透明的紅色

background: -webkit-linear-gradient(left,rgba(255,0,0,0),rgba(255,0,0,1)); /* Safari 5.1 - 6 */
background: -o-linear-gradient(right,rgba(255,0,0,0),rgba(255,0,0,1)); /* Opera 11.1 - 12*/
background: -moz-linear-gradient(right,rgba(255,0,0,0),rgba(255,0,0,1)); /* Firefox 3.6 - 15*/
background: linear-gradient(to right, rgba(255,0,0,0), rgba(255,0,0,1)); /* 標準的語法 */
複製程式碼

以上都是線性漸變

接下來是徑向漸變

radial-gradient(center, shape size, start-color, ..., last-color);
複製程式碼

若不指定前面的引數,只指明顏色,則按照預設情況對顏色進行均勻分佈

可以根據需求新增任意多個顏色。額外新增的顏色叫色標(color stop)

新增色標後,背景會從第一個顏色過渡到第二個顏色,再從第二個顏色過渡到第三個顏色,直到漸變的最後一個顏色為止。瀏覽器會平均分佈各個顏色

background: -webkit-radial-gradient(red, green, blue); /* Safari 5.1 - 6.0 */
background: -o-radial-gradient(red, green, blue); /* Opera 11.6 - 12.0 */
background: -moz-radial-gradient(red, green, blue); /* Firefox 3.6 - 15 */
background: radial-gradient(red, green, blue); /* 標準的語法 */
複製程式碼

如下為背景色從左到右開始漸變,最左邊是玫紅,在元素寬度20%的位置變成青色,80%的位置變成黃色,最後是藍色。

linear-gradient(to right, #E94E65, #15A892 20%, #A89215 80%, #1574A8);
複製程式碼

使用多色漸變時,第一個顏色和最後一個顏色無需指定位置,因為瀏覽器會嘉定第一個顏色從0%的位置開始,最後一個顏色在100%的位置結束。除非想把第一個顏色或最後一個顏色的位置放在指定的位置開始,才需要專門定位。

若想顏色不均勻分佈,可手動對顏色增加權重

background: -webkit-radial-gradient(red 5%, green 15%, blue 60%); /* Safari 5.1 - 6.0 */
background: -o-radial-gradient(red 5%, green 15%, blue 60%); /* Opera 11.6 - 12.0 */
background: -moz-radial-gradient(red 5%, green 15%, blue 60%); /* Firefox 3.6 - 15 */
background: radial-gradient(red 5%, green 15%, blue 60%); /* 標準的語法 */
複製程式碼

shape 引數定義了形狀。它可以是值 circle 或 ellipse。其中,circle 表示圓形,ellipse 表示橢圓形。預設值是 ellipse。

background: -webkit-radial-gradient(circle, red, yellow, green); /* Safari 5.1 - 6.0 */
background: -o-radial-gradient(circle, red, yellow, green); /* Opera 11.6 - 12.0 */
background: -moz-radial-gradient(circle, red, yellow, green); /* Firefox 3.6 - 15 */
background: radial-gradient(circle, red, yellow, green); /* 標準的語法 */
複製程式碼

repeating-radial-gradient() 函式用於重複徑向漸變

/* Safari 5.1 - 6.0 */
background: -webkit-repeating-radial-gradient(red, yellow 10%, green 15%);
/* Opera 11.6 - 12.0 */
background: -o-repeating-radial-gradient(red, yellow 10%, green 15%);
/* Firefox 3.6 - 15 */
background: -moz-repeating-radial-gradient(red, yellow 10%, green 15%);
/* 標準的語法 */
background: repeating-radial-gradient(red, yellow 10%, green 15%);
複製程式碼

佈局

需要文字內容水平垂直居中,這就涉及到一個老生常談的問題

一開始隨手一加,使用flex佈局

<body>
  <div class="container">
    <span>倒數計時</span>
  </div>
</body>
複製程式碼
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}
複製程式碼

發現效果並不理想,只水平居中了,垂直方向並沒有居中

這裡犯了一個flex佈局的理解錯誤,對某個元素進行flex的設定,將影響其子元素,而不是其本身的佈局,所以這裡其實想container這一級水平垂直居中,那麼display: flex;應該加在它的父級,即body的屬性上

而在body上加過多的樣式不是理想的做法,我們是想以 container 為頁面根級,所以在其上加flex佈局,然後將其子元素達到居中的效果,那麼要讓 container 作為頁面根級,則需要其鋪滿螢幕,這裡需要做一些樣式設計。

首先,發現 container 並未鋪滿螢幕,即元素沒有貼邊瀏覽器,這是因為body有一個預設外邊距,會隨著不同的瀏覽器有著不同的行為,所以即使 container 高度和寬度100%貼著body,也無法佔滿螢幕,這就是為什麼要對css作全域性初始樣式,重置其預設樣式

body {
    display: block;
    margin: 8px;
}
複製程式碼

需要在body上進行重置

button, p, pre {
    margin: 0;
}
複製程式碼

另外,要讓漸變色的背景鋪滿螢幕,這裡採用了對html和body元素設定高度100%,從而達到自適應,背景總佔滿螢幕的效果

html, body {
  width: 100%;
  height: 100%;
}
body {
  background-image: linear-gradient(45deg, #7A88FF, #7AFFAF);
}
複製程式碼

倒數計時

接下來,需要一個定時器來展示倒數計時

這裡結束時間從簡處理,即使用(後續可優化為目標時間從目標網站中獲取)

思路

倒數計時即是要計算剩餘時間,即目標時間的時間戳減去當下時間的時間戳來做一個格式化顯示,因為當下時間是實時變化的,所以並不需要做特殊處理,只要用目標時間戳(常量) - 當前時間(變數)便可得到倒數計時應該顯示的剩餘時間

這裡國際化是重點

首先來看一下 js 提供的當地時間(根據瀏覽器所設地區顯示相應時間)方法

new Date().toLocaleString()
// "2018/9/4 下午5:04:02"
new Date().toLocaleDateString()
// "2018/9/4"
new Date().toLocaleTimeString()
// "下午5:04:21"
複製程式碼

這是 js i18n程式提供的時間格式化方法

Date物件是js原生時間庫,以1970年1月1日00:00:00作為起點

Date物件作為普通函式直接呼叫會返回代表當前時間的字串(無論是否傳遞引數)

Date()
// "Tue Sep 04 2018 17:23:42 GMT+0800 (中國標準時間)"
Date('2018-08-08')
// "Tue Sep 04 2018 17:23:55 GMT+0800 (中國標準時間)"
Date(2018, 08, 08)
// "Tue Sep 04 2018 17:24:05 GMT+0800 (中國標準時間)"
複製程式碼

Date作為建構函式時,使用new返回一個Date物件例項

new Date()
// Tue Sep 04 2018 17:25:49 GMT+0800 (中國標準時間)
new Date('2018-08-08')
// Wed Aug 08 2018 08:00:00 GMT+0800 (中國標準時間)
new Date(2018, 08, 08)
// Sat Sep 08 2018 00:00:00 GMT+0800 (中國標準時間)
複製程式碼

*** 特殊地

普通物件求值,都預設呼叫其valueOf()方法,而Date例項求值,預設呼叫toString()方法

var a = 'hello'
a
// "hello"
a.valueOf()
// "hello"
a.toString()
// "hello"

var b = 3
b
// 3
b.valueOf()
// 3
b.toString()
// "3"

var c = new Date()
c
// Tue Sep 04 2018 17:31:30 GMT+0800 (中國標準時間)
c.valueOf()
// 1536053490129
c.toString()
// "Tue Sep 04 2018 17:31:30 GMT+0800 (中國標準時間)"
複製程式碼

使用Date建構函式生產日期例項可傳遞各種型別的引數

new Date().valueOf()
// 1536053659322

// 引數為時間零點開始計算的毫秒數
new Date(1536053659322)
// Tue Sep 04 2018 17:34:19 GMT+0800 (中國標準時間)

// 引數為日期字串
new Date('Sep 4, 2018')
// Tue Sep 04 2018 00:00:00 GMT+0800 (中國標準時間)

new Date('Oct 4, 2018')
// Thu Oct 04 2018 00:00:00 GMT+0800 (中國標準時間)

new Date('Oct 4, 2018, 08:59:59')
// Thu Oct 04 2018 08:59:59 GMT+0800 (中國標準時間)

new Date('Oct 4, 2018, 08:61:59')
// Invalid Date

// 引數為多個整數
// 代表年、月、日、小時、分鐘、秒、毫秒
new Date(2018, 10, 23, 6, 34, 59, 500)
// Fri Nov 23 2018 06:34:59 GMT+0800 (中國標準時間)

new Date('Fri Nov 23 2018 06:34:59')
// Fri Nov 23 2018 06:34:59 GMT+0800 (中國標準時間)
new Date('Fri Nov 23 2018 06:34:59').valueOf()
// 1542926099000
複製程式碼

既然這樣,那麼Date()構造方法的引數都可以是什麼格式的呢?

答:任何可以被Date.parse()方法解析的字串

注意點

  1. 引數可以是負整數,代表1970年元旦之前的時間

  2. 引數為多個整數時,至少需要兩個引數,即年和月,若只傳遞一個引數,將按照毫秒數處理

  3. 引數取值範圍

年:使用四位數年份,比如2000。如果寫成兩位數或個位數,則加上1900,即10代表1910年。如果是負數,表示公元前

月:0表示一月,依次類推,11表示12月

日:1到31

小時:0到23

分鐘:0到59

秒:0到59

毫秒:0到999
複製程式碼
  1. 引數如果超出了正常範圍,會被自動折算

  2. 引數只有一個時,使用負整數表示1970年元旦之前的時間,引數為多個整數時,使用負整數表示從基準日扣去相應的時間

new Date(-1542926099000)
// Wed Feb 09 1921 09:25:01 GMT+0800 (中國標準時間)

new Date(2018, 09, -1)
// Sat Sep 29 2018 00:00:00 GMT+0800 (中國標準時間)
new Date(2018, 0)
Mon Jan 01 2018 00:00:00 GMT+0800 (中國標準時間)
new Date(2018, 0, -1)
Sat Dec 30 2017 00:00:00 GMT+0800 (中國標準時間)
new Date(2018, 1, -1)
Tue Jan 30 2018 00:00:00 GMT+0800 (中國標準時間)
new Date(2018, 1)
Thu Feb 01 2018 00:00:00 GMT+0800 (中國標準時間)
複製程式碼

留個疑問,如何求明年的昨天,比如,現在是Tue Sep 04 2018 18:04:58 GMT+0800 (中國標準時間),明年的昨天即是Wed Sep 03 2019 18:04:58 GMT+0800 (中國標準時間),有好的方法可以提PR,

此處的目標時間如下:

2018 年 9 月 12 日上午 10 點(北京時間 9 月 13 日凌晨 1 點)
複製程式碼

後記

沒想到最終呈現出來這麼簡單的一個頁面竟涉及到這麼多東西,而且每一個環節都可以細究到很多深層次的東西,這就是web的世界

補充

使用vscode+搜狗輸入法編輯本md檔案上傳至github後發現隱藏字元,形如:

出現隱藏字元情況再現圖片

查得原因

在mac版vscode的中文輸入法下,按下任意字母,出現中文候選後按刪除鍵,刪除完剛才輸入的字母再按刪除會出現這個控制字元

mac版的vscode中這個隱藏字元預設隱藏,可通過修改如下配置開啟,將文件中顯示BS的退格符全域性搜尋並替換為空即可

//控制編輯器是否應呈現控制字元
"editor.renderControlCharacters": true
複製程式碼

原理解析:BS為ASCII碼中的退格符的Unicode表示法,而所有ASCII控制字元都有一個圖形外觀

參考連結:

jianshu-【CSS】漸變背景

runoob-CSS3 漸變

oschina-介紹 JavaScript 國際化 API

JavaScript 標準參考教程(alpha)之Date

segmentfault-JavaScript 時間與日期處理實戰:你肯定被坑過

runoob-jquery

jianshu-如何優雅的選擇字型

相關文章