JavaScript:新增互動性

JavaScript 是一種為網站新增互動性的程式語言。你可以用它來控制幾乎所有內容——表單資料驗證、按鈕功能、遊戲邏輯、動態樣式、動畫更新等等。本文將帶你入門 JavaScript,並引導你為你的第一個網站新增一些有趣的功能。

預備知識 對你的計算機作業系統、用於構建網站的基本軟體和檔案系統有基本瞭解。
學習成果
  • JavaScript 的目的和功能。
  • 對 JavaScript 語言基礎知識的基本理解,例如變數、運算子、條件語句、函式和事件。

什麼是 JavaScript?

JavaScript 是一種功能齊全的程式語言——它包含你可能在其他程式語言中見過(或至少聽說過)的所有經典程式設計功能,例如變數迴圈函式

JavaScript 在網頁上使用時(儘管它也可以在其他地方使用),通常透過以下方式工作:

  • 獲取對一個或多個值(例如數字或頁面上的元素)的引用。
  • 對這些值進行操作,例如將數字相加。
  • 返回一個結果,該結果可以用於後續的其他操作。例如,你可能希望在頁面上顯示這些數字的總和。

我們來看一個例子。我們將使用我們在前幾篇文章中看到的相同的基本列表

html
<p>Instructions for life:</p>

<ul>
  <li>Eat</li>
  <li>Sleep</li>
  <li>Repeat</li>
</ul>

我們還將定義一個名為 .done 的 CSS 類,它將樣式化任何應用它的元素,使其看起來像一個已完成的任務,帶有綠色文字顏色和刪除線。我們將在下一步中使用 JavaScript 將其應用於我們的 <li> 元素。

css
.done {
  color: darkseagreen;
  text-decoration: line-through solid black 2px;
}

現在是 JavaScript 部分。在這裡,我們首先將對 <li> 元素的引用儲存在一個名為 listItems 的變數中。然後我們定義一個名為 toggleDone() 的函式,如果列表項沒有 done 類,則新增該類;如果它有該類,則刪除該類。最後,我們遍歷列表項(使用 forEach())併為每個列表項新增一個事件監聽器(使用 addEventListener()),這樣當它被點選時,done 類就會被切換,從而應用我們之前定義的 CSS。

js
const listItems = document.querySelectorAll("li");

function toggleDone(e) {
  if (!e.target.className) {
    e.target.className = "done";
  } else {
    e.target.className = "";
  }
}

listItems.forEach((item) => {
  item.addEventListener("click", toggleDone);
});

如果你現在不理解上面的 JavaScript,請不要擔心。熟悉 JavaScript 比熟悉 HTML 和 CSS 更具挑戰性,但稍後在本課程中,事情會變得更清晰。

此示例將在網路瀏覽器中呈現如下:

嘗試點選列表項幾次,並注意“完成”樣式是如何因此而切換開和關的。對於 11 行 JavaScript 來說,這還不錯。

“Hello world!” 演練

為了讓你開始編寫 JavaScript,我們將引導你為你的示例網站新增一個 Hello world! 示例。(Hello world! 是標準的入門程式設計示例。)

警告:如果你沒有按照我們課程的其餘部分進行操作,請下載此示例程式碼並將其用作起點。

  1. 在你的 first-website 資料夾或你剛剛下載的示例資料夾中,建立一個名為 scripts 的新資料夾。

  2. scripts 資料夾中,建立一個名為 main.js 的新文字文件,並儲存它。

  3. 轉到你的 index.html 檔案,並在緊靠關閉 </head> 標籤之前的新行中輸入以下程式碼:

    html
    <script async src="scripts/main.js"></script>
    

    這與 CSS 的 <link> 元素作用相同——它將 JavaScript 應用到頁面,以便它可以影響 HTML(以及頁面上的 CSS 和其他任何內容)。

  4. 將此程式碼新增到你的 scripts/main.js 檔案中:

    js
    // Store a reference to the <h1> in a variable
    const myHeading = document.querySelector("h1");
    // Update the text content of the <h1>
    myHeading.textContent = "Hello world!";
    
  5. 確保 HTML 和 JavaScript 檔案已儲存,然後在瀏覽器中載入 index.html。你應該會看到類似以下內容:

Heading "hello world" above a firefox logo

讓我們分解一下這個例子是如何工作的。

我們使用 JavaScript 將標題文字更改為 Hello world!。我們獲取了標題的引用並將其儲存在一個名為 myHeading 的變數中(一個儲存值的容器)。這類似於你將 CSS 應用於元素的方式——你首先使用 CSS 選擇器選擇要影響的元素,然後定義這些元素所需的樣式。在這兩種情況下,當你想對元素執行某些操作時,你都需要先選擇它。

之後,我們將 myHeading 變數的 textContent 屬性(代表 <h1> 元素的文字內容)的值設定為 Hello world!

// 開頭的行是 JavaScript 註釋。與 HTML 和 CSS 註釋一樣,瀏覽器會忽略這些註釋,為你提供一種新增關於程式碼的註釋的方法,以幫助解釋其工作原理。

我們繼續為示例網站新增一些新功能。

警告:在繼續之前,請從 main.js 檔案中刪除“Hello world!”程式碼。如果你不這樣做,現有程式碼將與你即將新增的新程式碼衝突。

新增一個影像切換器

在本節中,你將使用 JavaScript 和 DOM API 功能在兩張圖片之間交替顯示。當用戶點選顯示的圖片時,將發生此更改。

  1. 選擇另一張圖片作為你示例網站的特色圖片。理想情況下,該圖片應與你之前新增的圖片大小相同,或儘可能接近。

  2. 將此圖片儲存到你的 images 資料夾中。

  3. 將以下 JavaScript 程式碼新增到你的 main.js 檔案中,確保將 firefox2.png 和兩個 firefox-icon.png 例項分別替換為你的第二張和第一張圖片名稱。

    js
    const myImage = document.querySelector("img");
    
    myImage.addEventListener("click", () => {
      const mySrc = myImage.getAttribute("src");
      if (mySrc === "images/firefox-icon.png") {
        myImage.setAttribute("src", "images/firefox2.png");
      } else {
        myImage.setAttribute("src", "images/firefox-icon.png");
      }
    });
    
  4. 儲存所有檔案並在瀏覽器中載入 index.html。現在當你點選圖片時,它應該會切換到另一張圖片。

在此程式碼中,你將對 <img> 元素的引用儲存在 myImage 變數中。然後你為其分配了一個 click 事件處理函式。每次點選 <img> 時,該函式都會執行以下操作:

  • 檢索影像的 src 屬性的值。
  • 使用條件語句(if...else 結構)檢查 src 值是否等於原始影像的路徑
    • 如果是,程式碼會將 src 值更改為第二張影像的路徑,強制將另一張影像載入到 <img> 元素中。
    • 如果不是(這意味著影像已經更改),src 值將換回到原始影像路徑。

注意:本節介紹了一些重要術語。關鍵概念包括:

  • API:一組允許開發人員與程式設計環境互動的功能。Web API(例如我們上面使用的 DOM API 功能)構建在 JavaScript 語言之上,允許你操縱瀏覽器的各個部分及其顯示的網頁。
  • 事件:瀏覽器中發生的事情。它們是使網站具有互動性的關鍵。你可以使用事件處理函式響應事件執行程式碼——這些是事件發生時執行的程式碼塊。最常見的例子是點選事件,當用戶點選某個東西時,瀏覽器會觸發該事件。
  • 函式:一種打包你希望重用程式碼的方式。你可以在函式中定義一次程式碼,然後根據需要多次執行它,這有助於你避免一遍又一遍地編寫相同的程式碼。在本例中,我們定義了一個 click 事件處理函式,該函式在使用者每次點選影像時執行。
  • 條件語句:用於測試表達式是返回 true 還是 false 並根據每個結果執行不同程式碼的程式碼結構。條件語句的一種非常常見的形式是 if...else 語句。

新增一個個性化歡迎訊息

接下來,讓我們更改頁面標題,以便在使用者首次訪問網站時顯示個性化的歡迎訊息。此歡迎訊息將使用 Web Storage API 儲存到瀏覽器中,因此如果使用者離開網站稍後返回,他們的個性化資料仍將存在。我們還將提供一種讓使用者更改訊息的方式。

  1. index.html 中,在關閉 </body> 標籤之前新增以下行:

    html
    <button>Change user</button>
    
  2. main.js 中,將以下程式碼放在檔案的底部,完全按照原樣寫入。這會建立對新按鈕和標題的引用,將每個引用儲存在變數中:

    js
    let myButton = document.querySelector("button");
    let myHeading = document.querySelector("h1");
    
  3. 新增以下函式來設定個性化問候語。這目前不會做任何事情;我們稍後會呼叫該函式。

    js
    function setUserName() {
      const myName = prompt("Please enter your name.");
      localStorage.setItem("name", myName);
      myHeading.textContent = `Mozilla is cool, ${myName}`;
    }
    

    setUserName() 函式包含一個 prompt() 函式,該函式要求使用者輸入資料,並在他們單擊確定後將其儲存在變數中。在此示例中,我們要求使用者輸入一個名稱並將其儲存在 myName 中。

    接下來,程式碼使用 Web Storage API,它允許我們將資料儲存在瀏覽器中並稍後檢索。我們使用 localStorage.setItem() 函式建立和儲存一個名為 "name" 的資料項,將其值設定為 myName 變數,其中包含使用者的輸入。

    最後,我們將標題的 textContent 設定為一個包含使用者儲存名稱的字串。

  4. 在函式宣告之後新增以下條件塊。這是我們的初始化程式碼——它在頁面首次載入時執行以啟動程式:

    js
    if (!localStorage.getItem("name")) {
      setUserName();
    } else {
      const storedName = localStorage.getItem("name");
      myHeading.textContent = `Mozilla is cool, ${storedName}`;
    }
    

    此塊的第一行使用否定運算子(邏輯非,由 ! 字元表示)檢查 name 資料項是否尚未儲存在 localStorage 中。如果未儲存,則執行 setUserName() 函式來建立它。如果它存在(即使用者在之前訪問期間設定了使用者名稱),我們使用 localStorage.getItem() 檢索儲存的名稱,並將標題的 textContent 設定為字串,再加上使用者的名稱——就像我們在 setUserName() 中所做的那樣。

  5. 向按鈕新增一個 click 事件處理函式。當點選時,setUserName() 執行。這允許使用者如果願意,可以儲存不同的名稱。

    js
    myButton.addEventListener("click", () => {
      setUserName();
    });
    
  6. 儲存所有檔案並在瀏覽器中載入 index.html。你應該會立即被要求輸入你的姓名。完成操作後,你的姓名將作為個性化問候語的一部分出現在 <h1> 中。請注意,即使重新載入頁面,個性化設定也會持久存在。你可以點選“更改使用者”按鈕輸入新名稱。

注意:術語運算子指的是對一個或多個值執行操作的 JavaScript 語言字元。示例包括 +(加值)、-(從一個值中減去另一個值)和 !(否定一個值——正如你之前看到的)。

使用者名稱為 null?

當你執行示例並出現提示你輸入姓名的對話方塊時,請嘗試按下取消按鈕。你最終會得到一個標題,上面寫著Mozilla 很酷,null。發生這種情況是因為當你取消提示時,該值被設定為null。在 JavaScript 中,null 是一個特殊值,表示缺少值。

另外,嘗試在不輸入姓名的情況下點選確定。你最終會得到一個標題,上面寫著Mozilla 很酷,,因為你已將 myName 設定為空字串。

為了避免這些問題,你可以新增另一個條件來檢查使用者是否未輸入空白名稱。將你的 setUserName() 函式更新為以下內容:

js
function setUserName() {
  const myName = prompt("Please enter your name.");
  if (!myName) {
    setUserName();
  } else {
    localStorage.setItem("name", myName);
    myHeading.textContent = `Mozilla is cool, ${myName}`;
  }
}

用人類語言來說,這意味著:如果 myName 沒有值,則從頭開始再次執行 setUserName()。如果它確實有值(如果上述語句不為真),則將該值儲存在 localStorage 中,並將其設定為標題的文字。

總結

如果你已按照本文中的所有說明進行操作,你最終會得到一個頁面,看起來如下圖所示。你也可以檢視我們的版本

Final look of HTML page after creating elements: a header, large centered logo, content, and a button

如果你遇到問題,可以將你的工作與我們 GitHub 上的最終示例程式碼進行比較。

在本文中,我們只是觸及了 JavaScript 的皮毛。你將在本課程稍後的 使用 JavaScript 進行動態指令碼程式設計核心模組中學習更多內容。

另見

Scrimba:學習 JavaScript MDN 學習合作伙伴

Scrimba 的 學習 JavaScript 課程透過解決 140 多個互動編碼挑戰,構建包括遊戲、瀏覽器擴充套件甚至移動應用程式在內的專案來教你 JavaScript。Scrimba 提供由知識淵博的老師講授的有趣互動課程。

學習 JavaScript

這是有抱負的 Web 開發人員的絕佳資源!在互動環境中學習 JavaScript,透過短課和互動測試,並透過自動化評估進行指導。前 40 節課是免費的。完整課程只需一次小額付款即可獲得。