JavaScript CSS3

Javascript 動態網頁程式設計 - 上課教材

動畫互動網頁程式設計 > 課程內容 > 第 08 章 - 時間與時間函數的應用

第 08 章 - 時間與時間函數的應用

上次更新日期 2020/11/02

有時候我們會需要用到時間來展示某些特別的時刻,所以需要取得某個時間點以及目前的時間點,所以,就需要時間物件。 另外,有時候我們會需要使用到計時器,這種功能也需要用到時間函數!這樣你就可以自由的指定時間來循環執行某個事件, 對於網頁程式來說,有時候也是相當重要的!

學習目標:

  1. 了解 DOM 物件,包括使用新增元素的方式
  2. 了解 Date 物件,包括如何計算日期等任務
  3. 學會使用 setInterval 與 setTimeout 函數,進行倒數或者是運動等任務

8.1: DOM 物件

上個章節我們介紹了不少 JavaScript 的物件,而其中我們一直在使用的 document 物件反而沒有詳細談到。 DOM 模型裡面,我們主要是透過 document 這個物件來處理各個元件,而 document 其實還有底下的屬性可用:

屬性說明
.charset目前使用的文字編碼
.characterSet預設的文字編碼
.domain其實就是伺服器的主機名稱 (或領域名稱)
.lastModified此網頁的最後編輯日期與時間
.referrer此文件的來源,意即是從哪一個網頁點擊過來的
.title這個網頁的 title
.URL就是這個網頁的網址

事實上,很多資料似乎在 location 物件裡面可以找到~沒關係,有用的資料越多越好。

例題 8-1-1:使用 for .. in .. 迴圈,列出 document 的屬性
  1. 建立新檔 unit08-1-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-1-1.php 當中,並查閱網頁顯示的狀態。
  3. 建立一個名為 gogo() 的函數,內容以 for ... in 的語法,將 document 的屬性列出來。 可以透過類似『 res = res + "<li>" + i + ":" + document[i] + "</li>"; 』之類的語法來處理。
  4. 最後在 body 載入完畢後,執行 gogo() 函數即可。
document 的屬性內容

同時透過上面的輸出,我們也能知道 document 這個 DOM 的屬性真的很多!包括 getElement... 之類的陣列物件也在這裡面列表, 查一查覺得相當有趣!

  • DOM 的新增/刪除元素功能

先來看看之前我們就玩過的 DOM 物件的幾個常見的方法:

方法說明
.getElementById()使用 id 名稱去取得某個元素的控制權
.getElementsByName()使用 name 名稱去取得某個元素的『陣列』控制權
.getElementsByTagName()使用 HTML 某標籤名稱去取得某個標籤的『陣列』控制權
.getElementsByClassName()使用 HTML 某類別(class)名稱去取得某個類別的『陣列』控制權
屬性說明
.innerHTML修改某元件的內部 HTML 資料,可以涵蓋標籤
.innerText修改某元件的內部資料,不可以涵蓋標籤
.outerHTML修改某元件的 HTML 資料,包括標籤本身資料,也可以涵蓋標籤
.outerText修改某元件的資料,包括標籤本身資料,不含有標籤功能

這幾個玩意兒是我們一直在課堂上玩弄的東西,不過,瞧一瞧,上面的方法,大部分都需要原本就有的一個 ID 或者是標籤等等, 才有辦法去『修改』它,那如果我們需要的是『憑空生出來』的元件呢?可能上頭的方案行不通。這時,就得要有新增元件 (createElement) 的功能! 而且,也需要有『放置該元件到何處 (appendchild)』 的功能才對。這幾個方法大概是:

方法說明
.createElement('tag')新增一個標籤,標籤名稱最好用大寫,例如 P, BUTTON...
.createTextNode('msg')增加一段內容文字,通常搭配上面的方式,來改變某元素的內容
.appendChild('nodename')在這個標籤後新增子標籤
.insertBefore(新元件,舊元件處)在舊元件後面插入新元件
.childNodes()控制該元素的子元素,例如抓取 ul 的 li,為陣列用法
.remove()移除整個元件
.removeChild()移除該元件的某個子元件(通常搭配陣列)
.setAttribute()設定某元素的屬性,例如 setAttribute("type","text")
.execCommand('動作')將某物件進行某動作(加粗、加黑等,通常搭配陣列)
屬性說明
.clientHeight取得/調整元件的高度
.clientWidth取得/調整元件的寬度

基本上,如果要在某個元件上面產生一個新的元件,例如,在某個 div 裡面增加許多圖示,可以這樣做:

var newitem = document.createElement('IMG');		// 建立新標籤,是圖片
newitem.src = 'where/to/find';				// 給予圖片檔名
document.getElementById('where').appendChild(newitem);	// 將圖片在 where 之後新增

現在,利用上面的特徵,讓我們來產生好幾個星星看看:

例題 8-1-2:使用 for 迴圈,搭配 createElement 來建立新的元件
  1. 建立新檔 unit08-1-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-1-2.php 當中,並查閱網頁顯示的狀態。
  3. 這個圖片 加到 images 的目錄去 (可以用其他圖片來取代)
  4. 建立一個名為 gogo() 的函數,開始新增星星的標籤 (tag) 了:
    • 取得 mystar 元件的控制權,變數名稱也取 mystar 好了。
    • 取得 mystar 的高度與寬度,等等用來設計星星所在位置的 X 與 Y 軸。變數取名為 ttx 與 tty 好了。
    • 透過 for 迴圈,建立 10 次的設計 (最終修改為 1000 次)
      • 建立新的 IMG 元件,取名為 star 好了
      • 給予 star 的圖片位置 (src),記得圖片放置到 images 目錄去
      • 設計 x 與 y 的座標位置,例如: Math.floor(Math.random()* ttx)
      • 給予 star 的 style 屬性有: position, width, borderRadius, overflow, left, top 等
      • 最終將這個元件新增到 mystar 裡面去。
  5. 測試結果如果沒有問題,再將星星放大到 1000 個,同時將圖示縮小到大約 5~10px,原形半徑自己設計。 要注意的是, x, y 為單純的數值,得要加上 px 才會是正常的 CSS 單位喔!
  6. 最後在 body 載入完畢後,執行 gogo() 函數即可。
增加 1000 顆星星

你也可以使用 innerHTML 的作法來處理,不過根據強者我同事蔡董大大說,createElement 的作法,要比 innerHTML 來的更加快速! 而且數量越大,感受越明顯!

  • 新增/刪除子元素功能

而除了這些基本的元素之外,如果你想要增加的是類似 input 這種表單的標籤,我們知道這種標籤需要的參數比較多, 例如 type, name 等等,這種屬性的設定,得要使用到 .setAttribute 的功能才行!而如果你的元素資料並沒有設定 name 或者是 id 時, 也可以透過 childNodes 的功能來抓取元素,作為控制的標的!

例題 8-1-3:使用 for 迴圈,增加 INPUT 元素
  1. 建立新檔 unit08-1-3.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-1-3.php 當中,並查閱網頁顯示的狀態。
  3. 開始建立載入網頁就能執行的 gogo() 函數內容-目標是建立四個可輸入興趣的 input 欄位:
    • 取得 myinput 的 ul 控制權,變數名稱也設定為 myinput 即可
    • 開始建立清單項目,使用 for 迴圈,指定設定 0~3 的數值範圍即可,開始迴圈內容設計:
      • 指定一個新的 LI 元素,使用 createElement 處理,元素名稱設為 newitem 好了;
      • newitem 的 innerHTML 撰寫,請參考底下圖示的文字部份處理
      • 增加名為 newinput 的元素,增加的元素為 INPUT 元素
      • 增加 newinput 的屬性 (setAttribute),設定 type 為 text
      • 增加 newinput 的屬性 (setAttribute),設定 name 為 inter
      • 增加 myinput 的子元素為 newitem
      • 增加 newitem 的子元素為 newinput
  4. 上述函數完成後,請先查閱到網頁是否已經呈現 4 個輸入框格?
  5. 開始處理 addli() 函數:
    • 取得 myinput 的控制權
    • 設定變數 oldnum ,這個數值的內容為 myinput 子元素的個數
    • 使用與 gogo 函數相同的方式,新增 newitem 與 newinput,只是增加的時候,給予的個數使用 oldnum 來處理。
  6. 開始處理 delli() 函數:
    • 取得 myinput 的控制權
    • 設定 oldnum 變數,其值為 myinput 子元素個數 -1 個,因為編號從 0 號開始的。
    • 使用 myinput.removeChild 的方式,將最後一個子元素 (myinput.childNodes[oldnum]) 刪除。
新增/刪除子元素 新增/刪除子元素 新增/刪除子元素

透過這種功能,就可以幫使用者在輸入狀況不足或過多的情況下,自行修改 input 的數量了。

8.2: Date 物件

時間函數我們在最前面第二章就稍微談到過,那就是 Date() 這個玩意兒。不過,我們有時候並不是單純的想要知道時間而已, 可能因為時間的判斷,因此需要取得更正確的時間點,包括只取得月份、日期或時間等。更有甚者,我們有時還得要設定一個『時間』, 目的是需要知道新/舊時間的差異!所以,先來理解一下 Date 的物件方法。假設你設定了:

var nowtime = new Date();

那麼常見的取得時間參數的方法有:

方法說明
nowtime.getYear()取得當年的西元年,超過 2000 年就回傳 4 位數,否則回傳 2 位數
nowtime.getFullYear()取得當年的西元年,回傳 4 位數
nowtime.getMonth()取得月份,數值為 0~11,個別代表 1~12 月,這個很怪異!
nowtime.getDate()取得該月的日期,數值為 1~31
nowtime.getDay()取得當週的星期幾,數值為 0~6,代表星期日到星期六
nowtime.getHours()取得當日的小時,數值為 0~23
nowtime.getMinutes()取得分鐘值,數值為 0~59
nowtime.getSeconds()取得秒鐘值,數值為 0~59
nowtime.getMilliseconds()取得千分之一秒值,數值為 0~999
nowtime.getTime()取得自 1970/01/01 開始計算的總計秒數*1000 (就是總毫秒數)
nowtime.getUTCXX()跟上面的語法相同,但取得的是國際標準時間 (UTC) 的資料,非本地資料
nowtime.getUTCFullYear()例如這個是:取得的是國際標準時間 (UTC) 的年份
nowtime.toString()將時間轉成字串直接輸出
nowtime.toLocaleString()回傳某地區的時間
nowtime.toISOString()回傳 ISO 格式的時間字串,結果類似:2020-11-01T08:24:52.029Z

來看看顯示的方法吧:

例題 8-2-1:使用 Date 物件的方法來取得相關的參數
  1. 建立新檔 unit08-2-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-2-1.php 當中,並查閱網頁顯示的狀態。
  3. 建立一個名為 gogo() 的函數,主要內容為:
    • 建立名為 nowd 的時間物件,內容為目前的時間 (new Date())
    • 建立名為 nowtime 的變數,內容為使用 getElementsByName 來取得 nowtime 的控制權
    • 透過一個一個的 nowtime[] 陣列的 innertHML,來設計好所有的輸出。
  4. 最後在 body 載入完畢後,執行 gogo() 函數即可。
Date 方法的使用

JavaScript 在日期的使用上,比較需要注意的其實是月份,因為月份的 1 月份輸出的數值會是 0 !這部份跟我們常用的習慣不太一樣。 第一次接觸時,要特別注意。那另外我們如果需要知道地球上各重要地區的時間,該如何處理?舉例來說,你需要知道日本東京、美國紐約、 美國舊金山、英國倫敦的時間,該如何設計?基本上,就是透過 toLcaleString 來設計即可。例如想要知道目前東京時間, 可以這樣做:

nowtime.toLocaleString('語系',{timeZone:'時區'});
nowtime.toLocaleString('zh-TW',{timeZone:'Asia/Taipei'});
nowtime.toLocaleString('ja',{timeZone:'Asia/Tokyo'});

更多語系、時間等資料,可以參考文末的連結來查詢。來思考一下,如何設計一個你需要知道的時區時間吧:

例題 8-2-2:使用 toLocaleString 的方法,都用台灣語系來顯示不同地區的時間
  1. 建立新檔 unit08-2-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-2-2.php 當中,並查閱網頁顯示的狀態。
  3. 建立一個名為 gogo() 的函數,主要內容為:
    • 建立名為 nowd 的時間物件,內容為目前的時間 (new Date())
    • 建立名為 nowtime 的變數,內容為使用 getElementsByName 來取得 nowtime 的控制權
    • 透過一個一個的 nowtime[] 陣列的 innertHML,來設計好所有的輸出。
  4. 最後在 body 載入完畢後,執行 gogo() 函數即可。
不同地區的時間輸出格式
  • 計算經過幾日後的日期

許多時候我們可能會遇到,再過幾天之後,會是幾月幾號禮拜幾的情境。舉例來說,我們在模擬數值模式,通常會模擬個 15 天類似這樣。 那請問 15 天之後,是幾月幾號禮拜幾呢?基本上,你應該需要這樣處理的:

var mydate = new Date();
mydate.setDate(mydate.getDate()+15);
mydate.toISOString().substring(0,10);
mydate.getDay();
例題 8-2-3:使用上述方法來取得未來日期
  1. 建立新檔 unit08-2-3.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-2-3.php 當中,並查閱網頁顯示的狀態。
  3. 事先宣告全域變數,名稱為 nowd,內容就是新的時間物件
  4. 建立一個名為 gogo() 的函數,主要內容為:
    • 取得 dnum 的 value 值,記得需要轉成整數
    • 以上述方法取得 dnum 之後的時間,然後分別取得 ISO 格式的日期,以及星期幾的條件
    • 將結果輸出到 show 的 id 物件中。
計算經過多少時間之後的日期
  • 倒數計算時間

有參加過馬拉松,或者是某些競賽的朋友都知道,在官方網站都會有列出一個還剩下多少時間的倒數時間器。 要取得倒數時間,就得要有兩個時間參數才行!那如何設定新的時間而不是目前的時間呢? 既然有所謂的 get[xx] 函數,例如 getDate(),那自然就有 setDate() 之類的函數啊!沒錯! 剛剛你看到的一堆 getDate() 函數,將 get 改成 set 就是設定新時間函數了。而其中還有一個很簡單的設計方式, 那就是透過 Date() 函數,例如設定時間為 2020/11/11 的 8:00 時,可以這樣做:

var newd = new Date(  年, 月, 日,時,分);
var newd = new Date(2020, 10, 11, 8, 0);

那要如何計算時間?最簡單的方法就是透過 getTime() 函數!因為這個函數會計算從 1970/01/01 0:00 總計來的毫秒數, 所以,兩者的毫秒數量相減,再分別去計算日子,就可以搞定了!例如底下這樣:

var t1 = new Date( 2020, 11, 11,  8, 0).getTime() / 1000;
var t2 = new Date( 2021,  1,  5, 15, 15).getTime() / 1000;
showd = Math.floor( (t2-t1) / (24*60*60) );
showh = Math.floor( (t2 - (t1 + showd*24*60*60))/ 3600 );
showm = Math.floor( (t2 - (t1+ showd*24*60*60+ showh*3600) )/60 );
shows = t2 - ( t1+ showd*24*60*60+ showh*3600 + showm*60);
res.innerHTML = showd + '天' + showh + '時' + showm + '分' + shows + '秒' ;
例題 8-2-4:使用上述方法開始倒數日期
  1. 建立新檔 unit08-2-4.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-2-4.php 當中,並查閱網頁顯示的狀態。
  3. 建立一個名為 gogo() 的函數,主要內容為:
    • 取得 myform 的元素控制權
    • 取得目前的西元年
    • 進入 for 迴圈,簡單的設計類似『mynew = mynew + '<option value="' + i + '">' + i + '</option>';』的內容, 但是西元年只會列出今年到 3 年後的日期而已。
    • 同上,但是列出 12 個月份,比較重要的是, javascript 的月份數值 (value) 會 -1 喔!
    • 同上,但是列出 31 天。
    • 最終將結果放入到所屬的 select 的 value 當中即可得到下拉式選單。
  4. 建立一個名為 shome() 的函數,內容將上面的程式碼抓下來,更改需要的項目來處理即可。
倒數日期的計算

8.3: 間隔時間的應用 setTimeout() 與 setInterval()

很多時候我們會需要動到時間參數,其中一個很重要的功能,就是每隔多少時間需要重新執行某一個函數的概念! 舉例來說,8.2 我們提到的倒數計時,每次都要自己刷新,實在很不合理~如果系統能夠自動每秒鐘更新一次, 那就太完美了。基本上,執行這個程式的範本有兩個常見的函數,大概是這樣做的:

// 方法一,每隔一段時間去進行
var timer = setInterval('func()',milliseconds);
function func() {
	....
}
function mystop() {
	clearInterval(timer);
}

// 方法二,延遲一段時間去進行
var timer = setTimeout('func()',milliseconds);
function func() {
	....
}
function mystop() {
	clearTimeout(timer);
}

基本上, setTimeout 是只會進行一次,而 setInterval 則是持續進行,因此,我們會比較常用 setInterval 這個物件來進行相關的持續運作行為。 舉例來說,如果我想要每 0.01 秒就跑一次『碼表』的設計時,可以參考底下的範例來看看:

例題 8-3-1:設計網頁碼表功能
  1. 建立新檔 unit08-3-1.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-3-1.php 當中,並查閱網頁顯示的狀態。
  3. 未來都會用到碼表的 timer 功能,因此,直接指定一個全域變數,直接以 var timer 指定即可,不須給予內容。
  4. 建立名為 tstart() 函數,內容指定 timer (不能宣告,直接指定) 會每 10 毫秒執行一次 gogo() 函數。
  5. 建立名為 gogo() 函數,內容是:
    • 分別定義 hh, mm, ss, ms 四個變數,內容分別是個別的 id 元件
    • 分別定義 h1, m1, s1, s2 四個變數,內容為上述四個元件的 innerHTML 轉成整數後的數值
    • 讓 s2 = s2 + 1
    • 判斷 s2 是否等於 60,若是的話,s2 等於 0 且 s1 = s1 +1 (秒數 +1 的意思)
    • 讓 ms 的 innerHTML 等於新的 s2
    • 判斷 s1 是否等於 60,若是的話, s1 等於 0 ,且 m1 = m1 +1 (分數 +1 的意思)
    • 讓 ss 的 innerHTML 等於新的 s1
    • 判斷 m1 是否等於 60,若是的話, m1 等於 0 ,且 h1 = h1 +1 (小時數 +1 的意思)
    • 讓 mm 的 innerHTML 等於新的 m1
    • 讓 hh 的 innerHTML 等於新的 h1
    • 注:如果要讓資料呈現好看的兩位數,應該加上一個函數,可以自動家讓 0 的函數來處理,會比較好!
  6. 建立名為 tstop() 函數,內容主要就是 clearInterval 而已!
  7. 建立名為 treset() 函數,內容除了 clear Interval 之外,也會將 hh, mm, ss, ms 歸零。
碼表計數器

既然碼表計數器沒有問題,那麼倒數計時的功能就沒有問題了!

例題 8-3-2:時間倒數功能
  1. 將 unit08-2-4.php 另存新檔 unit08-3-2.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 在 script 最上方增加 timer 為全域變數
  3. 將 showme 函數名稱改為 mygogo() 函數名稱。
  4. 撰寫新的 showme() 函數,內容為:
    • 先執行一次 mygogo();
    • 設定每 1000 毫秒執行一次 mygogo() 函數
  5. 修改舊的 mygogo() 函數內容,在函數的最後面增加一個條件判斷式:
    • 若 t2 <= t1 ,則代表現在的日期 (t1) 已經比較未來,因此顯示 '時間到期了' 的字樣
    • 清除 timer
圖示與 8-2-4 沒有什麼差異,只是數值會開始每秒跑動一次就是了!
  • 跑馬燈的淡出淡入功能

網頁設計課程曾經使用到 CSS 動畫調整三張圖片的淡出淡入功能,而這裡我們既然已經談到了 serInterval 這個好用的東西, 那麼能不能拿他來設計隨機計算圖片的功能呢?因為可以使用隨機指令,加上可以取得陣列的數量,因此就不需要考量圖片張數, 讓系統自動算就可以了!設計方式很簡單:

例題 8-3-3:設計標題圖片的隨機變換功能
  1. 建立新檔 unit08-3-3.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 隨意下載三個圖片檔案,這三個檔案最好尺寸相同。但是也不要太大!檔名假設為 8-3-3a.jpg, 8-3-3b.jpg, 8-3-3c.jpg
  3. 這個檔案內容 加到 unit08-3-3.php 當中,並查閱網頁顯示的狀態。
  4. 設計名為 gogo() 的函數,這個函數主要在:更換圖片檔名的功能:
    • 先取得 myfig 元素的控制權,取名為 myfig 變數名稱即可
    • 進入 while 迴圈,條件判斷設定為 true,此迴圈目的在判斷亂數取得的檔名是否與原有的圖片重複, 若重複就重新隨機找檔名一次,直到找到不同的檔名為止。
      • 使用 Math.floor( Math.random()* myfigs.length ) 找出需要的圖片陣列索引值 (本例為 0~2)
      • 設定 newfig = myfigs[myindex] 之類的方式,設計好新的檔名資料
      • 使用 myfig.src.split('/').reverse()[0] 找出現有的圖片檔名,只需要檔名即可,變數名假設為 oldfig
      • 判斷上面兩者是否相同,若不同,則 break。
      • 設計 check++ ,這個數值若大於 100 的話 (判斷 100 次了),就跳開 (避免迴圈跑不完)
    • 將 myfig.src 的檔名改成新的檔名
  5. 設計名為 mymain() 的函數,這個函數的主要目的在循環播放隨機圖片:
    • 設計 timer 為每 3 秒執行一次 gogo() 函數功能。

單獨顯示照片很突兀的,那麼能不能拿他來設計淡出淡入的功能呢?可以透過循環或者是亂數的方法來呈現淡出淡入幻燈片的功能。 那該如何設計呢?基本上,需要用到底下的 setTimeout 方法:

// 透過一個名為 fun1() 的函數,進行 timeout 設計的範例!很重要!不要向外呼叫!
function fun1() {
	if ( some conditions ) {
		setTimeout(function() {
			some programs;
			fun1()'
		}, timestep );
	}
}

基本設計的想法是:

  • 先讓原有的圖片淡出、這個時間可能需要使用到 setTimeout 功能
  • 淡出完畢之後,才呼叫下一個更換圖片的函數
  • 更換圖片完畢後,開始透過淡入的功能,將圖片呈現到網頁上。
  • 等待一段時間,回到第一步反覆執行。

跟剛剛上面的作法不會差太多,但是需要多兩個函數,而且,這三個函數之間是有相依性的,一個呼叫一個,而不是直接在主程式裡面運作。 這一點需要相當注意喔!否則就可能會失敗!

例題 8-3-4:設計標題圖片的隨機變換功能-加上淡出淡入特效
  1. 將 unit08-3-3.php 另存新檔為 unit08-3-4.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 設計名為 gogoout() 的函數,這個函數目的在進行圖片的淡出功能:
    • 事先取得 myfig 的元素控制權,變數名稱設定為 myfig 即可
    • 取得原本的濾鏡值,亦即 myfig.style.opacity 這個數值,並請轉成『浮點數』,不是整數喔!因為 opacity 的數值為 0~1 之間而已。 0 為全透明, 1 為全不透明。
    • 如果原本的濾鏡值大於 0 時,就開始進入淡出的特效,開始設定 setTimeout ( function() { .... }, 10 ); 的功能
      • 設定新的濾鏡值為『 舊的 - 1/50 』
      • 給予 myfig.style.opacity 新的濾鏡值
      • 重複執行 gogoout() 函數 (就是重新執行自己!於是程式碼就在自己的函數間進行!)
    • 若原本的濾鏡值不是大於 0 (就是用 else 處理的情境),就呼叫之前的 gogo() 函數,去變更圖片檔名。
  3. 修改 gogo() 變更圖片的函數:其實只要在最後一行呼叫淡入函數即可。亦即在最後一行增加 gogoin() 的執行即可。
  4. 設計名為 gogoin() 的函數,內容是進行新照片的淡入效果,基本上,跟 gogoout() 函數幾乎一模一樣, 但是 (1)條件判斷為舊的濾鏡值是否小於 1, (2)若小於 1 ,就進行 setTimeout 運作, (3)新的濾鏡值為 +1/50, (4)重複執行的函數是自己 gogoin()。
  5. 修改名為 mymain() 的函數,要注意,第一個被主動呼叫的函數應該要改為 gogoout() 才對!
    • 設計 myfig.style.opacity 預設值為 1 ,若沒有設定,這個數值會是空值,會導致淡出淡入的失敗。
    • 修改 setInterval 的執行函數,並將時間放大到 3000 毫秒進行一次。

你會發現系統開始進行淡出淡入的照片處理,如果要加快、放慢整個淡出淡入的效果,就更改 gogoin 與 gogoout 的新濾鏡數值變更幅度 (1/50),即可更改!

  • 繞圈圈的圖示

有時候,我們可能會製作一些可以在某個方塊裡面運動的小圖示,修改小圖示的位置其實很簡單,就透過 object.style.top 與 object.style.left 來修改即可。 但是,我們有時候得先要知道外層方塊的大小與內層方塊的大小,這樣才有辦法進行各項基本設定的,否則,會讓內部框框超出外部啊!

例題 8-3-5:設計小方塊會在大方塊裡面,沿著圍牆四處走動
  1. 建立新檔 unit08-3-5.php,並在 index.php 裡面加上相關的超連結,target 指向 js 視窗。
  2. 這個檔案內容 加到 unit08-3-5.php 當中,並查閱網頁顯示的狀態。
  3. 預計要取得許多共用變數,因此需要訂定全域變數,變數名稱大致與外層寬高、內層寬高的設計有關。
  4. 設計載入系統就取得的共用資料,使用 mymain() 函數處理: (注意,因為是全域變數,所以只能設定不能宣告!)
    • 取得 myblock, mycar, res 等元素的控制權
    • 取得 myblock 的寬度與高度,使用的方式為 myblock.clientWidth 等方法。
    • 取得 mycar 的寬度與高度
    • 注意,上面的四個寬度與高度,需要轉成整數喔!
    • 設計 timer 為每隔 10 毫秒運行一次 gogo() 函數。
  5. 設計名為 gogo() 的函數,這個函數主要在取得實際的 mycar 元素位置,然後根據該位置給予修訂任務
    • 設定 mycar 能走得最大寬度為 myblock 寬度 - mycar 寬度
    • 設定 mycar 能走得最大高度為 myblock 高度 - mycar 高度
    • 取得目前的 mycar x 定位點 (mycar.style.left)
    • 取得目前的 mycar y 定位點
    • 測試 x 與 y ,如果是非數值, (isNaN) 的話,就直接設定為 0 即可。
    • 進入上方水平運動:如果 y 小於等於 0 ,那 y 直接設定為 0,且 x 會加 2 個像素;
    • 進入右方垂直運動:如果 x 大於等於 maxw ,那 x 直接設定為 maxw,且 y 會加 2 個像素;
    • 進入下方水平運動:如果 y 大於等於 maxh ,那 y 直接設定為 maxh,且 x 會減 2 個像素;
    • 進入左方垂直運動:如果 x 小於等於 0 ,那 x 直接設定為 0 ,且 y 會減 2 個像素;
    • 設定 mycar 最新的 left 為 x + "px" 數值
    • 設定 mycar 最新的 top 為 y + "px" 數值
    • 讓 res.innerHTML 顯示出方塊寬高、車子寬高、最大寬高、目前車子座標
車子方塊的移動

8.4: 課後作業

  • 8-4-1、搭配萬聖節,製作出滿街的殭屍圖片

參考例題 8-1-2 的設計方式,建立一個滿版的或半滿版樣式的方塊,將自己取得的不能有侵權的殭屍圖示 (也可以自製), 讓使用者自己選擇殭屍數量,但數量不能超過 500 個,然後讓殭屍產生在畫面中。除了不同的位置之外,請盡量使用遠近 (放大與縮小), 旋轉等功能 (參考 transform),最終情境有點像底下這樣:

作業簡單示意圖
  • 8-4-2、搭配畫面美化,建立倒數 1 小時 2 分的畫面

以例題 8-3-2 為範本,當你進入到 8-x-2.php 時,程式會主動算出 01:02 (時:分) 的未來時間,未來時間的算法參考 8-2-3 的方式。 然後透過 UI 的設計,讓倒數版面黏在瀏覽器的右上角,並持續開始倒數。若時間到達 0 的時候,就顯示『倒數結束』的字樣即可。

另外,你需要注意的是,我們在 8-3-2 題當中,抓取的是『日期』而已,這個題目只需要用到『 01:02 (小時:分)』而已, 所以,你需要額外撰寫取得的小時、分鐘、秒鐘資料,才有辦法進入倒數的畫面,否則都會一直出現時間到了喔!要注意!要注意!

作業簡單示意圖
  • 8-4-3、車子隨便移動的狀態

模仿 8-3-5 例題的設計方式,只是,當你算出最大可移動的範圍 (0~maxw, 0~maxh) 之後,隨機計算一個座標點,然後再透過類似 setTimeout 函數的作法,讓車子方塊移動到該定位點,之後再往下一個定位點移動。因此,這個車子方塊會在裡面亂跑!這就是隨機處理的方式。

8.5: 參考資料