美思 原生 [JavaScript] 網頁程式設計:處理瀏覽器事件 (Browser Event)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

網頁前端程式本質上是一種事件驅動 (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 的值會在 truefalse 間切換,我們在程式中就相對應地更動按鈕風格。

為了保護變數 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 = "";

結語

當我們會處理瀏覽器事件後,就可以試著寫一些不用後端的網頁前端程式,像電子計算機、單位換算器、小時鐘等簡單的項目都可以拿來練習看看。筆者建了一個網頁程式的樣板專案,可簡化建置網頁程式專案的前期作業,有興趣的讀者可以參考一下。

關於作者

身為資訊領域碩士,美思認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

美思喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,美思將所學寫成文章,放在這個網站上和大家分享。