前言
網頁前端程式本質上是一種事件驅動 (event-driven) 程式。當網頁載入時,不會馬上執行程式,而是載入相關的事件處理器 (event handler)。待網站使用者和網頁互動時,觸發特定事件 (event),網頁程式才進行相對應的行為。本文介紹在網頁程式中處理頁面事件的方式。
偵測文件完全載入事件
文件完全載入事件 (DOMContentLoaded event) 對於網頁前端程式是重要的時間點。因為我們會確認網頁完全載入後才掛上相關的事件處理器,確保事件處理器都有順利掛上特定網頁元素。參考以下範例程式:
document.addEventListener("DOMContentLoaded", function () {
// Implement code here.
});
以程式設計的觀點來說,我們會將程式碼寫在回呼函式 (callback) 中。JavaScript 在本質上是函數式程式語言,這種寫法在 JavaScript 很常見,寫一陣子就會習慣。
偵測視窗完全載入事件
視窗完全載入事件 (Window: load event) 是在網頁所有的資料 (網頁、CSS 樣式表、JavaScript 命令稿、圖檔和其他靜態資源) 都載入後才觸發的事件。這個時間點對網頁程式就沒那麼重要。如果需要在這個時間點觸發一些程式,可參考以下範例程式:
window.onload(function () {
// Implement code here.
});
同樣地,我們會把程式寫在回呼函式中。
偵測視窗大小改變事件
視窗大小改變事件 (Window: resize event) 是在瀏覽器視窗的大小改變時所觸發的事件。這個事件的程式通常是用來調整使用者介面。參考以下範例程式:
window.addEventListener('resize', function () {
// Implement code here.
});
由於行動裝置上的瀏覽器不能改變視窗大小,所以這個事件的重要性相對沒那麼高。通常是為了桌面瀏覽器去寫此事件的事件處理器。
偵測按鈕事件
按鈕事件 (click event) 是事件處理器中相對單純的,所以會拿來當成學習寫事件處理器的練習對象。在本範例程式中,我們寫一個會轉換按鈕顏色的按鈕事件處理器。參考以下範例程式:
document.addEventListener("DOMContentLoaded", function() {
(function () {
let clicked = false;
let btn = document.getElementById('btn');
btn.addEventListener("click", function () {
if (!clicked) {
btn.style.backgroundColor = 'slateblue';
clicked = true;
}
else {
btn.style.backgroundColor = 'slategray';
clicked = false;
}
});
})();
});
如同前文所述,我們會把整個程式碼包在文件完全載入事件的回呼函式中,確保事件處理器能順利掛在按鈕上。
由於顏色轉換是二元的 (binary) 狀態,我們在此範例程式中使用 clicked
做為旗標,用來確認目前按鈕的狀態。在每次按按鈕時,clicked
的值會在 true
和 false
間切換,我們在程式中就相對應地更動按鈕風格。
為了保護變數 clicked
,我們用 IIFE 模式把變數包起來,以免後續的程式修改到此變數。
用 JavaScript 程式觸發按鈕事件
在先前的程式中,我們寫的是事件處理器。但我們也可以直接用 JavaScript 去觸發一些事件,像是用 HTMLElement.click() 函式直接模擬按按鈕的動作。
在以下範例程式中,我們用 JavaScript 去觸發某個超連結:
document.getElementById('download').click();
其效果等同於網站使用者去按下該超連結。
實例:簡易的 TODO 清單
在本節中,我們用 CodePen 寫了一個可線上執行的範例。該範例是一個簡易的 TODO 清單,使用者可動態新增和刪除清單項目。但該 TODO 清單軟體沒有資料持久性的特性,在頁面重新載入後清單就會歸零,所以只是展示用途,沒有實用性。
該程式的 JavaScript 部分的程式碼如下:
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("entry").addEventListener("keydown", function(event) {
if (event.which == 13) {
addTODO();
}
});
document.getElementById("add").addEventListener("click", function() {
addTODO();
});
function addTODO() {
let todo = document.createElement("div");
todo.classList.add("todo");
todo.textContent = document.getElementById("entry").value;
let span = document.createElement("span");
span.innerText = "x";
span.addEventListener('click', function (ev) {
ev.target.parentNode.remove();
});
todo.appendChild(span);
document.getElementById("todos").appendChild(todo);
document.getElementById("entry").value = "";
}
});
如同我們先前所說,我們會把程式包在文件完全載入事件的回呼函式中,確保相關的事件處理器都能掛上去。
本範例程式的第一個事件處理器在網站使用者在文字輸入框中按下 Enter 鈕時觸發。節錄程式碼如下:
document.getElementById("entry").addEventListener("keydown", function(event) {
if (event.which == 13) {
addTODO();
}
});
偵測鍵盤輸入的事件為 Element: keydown event。由於鋌盤有很多顆,我們要檢查 KeyboardEvent.which 的值,以確認網站使用者輸入到我們期待的鍵盤。 Enter 鈕的 which
值為 13
。
我們有兩個事件處理器會用到同一段程式,所以我們將其用 addTODO()
函式包起來。待會我們再看其細節。
第二個事件處理器在使用者按下頁面上的 Add 鈕時觸發。節錄程式碼如下:
document.getElementById("add").addEventListener("click", function() {
addTODO();
});
為什麼我們要在兩個不同的事件處理器觸發相同的事件呢?因為我們要讓網頁使用者有相對自然的使用經驗,可選擇自己習慣的使用方式。
我們接著來看 addTODO()
函式的細節。先來看製作 TODO 項目的程式碼:
let todo = document.createElement("div");
todo.classList.add("todo");
todo.textContent = document.getElementById("entry").value;
在此範例中,我們用 <div>
元素來做 TODO 的項目,使用輸入文字框內的文字當成該項目的文字。
接著來看如何製作 TODO 項目右方的 x
按鈕:
let span = document.createElement("span");
span.innerText = "x";
span.addEventListener('click', function (ev) {
ev.target.parentNode.remove();
});
todo.appendChild(span);
該 x
按鈕使用字母 x 當圖示,並掛上相對應的事件處理器。該事件處理器會在觸發時把 x
按鈕所在的 TODO 項目清掉。
到目前為止,頁面上都不會顯示 todo
物件。我們得將 todo
物件掛到頁面上:
document.getElementById("todos").appendChild(todo);
最後,把輸入框內的文字清掉,方便網頁使用者輸入下一個 TODO 項目:
document.getElementById("entry").value = "";
結語
當我們會處理瀏覽器事件後,就可以試著寫一些不用後端的網頁前端程式,像電子計算機、單位換算器、小時鐘等簡單的項目都可以拿來練習看看。筆者建了一個網頁程式的樣板專案,可簡化建置網頁程式專案的前期作業,有興趣的讀者可以參考一下。