chore(i18n): sync translations with latest source changes (chunk 11/20, 100 files)

pull/1668/head
localizeflow[bot] 3 months ago
parent e11291bd14
commit 2de47cc7f9

@ -1,23 +1,146 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "e3c6f2a03c2336e60412612d870af547",
"translation_date": "2025-08-23T23:44:47+00:00",
"original_hash": "b6897c02603d0045dd6d8256e8714baa",
"translation_date": "2026-01-06T13:56:57+00:00",
"source_file": "5-browser-extension/1-about-browsers/assignment.md",
"language_code": "tw"
}
-->
# 重新設計您的擴充功能
# Assignment: 重新設計你的瀏覽器擴充功能
## 概覽
現在你已經建立了碳足跡瀏覽器擴充功能的 HTML 結構,是時候讓它在視覺上更具吸引力且更友善給使用者。優秀的設計能提升用戶體驗,使你的擴充功能更專業且更吸引人。
你的擴充功能附帶了基本的 CSS 樣式,但這次作業挑戰你創造一個獨特的視覺識別,反映你的個人風格,同時保持優秀的可用性。
## 指示
此擴充功能的代碼庫已包含樣式,但您不必使用它們;透過編輯其 CSS 文件,重新設計您的擴充功能,使其成為您自己的風格。
### 第 1 部分:分析目前設計
在進行更改之前,檢視現有的 CSS 結構:
1. **定位** 擴充功能專案中的 CSS 檔案
2. **檢閱** 目前的樣式方法和配色方案
3. **找出** 佈局、排版和視覺層次的改進空間
4. **考慮** 設計如何支持使用者目標(如輕鬆填寫表單及清晰呈現數據)
### 第 2 部分:設計你的自訂樣式
創建一套統一的視覺設計,包括:
**配色方案:**
- 選擇與環保主題相符的主色調
- 確保足夠的對比度以達成無障礙性(可使用 WebAIM 的對比度檢查工具)
- 考慮顏色會如何在不同瀏覽器主題下呈現
**排版:**
- 選取在小尺寸擴充功能顯示下仍可讀的字型
- 建立明確的層次結構,搭配適當字型大小和字重
- 確保文字在亮/暗瀏覽器主題下皆清晰可讀
**佈局與間距:**
- 改善表單元素與數據顯示的視覺組織
- 添加適當的內邊距與外邊距以提升易讀性
- 考量不同螢幕尺寸的響應式設計原則
### 第 3 部分:實作你的設計
修改 CSS 檔案以實現你的設計:
```css
/* Example starting points for customization */
.form-data {
/* Style the configuration form */
background: /* your choice */;
padding: /* your spacing */;
border-radius: /* your preference */;
}
.result-container {
/* Style the data display area */
background: /* complementary color */;
border: /* your border style */;
margin: /* your spacing */;
}
/* Add your custom styles here */
```
**主要需要設計的區域:**
- **表單元素**:輸入欄位、標籤及送出按鈕
- **結果顯示**:資料容器、文字樣式和載入狀態
- **互動元件**:滑鼠懸停效果、按鈕狀態和過渡動畫
- **整體佈局**:容器間距、背景色及視覺層次
### 第 4 部分:測試與修正
1. 使用 `npm run build` **建置**你的擴充功能
2. **載入**更新後的擴充功能到瀏覽器
3. **測試**所有視覺狀態(表單輸入、載入、結果顯示、錯誤狀態)
4. 使用瀏覽器開發者工具**驗證**無障礙性
5. 根據實際使用狀況**調整**你的樣式
## 創意挑戰
### 基礎等級
- 更新顏色和字型,打造一致的主題
- 改善介面中的間距與排列
- 為互動元素加入細微的懸停效果
### 中階等級
- 設計自訂圖示或圖形作為擴充功能特色
- 實現不同狀態間的平滑過渡
- 創造專屬 API 呼叫的載入動畫
### 進階等級
- 設計多種主題選項(明亮/暗色/高對比)
- 實現對不同瀏覽器視窗大小的響應式設計
- 加入微互動功能,提升使用者體驗
## 提交準則
完成的作業應包含:
- **修改後的 CSS 檔案**,呈現你的自訂樣式
- **截圖**,顯示擴充功能於不同狀態(表單、載入、結果)
- **簡短描述**2-3 句),說明你的設計選擇及如何提升使用者體驗
## 評分標準
| 標準 | 卓越表現 | 合格表現 | 需要改進 |
| -------- | ------------------------------------------ | -------------------- | ----------------- |
| | 提交的代碼具有功能性的新樣式 | 樣式不完整 | 樣式存在問題 |
| 標準 | 優秀 (4) | 良好 (3) | 進階中 (2) | 初學 (1) |
|----------|---------------|----------------|----------------|----------------|
| **視覺設計** | 創意且統一的設計,增強可用性並反映出強烈的設計原則 | 良好的設計選擇,有一致的樣式與清晰層次 | 基本設計改進但存在一致性問題 | 樣式變動很少或設計不一致 |
| **功能性** | 所有樣式在不同狀態及瀏覽器環境下均完美運作 | 樣式運作良好,邊緣情況有少許問題 | 大多數樣式可用但有些顯示錯誤 | 具重大樣式問題影響可用性 |
| **程式碼品質** | CSS 清晰、組織良好,使用有意義的類別與高效選擇器 | CSS 結構良好,適當使用選擇器與屬性 | CSS 可接受但有些組織問題 | CSS 結構不佳或樣式過於複雜 |
| **無障礙性** | 優秀的色彩對比、可讀字型,並考慮障礙使用者需求 | 良好無障礙實踐,有少數可改進之處 | 基本無障礙考量但有些問題 | 對無障礙需求注意有限 |
## 成功秘訣
> 💡 **設計提示**:從細微的更改開始,逐步建立更戲劇性的樣式。排版與間距的小改進往往對品質感受有很大影響。
**最佳實務建議:**
- 在明亮和暗色瀏覽器主題中**測試**擴充功能
- 使用相對單位em, rem以利擴展性
- 使用 CSS 自訂屬性維持一致的間距
- 考慮不同視覺需求使用者對設計的感受
- 驗證 CSS 語法正確無誤
> ⚠️ **常見錯誤**:不要為了美觀犧牲可用性。你的擴充功能應該既美觀又實用。
**切記:**
- 保持重要資訊易於閱讀
- 確保按鈕和互動元素易於點擊
- 維持用戶操作的明確視覺反饋
- 用真實資料測試設計,而非僅用佔位文字
祝你成功打造一個功能強大且視覺驚艷的瀏覽器擴充功能!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原文文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯而引起的任何誤解或誤釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,37 +1,114 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a7587943d38d095de8613e1b508609f5",
"translation_date": "2025-08-29T15:20:33+00:00",
"original_hash": "2b6203a48c48d8234e0948353b47d84e",
"translation_date": "2026-01-06T13:50:40+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/README.md",
"language_code": "tw"
}
-->
# 瀏覽器擴充功能專案第 2 部分:呼叫 API使用本地儲存
# 瀏覽器擴充功能專案第二部分:呼叫 API使用本機儲存空間
```mermaid
journey
title 您的 API 整合與儲存歷程
section 基礎
設定 DOM 參考: 3: Student
新增事件監聽器: 4: Student
處理表單提交: 4: Student
section 資料管理
實作本地儲存: 4: Student
建立 API 呼叫: 5: Student
處理非同步操作: 5: Student
section 使用者體驗
新增錯誤處理: 5: Student
建立載入狀態: 4: Student
打磨互動流程: 5: Student
```
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/25)
### 簡介
在這節課中,你將透過提交瀏覽器擴充功能的表單來呼叫 API並在擴充功能中顯示結果。此外你還將學習如何將資料儲存在瀏覽器的本地儲存中以供未來參考和使用。
✅ 請按照適當檔案中的編號段落,了解應該在哪裡放置程式碼。
### 設置擴充功能中需要操作的元素:
到目前為止,你已經為瀏覽器擴充功能建立了表單和結果 `<div>` 的 HTML。接下來你需要在 `/src/index.js` 檔案中工作,逐步構建你的擴充功能。可以參考[上一節課](../1-about-browsers/README.md)來了解如何設置專案和構建流程。
`index.js` 檔案中,首先建立一些 `const` 變數來保存與各個欄位相關的值:
```JavaScript
// form fields
## 介紹
還記得你先前開始建置的瀏覽器擴充功能嗎?現在你已有一個美觀的表單,但它本質上是靜態的。今天,我們將讓它活起來,藉由連接真實資料並賦予它記憶功能。
想像阿波羅任務控制中心的電腦──它們不只是顯示固定資訊,而是持續與太空船溝通,更新遙測資料,並記錄關鍵任務參數。這就是我們今天將打造的動態行為。你的擴充功能將連網抓取真實的環境資料,並記住你的設定以便下次使用。
API 整合聽起來可能很複雜,但其實就是教導你的程式如何與其他服務溝通。不論你是在取得天氣資料、社群媒體資訊,還是像今天一樣抓碳足跡資料,重點都是建立這些數位連結。我們也會探討瀏覽器如何持久保存資料──就像圖書館曾使用卡片目錄記住書本的位置。
本課結束時,你將擁有一個能抓實時資料、儲存使用者偏好並提供順暢體驗的瀏覽器擴充功能。讓我們開始吧!
```mermaid
mindmap
root((動態擴充))
DOM 操作
元素選取
事件處理
狀態管理
使用者介面更新
本地儲存
資料持久化
鍵值對
會話管理
使用者偏好設定
API 整合
HTTP 請求
認證
資料解析
錯誤處理
非同步程式設計
承諾Promises
非同步/等待Async/Await
錯誤捕捉
非阻塞程式碼
使用者體驗
載入狀態
錯誤訊息
平滑過渡
資料驗證
```
✅ 請依據適當檔案中的編號段落來放置程式碼
## 設定要在擴充功能中操作的元素
在你的 JavaScript 能操控介面之前,需要先取得對特定 HTML 元素的參考。就像望遠鏡必須對準特定星星一樣──蓋利略研究木星的衛星前,得先找到並聚焦在木星本身。
在你的 `index.js` 檔案中,我們會建立 `const` 變數來擷取每個重要表單元素的參考。這就像科學家貼標籤給設備──不用每次都在實驗室裡東找西找,直接取得所需即可。
```mermaid
flowchart LR
A[JavaScript 程式碼] --> B[document.querySelector]
B --> C[CSS 選擇器]
C --> D[HTML 元素]
D --> E[".form-data"]
D --> F[".region-name"]
D --> G[".api-key"]
D --> H[".loading"]
D --> I[".errors"]
D --> J[".result-container"]
E --> K[表單元素]
F --> L[輸入欄位]
G --> M[輸入欄位]
H --> N[介面元素]
I --> O[介面元素]
J --> P[介面元素]
style A fill:#e1f5fe
style D fill:#e8f5e8
style K fill:#fff3e0
style L fill:#fff3e0
style M fill:#fff3e0
```
```javascript
// 表單欄位
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
const apiKey = document.querySelector('.api-key');
// results
// 結果
const errors = document.querySelector('.errors');
const loading = document.querySelector('.loading');
const results = document.querySelector('.result-container');
@ -41,200 +118,546 @@ const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');
```
所有這些欄位都是通過其 CSS 類名來引用的,這些類名是在上一節課的 HTML 中設置的。
### 添加監聽器
接下來,為表單和重置按鈕添加事件監聽器,這樣當使用者提交表單或點擊重置按鈕時,會觸發相應的操作,並在檔案底部添加初始化應用程式的呼叫:
```JavaScript
**此段程式碼的功能:**
- **擷取** 使用 `document.querySelector()` 搭配 CSS 類別選擇器來取得表單元素
- **建立** 輸入欄位如地域名稱與 API 金鑰的參考
- **設定** 用於顯示碳排放資料的結果元素連結
- **準備** 介面元件如載入指示器和錯誤訊息的參考
- **將** 每個元素參考存放於 `const` 變數以便在程式中重複使用
## 加入事件監聽器
接著讓你的擴充功能能對使用者行為做出反應。事件監聽器就是你的程式負責監控使用者互動的方式。想像早期電話交換員──他們聽有無來電,並在有人想接通時連接正確的電路。
```mermaid
sequenceDiagram
participant User
participant Form
participant JavaScript
participant API
participant Storage
User->>Form: 填寫區域/API 金鑰
User->>Form: 點擊提交
Form->>JavaScript: 觸發提交事件
JavaScript->>JavaScript: handleSubmit(e)
JavaScript->>Storage: 儲存使用者偏好
JavaScript->>API: 取得碳排資料
API->>JavaScript: 回傳資料
JavaScript->>Form: 更新介面顯示結果
User->>Form: 點擊清除按鈕
Form->>JavaScript: 觸發點擊事件
JavaScript->>Storage: 清除儲存資料
JavaScript->>Form: 重設為初始狀態
```
```javascript
form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();
```
✅ 注意這裡使用的簡寫方式來監聽提交或點擊事件,以及事件如何被傳遞到 handleSubmit 或 reset 函數中。你能用更長的格式寫出這個簡寫的等價形式嗎?你更喜歡哪種方式?
**理解這些概念:**
- **綁定** 表單提交事件的監聽器,當用戶按 Enter 鍵或點擊送出時觸發
- **綁定** 清除按鈕的點擊事件,重設表單
- **將** 事件對象 `(e)` 傳入處理函式以增強控制
- **立即呼叫** `init()` 函式來設定擴充功能的初始狀態
✅ 注意這裡使用的簡寫箭頭函式語法。這是較現代的 JavaScript 用法,比傳統函式表達式更簡潔,但兩種都能正常運作!
### 🔄 **教學檢核點**
**事件處理理解檢核**:在移至初始化前,請確保你能:
- ✅ 解釋 `addEventListener` 如何將使用者行為連結至 JavaScript 函式
- ✅ 理解為何要將事件物件 `(e)` 傳入處理函式
- ✅ 辨識 `submit``click` 事件的差異
- ✅ 描述 `init()` 函式什麼時候執行及原因
**快速自測**:如果忘了在表單提交時呼叫 `e.preventDefault()` 會發生什麼?
*回答:頁面會重新載入,導致所有 JavaScript 狀態遺失並中斷使用者體驗*
### 構建 init() 函數和 reset() 函數:
## 建立初始化與重設函式
現在你將構建初始化擴充功能的函數,該函數名為 init()
我們來撰寫你的擴充功能初始化邏輯。`init()` 函式就像航船的導航系統檢查儀器──判斷現況並調整介面。它會檢查使用者是否已使用過你的擴充功能,並載入先前設定。
```JavaScript
`reset()` 函式則讓使用者可以重新開始──像科學家在實驗間歇重設儀器以確保資料乾淨。
```javascript
function init() {
//if anything is in localStorage, pick it up
// 檢查使用者是否先前已儲存 API 憑證
const storedApiKey = localStorage.getItem('apiKey');
const storedRegion = localStorage.getItem('regionName');
//set icon to be generic green
//todo
// 將擴充功能圖示設為通用綠色(未來課程佔位符)
// 待辦事項:在下一課程中實作圖示更新
if (storedApiKey === null || storedRegion === null) {
//if we don't have the keys, show the form
// 新用戶:顯示設定表單
form.style.display = 'block';
results.style.display = 'none';
loading.style.display = 'none';
clearBtn.style.display = 'none';
errors.textContent = '';
} else {
//if we have saved keys/regions in localStorage, show results when they load
displayCarbonUsage(storedApiKey, storedRegion);
// 回訪用戶:自動載入已儲存的資料
displayCarbonUsage(storedApiKey, storedRegion);
results.style.display = 'none';
form.style.display = 'none';
clearBtn.style.display = 'block';
}
};
}
function reset(e) {
e.preventDefault();
//clear local storage for region only
// 清除已存地區以允許使用者選擇新位置
localStorage.removeItem('regionName');
// 重新啟動初始化程序
init();
}
```
在這個函數中,有一些有趣的邏輯。閱讀後你能看出發生了什麼嗎?
- 設置兩個 `const` 來檢查使用者是否在本地儲存中儲存了 APIKey 和地區代碼。
- 如果其中任何一個為 null則通過將表單的樣式顯示為 'block' 來顯示表單。
- 隱藏結果區域、加載區域和清除按鈕,並將任何錯誤訊息設為空字串。
- 如果存在金鑰和地區代碼,則啟動一個流程:
- 呼叫 API 獲取碳使用數據。
- 隱藏結果區域。
- 隱藏表單。
- 顯示重置按鈕。
在繼續之前,了解瀏覽器中一個非常重要的概念是很有幫助的:[LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage)。LocalStorage 是一種將字串以 `key-value` 配對形式儲存在瀏覽器中的實用方式。這種類型的網頁儲存可以通過 JavaScript 來操作以管理瀏覽器中的資料。LocalStorage 不會過期,而另一種網頁儲存 SessionStorage 則會在瀏覽器關閉時清除。這些不同類型的儲存方式各有優缺點。
> 注意 - 瀏覽器擴充功能有其自己的本地儲存;主瀏覽器視窗是另一個實例,行為是分開的。
例如,你可以將 APIKey 設置為一個字串值,並且可以通過 "檢查" 網頁(你可以右鍵點擊瀏覽器進行檢查)並進入 Applications 標籤來查看儲存內容。
![本地儲存面板](../../../../translated_images/localstorage.472f8147b6a3f8d141d9551c95a2da610ac9a3c6a73d4a1c224081c98bae09d9.tw.png)
**這段程式碼步驟說明:**
- **從瀏覽器本機儲存空間中** 取出 API 金鑰與地域名稱
- **判斷** 是否為新用戶(無儲存資料)或是回訪用戶
- **顯示** 新手設定表單並隱藏其他介面元素
- **自動載入** 儲存資料並顯示重設按鈕給回訪用戶
- **根據資料狀態管理** 使用者介面呈現
**關於本機儲存的關鍵概念:**
- **在瀏覽器會話間持久保存**資料(不同於 session storage
- **以鍵值對方式儲存資料**,透過 `getItem()``setItem()` 操作
- **當指定鍵無資料時會回傳 `null`**
- **簡便方式儲存使用者偏好與設定**
> 💡 **理解瀏覽器儲存空間**[LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) 就像給你的擴充功能一個持久記憶。想像古代亞歷山大圖書館如何保存羊皮卷──知識即使學者離開再次回來仍能被取得。
>
> **重要特性:**
> - 即使關閉瀏覽器仍持續保存資料
> - 可抵抗電腦重啟與瀏覽器當機
> - 提供足夠空間保存使用者偏好
> - 無需網路延遲即時存取
> **重要說明**:瀏覽器擴充功能擁有獨立的本機儲存空間,與一般網頁隔離。提供安全性並避免與其他網站衝突。
你可以打開瀏覽器開發者工具F12切換到 **Application** 分頁,展開 **Local Storage** 以查看儲存的資料。
```mermaid
stateDiagram-v2
[*] --> CheckStorage: 擴充功能啟動
CheckStorage --> FirstTime: 無儲存資料
CheckStorage --> Returning: 找到資料
FirstTime --> ShowForm: 顯示設定表單
ShowForm --> UserInput: 使用者輸入資料
UserInput --> SaveData: 儲存至 localStorage
SaveData --> FetchAPI: 取得碳排放資料
Returning --> LoadData: 從 localStorage 讀取
LoadData --> FetchAPI: 取得碳排放資料
FetchAPI --> ShowResults: 顯示資料
ShowResults --> UserAction: 使用者互動
UserAction --> Reset: 清除按鈕被點擊
UserAction --> ShowResults: 檢視資料
Reset --> ClearStorage: 移除儲存資料
ClearStorage --> FirstTime: 返回設定
```
![本機儲存面板](../../../../translated_images/localstorage.472f8147b6a3f8d1.tw.png)
✅ 想一想有哪些情況下你不應該將某些資料儲存在 LocalStorage 中。一般來說,將 API 金鑰儲存在 LocalStorage 中是一個壞主意!你能理解為什麼嗎?在我們的案例中,由於我們的應用程式純粹是為了學習,並且不會部署到應用程式商店,因此我們將使用這種方法。
> ⚠️ **安全性考量**:在正式應用程式中,將 API 金鑰存放於 LocalStorage 有安全風險,因為 JavaScript 可讀取此資料。學習階段可接受,但實際應用應使用安全的伺服器端儲存機制保存敏感憑證
注意,你可以使用 Web API 來操作 LocalStorage通過使用 `getItem()`、`setItem()` 或 `removeItem()`。這在各大瀏覽器中都有廣泛支援。
## 處理表單提交
在構建 `displayCarbonUsage()` 函數(在 `init()` 中被呼叫)之前,讓我們先構建處理初始表單提交的功能。
現在我們來處理使用者提交表單時的行為。瀏覽器預設會在表單提交時重新整理頁面,我們將攔截這個行為以提供更順暢的體驗
### 處理表單提交
這與任務控制中心處理太空船通訊類似──他們不會每次通訊時重新啟動整個系統,而是持續操作並處理新資訊。
建立一個名為 `handleSubmit` 的函數,該函數接受一個事件參數 `(e)`。阻止事件的傳播(在這種情況下,我們希望阻止瀏覽器刷新),並呼叫一個新函數 `setUpUser`,傳遞 `apiKey.value``region.value` 作為參數。通過這種方式,你可以使用初始表單中填寫的兩個值。
建立一個函式來捕捉表單提交事件並取得使用者輸入:
```JavaScript
```javascript
function handleSubmit(e) {
e.preventDefault();
setUpUser(apiKey.value, region.value);
}
```
✅ 回顧一下記憶 - 你在上一節課中設置的 HTML 包含兩個輸入欄位,其 `values` 是通過你在檔案頂部設置的 `const` 捕獲的,並且它們都是 `required`,因此瀏覽器會阻止使用者輸入空值。
**以上內容說明:**
- **阻止** 預設提交行為避免頁面重新整理
- **取得** API 金鑰與地域欄位的使用者輸入值
- **將** 表單資料交給 `setUpUser()` 函式處理
- **保持** 單頁應用程式行為,避免頁面重整
### 設置使用者
✅ 記得你的 HTML 表單欄位均設有 `required` 屬性,瀏覽器會自動驗證使用者是否輸入 API 金鑰和地域,才會觸發此函式。
接下來是 `setUpUser` 函數,這裡你將為 apiKey 和 regionName 設置本地儲存值。新增一個新函數:
## 設定使用者偏好
```JavaScript
`setUpUser` 函式負責儲存使用者憑證並啟動第一次 API 呼叫,讓流程從設定到結果展現順暢過渡。
```javascript
function setUpUser(apiKey, regionName) {
// 儲存使用者認證以供未來使用
localStorage.setItem('apiKey', apiKey);
localStorage.setItem('regionName', regionName);
// 更新使用者介面以顯示載入狀態
loading.style.display = 'block';
errors.textContent = '';
clearBtn.style.display = 'block';
//make initial call
// 使用使用者認證擷取碳排放使用資料
displayCarbonUsage(apiKey, regionName);
}
```
這個函數在呼叫 API 時顯示一條加載訊息。到這裡,你已經來到了這個瀏覽器擴充功能中最重要的函數!
### 顯示碳使用數據
最後,是時候查詢 API 了!
在進一步操作之前,我們應該討論一下 API。API即[應用程式介面](https://www.webopedia.com/TERM/A/API.html),是網頁開發人員工具箱中的關鍵元素。它們為程式之間的互動和介面提供了標準方式。例如,如果你正在建立一個需要查詢資料庫的網站,可能有人已經為你建立了一個 API 可以使用。雖然有許多類型的 API但其中一種最受歡迎的是 [REST API](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/)。
✅ "REST" 代表 "表現層狀態轉換"Representational State Transfer其特點是使用各種配置的 URL 來獲取資料。稍微研究一下開發人員可用的各種類型的 API。哪種格式最吸引你
這個函數有幾個重要的地方需要注意。首先,注意 [`async` 關鍵字](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function)。將函數寫成非同步的方式意味著它會等待某個動作(例如資料返回)完成後再繼續執行。
這裡有一段關於 `async` 的快速影片:
[![管理 Promise 的 Async 和 Await](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "管理 Promise 的 Async 和 Await")
> 🎥 點擊上方圖片觀看關於 async/await 的影片。
建立一個新函數來查詢 C02Signal API
```JavaScript
import axios from '../node_modules/axios';
**逐步說明:**
- **將** API 金鑰與地域名稱存入本機儲存空間以備日後使用
- **顯示** 載入中指示,告知使用者資料正在抓取
- **清除** 先前顯示的錯誤訊息
- **顯示** 清除按鈕以供使用者日後重設設定
- **開始** 呼叫 API 擷取真實碳排放資料
此函式統一管理資料持久化與使用者介面更新,確保使用者體驗流暢。
## 顯示碳排放資料
接著讓你的擴充功能連結外部資料來源──API將它從獨立工具轉變為可取得全球即時資訊的利器。
**理解 API**
[API](https://www.webopedia.com/TERM/A/API.html) 是應用程式間通訊的橋樑。可以將它想像成 19 世紀連結遙遠城市的電報系統,操作員發送請求至遠方站台,並取得所需回應。你每次查看社群媒體、問語音助理問題或用外送 App都在透過 API 交換資料。
```mermaid
flowchart TD
A[您的擴充功能] --> B[HTTP 請求]
B --> C[CO2 信號 API]
C --> D{有效的請求?}
D -->|是| E[查詢資料庫]
D -->|否| F[返回錯誤]
E --> G[碳排放資料]
G --> H[JSON 回應]
H --> I[您的擴充功能]
F --> I
I --> J[更新使用者介面]
subgraph "API 請求"
K[標頭auth-token]
L[參數countryCode]
M[方法GET]
end
subgraph "API 回應"
N[碳強度]
O[化石燃料百分比]
P[時間戳記]
end
style C fill:#e8f5e8
style G fill:#fff3e0
style I fill:#e1f5fe
```
**REST API 的核心概念:**
- **REST** 代表「表述性狀態轉換」Representational State Transfer
- **使用** 標準 HTTP 方法GET、POST、PUT、DELETE操作資料
- **回傳** 通常是格式確定的資料,如 JSON
- **提供** 穩定且基於 URL 的端點供不同請求使用
✅ 我們使用的 [CO2 Signal API](https://www.co2signal.com/) 提供全球電網的即時碳強度資料,有助使用者了解電力使用對環境的影響。
> 💡 **異步 JavaScript 理解**`async` 關鍵字讓你的程式能同時處理多項任務。當你向伺服器要求資料時,不希望整個擴充功能停擺──那就如同航空管制在等一架飛機回答時停止所有調度。
>
> **主要好處:**
> - **維持** 擴充功能回應性,資料加載期間不死機
> - **允許** 其他程式碼在網路請求時繼續執行
> - **改善** 可讀性,相較於傳統 callback 更直覺
> - **支援** 網路異常時的優雅錯誤處理
以下是一段關於 `async` 的簡短影片:
[![使用 Async 與 Await 管理 Promise](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "使用 Async 與 Await 管理 Promise")
> 🎥 點擊上方圖片觀看 async/await 介紹影片。
### 🔄 **教學檢核點**
**異步程式設計理解:** 在深入 API 函式前,請確認你了解:
- ✅ 為什麼使用 `async/await` 避免凍結擴充功能
- ✅ 如何用 `try/catch` 區塊優雅處理網路錯誤
- ✅ 同步與異步作業間的差異
- ✅ API 呼叫失敗原因與錯誤處理方式
**生活連結範例:**
- **點餐**:你不會站在廚房等,拿到收據後繼續忙別的事
- **寄信**:郵件發送時 App 不會凍結,你可以繼續寫信
- **網頁載入**:圖片可以邊載入邊讀文字
**API 認證流程**
```mermaid
sequenceDiagram
participant Ext as Extension
participant API as CO2 Signal API
participant DB as Database
Ext->>API: 使用認證令牌發出請求
API->>API: 驗證令牌
API->>DB: 查詢碳排放數據
DB->>API: 回傳數據
API->>Ext: JSON 回應
Ext->>Ext: 更新使用者介面
```
建立抓取並顯示碳排放資料的函式:
```javascript
// 現代 fetch API 方式(不需要外部依賴)
async function displayCarbonUsage(apiKey, region) {
try {
await axios
.get('https://api.co2signal.com/v1/latest', {
params: {
countryCode: region,
},
headers: {
'auth-token': apiKey,
},
})
.then((response) => {
let CO2 = Math.floor(response.data.data.carbonIntensity);
//calculateColor(CO2);
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region;
usage.textContent =
Math.round(response.data.data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)';
fossilfuel.textContent =
response.data.data.fossilFuelPercentage.toFixed(2) +
'% (percentage of fossil fuels used to generate electricity)';
results.style.display = 'block';
});
// 從 CO2 Signal API 擷取碳強度數據
const response = await fetch('https://api.co2signal.com/v1/latest', {
method: 'GET',
headers: {
'auth-token': apiKey,
'Content-Type': 'application/json'
},
// 為特定區域新增查詢參數
...new URLSearchParams({ countryCode: region }) && {
url: `https://api.co2signal.com/v1/latest?countryCode=${region}`
}
});
// 檢查 API 請求是否成功
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
const carbonData = data.data;
// 計算四捨五入的碳強度值
const carbonIntensity = Math.round(carbonData.carbonIntensity);
// 使用擷取的數據更新使用者介面
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region.toUpperCase();
usage.textContent = `${carbonIntensity} grams (grams CO₂ emitted per kilowatt hour)`;
fossilfuel.textContent = `${carbonData.fossilFuelPercentage.toFixed(2)}% (percentage of fossil fuels used to generate electricity)`;
results.style.display = 'block';
// TODO: calculateColor(carbonIntensity) - 下一課程實作
} catch (error) {
console.log(error);
console.error('Error fetching carbon data:', error);
// 顯示使用者友善的錯誤訊息
loading.style.display = 'none';
results.style.display = 'none';
errors.textContent = 'Sorry, we have no data for the region you have requested.';
errors.textContent = 'Sorry, we couldn\'t fetch data for that region. Please check your API key and region code.';
}
}
```
這是一個較大的函數。這裡發生了什麼?
**這段程式碼說明:**
- **使用** 現代的 `fetch()` API避免額外依賴如 Axios 等外部函式庫,使程式更精簡
- **加入** 正確的錯誤判斷 `response.ok`,提早偵測 API 呼叫失敗
- **以** `async/await` 管理非同步流程,使程式碼更易讀
- **透過** `auth-token` 標頭驗證 CO2 Signal API
- **解析** JSON 回應並取出碳強度資訊
- **更新** 多個介面元素,格式化呈現環境數據
- **在** API 發生錯誤時顯示友善的錯誤訊息
**展現 JavaScript 重要現代概念:**
- 利用 `${}` 的模板字串潔淨格式化文字
- 使用 try/catch 做錯誤處理,提升應用健壯性
- async/await 處理網路請求,控制流程自然
- 物件解構賦值取得 API 回傳中特定資料
- 方法鏈結應用於多重 DOM 操作
✅ 此函式示範多項網頁開發核心技巧──與外部伺服器通信、認證、資料處理、介面更新及錯誤管理。這些都是職業程式設計師日常運用的基本能力。
```mermaid
flowchart TD
A[開始 API 呼叫] --> B[取得請求]
B --> C{網路成功?}
C -->|否| D[網路錯誤]
C -->|是| E{回應正常?}
E -->|否| F[API 錯誤]
E -->|是| G[解析 JSON]
G --> H{資料有效?}
H -->|否| I[資料錯誤]
H -->|是| J[更新介面]
D --> K[顯示錯誤訊息]
F --> K
I --> K
J --> L[隱藏載入]
K --> L
style A fill:#e1f5fe
style J fill:#e8f5e8
style K fill:#ffebee
style L fill:#f3e5f5
```
### 🔄 **教學檢核點**
**系統全貌理解**:確認你已掌握整個流程:
- ✅ DOM 參考如何使 JavaScript 控制介面
- ✅ 為何本機儲存令資料能在瀏覽器會話間永久保存
- ✅ async/await 如何非凍結地進行 API 請求
- ✅ API 連線失敗時發生什麼及錯誤如何處理
- ✅ 使用者體驗包含載入狀態及錯誤訊息的原因
🎉 **你已完成:** 製作出一個:
- **連上互聯網並擷取真實環境資料**
- **在會話間持續保存使用者設定**
- **能夠錯誤優雅處理而非崩潰**
- **提供流暢且專業的使用者體驗**
嘗試使用 `npm run build` 並在瀏覽器重新載入擴充功能,現在你已有功能完善的碳足跡追蹤器。下一課將加入動態圖示功能,完成整個擴充功能專案。
- 遵循最佳實踐,你使用了 `async` 關鍵字,使這個函數以非同步方式運行。該函數包含一個 `try/catch` 區塊,因為當 API 返回資料時,它會返回一個 Promise。由於你無法控制 API 回應的速度(它可能根本不回應!),因此需要通過非同步方式來處理這種不確定性。
- 你正在查詢 co2signal API 以獲取你所在地區的數據,並使用你的 API 金鑰。為了使用該金鑰,你需要在標頭參數中使用一種類型的身份驗證。
- 一旦 API 回應,你將其回應資料的各個元素分配給你設置的螢幕部分以顯示這些資料。
- 如果出現錯誤,或者沒有結果,你將顯示一條錯誤訊息。
---
✅ 使用非同步程式設計模式是工具箱中的另一個非常有用的工具。閱讀[關於這種類型程式碼的各種配置方式](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function)。
## GitHub Copilot Agent 挑戰 🚀
恭喜!如果你構建了擴充功能(`npm run build`)並在擴充功能面板中刷新它,你已經擁有了一個可運行的擴充功能!唯一尚未完成的是圖示,你將在下一節課中修復它。
使用 Agent 模式完成以下挑戰:
**說明:** 透過新增錯誤處理改進和使用者體驗功能來增強瀏覽器擴充功能。這個挑戰將幫助你練習使用 API、本地存儲和現代 JavaScript 應用於 DOM 操作的技巧。
---
**提示:** 建立 displayCarbonUsage 函式的增強版包含1) 失敗 API 呼叫的指數退避重試機制2) 在進行 API 呼叫前對區域代碼進行輸入驗證3) 帶有進度指示器的加載動畫4) 以 localStorage 快取 API 回應並設定過期時間(快取 30 分鐘),以及 5) 顯示先前 API 呼叫歷史資料的功能。並新增適當的 TypeScript 風格 JSDoc 註解,記錄所有函式參數與回傳型別。
在此了解更多關於 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑戰
在這些課程中,我們已經討論了幾種類型的 API。選擇一個網頁 API深入研究它提供的功能。例如查看瀏覽器中可用的 API例如 [HTML 拖放 API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API)。在你看來,什麼樣的 API 是一個出色的 API
透過探索豐富的瀏覽器 API加深你對 API 的理解,這些瀏覽器 API 對網頁開發都非常重要。請從以下瀏覽器 API 中選擇一個,進行小型示範開發:
- [地理位置 API](https://developer.mozilla.org/docs/Web/API/Geolocation_API) - 取得使用者目前位置
- [通知 API](https://developer.mozilla.org/docs/Web/API/Notifications_API) - 傳送桌面通知
- [HTML 拖放 API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) - 建立互動式拖放介面
- [Web Storage API](https://developer.mozilla.org/docs/Web/API/Web_Storage_API) - 進階本地存儲技巧
- [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) - XMLHttpRequest 的現代替代方案
**研究問題以供考慮:**
- 這個 API 解決了哪些實際問題?
- 這個 API 如何處理錯誤與邊緣情況?
- 使用此 API 時有哪些安全性注意事項?
- 此 API 在不同瀏覽器中支援度如何?
完成研究後,請歸納出使 API 對開發者友善且可靠的特徵。
## 課後測驗
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/26)
## 回顧與自學
在這節課中,你學習了 LocalStorage 和 API這兩者對於專業的網頁開發人員來說都非常有用。你能想到這兩者如何協同工作嗎想一想你會如何設計一個網站將項目儲存起來以供 API 使用。
## 複習與自我學習
本課你學到 LocalStorage 與 API都是專業網頁開發者非常實用的技術。你能思考它們如何協同運作嗎試著想像你會如何架構一個網站將要由 API 使用的資料存取與保存。
### ⚡ **你接下來 5 分鐘能做的事情**
- [ ] 打開開發者工具 Application 分頁並探索任一網站的 localStorage
- [ ] 建立簡單的 HTML 表單並測試瀏覽器內建表單驗證
- [ ] 嘗試在瀏覽器控制台使用 localStorage 儲存及取回資料
- [ ] 使用 Network 分頁檢查送出的表單資料
### 🎯 **你這一小時可以達成目標**
- [ ] 完成課後測驗並了解表單處理概念
- [ ] 建立瀏覽器擴充功能的表單,並保存使用者偏好設定
- [ ] 實作客戶端表單驗證並顯示有用的錯誤訊息
- [ ] 練習使用 chrome.storage API 來維持擴充功能資料
- [ ] 建立響應已保存使用者設定的介面
### 📅 **你為期一週的擴充功能開發計畫**
- [ ] 完成具有完整表單功能的瀏覽器擴充功能
- [ ] 精通不同存儲選項local、sync 和 session
- [ ] 實作高級表單功能,如自動完成和驗證
- [ ] 新增使用者資料的匯入/匯出功能
- [ ] 在不同瀏覽器中完整測試你的擴充功能
- [ ] 打磨擴充功能的使用者體驗和錯誤處理
### 🌟 **你為期一個月的網頁 API 精通計畫**
- [ ] 使用多種瀏覽器存儲 API 建立複雜應用
- [ ] 學習離線優先開發模式
- [ ] 參與與資料持久化相關的開源專案
- [ ] 精通隱私導向開發與 GDPR 合規
- [ ] 建立可重複使用的表單處理及資料管理函式庫
- [ ] 分享有關網頁 API 和擴充功能開發的知識
## 🎯 你的擴充功能開發精通時間軸
```mermaid
timeline
title API 整合與儲存學習進度
section DOM 基礎 (15 分鐘)
元素參考: querySelector 精通
: 事件監聽器設定
: 狀態管理基礎
section 本地儲存 (20 分鐘)
資料持久化: 鍵值儲存
: 工作階段管理
: 使用者偏好處理
: 儲存檢查工具
section 表單處理 (25 分鐘)
使用者輸入: 表單驗證
: 事件阻止
: 資料擷取
: UI 狀態轉換
section API 整合 (35 分鐘)
外部通信: HTTP 請求
: 驗證模式
: JSON 資料解析
: 回應處理
section 非同步程式設計 (40 分鐘)
現代 JavaScript: Promise 處理
: Async/await 模式
: 錯誤管理
: 非阻塞操作
section 錯誤處理 (30 分鐘)
穩健應用程式: Try/catch 區塊
: 友善訊息
: 優雅降級
: 除錯技巧
section 進階模式 (1 週)
專業發展: 快取策略
: 速率限制
: 重試機制
: 效能優化
section 生產技能 (1 個月)
企業功能: 安全最佳實踐
: API 版本控制
: 監控與記錄
: 可擴充架構
```
### 🛠️ 你的全端開發工具組總結
完成本課後,你現在擁有:
- **DOM 精通**:精確的元素定位及操作
- **存儲專家**:以 localStorage 管理持久資料
- **API 整合**:即時資料擷取與身份驗證
- **非同步編程**:使用現代 JavaScript 非阻塞操作
- **錯誤處理**:打造能優雅應對錯誤的強健應用
- **使用者體驗**:加載狀態、驗證與流暢互動設計
- **現代開發模式**fetch API、async/await 與 ES6+ 功能
**專業技能提升**:你已實作出:
- **網頁應用**:單頁應用及外部資料來源
- **行動開發**:具離線能力的 API 驅動應用
- **桌面軟體**Electron 應用的持久存儲
- **企業系統**:身份驗證、快取與錯誤處理
- **現代框架**React/Vue/Angular 資料管理模式
**下一階段**:你已準備好探索更進階主題,如快取策略、即時 WebSocket 連線或複雜狀態管理!
## 作業
[採用一個 API](assignment.md)
[Adopt an API](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 所翻譯。雖然我們力求準確,但自動翻譯可能包含錯誤或不準確之處。原文之母語版本應視為權威資料來源。對於重要資訊,建議尋求專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或曲解負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,109 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a0c78d1dd9d1acdbf7f52e7cc3ebe1a7",
"translation_date": "2025-08-23T23:40:41+00:00",
"original_hash": "25b8d28b8531352d4eb67291fd7824c4",
"translation_date": "2026-01-06T13:52:35+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/assignment.md",
"language_code": "tw"
}
-->
# 採用一個 API
# 採用 API
## 指導說明
## 概述
API 可以非常有趣,這裡有一個[免費 API 的列表](https://github.com/public-apis/public-apis)。選擇一個 API並建立一個解決問題的瀏覽器擴充功能。這個問題可以很小例如缺少足夠的寵物圖片那麼可以試試 [dog CEO API](https://dog.ceo/dog-api/)),也可以是更大的問題——盡情享受吧!
API 為創意網頁開發開啟無限可能!在此作業中,你將選擇一個外部 API 並構建一個瀏覽器擴充功能,解決實際問題或為使用者提供有價值的功能。
## 指示
### 第一步:選擇你的 API
從此精選的[免費公共 API 清單](https://github.com/public-apis/public-apis)中選擇一個 API。考慮以下分類
**新手熱門選項:**
- **娛樂**:使用 [Dog CEO API](https://dog.ceo/dog-api/) 取得隨機狗狗圖片
- **天氣**:使用 [OpenWeatherMap](https://openweathermap.org/api) 獲取當前天氣資料
- **語錄**:使用 [Quotable API](https://quotable.io/) 取得勵志語錄
- **新聞**:使用 [NewsAPI](https://newsapi.org/) 獲取即時頭條
- **趣味事實**:使用 [Numbers API](http://numbersapi.com/) 獲得有趣的數字事實
### 第二步:規劃你的擴充功能
開始編碼前,請回答下列規劃問題:
- 你的擴充功能解決了什麼問題?
- 目標使用者是誰?
- 你會將哪些資料存放在本地儲存?
- 你將如何處理 API 錯誤或速率限制?
### 第三步:建立你的擴充功能
你的擴充功能應包含:
**必備功能:**
- 表單輸入以填寫必要的 API 參數
- API 整合並包含適當的錯誤處理
- 本地儲存使用者偏好或 API 金鑰
- 簡潔且響應式的用戶介面
- 載入狀態與使用者回饋
**程式碼要求:**
- 使用現代 JavaScript (ES6+) 特性
- 使用 async/await 實作 API 呼叫
- 使用 try/catch 區塊妥善處理錯誤
- 添加有意義的註解說明程式碼
- 遵循一致的程式碼格式
### 第四步:測試與修飾
- 用多種輸入測試你的擴充功能
- 處理邊界狀況無網路、API 回應無效)
- 確保瀏覽器重啟後擴充功能仍可正常運作
- 新增使用者友善的錯誤訊息
## 額外挑戰
讓你的擴充功能更上一層樓:
- 新增多個 API 端點以提供更豐富功能
- 實作資料快取以減少 API 呼叫
- 建立常用功能的鍵盤快捷鍵
- 新增資料匯入/匯出功能
- 實作使用者自訂選項
## 提交需求
1. **可運作的瀏覽器擴充功能**,成功整合你選擇的 API
2. **README 檔案**說明:
- 你選擇了哪個 API 以及原因
- 如何安裝及使用你的擴充功能
- 任何 API 金鑰或設定需求
- 擴充功能操作截圖
3. **乾淨且有註解的程式碼**,遵循現代 JavaScript 實務
## 評分標準
| 評分標準 | 優秀範例 | 足夠 | 需要改進 |
| -------- | -------------------------------------------------------------------------- | ------------------------------------ | --------------- |
| | 使用上述列表中的 API 提交了一個完整的瀏覽器擴充功能 | 提交了一個部分完成的瀏覽器擴充功能 | 提交的內容有錯誤 |
| 標準 | 優異 (90-100%) | 精通 (80-89%) | 發展中 (70-79%) | 初階 (60-69%) |
|----------|---------------------|---------------------|---------------------|--------------------|
| **API 整合** | 完美的 API 整合,含全面錯誤及邊界案例處理 | 成功整合 API具基本錯誤處理 | API 可用但錯誤處理有限 | API 整合存在嚴重問題 |
| **程式碼品質** | 乾淨、注釋完善的現代 JavaScript 符合最佳實務 | 良好的程式結構與適當注釋 | 程式碼可用但需更好組織 | 程式碼品質差且注釋少 |
| **使用者體驗** | 精緻介面,載入狀態及使用者回饋優秀 | 良好介面,基本使用者回饋 | 基本功能介面可用 | 使用者體驗差且介面混亂 |
| **本地儲存** | 精細運用本地儲存並含資料驗證與管理 | 為主要功能正確實作本地儲存 | 基本使用本地儲存 | 本地儲存使用極少或錯誤 |
| **文件** | 詳盡 README 含安裝說明及截圖 | 良好文件,涵蓋多數需求 | 基本文件缺部分細節 | 文件缺失或不足 |
## 入門提示
1. **從簡單開始**:選擇不需複雜認證的 API
2. **閱讀文件**:徹底了解所選 API 的端點與回應
3. **規劃介面**:撰寫介面草圖再開始編碼
4. **頻繁測試**:逐步建立並測試各項功能
5. **錯誤處理**:隨時假設 API 呼叫可能失敗並做好準備
## 資源
- [瀏覽器擴充功能文件](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions)
- [Fetch API 指南](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch)
- [本地儲存教學](https://developer.mozilla.org/docs/Web/API/Window/localStorage)
- [JSON 解析與處理](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON)
祝你打造出有用且富創意的作品!🚀
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們力求準確,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所引起的任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,175 +1,596 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "b91cbf14240ee59411b96448b994ace1",
"translation_date": "2025-10-03T12:17:27+00:00",
"original_hash": "b275fed2c6fc90d2b9b6661a3225faa2",
"translation_date": "2026-01-06T13:52:53+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/README.md",
"language_code": "tw"
}
-->
# 瀏覽器擴充功能專案第 3 部分:了解背景任務與效能
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/27)
### 簡介
在本模組的前兩節課中,您學習了如何建立表單以及顯示從 API 獲取的資料區域。這是一種非常標準的方式來建立網頁。您甚至學會了如何處理非同步資料獲取。您的瀏覽器擴充功能已經接近完成。
現在需要管理一些背景任務,包括刷新擴充功能圖示的顏色,因此這是一個很好的時機來討論瀏覽器如何管理這類任務。在建立網頁資產時,讓我們從效能的角度來思考這些瀏覽器任務。
# 瀏覽器擴充套件專案第三部分:了解背景工作與效能
```mermaid
journey
title 您的效能優化旅程
section 基礎
學習瀏覽器工具: 3: Student
了解效能分析: 4: Student
辨識瓶頸: 4: Student
section 擴充功能
建立色彩系統: 4: Student
建立背景工作: 5: Student
動態更新圖示: 5: Student
section 優化
監控效能: 5: Student
除錯問題: 4: Student
精進體驗: 5: Student
```
是否曾好奇為什麼有些瀏覽器擴充套件感覺流暢且回應迅速,而其他的則顯得遲鈍?祕密就在幕後發生的事情。當使用者在您的擴充套件介面上點擊時,背後有一整個世界的背景程序靜靜地在管理資料擷取、圖示更新和系統資源。
這是瀏覽器擴充套件系列的最後一課,我們將讓您的碳足跡追蹤器順暢運作。您將新增動態圖示更新,並學會如何提前發現效能問題,避免成為麻煩。這就像調校賽車──小幅調整就能讓整體運作大不相同。
完成後,您將擁有一個精緻的擴充套件,並理解分隔優秀與卓越網頁應用的效能原則。讓我們深入瀏覽器優化的世界吧。
## 課前小測驗
[課前小測驗](https://ff-quizzes.netlify.app/web/quiz/27)
### 介紹
在之前的課程中,您建立了一個表單,連接 API並處理非同步資料擷取。您的擴充套件正逐漸成形。
現在我們需要加上最後的修飾,例如讓擴充套件圖示根據碳排放資料改變顏色。這讓我想起 NASA 必須優化阿波羅太空船上的每個系統。他們無法承受任何浪費的運算週期或記憶體,因為生命安全依賴效能。雖然我們的瀏覽器擴充套件沒有那麼關鍵,但相同的原則依然適用──有效率的程式碼能帶來更佳的使用者體驗。
```mermaid
mindmap
root((效能與背景工作))
Browser Performance
Rendering Pipeline
Asset Optimization
DOM Manipulation
JavaScript Execution
Profiling Tools
Developer Tools
Performance Tab
Timeline Analysis
Bottleneck Detection
Extension Architecture
Background Scripts
Content Scripts
Message Passing
Icon Management
Optimization Strategies
Code Splitting
Lazy Loading
Caching
Resource Compression
Visual Feedback
Dynamic Icons
Color Coding
Real-time Updates
User Experience
```
## 網頁效能基礎
> 「網站效能關乎兩件事:頁面載入速度,以及頁面上的程式碼執行速度。」-- [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
如何讓您的網站在各種裝置、各種使用者以及各種情況下都能快速運行是一個非常廣泛的主題。以下是一些在建立標準網頁專案或瀏覽器擴充功能時需要注意的要點。
確保您的網站高效運行的第一步是收集其效能的相關資料。第一個地方可以查看的是您網頁瀏覽器的開發者工具。在 Edge 中,您可以選擇「設定及更多」按鈕(瀏覽器右上角的三點圖示),然後導航到「更多工具 > 開發者工具」,並打開「效能」標籤。您也可以使用快捷鍵 `Ctrl` + `Shift` + `I`Windows`Option` + `Command` + `I`Mac來打開開發者工具。
「效能」標籤包含一個分析工具。打開一個網站(例如 [https://www.microsoft.com](https://www.microsoft.com/?WT.mc_id=academic-77807-sagibbon)),然後點擊「記錄」按鈕,接著刷新網站。隨時停止記錄,您將能看到生成的例程,包括「腳本」、「渲染」和「繪製」網站的過程:
![Edge 分析工具](../../../../translated_images/profiler.5a4a62479c5df01cfec9aab74173dba13f91d2c968e1a1ae434c26165792df15.tw.png)
✅ 參考 [Microsoft 文件](https://docs.microsoft.com/microsoft-edge/devtools-guide/performance/?WT.mc_id=academic-77807-sagibbon) 中有關 Edge 中效能面板的內容
> 提示:為了獲得網站啟動時間的準確讀數,請清除瀏覽器的快取
選擇分析時間軸的元素,放大頁面載入時發生的事件。
透過選擇分析時間軸的一部分並查看摘要窗格,獲取頁面效能的快照:
![Edge 分析工具快照](../../../../translated_images/snapshot.97750180ebcad73794a3594b36925eb5c8dbaac9e03fec7f9b974188c9ac63c7.tw.png)
檢查事件日誌窗格,查看是否有任何事件超過 15 毫秒:
![Edge 事件日誌](../../../../translated_images/log.804026979f3707e00eebcfa028b2b5a88cec6292f858767bb6703afba65a7d9c.tw.png)
✅ 熟悉您的分析工具!打開此網站的開發者工具,看看是否有任何瓶頸。哪個資產載入最慢?哪個最快?
## 分析檢查
一般來說,為了避免在部署到生產環境時出現意外,每位網頁開發者都應該注意一些「問題區域」。
**資產大小**:過去幾年,網頁變得「更重」,因此也更慢。其中一些重量與使用圖片有關。
✅ 查看 [Internet Archive](https://httparchive.org/reports/page-weight) 以了解頁面重量的歷史視圖及更多資訊。
一個好的做法是確保您的圖片已經過最佳化,並以適合使用者的大小和解析度交付。
**DOM 遍歷**瀏覽器必須根據您撰寫的程式碼建立其文件物件模型DOM因此為了良好的頁面效能應保持標籤的最小化只使用和樣式化頁面所需的內容。基於此點與頁面相關的多餘 CSS 可以進行最佳化;僅需在某一頁面使用的樣式不需要包含在主樣式表中。
**JavaScript**:每位 JavaScript 開發者都應注意「渲染阻塞」腳本,這些腳本必須在 DOM 被遍歷並繪製到瀏覽器之前載入。考慮在內嵌腳本中使用 `defer`(如在 Terrarium 模組中所示)。
✅ 在 [網站速度測試網站](https://www.webpagetest.org/) 上嘗試一些網站,了解用於判斷網站效能的常見檢查。
現在您已經了解瀏覽器如何渲染您傳送的資產,讓我們來看看完成擴充功能所需的最後幾件事:
### 建立計算顏色的函數
`/src/index.js` 中,於您設置的一系列 `const` 變數之後新增一個名為 `calculateColor()` 的函數,以便訪問 DOM
```JavaScript
當您的程式碼有效率地運行時,人們真的能“感受到”差異。您知道那種網頁瞬間載入或動畫流暢播放的感覺嗎?那就是良好效能的展現。
效能不僅關乎速度更是打造感覺自然、不笨拙且不令人挫折的網頁體驗。早期電腦時代Grace Hopper 著名地在桌上放了一段納秒長的線(約一英尺),用來說明光在十億分之一秒內能傳多遠。這是她解釋為何每一微秒在運算中都很重要的方式。讓我們一起探索協助您找出效能瓶頸的偵查工具。
>「網站效能關乎兩件事:頁面載入速度,以及其上的程式碼執行速度。」-- [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
如何讓您的網站在各式裝置、面對各種使用者、處於不同情境時都極速響應,這話題不意外地相當廣泛。以下是一些建議,無論您是開發標準網頁專案或瀏覽器擴充套件,都能參考。
優化網站的第一步是了解底層實際發生什麼。幸運的是,您的瀏覽器內建強而有力的偵察工具。
```mermaid
flowchart LR
A[HTML] --> B[解析]
B --> C[DOM 樹]
D[CSS] --> E[解析]
E --> F[CSSOM]
G[JavaScript] --> H[執行]
C --> I[渲染樹]
F --> I
H --> I
I --> J[佈局]
J --> K[繪製]
K --> L[合成]
L --> M[顯示]
subgraph "關鍵渲染路徑"
N["1. 解析 HTML"]
O["2. 解析 CSS"]
P["3. 執行 JS"]
Q["4. 建構渲染樹"]
R["5. 元素佈局"]
S["6. 繪製像素"]
T["7. 合成圖層"]
end
style M fill:#e8f5e8
style I fill:#fff3e0
style H fill:#ffebee
```
在 Edge 中開啟開發者工具,點擊右上角三個點,再選擇「更多工具」>「開發者工具」。或用快捷鍵Windows 是 `Ctrl` + `Shift` + `I`Mac 則是 `Option` + `Command` + `I`。進去後,點選「效能」標籤──這裡就是您的偵查場域。
**這是您的效能偵查工具箱:**
- **開啟** 開發者工具(作為開發者您會一直用到它!)
- **前往** 效能標籤──想像它是您的網頁健身追蹤器
- **點擊** 錄製按鈕,觀察頁面運作情形
- **檢視** 結果,找出哪些環節拖慢速度
試試看這個方法。開啟一個網站Microsoft.com 效果不錯),按「錄製」。現在重新整理頁面,觀察分析器捕捉的過程。停止錄製後,您會看到瀏覽器如何「腳本執行」、「渲染」及「繪製」的詳細流程。這讓我想起火箭發射任務控制中心監控所有系統的即時數據──您可以確切知道何時發生了什麼。
![Edge profiler](../../../../translated_images/profiler.5a4a62479c5df01c.tw.png)
✅ [Microsoft 文件](https://docs.microsoft.com/microsoft-edge/devtools-guide/performance/?WT.mc_id=academic-77807-sagibbon)提供了更多深入細節,想深入了解請參考
> 專業提示:測試之前清除瀏覽器快取,來看看您的網站對第一次訪客的效能──通常與回訪者有顯著差異!
在分析時間軸中選擇特定事件,放大觀察頁面載入時的細節。
挑選部分分析時間軸,查看摘要面板,就能獲得您的頁面效能快照:
![Edge profiler snapshot](../../../../translated_images/snapshot.97750180ebcad737.tw.png)
檢查事件記錄面板,看看是否有事件耗時超過 15 毫秒:
![Edge event log](../../../../translated_images/log.804026979f3707e0.tw.png)
✅ 熟悉您的分析器!打開本網站的開發者工具,檢查是否有瓶頸。哪個資源載入最慢?最快的是哪個?
```mermaid
flowchart TD
A[開啟開發者工具] --> B[切換到效能標籤]
B --> C[點擊錄製按鈕]
C --> D[執行操作]
D --> E[停止錄製]
E --> F{分析結果}
F --> G[檢查時間軸]
F --> H[檢視網路]
F --> I[檢查腳本]
F --> J[識別繪製事件]
G --> K{長任務?}
H --> L{大型資源?}
I --> M{渲染阻塞?}
J --> N{昂貴的繪製?}
K -->|是| O[優化 JavaScript]
L -->|是| P[壓縮資源]
M -->|是| Q[新增 Async/Defer]
N -->|是| R[簡化樣式]
O --> S[再次測試]
P --> S
Q --> S
R --> S
style A fill:#e1f5fe
style F fill:#fff3e0
style S fill:#e8f5e8
```
## 分析時該注意什麼
執行分析只是起點──真正的技巧是理解那些彩色圖表意指何物。別擔心,很快您就能讀懂。資深開發者能在問題形成前發現警訊。
讓我們談談常見的嫌疑犯──經常潛入網頁專案的效能問題。就像 Marie Curie 必須仔細監控實驗室中的輻射值,我們也要注意顯示潛在問題的特定模式。提早偵測可以省去您(以及使用者)很多挫折。
**資產大小**:網站載入的「重量」多年來日益增長,而其中許多為圖片所致。就像我們往數位行李箱塞入越來越多東西。
✅ 查看[網際網路檔案館](https://httparchive.org/reports/page-weight),瞭解頁面大小的歷年變化,非常有啟發。
**保持資產優化方式:**
- **壓縮** 圖片!現代格式像 WebP 能顯著減小檔案大小
- **為** 每種裝置服務適合的圖片尺寸──無需將超大桌面圖傳給手機
- **縮小** CSS 與 JavaScript 檔案──每個字節都重要
- **使用** 延遲載入,圖片僅在使用者捲動至該區時下載
**DOM 遍歷**瀏覽器根據您的程式碼建構文件物件模型DOM因此為了效能盡量使用必要且最簡潔的標籤。舉例來說頁面不需要的 CSS 可以優化;只在單頁使用的樣式不必放在主要樣式表。
**DOM 優化關鍵策略:**
- **減少** HTML 元素數量與巢狀層級
- **移除** 未使用的 CSS 規則,並有效整合樣式表
- **規劃** CSS 只載入每頁所需
- **結構化** HTML使用語意標籤提升瀏覽器解析效率
**JavaScript**:每個 JavaScript 開發者都該注意『阻斷渲染』的腳本,這些腳本必須先被載入才能繼續解析並繪製 DOM。考慮對內嵌腳本使用 `defer`(如 Terrarium 模組所示)。
**現代 JavaScript 優化技巧:**
- **使用** `defer` 屬性讓腳本在 DOM 解析後載入
- **實作** 程式碼拆分,只載入必要 JavaScript
- **應用** 延遲載入非關鍵功能
- **減少** 使用笨重的函式庫與框架(若可能)
✅ 在[網站速度測試網站](https://www.webpagetest.org/)試試各種網站,瞭解判斷網站效能的常見檢測
### 🔄 **教學檢核點**
**效能理解**:建立擴充套件功能前,請確保您可以:
- ✅ 解釋從 HTML 到像素的關鍵渲染路徑
- ✅ 識別網頁應用常見效能瓶頸
- ✅ 使用瀏覽器開發者工具分析頁面效能
- ✅ 瞭解資產大小與 DOM 複雜度如何影響速度
**快速自測**:當您有阻斷渲染的 JavaScript 時會發生什麼?
*答案:瀏覽器必須先下載並執行該腳本,才能繼續解析 HTML 並渲染頁面*
**實務效能影響:**
- **100 毫秒延遲**:用戶察覺速度變慢
- **1 秒延遲**:用戶開始失去專注
- **3 秒以上**40% 用戶離開頁面
- **行動網路**:效能更為重要
現在您對瀏覽器如何呈現您送出的資產已有基礎認識,我們來看完成擴充套件還剩哪些步驟:
### 建立配色函式
現在我們將建立一個函式,把數字資料轉換成有意義的顏色。可以把它想像成交通號誌系統──綠色代表清潔能源,紅色代表碳密度高。
這個函式會從 API 取得的 CO2 資料判斷出最適合呈現環境影響的顏色。就像科學家在熱圖中用色彩視覺化複雜資料模式一樣──從海洋溫度到恆星形成。我們將它加入 `/src/index.js`,緊接之前設定的那些 `const` 變數之後:
```mermaid
flowchart LR
A[二氧化碳值] --> B[尋找最接近的刻度點]
B --> C[取得刻度索引]
C --> D[映射到顏色]
D --> E[發送到背景]
subgraph "顏色刻度"
F["0-150: 綠色(清潔)"]
G["150-600: 黃色(中度)"]
H["600-750: 橙色(高)"]
I["750+: 棕色(非常高)"]
end
subgraph "訊息傳遞"
J[內容腳本]
K[chrome.runtime.sendMessage]
L[背景腳本]
M[圖示更新]
end
style A fill:#e1f5fe
style D fill:#e8f5e8
style E fill:#fff3e0
```
```javascript
function calculateColor(value) {
let co2Scale = [0, 150, 600, 750, 800];
let colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
// 定義二氧化碳強度刻度(每千瓦時克數)
const co2Scale = [0, 150, 600, 750, 800];
// 對應顏色由綠色(清潔)到深棕色(高碳)
const colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
let closestNum = co2Scale.sort((a, b) => {
// 找出最接近輸入的刻度值
const closestNum = co2Scale.sort((a, b) => {
return Math.abs(a - value) - Math.abs(b - value);
})[0];
console.log(value + ' is closest to ' + closestNum);
let num = (element) => element > closestNum;
let scaleIndex = co2Scale.findIndex(num);
let closestColor = colors[scaleIndex];
console.log(`${value} is closest to ${closestNum}`);
// 找出對應顏色映射的索引值
const num = (element) => element > closestNum;
const scaleIndex = co2Scale.findIndex(num);
const closestColor = colors[scaleIndex];
console.log(scaleIndex, closestColor);
// 傳送顏色更新訊息給背景腳本
chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } });
}
```
這裡發生了什麼?您傳入一個值(來自上一課完成的 API 呼叫中的碳強度),然後計算其值與顏色陣列中索引的接近程度。接著,您將最接近的顏色值傳送到 chrome runtime。
chrome.runtime 有 [一個 API](https://developer.chrome.com/extensions/runtime) 用於處理各種背景任務,您的擴充功能正在利用它:
> 「使用 chrome.runtime API 來檢索背景頁面、返回有關 manifest 的詳細資訊,並監聽和響應應用程式或擴充功能生命週期中的事件。您還可以使用此 API 將 URL 的相對路徑轉換為完全限定的 URL。」
✅ 如果您正在為 Edge 開發此瀏覽器擴充功能,可能會驚訝於您正在使用 chrome API。新版 Edge 瀏覽器基於 Chromium 瀏覽器引擎,因此您可以利用這些工具。
> 注意,如果您想分析瀏覽器擴充功能,請從擴充功能本身內部啟動開發者工具,因為它是獨立的瀏覽器實例。
**讓我們拆解這個巧妙的小函式:**
- **建立** 兩個陣列──一個存 CO2 水平,另一個存顏色(綠色 = 清潔,棕色 = 污染!)
- **透過** 陣列排序找到最接近實際 CO2 值的選項
- **用** findIndex() 方法抓出對應顏色
- **發送** 訊息到 Chrome 背景腳本,帶上選定的顏色字串
- **利用** 模板字串(反引號)讓字串格式更清晰
- **用** const 宣告保持程式有條理
`chrome.runtime` [API](https://developer.chrome.com/extensions/runtime) 就像您的擴充套件神經系統──它處理幕後通訊和各項工作流程:
>「使用 chrome.runtime API 取得背景頁面、回傳清單細節,監聽及回應應用程式或擴充套件生命週期事件。您也可以用此 API 將相對路徑 URL 轉成完整 URL。」
**為何 Chrome Runtime API 如此方便:**
- **讓** 擴充套件各部分互相溝通
- **在背景** 執行工作而不凍結使用者介面
- **管理** 擴充套件的生命週期事件
- **方便** 脚本間訊息傳遞
✅ 如果您在 Edge 開發此擴充套件,可能會驚訝它用的是 Chrome API。新版 Edge 瀏覽器基於 Chromium 引擎,因此可以利用這些工具。
```mermaid
architecture-beta
group browser(logos:chrome)[瀏覽器]
service popup(logos:html5)[彈出式介面] in browser
service content(logos:javascript)[內容腳本] in browser
service background(database)[背景腳本] in browser
service api(logos:api)[外部 API] in browser
popup:R -- L:content
content:R -- L:background
background:T -- B:api
content:T -- B:api
junction junctionCenter in browser
popup:R -- L:junctionCenter
junctionCenter:R -- L:background
```
> **專業提示**:若想分析瀏覽器擴充套件的效能,請從該擴充套件本身啟動開發者工具,因為它是獨立的瀏覽器實例。這樣您可以取得擴充特定的效能指標。
### 設定預設圖示顏色
現在,在 `init()` 函數中,透過再次調用 chrome 的 `updateIcon` 操作,將圖示設置為預設的綠色:
在開始擷取真實資料前,先給擴充套件一個起始狀態。沒有人喜歡看見空白或損壞的圖示。我們先以綠色開始,讓使用者在安裝後立即知道擴充套件正常運作。
在您的 `init()` 函式中,設定這個預設綠色圖示:
```JavaScript
```javascript
chrome.runtime.sendMessage({
action: 'updateIcon',
value: {
color: 'green',
},
value: {
color: 'green',
},
});
```
### 呼叫函數並執行呼叫
接下來,透過將其新增到 C02Signal API 返回的 promise 中,呼叫您剛剛建立的函數:
**此初始化達成:**
- **將** 中性綠色設為預設狀態
- **提供** 擴充套件載入時的即時視覺反饋
- **建立** 與背景腳本通訊的模式
- **確保** 使用者在資料載入前看到功能正常的擴充套件
### 呼叫函式,執行呼叫
```JavaScript
//let CO2...
現在將所有部分串連,確保新 CO2 資料一到,您的圖示自動用對應顏色更新。這如同電子裝置中接通最後一條電路──所有元件瞬間協同工作。
在取得 API CO2 資料後,加入這行程式碼:
```javascript
// 從 API 取得二氧化碳數據後
// 讓 CO2 = data.data[0].intensity.actual;
calculateColor(CO2);
```
最後,在 `/dist/background.js` 中,新增監聽器以監聽這些背景操作呼叫:
**此整合達成:**
- **連結** API 資料流與視覺指示系統
- **自動** 觸發圖示更新,反映新資料
- **提供** 根據當前碳強度的即時視覺回饋
- **保持** 資料擷取與顯示邏輯的分離
```JavaScript
最後,在 `/dist/background.js` 新增監聽背景動作呼叫的事件:
```javascript
// 監聽來自內容腳本的訊息
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.action === 'updateIcon') {
chrome.action.setIcon({ imageData: drawIcon(msg.value) });
}
});
//borrowed from energy lollipop extension, nice feature!
// 使用 Canvas API 繪製動態圖示
// 借用自 energy lollipop 擴充功能 - 很棒的功能!
function drawIcon(value) {
let canvas = new OffscreenCanvas(200, 200);
let context = canvas.getContext('2d');
// 建立離屏畫布以提升效能
const canvas = new OffscreenCanvas(200, 200);
const context = canvas.getContext('2d');
// 繪製代表碳強度的彩色圓圈
context.beginPath();
context.fillStyle = value.color;
context.arc(100, 100, 50, 0, 2 * Math.PI);
context.fill();
// 回傳瀏覽器圖示的圖像資料
return context.getImageData(50, 50, 100, 100);
}
```
在此程式碼中,您新增了一個監聽器,用於監聽傳送到後端任務管理器的任何訊息。如果訊息名為 'updateIcon',則執行接下來的程式碼以使用 Canvas API 繪製適當顏色的圖示。
**此背景腳本功能:**
- **監聽** 您主脚本發來的訊息(就像接待員接電話)
- **處理** 'updateIcon' 請求以改變工具列圖示
- **使用** Canvas API 動態繪製新圖示
- **繪製** 一個簡單彩色圓圈,顯示當前碳強度
- **更新** 您的瀏覽器工具列圖示
- **利用** OffscreenCanvas 確保平滑效能(不阻塞 UI
✅ 您會在[太空遊戲課程](../../6-space-game/2-drawing-to-canvas/README.md)中學到更多 Canvas API
```mermaid
sequenceDiagram
participant CS as 內容腳本
participant BG as 背景腳本
participant Canvas as 離屏畫布
participant Browser as 瀏覽器圖示
CS->>BG: sendMessage({action: 'updateIcon', color})
BG->>Canvas: new OffscreenCanvas(200, 200)
Canvas->>Canvas: getContext('2d')
Canvas->>Canvas: beginPath() + fillStyle + arc()
Canvas->>Canvas: fill() + getImageData()
Canvas->>BG: 返回影像資料
BG->>Browser: chrome.action.setIcon(imageData)
Browser->>Browser: 更新工具列圖示
```
### 🔄 **教學檢核點**
**完整擴充套件理解**:驗證您對整個系統的掌握:
- ✅ 擴充套件不同脚本間的訊息傳遞如何運作?
- ✅ 為什麼效能上會使用 OffscreenCanvas 而非一般 Canvas
- ✅ Chrome Runtime API 在擴充功能架構中扮演什麼角色?
- ✅ 顏色計算演算法如何將資料映射到視覺反饋?
✅ 您將在 [太空遊戲課程](../../6-space-game/2-drawing-to-canvas/README.md) 中學到更多有關 Canvas API 的內容。
**效能考量**:您的擴充功能現在展示了:
- **高效訊息傳遞**:腳本上下文之間的乾淨通訊
- **優化呈現**OffscreenCanvas 防止 UI 阻塞
- **即時更新**:根據即時資料動態更改圖示
- **記憶體管理**:適當清理和資源處理
現在,重新建置您的擴充功能(`npm run build`),刷新並啟動您的擴充功能,並觀察顏色變化。是時候去跑腿或洗碗了嗎?現在您知道了!
**是時候測試您的擴充功能了:**
- **使用** `npm run build` 建置所有內容
- **在瀏覽器** 重新載入您的擴充功能(別忘了這步驟)
- **開啟** 擴充功能並觀察圖示變色
- **檢查** 它如何響應來自全球的真實碳排放資料
恭喜您,您已經建立了一個實用的瀏覽器擴充功能,並且更深入了解瀏覽器的運作方式以及如何分析其效能。
現在您可以一眼判斷是否適合洗衣服,或是應該等待更乾淨的能源。您剛剛建立了一個真正有用的功能,同時學會了瀏覽器效能。
---
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
**描述:** 透過新增追蹤並顯示擴充功能不同元件載入時間的功能,增強瀏覽器擴充功能的效能監控能力。
**提示:** 建立一個效能監控系統,測量並紀錄從 API 抓取 CO2 資料、計算顏色和更新圖示所需時間。新增名為 `performanceTracker` 的函式,利用 Performance API 來測量這些操作,並在瀏覽器主控台顯示帶有時間戳記和持續時間的結果。
欲了解更多 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 內容。
## 🚀 挑戰
調查一些已存在很久的開源網站,並根據其 GitHub 歷史記錄,看看是否能判斷它們在效能方面的最佳化過程。如果有的話,最常見的痛點是什麼?
這是一個有趣的偵探任務:挑選幾個存在多年的開源網站(如 Wikipedia、GitHub、Stack Overflow 等),深入挖掘他們的提交歷史。你能發現他們何時做出效能改進嗎?並且這些問題經常是什麼?
**你的調查方法:**
- **搜尋** 提交訊息中包含「optimize」、「performance」或「faster」等字眼
- **觀察** 是否有模式——他們是否持續修正相同類型問題?
- **識別** 造成網站變慢的常見元凶
- **分享** 你發現的內容,讓其他開發者從實際案例中學習
## 課後測驗
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/28)
## 回顧與自學
考慮訂閱 [效能電子報](https://perf.email/)
調查瀏覽器如何透過其網頁工具中的效能標籤來評估網頁效能。您是否發現任何主要差異?
## 複習與自學
考慮訂閱一份 [效能電子報](https://perf.email/)
透過瀏覽器開發工具的效能分頁,研究瀏覽器如何評估網頁效能。你發現了哪些主要差異?
### ⚡ **接下來 5 分鐘能做的事**
- [ ] 開啟瀏覽器工作管理員Chrome 使用 Shift+Esc查看擴充功能的資源使用情況
- [ ] 使用開發工具效能分頁錄製與分析網頁效能
- [ ] 檢查瀏覽器擴充功能頁面,找出哪些擴充功能影響啟動時間
- [ ] 暫時停用擴充功能,觀察效能差異
### 🎯 **這一小時可以完成的任務**
- [ ] 完成課後測驗並理解效能概念
- [ ] 為瀏覽器擴充功能實作背景腳本
- [ ] 學習使用 browser.alarms 進行高效背景任務
- [ ] 練習內容腳本與背景腳本之間的訊息傳遞
- [ ] 測量並優化擴充功能的資源使用
### 📅 **一周內的效能旅程**
- [ ] 完成具備背景功能的高效能瀏覽器擴充功能
- [ ] 精通 Service Worker 及現代擴充功能架構
- [ ] 實作高效資料同步與快取策略
- [ ] 學習進階擴充功能效能除錯技術
- [ ] 優化擴充功能的功能與資源效率
- [ ] 建立擴充功能效能測試範例
### 🌟 **一個月的優化掌握**
- [ ] 打造企業級高性能瀏覽器擴充功能
- [ ] 掌握 Web Workers、Service Workers 及現代網頁效能技術
- [ ] 參與專注於效能優化的開源專案
- [ ] 精通瀏覽器內部及進階除錯技術
- [ ] 建立效能監控工具與最佳實踐指南
- [ ] 成為幫助優化網頁應用的效能專家
## 🎯 您的瀏覽器擴充功能掌握時程
```mermaid
timeline
title 完整擴充功能開發進度
section 性能基礎 (20 分鐘)
瀏覽器分析:開發者工具精通
: 時間軸分析
: 瓶頸識別
: 關鍵渲染路徑
section 後台任務 (25 分鐘)
擴充功能架構:訊息傳遞
: 後台腳本
: 執行時 API 使用
: 跨上下文通訊
section 視覺回饋 (30 分鐘)
動態介面:顏色計算演算法
: Canvas API 整合
: 圖示生成
: 即時更新
section 性能優化 (35 分鐘)
高效程式碼:非同步操作
: 記憶體管理
: 資源清理
: 性能監控
section 生產準備 (45 分鐘)
精修與測試:跨瀏覽器相容性
: 錯誤處理
: 使用者體驗
: 性能驗證
section 進階功能 (1 週)
擴充生態系Chrome 線上應用程式商店
: 使用者回饋
: 分析整合
: 更新管理
section 專業發展 (2 週)
企業擴充功能:團隊協作
: 程式碼審查
: 持續整合/持續部署管線
: 安全稽核
section 專家精通 (1 個月)
平台專業知識:進階 Chrome API
: 性能優化
: 架構模式
: 開源貢獻
```
### 🛠️ 您的完整擴充功能開發工具組
完成此三部曲後,您已掌握:
- **瀏覽器架構**:深入瞭解擴充功能如何與瀏覽器系統整合
- **效能分析**:使用開發者工具識別與修正瓶頸
- **非同步程式設計**:現代 JavaScript 模式,實現回應式且非阻塞操作
- **API 整合**:利用授權與錯誤處理抓取外部資料
- **視覺設計**:動態 UI 更新與基於 Canvas 的圖形生成
- **訊息傳遞**:擴充功能架構中的跨腳本通訊
- **用戶體驗**:載入狀態、錯誤處理與直覺互動
- **生產技能**:測試、除錯與針對實務環境的優化
**實務應用**:您的擴充功能開發技能直接適用於:
- **漸進式網頁應用**:相似架構與效能模式
- **Electron 桌面應用**:使用網頁技術的跨平台應用
- **行動混合應用**Cordova/PhoneGap 使用網頁 API 開發
- **企業級網頁應用**:複雜儀表板和生產力工具
- **Chrome DevTools 擴充功能**:開發者進階工具與除錯
- **Web API 整合**:任何與外部服務通訊的應用程式
**專業影響**:您現在能夠:
- **構建** 從概念到部署的生產級瀏覽器擴充功能
- **優化** 使用業界標準分析工具的網頁應用效能
- **架構** 具適當職責分離的可擴展系統
- **除錯** 複雜非同步操作與跨上下文通訊
- **貢獻** 開源擴充功能專案與瀏覽器標準
**下一階段機會**
- **Chrome 網路商店開發者**:為數百萬用戶發佈擴充功能
- **網頁效能工程師**:專長優化與用戶體驗
- **瀏覽器平台開發者**:貢獻瀏覽器引擎開發
- **擴充功能框架打造者**:構建協助其他開發者的工具
- **開發者關係**:透過教學與內容創作分享知識
🌟 **成就解鎖**:您已打造出一個完整、功能齊備的瀏覽器擴充功能,展示專業開發實踐與現代網頁標準!
## 作業
[分析網站效能](assignment.md)
[分析一個網站效能](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們努力追求準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的原文版本應被視為權威依據。對於重要資訊,建議採用專業人工翻譯。我們不對因使用此翻譯而產生的任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,21 +1,109 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "fc09b0fb314a5ab0507ba99216e6a843",
"translation_date": "2025-08-23T23:47:44+00:00",
"original_hash": "a203e560e58ccc6ba68bffc40c7c8676",
"translation_date": "2026-01-06T13:54:49+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/assignment.md",
"language_code": "tw"
}
-->
# 分析網站效能
提供一份網站的詳細報告,指出效能問題的區域。分析網站為何速度緩慢,以及可以採取哪些措施來加快速度。不僅僅依賴瀏覽器工具,還要研究其他可以幫助撰寫報告的工具。
## 作業概述
效能分析是現代網頁開發人員的重要技能。在此作業中,您將針對一個真實網站進行全面的效能審核,使用瀏覽器內建工具及第三方服務來找出瓶頸並提出優化策略。
您的任務是提交一份詳盡的效能報告,展示您對網頁效能原則的理解,以及有效使用專業分析工具的能力。
## 作業說明
**選擇一個網站** 進行分析—可從以下選項擇一:
- 您常使用的熱門網站(新聞、社群媒體、電商)
- 開放原始碼專案網站GitHub pages、文件網站
- 本地商家網站或個人作品集
- 您自己的專案或過去課程作業
**進行多工具分析**,至少使用三種不同方法:
- **瀏覽器開發者工具** — 使用 Chrome/Edge 的效能頁籤進行詳細剖析
- **線上審核工具** — 嘗試 Lighthouse、GTmetrix 或 WebPageTest
- **網路分析** — 檢查資源載入、檔案大小與請求模式
**撰寫發現報告**,內容包含:
### 效能指標分析
- **載入時間量測**,涵蓋多個工具與角度
- **核心網頁指標** 分數LCP、FID、CLS及其意涵
- **資源分解**,顯示哪些資產對載入時間貢獻最大
- **網路瀑布圖分析**,找出阻塞資源
### 問題識別
- **具體效能瓶頸**及支援數據
- **根本原因分析**,說明每個問題為何發生
- **使用者影響評估**,描述問題對實際用戶的影響
- **問題優先級排序**,依嚴重程度和修復難度定排行
### 優化建議
- **具體且可執行的改善方案**及預期效果
- **每項建議的實作策略**
- **可採用的現代最佳實務**(如延遲加載、壓縮等)
- **持續效能監控的工具和技術**
## 研究要求
**不要只依賴瀏覽器工具**,擴展分析可使用:
**第三方審核服務:**
- [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) — 全面審核
- [GTmetrix](https://gtmetrix.com/) — 效能與優化洞察
- [WebPageTest](https://www.webpagetest.org/) — 實際網路測試環境
- [Pingdom](https://tools.pingdom.com/) — 全球效能監控
**專門分析工具:**
- [Bundle Analyzer](https://bundlephobia.com/) — JavaScript 套件大小分析
- [影像優化工具](https://squoosh.app/) — 資產優化機會
- [安全標頭分析](https://securityheaders.com/) — 安全性對效能的影響
## 交付格式
製作一份專業報告2-3頁包含
1. **執行摘要** — 主要發現與建議概述
2. **方法論** — 使用工具與測試方法
3. **當前效能評估** — 基線指標與量測結果
4. **識別問題** — 詳細問題分析與數據說明
5. **建議方案** — 優先改善策略
6. **實施規劃** — 優化步驟計畫
**包含視覺證據:**
- 效能工具與指標截圖
- 展示效能數據的圖表
- 前後比較(若可能)
- 網路瀑布圖與資源分解
## 評分標準
| 評分標準 | 優異 | 合格 | 有待改進 |
| -------- | ---------------------------------------------------------------------------------------------------------- | --------------------------- | ----------------------------- |
| | 提供的報告不僅包含來自瀏覽器工具的詳細資訊,還包括(如果有的話)來自第三方工具的資料 | 提供一份基本的報告 | 提供一份簡略的報告 |
| 評分標準 | 優異 (90-100%) | 合格 (70-89%) | 需改進 (50-69%) |
| -------- | -------------- | ------------- | ---------------- |
| **分析深度** | 使用4種以上工具進行全面分析具詳細指標、根因與用戶影響評估 | 使用3種工具有明確指標及基本問題識別 | 使用2種工具分析淺且問題識別有限 |
| **工具多樣性** | 使用瀏覽器工具加3種以上第三方服務並有比較分析與洞察 | 使用瀏覽器工具加2種第三方服務有部分比較分析 | 使用瀏覽器工具加1種第三方服務有限比較 |
| **問題識別** | 識別5個以上具體效能問題含詳細根因分析與量化影響 | 識別3-4個效能問題有良好分析與部分影響測量 | 識別1-2個效能問題僅基本分析 |
| **建議方案** | 提出具體可行建議,含實作細節、預期效果及現代最佳實務 | 提供良好建議,有部分實作指引與預期成果 | 所提建議基礎,缺乏詳細實作說明 |
| **專業呈現** | 井然有序報告,結構清晰、視覺證據、執行摘要及專業格式 | 組織良好,部分視覺證據與結構清楚 | 組織基本,視覺證據有限 |
## 學習目標
完成此作業,您將展現能夠:
- **運用**專業效能分析工具與方法論
- **識別**以資料為依據的效能瓶頸
- **分析**程式碼品質與使用者體驗的關聯
- **建議**具體且可行的優化策略
- **以專業格式**溝通技術性發現
此作業將強化課程中所學效能概念,並培養您在網站開發職涯中會用到的實務技能。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原文文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。文件的原始語言版本應視為權威資料來源。對於重要資訊,建議採用專業人工翻譯。我們對因使用此翻譯所產生的任何誤解或誤譯不負任何責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,50 +1,142 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "979cfcce2413a87d9e4c67eb79234bc3",
"translation_date": "2025-08-29T15:23:06+00:00",
"original_hash": "a6332a7bb4d0be3bfd24199c83993777",
"translation_date": "2026-01-06T13:46:20+00:00",
"source_file": "6-space-game/1-introduction/README.md",
"language_code": "tw"
}
-->
# 建立太空遊戲第一部分:介紹
![video](../../../../6-space-game/images/pewpew.gif)
# 建造太空遊戲第一部分:簡介
```mermaid
journey
title 你的遊戲開發旅程
section 基礎
學習遊戲架構: 3: Student
了解繼承: 4: Student
探索組合: 4: Student
section 溝通
建立發布/訂閱系統: 4: Student
設計事件流程: 5: Student
連接元件: 5: Student
section 應用
創建遊戲物件: 5: Student
實作設計模式: 5: Student
規劃遊戲架構: 5: Student
```
![太空遊戲動畫顯示遊戲玩法](../../../../6-space-game/images/pewpew.gif)
就像 NASA 的任務控制中心在太空發射期間協調多個系統一樣,我們將建造一款太空遊戲,展示程式不同部分如何無縫協作。在創造你實際可以玩的東西時,你將學習適用於任何軟體專案的重要程式設計概念。
我們將探索兩種基本的程式碼組織方法:繼承和組合。這些不僅是學術概念——它們是推動從電子遊戲到銀行系統一切的相同模式。我們還將實現一種稱為發布/訂閱pub/sub的通訊系統其運作方式類似於航天器中使用的通訊網路允許不同元件共享資訊而不產生彼此依賴。
透過本系列結束時,你將了解如何構建可擴展且可演進的應用程式——無論你是在開發遊戲、網頁應用程式還是其他軟體系統。
```mermaid
mindmap
root((遊戲架構))
Object Organization
繼承
組合
類別繼承階層
行為混合
Communication Patterns
發佈/訂閱系統
事件發射器
訊息傳遞
鬆散耦合
Game Objects
屬性 (x, y)
行為 (移動, 碰撞)
生命週期管理
狀態管理
Design Patterns
工廠函數
觀察者模式
組件系統
事件驅動架構
Scalability
模組化設計
可維護程式碼
測試策略
性能優化
```
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/29)
### 遊戲開發中的繼承與組合
## 遊戲開發中的繼承與組合
在之前的課程中,由於專案範圍較小,您不需要太擔心應用程式的設計架構。然而,當應用程式的規模和範圍擴大時,架構設計的決策就變得更加重要。在 JavaScript 中,建立大型應用程式有兩種主要方法:*組合* 或 *繼承*。這兩種方法各有優缺點,但我們將以遊戲的背景來解釋它們。
隨著專案複雜度增加,程式碼組織變得關鍵。一開始可能只是簡單的腳本,但缺乏良好結構的話,會變得難以維護——就像阿波羅任務需要仔細協調成千上萬的元件一樣
✅ 有一本非常著名的程式設計書籍與[設計模式](https://en.wikipedia.org/wiki/Design_Patterns)有關。
我們將探索兩種基本的程式碼組織方法:繼承與組合。每種方法都有其獨特優勢,理解兩者將幫助你在不同情況下選擇合適方法。我們將透過太空遊戲示範這些概念,在遊戲中,英雄、敵人、加成物和其他物件必須高效互動
在遊戲中,您會有 `遊戲物件`,這些物件存在於螢幕上。這意味著它們在笛卡爾座標系統中有一個位置,具體來說就是 `x``y` 座標。當您開發遊戲時,您會注意到所有的遊戲物件都有一些標準屬性,這些屬性在每個遊戲中都是通用的,主要包括以下幾個元素:
✅ 最著名的程式設計書籍中就有一本專注於[設計模式](https://en.wikipedia.org/wiki/Design_Patterns)。
- **基於位置** 大多數(如果不是全部的話)遊戲元素都是基於位置的。這意味著它們有一個位置,即 `x``y`
- **可移動** 這些是可以移動到新位置的物件。通常是英雄、怪物或 NPC非玩家角色但例如像樹這樣的靜態物件則不是。
- **自我銷毀** 這些物件只存在於一段時間內,然後會自動設置為刪除。通常這是通過一個 `dead``destroyed` 的布林值來表示,告訴遊戲引擎該物件不再需要渲染。
- **冷卻時間** "冷卻時間" 是短暫存在的物件中常見的屬性。一個典型的例子是文字或圖形效果(如爆炸),這些效果只應顯示幾毫秒。
在任何遊戲中,你都會碰到`遊戲物件`——遊戲世界中互動的元素。英雄、敵人、加成物與視覺特效都是遊戲物件。每個物件都存在於特定螢幕座標,使用`x`與`y`值,類似在座標平面繪點。
✅ 想想像《吃豆人》這樣的遊戲。您能在這個遊戲中識別出上述四種類型的物件嗎?
儘管外觀不同,這些物件通常有基本共同行為:
### 表達行為
- **它們存在於某處**——每個物件有 x 和 y 座標,遊戲才知道要畫在哪裡
- **許多會移動**——英雄奔跑,敵人追逐,子彈飛過螢幕
- **它們有壽命**——有些永遠存在,有些(例如爆炸)短暫出現後消失
- **它們對事件作出反應**——當碰撞發生、取得加成物、血條更新
✅ 想想 Pac-Man 這款遊戲。你能在這遊戲中識別上面列出的四種物件類型嗎?
```mermaid
classDiagram
class GameObject {
+x: number
+y: number
+type: string
+exists_somewhere()
}
class MovableObject {
+moveTo(x, y)
+can_move_around()
}
class TemporaryObject {
+lifespan: number
+has_lifespan()
}
class InteractiveObject {
+onCollision()
+reacts_to_stuff()
}
GameObject <|-- MovableObject
GameObject <|-- TemporaryObject
GameObject <|-- InteractiveObject
MovableObject <|-- Hero
MovableObject <|-- Enemy
MovableObject <|-- Bullet
TemporaryObject <|-- PowerUp
TemporaryObject <|-- Explosion
InteractiveObject <|-- Collectible
InteractiveObject <|-- Obstacle
```
### 用程式碼表達行為
上述描述的所有內容都是遊戲物件可能具有的行為。那麼,我們如何編碼這些行為呢?我們可以將這些行為表達為與類別或物件相關聯的方法。
現在你了解遊戲物件共享的共同行為,我們來探討如何用 JavaScript 實現這些行為。你可以透過附加到類別或個別物件上的方法表達物件行為,有幾種方法可供選擇
**類別**
**基於類別的方法**
這種方法的核心思想是使用 `類別``繼承` 來為類別添加特定的行為。
類別與繼承提供了一種結構化的方法來組織遊戲物件。像 Carl Linnaeus 開發的生物分類系統一樣,你先有一個包含共同屬性的基底類別,然後建立繼承基本特性並增加專門功能的子類別
✅ 繼承是一個重要的概念。可以在 [MDN 的繼承文章](https://developer.mozilla.org/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) 中了解更多。
✅ 繼承是很重要的概念。詳細了解請看 [MDN 繼承文章](https://developer.mozilla.org/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)。
用程式碼表達時,遊戲物件通常看起來像這樣:
以下示範如何使用類別和繼承實作遊戲物件
```javascript
//set up the class GameObject
// 第一步:建立基礎的 GameObject 類別
class GameObject {
constructor(x, y, type) {
this.x = x;
@ -52,173 +144,390 @@ class GameObject {
this.type = type;
}
}
```
**一步步拆解:**
- 我們創建了一個基礎範本供所有遊戲物件使用
- 建構子保存物件所在位置(`x`, `y`)以及物件類型
- 這成為你所有遊戲物件建造的基礎
//this class will extend the GameObject's inherent class properties
```javascript
// 第2步透過繼承新增移動功能
class Movable extends GameObject {
constructor(x,y, type) {
super(x,y, type)
constructor(x, y, type) {
super(x, y, type); // 呼叫父類別建構子
}
//this movable object can be moved on the screen
// 新增移動至新位置的能力
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
```
**以上程式我們:**
- **擴展**了 GameObject 類別,新增移動功能
- **使用** `super()` 呼叫父建構子以初始化繼承屬性
- **新增** `moveTo()` 方法更新物件位置
//this is a specific class that extends the Movable class, so it can take advantage of all the properties that it inherits
```javascript
// 第3步建立特定的遊戲物件類型
class Hero extends Movable {
constructor(x,y) {
super(x,y, 'Hero')
constructor(x, y) {
super(x, y, 'Hero'); // 自動設定類型
}
}
//this class, on the other hand, only inherits the GameObject properties
class Tree extends GameObject {
constructor(x,y) {
super(x,y, 'Tree')
constructor(x, y) {
super(x, y, 'Tree'); // 樹木不需要移動
}
}
//a hero can move...
const hero = new Hero();
hero.moveTo(5,5);
// 第4步使用你的遊戲物件
const hero = new Hero(0, 0);
hero.moveTo(5, 5); // 英雄可以移動!
//but a tree cannot
const tree = new Tree();
const tree = new Tree(10, 15);
// tree.moveTo() 會造成錯誤-樹木無法移動
```
✅ 花幾分鐘重新構想一個《吃豆人》的英雄(例如 Inky、Pinky 或 Blinky並思考如何用 JavaScript 編寫它。
**理解這些概念:**
- **創造**繼承適當行為的專門物件類型
- **展示**繼承如何允許選擇性地加入功能
- **說明**英雄會移動,樹木則保持靜止
- **解釋**類別層級防止不當動作發生
✅ 花幾分鐘重新想像 Pac-Man 英雄(例如 Inky、Pinky 或 Blinky如何用 JavaScript 寫出。
**組合**
**組合方法**
另一種處理物件繼承的方法是使用 *組合*。在這種情況下,物件表達它們的行為如下:
組合遵循模組化設計哲學,類似於工程師設計航天器時使用可互換元件。你不從父類繼承,而是混合特定行為來創造具備所需功能的物件。此方法提供彈性,沒有嚴格層級限制。
```javascript
//create a constant gameObject
// 步驟1建立基本行為物件
const gameObject = {
x: 0,
y: 0,
type: ''
};
//...and a constant movable
const movable = {
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//then the constant movableObject is composed of the gameObject and movable constants
const movableObject = {...gameObject, ...movable};
};
```
**這段程式碼作用:**
- **定義**基底 `gameObject` 含位置與類型屬性
- **建立**獨立的 `movable` 行為物件提供移動功能
- **將**位置數據與移動邏輯分開,解耦
//then create a function to create a new Hero who inherits the movableObject properties
```javascript
// 步驟 2透過組合行為來組合物件
const movableObject = { ...gameObject, ...movable };
// 步驟 3為不同物件類型建立工廠函式
function createHero(x, y) {
return {
...movableObject,
x,
y,
type: 'Hero'
}
};
}
//...and a static object that inherits only the gameObject properties
function createStatic(x, y, type) {
return {
...gameObject
...gameObject,
x,
y,
type
}
};
}
//create the hero and move it
const hero = createHero(10,10);
hero.moveTo(5,5);
//and create a static tree which only stands around
const tree = createStatic(0,0, 'Tree');
```
**應該使用哪種模式?**
**以上程式我們:**
- **用展開語法**結合基底物件屬性與移動行為
- **創建**回傳客製物件的工廠函式
- **實現**無階級結構的彈性物件創建
- **允許**物件擁有其恰當的行為組合
選擇哪種模式完全取決於您。JavaScript 支援這兩種範式。
```javascript
// 第4步創建並使用您的組合物件
const hero = createHero(10, 10);
hero.moveTo(5, 5); // 運作完美!
--
const tree = createStatic(0, 0, 'Tree');
// tree.moveTo() 未定義 - 沒有組合移動行為
```
在遊戲開發中,另一種常見的模式是解決遊戲用戶體驗和效能問題。
**關鍵重點:**
- **透過混合行為來組合物件,而非繼承**
- **比嚴格繼承層級更具彈性**
- **讓物件只有它們需要的特性**
- **使用現代 JavaScript 展開語法清理物件結合**
```
**Which Pattern Should You Choose?**
**Which Pattern Should You Choose?**
```mermaid
quadrantChart
title Code Organization Patterns
x-axis Simple --> Complex
y-axis Rigid --> Flexible
quadrant-1 Advanced Composition
quadrant-2 Hybrid Approaches
quadrant-3 Basic Inheritance
quadrant-4 Modern Composition
Class Inheritance: [0.3, 0.2]
Interface Implementation: [0.6, 0.4]
Mixin Patterns: [0.7, 0.7]
Pure Composition: [0.8, 0.9]
Factory Functions: [0.5, 0.8]
Prototype Chain: [0.4, 0.3]
```
## Pub/Sub 模式
> 💡 **專家小技巧**:這兩種模式在現代 JavaScript 開發中都有應用。類別適合明確定義的層級結構,組合則適合最大彈性的需求。
>
**何時使用哪一種:**
- **有明確「是個」關係時選用繼承**(英雄 *是個* 可移動物件)
- **當需要「擁有」關係時選擇組合**(英雄 *擁有* 移動能力)
- **考慮團隊偏好與專案要求**
- **記得可以在同一應用中混用兩種方式**
### 🔄 **教學自我檢測**
**物件組織理解**:在進入通訊模式前,確保你可以:
- ✅ 解釋繼承與組合的差異
- ✅ 判斷何時使用類別 vs 工廠函式
- ✅ 了解繼承中 `super()` 怎麼運作
- ✅ 認識兩種方式對遊戲開發的優點
**快速自測**:如何用這兩種方法創建一個能移動且會飛的敵人?
- **繼承方式**`class FlyingEnemy extends Movable`
- **組合方式**`{ ...movable, ...flyable, ...gameObject }`
**實務連結**:這些模式隨處可見:
- **React Components**屬性組合vs 類別繼承
- **遊戲引擎**:實體-組件系統採用組合
- **行動應用程式**UI 框架常用繼承層級
## 通訊模式:發布/訂閱系統
隨著應用愈發龐大,管理元件間通訊成挑戰。發布/訂閱模式利用類似無線廣播原理——一個發送者可以觸及多個接收者,且發送者不需知道誰在聽。
想想當英雄受傷時發生什麼血條更新、音效撥放、視覺反饋出現。與其讓英雄物件直接耦合這些系統pub/sub 允許英雄廣播「受傷」訊息。任何需要回應的系統都可以訂閱該訊息類型並作出反應。
**Pub/Sub** 是「發布-訂閱」的縮寫。
```mermaid
flowchart TD
A[英雄受到傷害] --> B[發布HERO_DAMAGED]
B --> C[事件系統]
C --> D[血量條訂閱者]
C --> E[音效系統訂閱者]
C --> F[視覺效果訂閱者]
C --> G[成就系統訂閱者]
D --> H[更新血量顯示]
E --> I[播放受傷音效]
F --> J[顯示紅色閃光]
G --> K[檢查存活成就]
style A fill:#ffebee
style B fill:#e1f5fe
style C fill:#e8f5e8
style H fill:#fff3e0
style I fill:#fff3e0
style J fill:#fff3e0
style K fill:#fff3e0
```
### 理解 Pub/Sub 架構
✅ Pub/Sub 代表 "發布-訂閱"。
pub/sub 模式讓應用不同部分鬆散耦合,意即它們能配合運作,卻非彼此直接依賴。此分離使程式碼更易維護、測試且彈性高
這種模式的核心思想是應用程式的不同部分不應該彼此了解。為什麼呢?因為這樣可以更容易地了解整體情況。如果各部分是分離的,那麼當您需要改變行為時也會更容易。那麼我們如何實現這一點呢?我們通過建立以下概念來實現:
**pub/sub 重要角色:**
- **訊息**——簡單標籤類似 `'PLAYER_SCORED'` 描述發生了什麼(可帶額外資訊)
- **發布者**——負責「事情發生了!」訊息傳出給關注者
- **訂閱者**——表示「對該事件有興趣」並在事件發生時作出反應的物件
- **事件系統**——中介者確保訊息送達正確的聽眾
- **訊息**:訊息通常是一個文字字串,伴隨著一個可選的有效負載(用於說明訊息內容的一段資料)。遊戲中的典型訊息可以是 `KEY_PRESSED_ENTER`
- **發布者**:這個元素*發布*一個訊息,並將其發送給所有訂閱者。
- **訂閱者**:這個元素*監聽*特定的訊息,並在接收到該訊息後執行某些任務,例如發射雷射。
### 建立事件系統
這種模式的實現非常簡單,但它是一個非常強大的模式。以下是它的實現方式:
讓我們創建簡單但強大的事件系統示範以上概念:
```javascript
//set up an EventEmitter class that contains listeners
// 第一步:建立 EventEmitter 類別
class EventEmitter {
constructor() {
this.listeners = {};
this.listeners = {}; // 儲存所有事件監聽器
}
//when a message is received, let the listener to handle its payload
// 為特定的訊息類型註冊監聽器
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
//when a message is sent, send it to a listener with some payload
// 向所有已註冊的監聽器傳送訊息
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach(l => l(message, payload))
this.listeners[message].forEach(listener => {
listener(message, payload);
});
}
}
}
```
要使用上述程式碼,我們可以創建一個非常小的實現:
**程式運作分析:**
- **創建**中心事件管理系統使用簡單類別
- **使用物件**以訊息類型分類儲存監聽器
- **`on()` 註冊**新監聽器
- **`emit()` 向所有相關監聽器廣播訊息**
- **支援可選數據載荷傳遞相關資訊**
### 實做範例
來看看實際應用!我們打造簡單移動系統,展示 pub/sub 乾淨且彈性的特色:
```javascript
//set up a message structure
// 第一步:定義您的訊息類型
const Messages = {
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT'
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT',
HERO_MOVE_RIGHT: 'HERO_MOVE_RIGHT',
ENEMY_SPOTTED: 'ENEMY_SPOTTED'
};
//invoke the eventEmitter you set up above
// 第二步:建立您的事件系統和遊戲物件
const eventEmitter = new EventEmitter();
//set up a hero
const hero = createHero(0,0);
//let the eventEmitter know to watch for messages pertaining to the hero moving left, and act on it
const hero = createHero(0, 0);
```
**程式碼功能簡述:**
- **定義**常數物件避免訊息名稱拼寫錯誤
- **創建**事件發射器物件處理通訊
- **初始化**英雄物件於起始位置
```javascript
// 第三步:設置事件監聽器(訂閱者)
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
hero.moveTo(hero.x - 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
//set up the window to listen for the keyup event, specifically if the left arrow is hit, emit a message to move the hero left
window.addEventListener('keyup', (evt) => {
if (evt.key === 'ArrowLeft') {
eventEmitter.emit(Messages.HERO_MOVE_LEFT)
}
eventEmitter.on(Messages.HERO_MOVE_RIGHT, () => {
hero.moveTo(hero.x + 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
```
在上面的例子中,我們連接了一個鍵盤事件 `ArrowLeft`,並發送了 `HERO_MOVE_LEFT` 訊息。我們監聽該訊息,並因此移動 `hero`。這種模式的優勢在於事件監聽器和英雄彼此之間並不知道對方的存在。您可以將 `ArrowLeft` 重新映射到 `A` 鍵。此外,通過對 eventEmitter 的 `on` 函數進行一些編輯,還可以在 `ArrowLeft` 上執行完全不同的操作:
**以上程式我們:**
- **註冊**事件監聽器回應移動訊息
- **根據移動方向更新**英雄位置
- **新增**控制台日誌追蹤英雄位置
- **將移動邏輯從輸入處理分離**
```javascript
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
// 第4步將鍵盤輸入連接到事件發布者
window.addEventListener('keydown', (event) => {
switch(event.key) {
case 'ArrowLeft':
eventEmitter.emit(Messages.HERO_MOVE_LEFT);
break;
case 'ArrowRight':
eventEmitter.emit(Messages.HERO_MOVE_RIGHT);
break;
}
});
```
隨著遊戲規模的增長,事情變得更加複雜,但這種模式的複雜性保持不變,並且您的程式碼保持乾淨。非常推薦採用這種模式。
**理解這些概念:**
- **連接**鍵盤輸入與遊戲事件,無需緊耦合
- **讓輸入系統間接與遊戲物件通訊**
- **允許多系統回應同一鍵盤事件**
- **便於更換按鍵配置或添入新輸入方法**
```mermaid
sequenceDiagram
participant User
participant Keyboard
participant EventEmitter
participant Hero
participant SoundSystem
participant Camera
User->>Keyboard: 按下向左箭頭
Keyboard->>EventEmitter: emit('HERO_MOVE_LEFT')
EventEmitter->>Hero: 向左移動5像素
EventEmitter->>SoundSystem: 播放腳步聲
EventEmitter->>Camera: 跟隨英雄
Hero->>Hero: 更新位置
SoundSystem->>SoundSystem: 播放音效
Camera->>Camera: 調整視窗
```
> 💡 **專家小技巧**:此模式美妙之處在於彈性!你能簡單地添入音效、畫面震動或粒子效果,只需加更多事件監聽器,無須修改現有鍵盤或移動程式碼。
>
**這就是你會喜歡此方法的理由:**
- 新增功能變得超簡單,只要監聽你關注的事件
- 多個系統能對同一事件產生反應,互不干擾
- 測試更容易,因為各部分獨立運作
- 出錯時明確知道該從哪裡找問題
### 為什麼 Pub/Sub 可有效擴展
Pub/sub 模式在應用複雜度提升時仍維持簡潔。無論管理數十個敵人、動態 UI 更新或音效系統,該模式能在不改變架構下應對更大規模。新功能輕鬆整合進既有事件系統,不影響現有功能。
> ⚠️ **常見錯誤**:剛開始別創造過多特定訊息類型。先用大類別,之後根據遊戲需求細化。
>
**最佳實作建議:**
- **將相關訊息分組歸類**
- **使用清楚描述發生事件的名稱**
- **使訊息載荷簡潔聚焦**
- **為團隊協作做好訊息類型文件化**
### 🔄 **教學自我檢測**
**事件驅動架構理解**:檢驗你對系統完整概念的掌握:
- ✅ Pub/sub 如何避免組件間緊耦合?
- ✅ 為何事件驅動使新增功能更簡單?
- ✅ EventEmitter 在通訊流程中扮演什麼角色?
- ✅ 訊息常數如何避免錯誤並提升維護性?
**設計挑戰**:你會如何用 pub/sub 處理以下遊戲場景?
1. **敵人死亡**:更新分數、撥放音效、生成加成道具、從畫面移除
2. **關卡完成**:停止音樂、顯示介面、存檔進度、載入下一關
3. **加成物被收集**:提升能力、更新 UI、撥放效果、啟動計時器
**專業連結**:此模式廣泛應用於:
- **前端框架**React/Vue 事件系統
- **後端服務**:微服務通訊
- **遊戲引擎**Unity 事件系統
- **行動開發**iOS/Android 通知系統
---
## 🚀 挑戰
## GitHub Copilot Agent 挑戰 🚀
思考 Pub/Sub 模式如何提升遊戲的表現。哪些部分應該發出事件,遊戲應該如何對這些事件做出反應?現在是發揮創意的時候了,想像一個新遊戲以及它的各個部分可能如何運作。
使用 Agent 模式完成以下挑戰:
**描述:** 建立簡單遊戲物件系統,結合繼承與 pub/sub 模式。實作基礎遊戲,讓不同物件能透過事件通訊,不需彼此直接認識。
**提示:** 用 JavaScript 建立遊戲系統要求如下1) 創建含 x, y 座標與 type 屬性的基礎 GameObject 類別。2) 創建可移動的 Hero 類別繼承 GameObject。3) 創建可追逐英雄的 Enemy 類別繼承 GameObject。4) 實作用於 pub/sub 模式的 EventEmitter 類別。5) 設置事件監聽器,當英雄移動時,附近敵人士接收到 'HERO_MOVED' 事件並更新位置向英雄靠近。加入 console.log 來顯示物件間通訊。
了解更多[agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)資訊。
## 🚀 挑戰
考慮 pub-sub 模式如何增強遊戲架構。識別哪些元件應該發送事件以及系統應如何響應。設計一個遊戲概念並繪製其元件之間的通訊模式。
## 課後測驗
@ -226,13 +535,128 @@ eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
## 複習與自學
通過[閱讀相關內容](https://docs.microsoft.com/azure/architecture/patterns/publisher-subscriber/?WT.mc_id=academic-77807-sagibbon)來進一步了解 Pub/Sub。
透過[閱讀相關內容](https://docs.microsoft.com/azure/architecture/patterns/publisher-subscriber/?WT.mc_id=academic-77807-sagibbon),深入了解 Pub/Sub。
### ⚡ **您可以在接下來的 5 分鐘內做什麼**
- [ ] 開啟任意 HTML5 線上遊戲並使用開發者工具檢查其程式碼
- [ ] 建立一個簡單的 HTML5 Canvas 元素並繪製基本形狀
- [ ] 試用 `setInterval` 創建簡單動畫迴圈
- [ ] 探索 Canvas API 文件並試用繪圖方法
### 🎯 **您可以在這一小時內完成什麼**
- [ ] 完成課後測驗並理解遊戲開發概念
- [ ] 建立含 HTML、CSS 和 JavaScript 檔案的遊戲專案結構
- [ ] 建立一個持續更新和渲染的基本遊戲迴圈
- [ ] 在畫布上繪製第一個遊戲精靈
- [ ] 實作基本的圖像與音效資產載入
### 📅 **您的一週遊戲製作計畫**
- [ ] 完成全部預定功能的太空遊戲
- [ ] 新增精緻的圖形、音效與流暢動畫
- [ ] 實作遊戲狀態(開始畫面、遊戲中、遊戲結束)
- [ ] 建立計分系統及玩家進度追蹤
- [ ] 使遊戲可以跨裝置響應並兼顧無障礙性
- [ ] 線上分享遊戲並蒐集玩家回饋
### 🌟 **您的一個月遊戲開發計畫**
- [ ] 製作多款遊戲,探索不同類型與機制
- [ ] 學習 Phaser 或 Three.js 等遊戲開發框架
- [ ] 參與開源遊戲開發專案
- [ ] 精通進階遊戲程式設計模式與優化技巧
- [ ] 建立展示遊戲開發技能的作品集
- [ ] 指導對遊戲開發與互動媒體感興趣的新人
## 🎯 您的遊戲開發精通時間表
```mermaid
timeline
title 遊戲架構學習進程
section 物件模式20分鐘
程式碼組織:類別繼承
:組合模式
:工廠函式
:行為混合
section 通訊系統25分鐘
事件架構:發布/訂閱實作
:訊息設計
:事件觸發器
:鬆散耦合
section 遊戲物件設計30分鐘
實體系統:屬性管理
:行為組合
:狀態處理
:生命週期管理
section 架構模式35分鐘
系統設計:組件系統
:觀察者模式
:命令模式
:狀態機
section 進階概念45分鐘
可擴展架構:效能優化
:記憶體管理
:模組化設計
:測試策略
section 遊戲引擎概念(一週)
專業發展:場景圖
:資產管理
:渲染流程
:物理整合
section 框架精通(兩週)
現代遊戲開發React 遊戲模式
Canvas 優化
WebGL 基礎
:進階網頁應用遊戲
section 業界實務(一個月)
專業技能:團隊合作
:程式碼審查
:遊戲設計模式
:效能剖析
```
### 🛠️ 您的遊戲架構工具組總結
完成本課程後,您已具備:
- **設計模式精通**:理解繼承與組合的取捨
- **事件驅動架構**Pub/sub 實作以支援可擴充通訊
- **物件導向設計**:類別繼承與行為組合
- **現代 JavaScript**:工廠函式、展開語法及 ES6+ 模式
- **可擴充架構**:鬆耦合與模組化設計原則
- **遊戲開發基礎**:實體系統與元件模式
- **專業模式**:業界標準程式碼組織方法
**實務應用**:這些模式可直接應用於:
- **前端框架**React/Vue 元件架構及狀態管理
- **後端服務**:微服務通訊與事件驅動系統
- **行動開發**iOS/Android 應用架構與通知系統
- **遊戲引擎**Unity、Unreal 以及 Web 遊戲開發
- **企業軟體**:事件溯源與分散式系統設計
- **API 設計**RESTful 服務及即時通訊
**專業技能獲得**:您現在能夠:
- **設計** 使用已驗證模式的可擴充軟體架構
- **實作** 處理複雜互動的事件驅動系統
- **選擇** 適當的程式碼組織策略因應不同場景
- **除錯** 與維護鬆耦合系統的效率提升
- **溝通** 使用業界標準術語說明技術決策
**下一階段**:您已準備好將這些模式應用於真實遊戲,探索進階遊戲開發主題,或在 Web 應用中實踐這些架構概念!
🌟 **成就解鎖**:您已掌握從簡單遊戲到複雜企業系統所需的基本軟體架構模式!
## 作業
[設計一個遊戲](assignment.md)
[製作一款遊戲模擬](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對於因使用本翻譯而引起的任何誤解或錯誤解讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻譯而成。雖然我們力求準確,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件之原文版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所導致之任何誤解或誤釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,102 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "009bdedee9cc82988264be8cb31f9bf4",
"translation_date": "2025-08-23T23:06:15+00:00",
"original_hash": "c8fc39a014d08247c082878122e2ba73",
"translation_date": "2026-01-06T13:48:19+00:00",
"source_file": "6-space-game/1-introduction/assignment.md",
"language_code": "tw"
}
-->
# 模擬一個遊戲
# 模擬一款遊戲:應用設計模式
## 說明
## 作業概述
使用課程中的程式碼範例,撰寫一個你喜歡的遊戲的簡易版本。這必須是一個簡單的遊戲,但目標是使用類別或組合模式以及發布/訂閱模式來展示遊戲如何啟動。發揮創意!
運用你新學到的設計模式知識,製作一個簡單的遊戲原型!此作業將幫助你練習本課程中學到的架構模式(繼承或組合)以及發佈/訂閱通訊系統。
## 指示
建立一個簡單的遊戲表示,展示本課程中的設計模式。你的遊戲應該是可運作的,但不需要複雜的圖形——重點在底層架構與通訊模式。
### 要求
**選擇你的架構模式:**
- **選項 A**:使用基於類別的繼承(如 `GameObject``Movable``Hero` 範例)
- **選項 B**:使用組合(如工廠函式方法搭配混合行為)
**實現通訊:**
- **包含** 一個 `EventEmitter` 類別以實現發佈/訂閱訊息功能
- **設定** 至少 2-3 種不同的訊息類型(如 `PLAYER_MOVE`、`ENEMY_SPAWN`、`SCORE_UPDATE`
- **連接** 使用者輸入(鍵盤 / 滑鼠)透過事件系統觸發遊戲事件
**遊戲元素包含:**
- 至少一個由玩家控制的角色
- 至少一個其他遊戲物件(敵人、可收集物品或環境元素)
- 物件間的基本互動(碰撞、收集或通訊)
### 建議遊戲題材
**可考慮的簡單遊戲:**
- **貪食蛇遊戲**——蛇身節段跟隨蛇頭,食物隨機生成
- **乒乓球變化版**——球拍回應輸入,球碰牆彈跳
- **收集者遊戲**——玩家移動收集物品,同時避開障礙
- **防禦塔基礎**——防禦塔偵測並射擊移動敵人
### 程式碼結構指引
```javascript
// 範例起始結構
const Messages = {
// 在此定義您的遊戲訊息
};
class EventEmitter {
// 您的事件系統實作
}
// 選擇類別導向或組合式方法
// 類別導向範例:
class GameObject { /* base properties */ }
class Player extends GameObject { /* player-specific behavior */ }
// 或組合式範例:
const gameObject = { /* base properties */ };
const movable = { /* movement behavior */ };
function createPlayer() { /* combine behaviors */ }
```
### 測試你的實作
**驗證你的程式碼是否運行:**
- **測試** 事件觸發時物件是否移動或改變
- **確認** 多個物件是否能回應相同事件
- **檢查** 是否能添加新行為而不修改現有程式碼
- **確保** 鍵盤 / 滑鼠輸入正確觸發遊戲事件
## 提交指南
**你的提交應包含:**
1. **JavaScript 檔案**,實現你的遊戲
2. **HTML 檔案**,執行並測試你的遊戲(可簡單)
3. **註解**,說明你選擇的設計模式與原因
4. **簡要文件**,說明你的訊息類型及其功能
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | ------------------------------------------------- | ------------------------------------------------- | --------------------------------------------- |
| | 在螢幕上放置並操作三個元素 | 在螢幕上放置並操作兩個元素 | 在螢幕上放置並操作一個元素 |
| 標準 | 優異 (3 分) | 適當 (2 分) | 需改善 (1 分) |
|------|-------------|-------------|---------------|
| **架構模式** | 正確實作繼承或組合,類別 / 物件層級清晰 | 使用所選模式,但有些微問題或不一致 | 嘗試使用模式,但實作有明顯問題 |
| **發佈/訂閱實作** | EventEmitter 正確運作,多訊息類型及事件流程妥當 | 基本發佈/訂閱系統運作,有部分事件處理 | 有事件系統,但不穩定或無法運作 |
| **遊戲功能性** | 三個以上互動元素,透過事件互通 | 兩個互動元素,有基本事件通訊 | 一個元素回應事件或只有基本互動 |
| **程式碼品質** | 簡潔,詳盡註解,組織邏輯清楚,且採用現代 JavaScript | 大致組織良好,註解適中 | 程式碼可運作但缺組織與清楚註解 |
**額外加分:**
- **具創意的遊戲機制**,展現設計模式有趣的應用
- **多元輸入方式**(鍵盤及滑鼠事件皆有)
- **可擴充架構**,便於未來加入新功能
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。文件原文應視為權威資料來源。對於重要資訊,建議採用專業人工翻譯。我們對因使用本翻譯版本而產生的任何誤解或誤譯概不負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,216 +1,489 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "056641280211e52fd0adb81b6058ec55",
"translation_date": "2025-08-29T15:22:21+00:00",
"original_hash": "7994743c5b21fdcceb36307916ef249a",
"translation_date": "2026-01-06T13:40:41+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/README.md",
"language_code": "tw"
}
-->
# 建立太空遊戲第二部分:將英雄和怪物繪製到 Canvas
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/31)
# 建造太空遊戲 第2部分將英雄與怪物繪製到畫布上
```mermaid
journey
title 你的 Canvas 圖形旅程
section 基礎
了解 Canvas API: 3: Student
學習座標系統: 4: Student
繪製基本形狀: 4: Student
section 影像處理
載入遊戲資產: 4: Student
處理非同步載入: 5: Student
定位精靈圖: 5: Student
section 遊戲渲染
建立遊戲畫面: 5: Student
組建陣型: 5: Student
優化效能: 4: Student
```
Canvas API 是網頁開發中最強大的功能之一,可在瀏覽器中即時創建動態且互動的圖像。在本課程中,我們將把那個空白的 HTML `<canvas>` 元素變成充滿英雄與怪物的遊戲世界。你可以把 Canvas 想像成你的數位畫布,程式碼就是你的畫筆。
我們將建立在上一課所學的基礎上,現在要深入視覺部分。你將學會如何載入並顯示遊戲精靈圖(sprite)、精確地定位元素,以及為你的太空遊戲建立視覺基礎。這彌合了靜態網頁與動態、互動體驗之間的差距。
完成本課後,你將擁有一個完整的遊戲場景,英雄飛船正確定位,敵軍編隊已準備好戰鬥。你將了解現代遊戲如何在瀏覽器中渲染圖形,並獲得打造自己互動視覺體驗的技能。讓我們探索 Canvas 圖形,讓你的太空遊戲栩栩如生吧!
```mermaid
mindmap
root((畫布繪圖))
Canvas Element
HTML5 功能
2D 上下文
坐標系統
像素控制
Drawing Operations
基本形狀
文字渲染
圖像顯示
路徑繪製
Asset Management
圖像載入
非同步操作
錯誤處理
效能
Game Rendering
精靈定位
陣型配置
場景合成
幀更新
Visual Effects
顏色與樣式
變換
動畫
層次
```
## 課前小測驗
[課前小測驗](https://ff-quizzes.netlify.app/web/quiz/31)
## Canvas
Canvas 是一個 HTML 元素,預設沒有任何內容;它是一個空白的畫布。你需要透過在上面繪圖來添加內容。
那麼 `<canvas>` 元素到底是什麼?它是 HTML5 用於在網頁瀏覽器中創建動態圖形與動畫的解決方案。與靜態的普通圖片或影片不同canvas 讓你能像素級別地控制畫面上的所有元素。這使它非常適合用來開發遊戲、資料視覺化和互動藝術。你可以把它當成程式化的繪圖表面JavaScript 就是你的油畫筆
✅ 在 MDN 上閱讀 [更多關於 Canvas API 的內容](https://developer.mozilla.org/docs/Web/API/Canvas_API)。
預設情況下,畫布元素看起來像頁面上的一個空白透明矩形。但這正是潛力所在!當你用 JavaScript 畫形狀、載入圖片、製作動畫並讓物件對使用者互動做出反應時canvas 才展現出真正的威力。這和 1960 年代貝爾實驗室的早期電腦圖形先驅必須為每一個像素編寫程式以創建第一批數位動畫的方式相似
以下是它通常在頁面 body 中的宣告方式:
✅ 在 MDN 上閱讀更多有關 [Canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API)。
它通常這樣被宣告,作為頁面主體的一部分:
```html
<canvas id="myCanvas" width="200" height="100"></canvas>
```
上面我們設定了 `id`、`width` 和 `height`
- `id`:設定這個值以便在需要與其互動時取得參考。
- `width`:這是元素的寬度。
- `height`:這是元素的高度。
**這段程式碼做了什麼:**
- **設定** `id` 屬性方便你用 JavaScript 參考這個特定的 canvas 元素
- **定義** 以像素為單位的 `width`,控制 canvas 的水平大小
- **設定** 以像素為單位的 `height`,決定 canvas 的垂直尺寸
## 繪製簡單幾何圖形
Canvas 使用笛卡爾座標系統來繪製物件。因此,它使用 x 軸和 y 軸來表示物件的位置。位置 `0,0` 是左上角,而右下角則是你設定的 Canvas 的寬度和高度。
![Canvas 的網格](../../../../translated_images/canvas_grid.5f209da785ded492a01ece440e3032afe51efa500cc2308e5ea4252487ceaf0b.tw.png)
既然你知道了 canvas 元素是什麼我們來實際嘗試在上面繪圖吧canvas 使用的座標系統可能讓你想起數學課,但有一個針對電腦圖形特別的關鍵差異。
canvas 採用笛卡兒座標系,有 x 軸(水平)與 y 軸(垂直)來定位你所繪製的元素。但重點是:與數學課中的座標系不同,原點 `(0,0)` 是放在左上角x 值向右遞增y 值向下遞增。這套做法來自早期電腦顯示器電子束自上而下掃描的方式,左上即為自然起點。
```mermaid
quadrantChart
title 畫布座標系統
x-axis 左 --> 右
y-axis 上 --> 下
quadrant-1 第一象限
quadrant-2 第二象限
quadrant-3 第三象限
quadrant-4 第四象限
Origin Point: [0.1, 0.1]
Hero Center: [0.5, 0.8]
Enemy Formation: [0.3, 0.2]
Power-up: [0.7, 0.6]
UI Elements: [0.9, 0.1]
```
![the canvas's grid](../../../../translated_images/canvas_grid.5f209da785ded492.tw.png)
> 圖片來源:[MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)
要在 Canvas 元素上繪圖,你需要完成以下步驟:
1. **取得 Canvas 元素的參考**。
2. **取得位於 Canvas 元素上的 Context 元素的參考**。
3. **使用 Context 元素執行繪圖操作**。
上述步驟的程式碼通常如下所示:
在 canvas 元素上繪圖,你需要遵循所有 canvas 圖形基礎的三個步驟。多練習幾次後,這將成為你的第二天性:
```mermaid
flowchart LR
A[HTML Canvas 元素] --> B[取得 Canvas 參考]
B --> C[取得 2D 繪圖上下文]
C --> D[繪圖操作]
D --> E[繪製形狀]
D --> F[繪製文字]
D --> G[繪製圖像]
D --> H[套用樣式]
E --> I[畫面呈現]
F --> I
G --> I
H --> I
style A fill:#e1f5fe
style C fill:#e8f5e8
style I fill:#fff3e0
```
1. **從 DOM 中取得參考**:就像其他任何 HTML 元素一樣,取得 canvas 元素
2. **取得 2D 繪圖上下文**:提供所有繪圖相關方法的物件
3. **開始繪圖!** 利用該上下文的內建方法進行繪製
程式碼示範如下:
```javascript
// draws a red rectangle
//1. get the canvas reference
canvas = document.getElementById("myCanvas");
// 第一步:取得畫布元素
const canvas = document.getElementById("myCanvas");
//2. set the context to 2D to draw basic shapes
ctx = canvas.getContext("2d");
// 第二步取得2D繪圖上下文
const ctx = canvas.getContext("2d");
//3. fill it with the color red
// 第三步:設定填充顏色並繪製矩形
ctx.fillStyle = 'red';
//4. and draw a rectangle with these parameters, setting location and size
ctx.fillRect(0,0, 200, 200) // x,y,width, height
ctx.fillRect(0, 0, 200, 200); // x, y, 寬度, 高度
```
**一步步來拆解:**
- 我們利用 ID 抓取 canvas 元素並存入變數
- 取得 2D 繪圖上下文,是我們用來繪製圖形的工具箱
- 設定 fillStyle 為紅色,表示接下來填滿的顏色
- 繪製一個起點為(0,0)、寬高皆為200像素的紅色矩形
✅ Canvas API 主要專注於 2D 圖形,但你也可以在網站上繪製 3D 元素;為此,你可以使用 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API)。
✅ Canvas API 主要專注於繪製 2D 形狀,但你也可以用它來繪製 3D 元素;這時可能會用到 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API)。
使用 Canvas API你可以繪製各種內容例如
Canvas API 可以畫出各式各樣的東西,例如:
- **幾何圖形**,我們已經展示了如何繪製矩形,但還有更多可以繪製的內容。
- **文字**,你可以繪製任何字體和顏色的文字。
- **圖片**,你可以基於圖片資源(例如 .jpg 或 .png繪製圖片。
- **幾何形狀**,我們已示範如何繪製矩形,但還有更多圖形可以繪製。
- **文字**,你可以用任何字型和顏色繪製文字。
- **圖片**,你可以基於圖片資源(例如 .jpg 或 .png來繪製影像。
✅ 試試看!你已經知道如何繪製矩形,那麼你能在頁面上繪製一個圓形嗎?看看 CodePen 上一些有趣的 Canvas 繪圖。這裡有一個 [特別令人印象深刻的例子](https://codepen.io/dissimulate/pen/KrAwx)。
✅ 試試看!你會畫矩形了,能在頁面上畫個圓形嗎?看看 CodePen 上一些有趣的 Canvas 繪圖作品,這是其中一個 [特別令人印象深刻的範例](https://codepen.io/dissimulate/pen/KrAwx)。
## 載入並繪製圖片資源
### 🔄 **教學小檢查**
**Canvas 基礎認知**:在學習載入圖片之前,確保你能:
- ✅ 解釋 canvas 座標系統與數學座標系有何不同
- ✅ 了解 canvas 繪圖操作的三步驟流程
- ✅ 了解 2D 繪圖上下文提供了什麼
- ✅ 描述 fillStyle 與 fillRect 如何搭配工作
**快速自我測試**你會如何繪製一個半徑25、中心位於(100, 50)的藍色圓形?
```javascript
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(100, 50, 25, 0, 2 * Math.PI);
ctx.fill();
```
**你已學會的 Canvas 繪圖方法:**
- **fillRect()**:繪製填滿矩形
- **fillStyle**:設定顏色與樣式
- **beginPath()**:開始新的繪製路徑
- **arc()**:繪製圓形與曲線
你可以透過建立一個 `Image` 物件並設定其 `src` 屬性來載入圖片資源。然後,監聽 `load` 事件以確保圖片已準備好使用。程式碼如下:
## 載入並繪製圖片資源
### 載入資源
繪製基本形狀很適合入門,但大多數遊戲需要使用實際圖片!精靈圖、背景與材質為遊戲增添視覺吸引力。載入並在畫布上顯示圖片的方式與繪製幾何圖形不同,但一旦了解流程後,也很簡單。
你需要建立一個 `Image` 物件,載入圖片檔(這是非同步進行的,也就是「在背景」運作),然後圖像準備好後再把它畫到畫布上。這種方法確保圖片正常顯示,不會在載入時阻塞應用程式。
```mermaid
sequenceDiagram
participant JS as JavaScript
participant Img as 圖像物件
participant Server as 檔案伺服器
participant Canvas as 畫布上下文
JS->>Img: new Image()
JS->>Img: 設定 src 屬性
Img->>Server: 請求圖像檔案
Server->>Img: 回傳圖像資料
Img->>JS: 觸發 onload 事件
JS->>Canvas: drawImage(img, x, y)
Canvas->>Canvas: 渲染至畫面
Note over JS,Canvas: 非同步加載避免阻塞介面
```
### 基本的圖片載入
```javascript
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// image loaded and ready to be used
}
// 圖像已加載並準備使用
console.log('Image loaded successfully!');
};
```
**這段程式碼在做什麼:**
- 建立一個新的 Image 物件來保存遊戲精靈或材質
- 設定圖片來源路徑,告訴它要載入哪個檔案
- 監聽載入事件,確保在圖片準備好時才使用它
### 載入資源模式
### 更好的載入圖片方
建議將上述程式碼包裝在如下結構中,這樣更容易使用,並且只有在圖片完全載入後才嘗試操作它:
這裡有一種更健壯的圖片載入方法,是專業開發者常用的。將圖片載入包裝成基於 Promise 的函式——隨著 ES6中 JavaScript Promises 的普及,這種方式能讓程式碼更有條理,也可以更優雅地處理錯誤
```javascript
function loadAsset(path) {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = path;
img.onload = () => {
// image loaded and ready to be used
resolve(img);
}
})
};
img.onerror = () => {
reject(new Error(`Failed to load image: ${path}`));
};
});
}
// use like so
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
// 使用現代的 async/await 方法
async function initializeGame() {
try {
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// 圖片現在已準備好使用
} catch (error) {
console.error('Failed to load game assets:', error);
}
}
```
**我們做了什麼:**
- 將所有圖片載入邏輯包裝在 Promise 中,更方便處理結果
- 增加錯誤處理,能在出錯時通知我們
- 採用現代 async/await 語法,閱讀體驗更順暢
- 使用 try/catch 區塊,優雅應對載入時的異常
要將遊戲資源繪製到螢幕上,程式碼會如下所示:
圖片載入完成後,把它畫到畫布上其實相當直觀
```javascript
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.drawImage(heroImg, canvas.width/2,canvas.height/2);
ctx.drawImage(monsterImg, 0,0);
async function renderGameScreen() {
try {
// 載入遊戲資源
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// 取得畫布與繪圖上下文
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 將圖片繪製到特定位置
ctx.drawImage(heroImg, canvas.width / 2, canvas.height / 2);
ctx.drawImage(monsterImg, 0, 0);
} catch (error) {
console.error('Failed to render game screen:', error);
}
}
```
## 現在是時候開始建立你的遊戲了
### 要建立什麼
你將建立一個包含 Canvas 元素的網頁。它應該渲染一個黑色螢幕,大小為 `1024*768`。我們已經為你提供了兩張圖片:
**逐步說明:**
- 使用 await 同步等待載入英雄與怪物圖片
- 抓取我們的 canvas 元素並取得所需的 2D 渲染上下文
- 用簡單的座標計算將英雄圖置中
- 把怪物的圖放在左上角,作為敵人編隊的起點
- 捕捉並處理載入或渲染過程中可能發生的錯誤
```mermaid
flowchart TD
A[載入資產] --> B{所有圖片都載入了嗎?}
B -->|否| C[顯示載入中]
B -->|是| D[取得畫布上下文]
C --> B
D --> E[清除畫面]
E --> F[繪製背景]
F --> G[繪製敵人編隊]
G --> H[繪製英雄飛船]
H --> I[套用視覺效果]
I --> J[渲染幀]
subgraph "渲染管線"
K[資產管理]
L[場景組成]
M[繪圖操作]
N[幀輸出]
end
style A fill:#e1f5fe
style J fill:#e8f5e8
style I fill:#fff3e0
```
## 現在開始打造你的遊戲吧
現在把前面學到的知識合而為一,為你的太空遊戲建立視覺基礎。你已紮實了解了 canvas 基礎及圖片載入技巧,這個實作部分會帶你完成一個包含精靈圖正確定位的完整遊戲畫面。
### 建置目標
你將建立一個帶有 Canvas 元素的網頁。應呈現尺寸為 `1024*768` 的黑色螢幕。我們提供了兩張圖片:
- 英雄飛船
![英雄飛船](../../../../translated_images/player.dd24c1afa8c71e9b82b2958946d4bad13308681392d4b5ddcc61a0e818ef8088.tw.png)
![Hero ship](../../../../translated_images/player.dd24c1afa8c71e9b.tw.png)
- 5*5 怪物
- 5×5 的怪物陣列
![怪物飛船](../../../../translated_images/enemyShip.5df2a822c16650c2fb3c06652e8ec8120cdb9122a6de46b9a1a56d54db22657f.tw.png)
![Monster ship](../../../../translated_images/enemyShip.5df2a822c16650c2.tw.png)
### 建議的開發步驟
### 推薦的開發步驟
找到在 `your-work` 子資料夾中為你建立的檔案。它應該包含以下內容:
請定位 `your-work` 子資料夾中已為你建立的起始檔案。你的專案結構應包含
```bash
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
your-work/
├── assets/
│ ├── enemyShip.png
│ └── player.png
├── index.html
├── app.js
└── package.json
```
**你手上的資源:**
- 遊戲精靈圖存放在 `assets/` 資料夾,保持整潔有序
- 你的主要 HTML 檔設置 canvas 元素並做好準備
- 一個 JavaScript 檔案用來撰寫遊戲的渲染邏輯
- 一個 package.json 設定開發伺服器以方便本地測試
在 Visual Studio Code 中打開這個資料夾的副本。你需要設置一個本地開發環境,最好是使用已安裝 NPM 和 Node 的 Visual Studio Code。如果你的電腦上尚未設置 `npm`[這裡有教學](https://www.npmjs.com/get-npm)。
在 Visual Studio Code 中開啟此資料夾開始開發。你需要在電腦上安裝 Visual Studio Code、NPM 與 Node.js若尚未安裝 npm[這裡教你怎麼安裝](https://www.npmjs.com/get-npm)。
透過導航到 `your_work` 資料夾來啟動你的專案:
切換到 `your-work` 資料夾啟動開發伺服器
```bash
cd your-work
npm start
```
**這條指令的效用:**
- **啟動** 本地伺服器 http://localhost:5000方便測試遊戲
- **正確提供** 所有檔案讓瀏覽器能正常載入
- **監控** 你的檔案變動,讓開發過程順暢不中斷
- **打造** 一個專業的開發環境供你測試
上述指令會在地址 `http://localhost:5000` 啟動一個 HTTP 伺服器。打開瀏覽器並輸入該地址。目前它是一個空白頁面,但這將會改變。
> 💡 **提示**:瀏覽器初次開啟會顯示空白頁面,這很正常!隨著你加入程式碼,刷新瀏覽器即可看見變化。這種反覆測試的開發模式,和 NASA 在打造阿波羅導航電腦時,每個元件先分別測試再整合的方式相似
> 注意:要在螢幕上看到變更,請重新整理瀏覽器。
### 加入程式碼
### 添加程式碼
把必須的程式碼加到 `your-work/app.js` ,完成以下工作:
`your-work/app.js` 中添加所需的程式碼來完成以下內容:
1. **畫出黑色背景的畫布**
> 💡 **操作方式**:在 `/app.js` 尋找 TODO新增兩行。將 `ctx.fillStyle` 設為黑色,然後用 `ctx.fillRect()` 從(0,0)開始,以畫布寬高全填滿即可。簡單!
1. **繪製**一個黑色背景的 Canvas
> 提示:在 `/app.js` 中適當的 TODO 下添加兩行程式碼,將 `ctx` 元素設置為黑色,並將頂部/左側座標設置為 0,0高度和寬度等於 Canvas 的大小。
2. **載入**材質
> 提示:使用 `await loadTexture` 並傳入圖片路徑來添加玩家和敵人的圖片。你目前還不會在螢幕上看到它們!
3. **繪製**英雄在螢幕下半部的中央
> 提示:使用 `drawImage` API 將 heroImg 繪製到螢幕上,設定 `canvas.width / 2 - 45``canvas.height - canvas.height / 4`
4. **繪製** 5*5 的怪物
> 提示:現在你可以取消註解程式碼,將敵人繪製到螢幕上。接下來,前往 `createEnemies` 函數並完成它。
2. **載入遊戲貼圖**
> 💡 **操作方式**:利用 `await loadAsset()` 載入玩家和敵人圖片。將它們存到變數以方便後續使用。記住——圖片只在你實際繪製時才會顯示!
首先,設置一些常數:
3. **在中央底部繪製英雄飛船**
> 💡 **操作方式**:用 `ctx.drawImage()` 定位英雄飛船。x座標試著用 `canvas.width / 2 - 45` 置中y座標用 `canvas.height - canvas.height / 4` 放到底部附近。
```javascript
const MONSTER_TOTAL = 5;
const MONSTER_WIDTH = MONSTER_TOTAL * 98;
const START_X = (canvas.width - MONSTER_WIDTH) / 2;
const STOP_X = START_X + MONSTER_WIDTH;
```
4. **繪製 5×5 的敵人艦隊陣型**
> 💡 **操作方式**:找到 `createEnemies` 函式並設置巢狀迴圈。你得做一些定位與間隔的數學計算,但別擔心——我會一步步教你!
然後,建立一個迴圈來將怪物陣列繪製到螢幕上
首先,建立用以排兵布陣的常數:
```javascript
for (let x = START_X; x < STOP_X; x += 98) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
```
```javascript
const ENEMY_TOTAL = 5;
const ENEMY_SPACING = 98;
const FORMATION_WIDTH = ENEMY_TOTAL * ENEMY_SPACING;
const START_X = (canvas.width - FORMATION_WIDTH) / 2;
const STOP_X = START_X + FORMATION_WIDTH;
```
**這些常數的作用說明:**
- 設定每行與每列有 5 個敵人(整齊的 5×5 網格)
- 定義敵人之間保持多少間距,避免擁擠
- 計算整個陣列的寬度
- 找出起始與終止位置,使陣列置中
```mermaid
flowchart LR
A["畫布寬度1024px"] --> B["陣型寬度490px"]
B --> C["起始X267px"]
C --> D["敵人間距98px"]
subgraph "5x5 敵人陣型"
E["第1列Y=0"]
F["第2列Y=50"]
G["第3列Y=100"]
H["第4列Y=150"]
I["第5列Y=200"]
end
subgraph "列間距"
J["第1欄X=267"]
K["第2欄X=365"]
L["第3欄X=463"]
M["第4欄X=561"]
N["第5欄X=659"]
end
style A fill:#e1f5fe
style B fill:#e8f5e8
style C fill:#fff3e0
```
接著,寫巢狀迴圈繪製敵人陣型:
```javascript
for (let x = START_X; x < STOP_X; x += ENEMY_SPACING) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
```
**此巢狀迴圈做了什麼:**
- 外層迴圈從左到右移動,覆蓋整個陣列寬度
- 內層迴圈從上到下,繪製出整齊列數
- 按計算好的 x,y 座標繪製每個敵人精靈圖
- 以均勻間隔排列,使畫面更專業且有條理
### 🔄 **教學小檢查**
**遊戲渲染專精**:檢核你對完整渲染系統的理解:
- ✅ 非同步載入圖片如何避免遊戲啟動時卡住介面?
- ✅ 為什麼使用常數計算敵人陣型位置比硬編碼更好?
- ✅ 2D 繪圖上下文在繪製操作中扮演什麼角色?
- ✅ 巢狀迴圈如何創建有組織的精靈圖陣列?
**效能考量**:你的遊戲現已具備:
- **高效資源載入**:基於 Promise 的圖片管理
- **有條理的渲染**:有結構化的繪圖流程
- **數學定位**:計算後的精靈位置排列
- **錯誤處理**:優雅處理載入失敗狀況
**視覺程式概念**:你已學會:
- **座標系統**:將數學轉換為螢幕位置
- **精靈管理**:載入及顯示遊戲圖形
- **編隊演算法**:有組織佈局的數學模式
- **非同步操作**:現代 JavaScript 以達流暢使用者體驗
## 結果
完成後的結果應如下所示:
完成的結果應如下所示:
![黑色螢幕,包含一個英雄和 5*5 的怪物](../../../../translated_images/partI-solution.36c53b48c9ffae2a5e15496b23b604ba5393433e4bf91608a7a0a020eb7a2691.tw.png)
![黑色螢幕,有一名英雄與 5*5 怪物](../../../../translated_images/partI-solution.36c53b48c9ffae2a.tw.png)
## 解答
請先嘗試自己解決,但如果卡住了,可以查看 [解答](../../../../6-space-game/2-drawing-to-canvas/solution/app.js)。
請先嘗試自行解題,若卡住,請參考[解答](../../../../6-space-game/2-drawing-to-canvas/solution/app.js)
---
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式來完成以下挑戰:
**說明:** 利用你所學過的 Canvas API 技巧,為你的太空遊戲畫布增添視覺效果和互動元素。
**提示:** 建立一個名為 `enhanced-canvas.html` 的新檔案,包含一個可顯示背景動畫星星的畫布,一個為英雄飛船設計的脈動生命條,還有緩慢向下移動的敵機。包含的 JavaScript 程式碼應以隨機位置和透明度繪製閃爍星星,實作會依生命值變色的生命條(綠 > 黃 > 紅),並讓敵機以不同速度向下移動動畫。
閱讀更多關於 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑戰
你已經學習了使用以 2D 為主的 Canvas API現在看看 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API),嘗試繪製一個 3D 物件。
你已學會用以 2D 為主的 Canvas API 繪圖;不妨探索一下 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API),試繪製一個 3D 物件。
## 課後測驗
@ -218,7 +491,126 @@ npm start
## 複習與自學
透過 [閱讀相關內容](https://developer.mozilla.org/docs/Web/API/Canvas_API) 來進一步了解 Canvas API。
透過[閱讀資料](https://developer.mozilla.org/docs/Web/API/Canvas_API)來更深入了解 Canvas API。
### ⚡ **你可以在接下來的 5 分鐘內完成的事**
- [ ] 開啟瀏覽器控制台並使用 `document.createElement('canvas')` 建立一個 canvas 元素
- [ ] 嘗試使用 canvas context 的 `fillRect()` 方法繪製矩形
- [ ] 使用 `fillStyle` 屬性嘗試不同顏色
- [ ] 使用 `arc()` 方法繪製簡單的圓形
### 🎯 **你這小時內可以完成的目標**
- [ ] 完成課後測驗並了解 canvas 基礎
- [ ] 建立多種形狀與顏色的 canvas 繪圖應用程式
- [ ] 實作圖片載入和精靈渲染於遊戲中
- [ ] 製作物體在 canvas 上移動的簡單動畫
- [ ] 練習 canvas 變換(縮放、旋轉、位移)
### 📅 **你一週的 Canvas 旅程**
- [ ] 完成帶有精緻圖形與精靈動畫的太空遊戲
- [ ] 熟練進階 canvas 技巧如漸層、圖案與合成
- [ ] 利用 canvas 創建互動可視化資料
- [ ] 學習 canvas 優化技術以提升效能
- [ ] 打造多工具繪畫或繪圖應用
- [ ] 探索以 canvas 進行創意編碼和生成藝術
### 🌟 **你一個月的圖形大師之路**
- [ ] 利用 Canvas 2D 與 WebGL 建構複雜視覺應用
- [ ] 學習圖形程式設計理念與著色器入門
- [ ] 參與開源圖形庫和可視化工具的貢獻
- [ ] 精通圖形高負載應用的效能優化
- [ ] 製作教學內容,分享 canvas 程式與電腦圖形知識
- [ ] 成為協助他人打造視覺體驗的圖形程式專家
## 🎯 你的 Canvas 圖形大師時間軸
```mermaid
timeline
title Canvas API 學習進度
section Canvas 基礎知識 (15 分鐘)
基本操作: 元素參考
: 2D 上下文存取
: 座標系統
: 簡單圖形繪製
section 繪圖技巧 (20 分鐘)
圖形原語: 矩形與圓形
: 顏色與樣式
: 文字繪製
: 路徑操作
section 影像處理 (25 分鐘)
資產管理: 影像物件建立
: 非同步載入模式
: 錯誤處理
: 效能優化
section 遊戲圖像 (30 分鐘)
精靈繪製: 位置演算法
: 編隊計算
: 場景組合
: 畫面渲染
section 進階技巧 (40 分鐘)
視覺效果: 變換
: 動畫
: 層次
: 狀態管理
section 效能 (35 分鐘)
優化: 高效繪製
: 記憶體管理
: 幀率控制
: 資產快取
section 專業技能 (1 週)
製作圖形: WebGL 整合
: Canvas 函式庫
: 遊戲引擎
: 跨平台考量
section 進階圖形 (1 個月)
專門應用: 資料視覺化
: 互動藝術
: 即時效果
: 3D 圖形
```
### 🛠️ 你的 Canvas 圖形工具總結
完成本課程後,你已擁有:
- **Canvas API 精通**:對 2D 圖形程式設計有完整理解
- **座標數學**:精準定位與佈局演算法
- **資產管理**:專業的圖片載入與錯誤處理
- **渲染流程**:有結構的場景組合方法
- **遊戲圖形**:精靈定位與編隊計算
- **非同步程式**:現代 JavaScript 模式提升性能
- **視覺編程**:將數學概念轉化為螢幕圖形
**真實世界應用**:你的 Canvas 技能直接適用於:
- **資料視覺化**:圖表、曲線及互動式儀表板
- **遊戲開發**2D 遊戲、模擬與互動體驗
- **數位藝術**:創意編碼與生成藝術專案
- **UI/UX 設計**:自訂圖形與互動元素
- **教育軟體**:視覺學習工具與模擬
- **網頁應用**:動態圖形與即時視覺化
**你所獲得的專業技能**:你現在可以:
- **建立** 無需外部程式庫的自訂圖形解決方案
- **優化** 渲染效能,提升使用者體驗流暢度
- **除錯** 利用瀏覽器開發工具解決複雜視覺問題
- **設計** 以數學原理構建可擴充的圖形系統
- **整合** Canvas 圖形與現代網頁應用框架
**你已精通的 Canvas API 方法**
- **元素管理**getElementById、getContext
- **繪圖操作**fillRect、drawImage、fillStyle
- **資產載入**Image 物件、Promise 模式
- **數學定位**:座標計算、編隊演算法
**下一步**:你已準備好加入動畫、使用者互動、碰撞偵測,或嘗試 WebGL 3D 圖形!
🌟 **成就解鎖**:你使用基礎 Canvas API 技巧建立完整遊戲渲染系統了!
## 作業
@ -226,5 +618,7 @@ npm start
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。
本文件係使用人工智慧翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 所翻譯。雖然我們致力於翻譯的準確性,但請注意,機器翻譯可能會包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議進行專業人工翻譯。我們對因使用本翻譯而產生之任何誤解或誤釋不負任何責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,83 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "ca1cf78a4c60df77ab32a154ec024d7f",
"translation_date": "2025-08-23T22:59:56+00:00",
"original_hash": "87cd43afe5b69dbbffb5c4b209ea6791",
"translation_date": "2026-01-06T13:42:30+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/assignment.md",
"language_code": "tw"
}
-->
# 使用 Canvas API 玩創意
# 作業:探索 Canvas API
## 說明
## 學習目標
選擇 Canvas API 的一個元素,圍繞它創造一些有趣的東西。你能創造一個由重複星星組成的小銀河嗎?你能創造一個由彩色線條組成的有趣紋理嗎?你可以參考 CodePen 尋找靈感(但不要抄襲)。
完成此作業後,您將能展現對 Canvas API 基礎的理解,並運用創意解決問題,利用 JavaScript 和 HTML5 canvas 建構視覺元素。
## 指示
選擇 Canvas API 中您感興趣的一個面向,並圍繞它創建一個引人入勝的視覺專案。本作業鼓勵您在學習了繪圖功能後進行實驗,同時打造獨特的作品。
### 啟發靈感的專案點子
**幾何圖案:**
- **創造** 一個使用隨機位置的動畫閃爍星星銀河
- **設計** 利用重複幾何形狀的有趣紋理
- **構建** 帶有旋轉彩色圖案的萬花筒效果
**互動元素:**
- **開發** 一個響應滑鼠移動的繪圖工具
- **實作** 被點擊時會改變顏色的形狀
- **設計** 一個帶有移動元素的簡單動畫循環
**遊戲相關圖像:**
- **製作** 太空遊戲的捲動背景
- **建構** 爆炸或魔法咒語的粒子效果
- **創建** 多幀動畫精靈圖像
### 開發指南
**研究與靈感來源:**
- **瀏覽** CodePen 的創意 canvas 範例(用於靈感,不是複製)
- **研究** [Canvas API 文件](https://developer.mozilla.org/docs/Web/API/Canvas_API) 了解更多方法
- **嘗試** 不同繪圖函數、顏色及動畫效果
**技術要求:**
- **使用** 以 `getContext('2d')` 正確設定 canvas
- **加入** 有意義的註解說明您的實作方式
- **徹底測試** 代碼確保無錯誤執行
- **採用** 現代 JavaScript 語法const/let箭頭函式
**創意表現:**
- **專注** 一個 Canvas API 功能,深入探索
- **新增** 您的創意巧思,讓專案更具個人特色
- **思考** 作品如何成為更大型應用程式的一部分
### 提交指南
請提交一個包含嵌入式 CSS 和 JavaScript 的單一 HTML 檔案,或放在資料夾中的分開檔案。包含一段簡短註解,說明您的創意選擇以及探索的 Canvas API 功能。
## 評分標準
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | --------------------------------------------------------- | --------------------------------- | --------------------- |
| | 提交的程式碼展示了一個有趣的紋理或形狀 | 提交了程式碼,但無法執行 | 未提交程式碼 |
| 評分標準 | 優異 | 足夠 | 需改進 |
|----------|-----------|----------|-------------------|
| **技術實作** | 創意使用多項 Canvas API 功能,程式碼完美執行,使用現代 JavaScript 語法 | Canvas API 使用正確,程式執行有小問題,基本實作 | 嘗試使用 Canvas API但程式有錯誤或無法執行 |
| **創意與設計** | 高度原創的概念,視覺呈現精緻,深入探索選定 Canvas 功能 | 良好利用 Canvas 功能,帶有部分創意元素,視覺效果穩健 | 基本實作,創意與視覺吸引力有限 |
| **程式碼品質** | 程式碼結構良好且有註解,遵循最佳實踐,演算法效率佳 | 程式碼乾淨且有些許註解,遵循基本編碼標準 | 程式碼組織不佳,註解少,執行效率低 |
## 反思問題
完成專案後,請思考以下問題:
1. **您選擇了哪個 Canvas API 功能?為什麼?**
2. **在建構專案過程中遇到了哪些挑戰?**
3. **您如何將此專案擴展為更大型的應用程式或遊戲?**
4. **接下來想探索哪些 Canvas API 的其他功能?**
> 💡 **專家提示**:從簡單開始,逐步增加複雜度。執行良好的簡單專案,勝過過度雄心卻無法正常運作的專案!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原文文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們力求準確,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件之母語版本應視為權威來源。對於重要資訊,建議聘請專業人工翻譯。我們不對因使用本翻譯而產生之任何誤解或錯誤詮釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,38 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "ccfcd8c2932761359fbaff3d6b01ace4",
"translation_date": "2025-08-23T22:57:26+00:00",
"original_hash": "c162b3b3a1cafc1483c8015e9b266f0d",
"translation_date": "2026-01-06T13:50:31+00:00",
"source_file": "6-space-game/3-moving-elements-around/assignment.md",
"language_code": "tw"
}
-->
# 為程式碼添加註解
# 用註解說明您的程式碼
## 說明
## 指示
檢查你遊戲資料夾中的 /app.js 檔案,找出可以添加註解和整理的地方。程式碼很容易變得混亂,現在是一個好機會添加註解,確保你的程式碼易於閱讀,方便日後使用
乾淨、良好註解的程式碼對於維護和共享您的專案是必不可少的。在這個作業中,您將練習專業開發者最重要的習慣之一:撰寫清晰、有幫助的註解,以解釋您的程式碼的目的和功能
## 評分標準
檢視您遊戲資料夾中目前的 `app.js` 檔案,尋找為它加入註解並整理程式碼的方法。程式碼很容易失控,現在是增加註解的好機會,以確保您的程式碼可讀,方便日後再次使用。
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | ------------------------------------------------------------- | --------------------------------- | ---------------------------------------------------- |
| | `app.js` 程式碼完全添加了註解,並整理成邏輯區塊 | `app.js` 程式碼有適當的註解 | `app.js` 程式碼有些混亂,缺乏良好的註解 |
**您的任務包含:**
- **新增註解**說明每個主要區塊程式碼的用途
- **註解函式**並清楚描述其目的及參數
- **將程式碼分組**為具有區塊標題的邏輯區塊
- **刪除**任何未使用或多餘的程式碼
- **使用一致的**變數與函式命名慣例
## 評分規準
| 評分標準 | 優秀 | 適中 | 需改進 |
| -------- | --------- | -------- | ----------------- |
| **程式碼註解** | `app.js` 程式碼完整註解,對所有主要區塊及函式都有清楚有用的說明 | `app.js` 程式碼有適當註解,對大部分區塊有基本說明 | `app.js` 程式碼註解極少,缺乏清楚說明 |
| **程式碼組織** | 程式碼有條理地分組為具明確區塊標題的邏輯區塊,結構一致 | 程式碼稍有組織,對相關功能有基本分組 | 程式碼結構較混亂、不易理解 |
| **程式碼品質** | 所有變數和函式皆使用具描述性的命名,無未使用的程式碼,遵循一致慣例 | 大部分程式碼使用良好命名,僅少量未使用程式碼 | 變數命名不清楚,有未使用程式碼,風格不一致 |
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們力求準確,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議尋求專業人工翻譯。因使用本翻譯所產生之任何誤解或誤譯,本公司概不負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,131 +1,325 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a6ce295ff03bb49df7a3e17e6e7100a0",
"translation_date": "2025-08-29T15:21:55+00:00",
"original_hash": "039b4d8ce65f5edd82cf48d9c3e6728c",
"translation_date": "2026-01-06T13:38:44+00:00",
"source_file": "6-space-game/4-collision-detection/README.md",
"language_code": "tw"
}
-->
# 建立太空遊戲第 4 部分:新增雷射與碰撞檢測
# 建立太空遊戲 第四部分:新增雷射並偵測碰撞
```mermaid
journey
title 你的碰撞檢測旅程
section 物理基礎
了解矩形: 3: 學生
學習交集數學: 4: 學生
掌握座標系統: 4: 學生
section 遊戲機制
實作雷射射擊: 4: 學生
添加物件生命週期: 5: 學生
建立碰撞規則: 5: 學生
section 系統整合
建置碰撞檢測: 5: 學生
優化效能: 5: 學生
測試互動系統: 5: 學生
```
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/35)
在這一課中,你將學習如何使用 JavaScript 發射雷射!我們將為遊戲新增以下兩個功能:
想想《星際大戰》中路克的質子魚雷擊中死星排氣口的那一刻。那精確的碰撞偵測改變了銀河的命運!在遊戲中,碰撞偵測運作原理一樣:判斷物件何時互動,以及接下來會發生什麼。
在本課中,你將為你的太空遊戲新增雷射武器並實作碰撞偵測。就像 NASA 任務規劃者計算太空船軌跡以避開碎片,你會學會偵測遊戲物件何時交集。我們將一步步拆解這個流程,逐步建立系統。
最後,你將擁有一套可運作的戰鬥系統,雷射能摧毀敵人,碰撞會觸發遊戲事件。這些碰撞偵測原則廣泛應用於物理模擬和互動式網頁介面。
```mermaid
mindmap
root((碰撞檢測))
Physics Concepts
Rectangle Boundaries
Intersection Testing
Coordinate Systems
Separation Logic
Game Objects
Laser Projectiles
Enemy Ships
Hero Character
Collision Zones
Lifecycle Management
Object Creation
Movement Updates
Destruction Marking
Memory Cleanup
Event Systems
Keyboard Input
Collision Events
Game State Changes
Audio/Visual Effects
Performance
Efficient Algorithms
Frame Rate Optimization
Memory Management
Spatial Partitioning
```
✅ 研究一下最早的電腦遊戲是什麼。它的功能是什麼?
- **雷射**:從英雄的飛船發射,垂直向上移動。
- **碰撞檢測**:作為實現射擊功能的一部分,我們還會加入一些有趣的遊戲規則:
- **雷射擊中敵人**:敵人被雷射擊中後會死亡。
- **雷射擊中螢幕頂部**:雷射擊中螢幕頂部後會被銷毀。
- **敵人與英雄碰撞**:敵人與英雄相撞後雙方都會被銷毀。
- **敵人到達螢幕底部**:敵人到達螢幕底部時,敵人和英雄都會被銷毀。
## 碰撞偵測
簡而言之,你——*英雄*——需要在敵人到達螢幕底部之前,用雷射擊敗所有敵人。
碰撞偵測類似阿波羅登月艙的接近感應器——持續檢查距離並在物體靠得太近時發出警報。在遊戲中,這系統判斷何時物體交互且該發生什麼事。
✅ 做一些研究,了解第一款電腦遊戲的功能是什麼?
我們使用的方法是將每個遊戲物件視為一個矩形,就像空中交通管制系統用簡化幾何形狀追蹤飛機位置。這種矩形方式看起來簡單,但計算效率高,且適用於大多數遊戲場景。
讓我們一起成為英雄吧!
### 矩形表示法
## 碰撞檢測
每個遊戲物件需要座標邊界,類似火星探路者車輛在火星表面定位。我們定義如下邊界座標:
我們該如何進行碰撞檢測?我們需要將遊戲中的物件視為移動的矩形。你可能會問,為什麼是矩形?因為用來繪製遊戲物件的圖像本身就是一個矩形:它有 `x`、`y`、`width` 和 `height`
```mermaid
flowchart TD
A["🎯 遊戲物件"] --> B["📍 位置 (x, y)"]
A --> C["📏 尺寸 (寬度, 高度)"]
B --> D["上邊: y"]
B --> E["左邊: x"]
C --> F["下邊: y + 高度"]
C --> G["右邊: x + 寬度"]
D --> H["🔲 矩形邊界"]
E --> H
F --> H
G --> H
H --> I["碰撞檢測準備完成"]
style A fill:#e3f2fd
style H fill:#e8f5e8
style I fill:#fff3e0
```
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
```
如果兩個矩形(例如英雄和敵人)*相交*,那麼就發生了碰撞。碰撞後應該發生什麼,則取決於遊戲規則。要實現碰撞檢測,你需要以下幾點:
**解析如下:**
- **上邊**物件的垂直開始位置y 座標)
- **左邊**物件的水平開始位置x 座標)
- **下邊**y 座標加上物件高度 - 即結束位置
- **右邊**x 座標加上物件寬度 - 完整邊界
1. 一種方法來獲取遊戲物件的矩形表示,例如:
### 交集演算法
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
```
偵測矩形交集的邏輯類似哈伯太空望遠鏡判斷視野中天體是否重疊的原理。演算法檢查物件是否分離:
2. 一個比較函數,該函數可以像這樣:
```mermaid
flowchart LR
A["矩形 1"] --> B{"分離測試"}
C["矩形 2"] --> B
B --> D["R2 左側 > R1 右側?"]
B --> E["R2 右側 < R1 "]
B --> F["R2 上方 > R1 底部?"]
B --> G["R2 底部 < R1 "]
D --> H{"有任一為真?"}
E --> H
F --> H
G --> H
H -->|是| I["❌ 無碰撞"]
H -->|否| J["✅ 偵測到碰撞"]
style B fill:#e3f2fd
style I fill:#ffebee
style J fill:#e8f5e8
```
```javascript
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
```
```javascript
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
```
**分離測試類似雷達系統判斷:**
- 矩形2是否完全在矩形1的右方
- 矩形2是否完全在矩形1的左方
- 矩形2是否完全在矩形1的下方
- 矩形2是否完全在矩形1的上方
## 如何銷毀物件
只要這些條件都不成立,矩形一定會重疊。這方法就像雷達操作員檢查兩架飛機是否保持安全距離。
要在遊戲中銷毀物件,你需要讓遊戲知道在某個時間間隔觸發的遊戲迴圈中不再繪製該物件。一種方法是當某些事件發生時,將遊戲物件標記為*死亡*,如下所示:
## 管理物件生命周期
當雷射擊中敵人,兩者都需從遊戲中移除。但直接在迴圈中刪除物件會導致崩潰——這是早期電腦系統(如阿波羅導航計算機)曾教過的課。我們改用「標記刪除」方式,在幀更新間安全移除物件。
```mermaid
stateDiagram-v2
[*] --> Active: 物件建立
Active --> Collided: 偵測碰撞
Collided --> MarkedDead: 設定死 = true
MarkedDead --> Filtered: 下一幀
Filtered --> [*]: 物件移除
Active --> OutOfBounds: 離開畫面
OutOfBounds --> MarkedDead
note right of MarkedDead
安全繼續
目前幀
end note
note right of Filtered
物件移除
幀之間
end note
```
這是如何標記待刪除物件:
```javascript
// collision happened
enemy.dead = true
// 標記物件以便移除
enemy.dead = true;
```
然後你可以在重新繪製螢幕之前,篩選出*死亡*的物件,如下所示:
**這種方式的優點:**
- 將物件標記為「死亡」,但不馬上刪除
- 允許當前遊戲幀安全完成
- 避免使用已消失物件導致崩潰!
接著在下次渲染前篩除標記的物件:
```javascript
gameObjects = gameObject.filter(go => !go.dead);
gameObjects = gameObjects.filter(go => !go.dead);
```
## 如何發射雷射
**此篩除作用:**
- 建立只包含「存活」物件的新清單
- 丟棄已標記死亡的物件
- 讓遊戲運行更暢順
- 防止刪除物件堆積導致記憶體暴增
## 實作雷射機制
發射雷射的過程是響應按鍵事件並創建一個向某個方向移動的物件。因此,我們需要執行以下步驟:
遊戲中的雷射子彈原理跟《星際爭霸戰》的光子魚雷類似——它們是獨立物件,直線射出直到撞擊。每次按空白鍵會產生一個新的雷射物件在畫面移動。
1. **創建雷射物件**:從英雄飛船的頂部發射,並在創建後開始向螢幕頂部移動。
2. **綁定按鍵事件**:我們需要選擇鍵盤上的某個按鍵來代表玩家發射雷射。
3. **當按鍵被按下時,創建一個看起來像雷射的遊戲物件**。
這需要協調以下幾個部分:
## 雷射的冷卻時間
**關鍵組件:**
- **建立** 從英雄位置發射的雷射物件
- **處理** 鍵盤輸入觸發雷射產生
- **管理** 雷射的移動與生命週期
- **實現** 雷射子彈的視覺表示
雷射需要在每次按下按鍵(例如空白鍵)時發射。為了防止遊戲在短時間內生成過多雷射,我們需要解決這個問題。解決方法是實現所謂的*冷卻時間*,即一個計時器,確保雷射只能在一定時間間隔內發射一次。你可以這樣實現:
## 實作射速控制
無限制射擊會壓垮遊戲引擎且讓遊戲太容易。真實武器也有類似限制——就連企業號光子炮射擊間也需充能。
我們實作一套冷卻系統,防止連續射擊,同時保持操作流暢:
```mermaid
sequenceDiagram
participant Player
participant Weapon
participant Cooldown
participant Game
Player->>Weapon: 按下空白鍵
Weapon->>Cooldown: 檢查是否冷卻中
alt 武器已準備好
Cooldown->>Weapon: cool = true
Weapon->>Game: 創建雷射
Weapon->>Cooldown: 開始新冷卻時間
Cooldown->>Cooldown: cool = false
Note over Cooldown: 等待 500 毫秒
Cooldown->>Cooldown: cool = true
else 武器冷卻中
Cooldown->>Weapon: cool = false
Weapon->>Player: 無動作
end
```
```javascript
class Cooldown {
constructor(time) {
this.cool = false;
setTimeout(() => {
this.cool = true;
}, time)
}, time);
}
}
class Weapon {
constructor {
constructor() {
this.cooldown = null;
}
fire() {
if (!this.cooldown || this.cooldown.cool) {
// produce a laser
// 建立雷射射彈
this.cooldown = new Cooldown(500);
} else {
// do nothing - it hasn't cooled down yet.
// 武器仍在冷卻中
}
}
}
```
✅ 回顧太空遊戲系列的第一課,重新了解*冷卻時間*的概念。
**冷卻機制運作:**
- 剛生成武器為「熱」狀態(不能射擊)
- 超過冷卻時間後變「冷」狀態(可射擊)
- 射擊前檢查武器是否處於冷卻完成
- 防止濫射但不降低反應速度
✅ 回顧太空遊戲系列第一堂課,溫習冷卻機制。
## 建立碰撞系統
你將擴充現有太空遊戲程式碼,製作碰撞偵測系統。就像國際太空站自動避碰系統會持續監控物體位置並應對,遊戲也會持續檢查並反應碰撞。
從上一課的程式碼開始,我們加入碰撞偵測及控制物件互動規則。
## 要建構的內容
> 💡 **專業提示**:雷射圖片已放在資源資料夾並在程式碼中引用,準備好使用了。
你將基於上一課的程式碼(應該已經清理並重構過)進行擴展。可以從第 II 部分的程式碼開始,或者使用 [第 III 部分的起始程式碼](../../../../../../../../../your-work)。
### 需要實作的碰撞規則
> 提示:你將使用的雷射已經在資產資料夾中,並且已在程式碼中引用。
**遊戲機制新增:**
1. **雷射擊中敵人**:敵人被雷射擊中即毀滅
2. **雷射碰觸螢幕邊界**:雷射達到頂部時消失
3. **敵人與英雄碰撞**:雙方交集皆毀滅
4. **敵人到達底部**:敵人觸底判定遊戲結束
- **新增碰撞檢測**,當雷射與某物件碰撞時,應遵循以下規則:
1. **雷射擊中敵人**:敵人被雷射擊中後會死亡。
2. **雷射擊中螢幕頂部**:雷射擊中螢幕頂部後會被銷毀。
3. **敵人與英雄碰撞**:敵人與英雄相撞後雙方都會被銷毀。
4. **敵人到達螢幕底部**:敵人到達螢幕底部時,敵人和英雄都會被銷毀。
### 🔄 **教學檢核**
**碰撞偵測基礎**:實作前確認了解:
- ✅ 矩形邊界如何定義碰撞區域
- ✅ 為什麼分離測試比求交集計算更有效
- ✅ 物件生命周期管理在遊戲迴圈的重要性
- ✅ 事件驅動系統如何協調碰撞反應
## 建議步驟
**快速自測**:如果你馬上刪除物件會怎樣?
*答:迴圈中途刪除可能導致程式崩潰或跳過某些物件*
找到在 `your-work` 子資料夾中為你創建的檔案。它應包含以下內容:
**物理理解**:你懂得:
- **座標系統**:位置與尺寸如何建立邊界
- **交集邏輯**:碰撞偵測背後的數學原理
- **效能優化**:為何高效算法是即時系統關鍵
- **記憶體管理**:安全的物件生命週期模式
## 設定開發環境
好消息──我們已經幫你架好大部分基礎!所有遊戲素材和基本架構都在 `your-work` 子資料夾,等你加入酷炫的碰撞功能。
### 專案結構
```bash
-| assets
@ -137,161 +331,430 @@ class Weapon {
-| package.json
```
你可以通過輸入以下指令來啟動專案:
**檔案結構概覽:**
- **包含** 遊戲物件所需所有精靈圖片
- **帶有** 主要 HTML 檔與 JavaScript 程式碼
- **提供** 用於本地開發伺服器的套件設定
### 啟動本地開發伺服器
切換進專案目錄並啟動本地伺服器:
```bash
cd your-work
npm start
```
上述指令會在位址 `http://localhost:5000` 啟動一個 HTTP 伺服器。打開瀏覽器並輸入該位址,目前應該只會顯示英雄和所有敵人,暫時還沒有任何移動。
**此命令執行了:**
- **切換資料夾**至專案工作目錄
- **啟動本地 HTTP 伺服器**於 `http://localhost:5000`
- **供應遊戲檔案**用於測試與開發
- **支援即時開發**含自動重新載入功能
打開瀏覽器造訪 `http://localhost:5000`,即可看到目前有英雄與敵人繪製在畫面。
### 逐步實作流程
像 NASA 系統性編寫旅行者號太空船程式,我們會逐步實作碰撞偵測,每個元件分階段完成。
```mermaid
flowchart TD
A["1. 矩形邊界"] --> B["2. 相交檢測"]
B --> C["3. 雷射系統"]
C --> D["4. 事件處理"]
D --> E["5. 碰撞規則"]
E --> F["6. 冷卻系統"]
G["物體邊界"] --> A
H["物理演算法"] --> B
I["投射物建立"] --> C
J["鍵盤輸入"] --> D
K["遊戲邏輯"] --> E
L["速率限制"] --> F
F --> M["🎮 完整遊戲"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
style M fill:#e1f5fe
```
#### 1. 新增矩形碰撞邊界
先教遊戲物件如何描述自己的邊界。為 `GameObject` 類別新增此方法:
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
```
**此方法做了:**
- **建立** 一個包含精確邊界座標的矩形物件
- **利用** 位置加尺寸計算底邊和右邊
- **回傳** 適用於碰撞偵測的物件格式
- **提供** 遊戲物件通用介面
#### 2. 實作交集偵測
現在製作碰撞偵探──可判斷兩矩形是否重疊的函數:
```javascript
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
```
**演算法邏輯為:**
- **測四個分離條件**判斷矩形是否有間距
- **任一分離成立**回傳 `false`
- **皆不成立則表示碰撞**
- **使用邏輯否定**增加判斷效率
#### 3. 實作雷射射擊系統
精彩部分!開始架設雷射射擊系統。
### 新增程式碼
##### 訊息常數
1. **為遊戲物件設置矩形表示,以處理碰撞** 以下程式碼允許你獲取 `GameObject` 的矩形表示。編輯你的 GameObject 類別以擴展它:
首先定義一些訊息類型,方便遊戲不同系統溝通
```javascript
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
```javascript
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
```
**這些常數作用:**
- **統一命名**以利事件管理
- **保持架構一致性**
- **避免註冊事件時打錯字**
##### 鍵盤輸入處理
加入偵測空白鍵的事件監聽程式:
```javascript
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
```
**此輸入處理:**
- **偵測空白鍵**(keyCode 32)
- **發送標準化事件訊息**
- **利於分離射擊邏輯**
##### 事件監聽設置
`initGame()` 中註冊射擊事件:
```javascript
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
});
```
**該事件監聽:**
- **回應空白鍵事件**
- **檢查射擊冷卻狀態**
- **允許時觸發雷射生成**
新增雷射與敵人的碰撞處理:
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
});
```
**碰撞處理邏輯:**
- **接收碰撞事件並取得雙方物件**
- **標記雙方為待刪除**
- **確保碰撞後正確清理**
#### 4. 新建雷射類別
實作向上移動並自我管理生命週期的雷射子彈:
```javascript
class Laser extends GameObject {
constructor(x, y) {
super(x, y);
this.width = 9;
this.height = 33;
this.type = 'Laser';
this.img = laserImg;
let id = setInterval(() => {
if (this.y > 0) {
this.y -= 15;
} else {
this.dead = true;
clearInterval(id);
}
```
2. **新增檢查碰撞的程式碼** 這將是一個新函數,用於測試兩個矩形是否相交:
```javascript
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
```
3. **新增雷射發射功能**
1. **新增按鍵事件訊息**。按下*空白鍵*應在英雄飛船的正上方創建一個雷射。在 Messages 物件中新增三個常數:
```javascript
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
```
1. **處理空白鍵**。編輯 `window.addEventListener` 的 keyup 函數以處理空白鍵:
```javascript
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
```
1. **新增監聽器**。編輯 `initGame()` 函數,確保當按下空白鍵時英雄可以發射雷射:
```javascript
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
```
並新增一個新的 `eventEmitter.on()` 函數,以確保當敵人與雷射碰撞時觸發行為:
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
})
```
1. **移動物件**,確保雷射逐漸移動到螢幕頂部。你將創建一個新的 Laser 類別,繼承自 `GameObject`,如之前所做的那樣:
```javascript
class Laser extends GameObject {
constructor(x, y) {
super(x,y);
(this.width = 9), (this.height = 33);
this.type = 'Laser';
this.img = laserImg;
let id = setInterval(() => {
if (this.y > 0) {
this.y -= 15;
} else {
this.dead = true;
clearInterval(id);
}
}, 100)
}
}, 100);
}
}
```
**此類別特性:**
- **繼承 GameObject 基礎功能**
- **設定雷射精靈的寬高**
- **用 setInterval() 實現自動向上移動**
- **碰到螢幕頂端自行銷毀**
- **管理動畫更新與清理**
#### 5. 實作碰撞偵測系統
建立完整的碰撞偵測函式:
```javascript
function updateGameObjects() {
const enemies = gameObjects.filter(go => go.type === 'Enemy');
const lasers = gameObjects.filter(go => go.type === "Laser");
// 測試雷射與敵人的碰撞
lasers.forEach((laser) => {
enemies.forEach((enemy) => {
if (intersectRect(laser.rectFromGameObject(), enemy.rectFromGameObject())) {
eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
first: laser,
second: enemy,
});
}
```
1. **處理碰撞**,實現雷射的碰撞規則。新增一個 `updateGameObjects()` 函數,用於測試碰撞物件是否發生碰撞:
```javascript
function updateGameObjects() {
const enemies = gameObjects.filter(go => go.type === 'Enemy');
const lasers = gameObjects.filter((go) => go.type === "Laser");
// laser hit something
lasers.forEach((l) => {
enemies.forEach((m) => {
if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) {
eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
first: l,
second: m,
});
}
});
});
gameObjects = gameObjects.filter(go => !go.dead);
}
```
確保在 `window.onload` 的遊戲迴圈中加入 `updateGameObjects()`
4. **實現雷射的冷卻時間**,確保雷射只能在一定時間間隔內發射。
最後,編輯 Hero 類別以實現冷卻功能:
```javascript
class Hero extends GameObject {
constructor(x, y) {
super(x, y);
(this.width = 99), (this.height = 75);
this.type = "Hero";
this.speed = { x: 0, y: 0 };
this.cooldown = 0;
}
fire() {
gameObjects.push(new Laser(this.x + 45, this.y - 10));
this.cooldown = 500;
let id = setInterval(() => {
if (this.cooldown > 0) {
this.cooldown -= 100;
} else {
clearInterval(id);
}
}, 200);
}
canFire() {
return this.cooldown === 0;
}
});
});
// 移除已被摧毀的物件
gameObjects = gameObjects.filter(go => !go.dead);
}
```
**碰撞系統做了:**
- **依物件類別過濾清單,提高效能**
- **逐一測試所有雷射與敵人的交集**
- **偵測到交集時發送碰撞事件**
- **碰撞後清理銷毀物件**
> ⚠️ **重要提醒**:在 `window.onload` 主要遊戲迴圈加入 `updateGameObjects()`,啟用碰撞檢測功能。
#### 6. 在 Hero 類別加入冷卻系統
增強 Hero 類別,新增射擊能力與射速控制:
```javascript
class Hero extends GameObject {
constructor(x, y) {
super(x, y);
this.width = 99;
this.height = 75;
this.type = "Hero";
this.speed = { x: 0, y: 0 };
this.cooldown = 0;
}
fire() {
gameObjects.push(new Laser(this.x + 45, this.y - 10));
this.cooldown = 500;
let id = setInterval(() => {
if (this.cooldown > 0) {
this.cooldown -= 100;
} else {
clearInterval(id);
}
```
}, 200);
}
canFire() {
return this.cooldown === 0;
}
}
```
**增強版本 Hero 類別說明:**
- **初始化冷卻時間為 0可射擊**
- **產生雷射物件,位置在英雄上方**
- **設定冷卻時間防止連續射擊**
- **用定時器倒數冷卻時間**
- **提供 `canFire()` 回傳可否射擊狀態**
### 🔄 **教學檢核**
**系統整體理解**:確認你掌握:
- ✅ 矩形邊界如何高效支援碰撞偵測
- ✅ 物件生命週期管理為何維持遊戲穩定關鍵
- ✅ 冷卻系統如何防止效能瓶頸
- ✅ 事件驅動架構在碰撞處理中的角色
**系統整合**:你的碰撞系統示範了:
- **數學精準性**:矩形交集演算法
- **效能優化**:高效碰撞測試模式
- **記憶體管理**:安全物件創建與銷毀
- **事件協調**:鬆耦合系統間溝通
- **即時處理**:框架式更新循環
**專業模式**:你實現:
- **關注點分離**:物理、渲染與輸入分工
- **物件導向設計**:繼承與多型
- **狀態管理**:物件生命週期與遊戲狀態追蹤
- **效能優化**:低耗能即時算法
### 測試你的實作
你現在的太空遊戲擁有完整碰撞偵測與戰鬥機制。🚀 測試新功能:
- **用方向鍵操控角色確認移動**
- **按空白鍵射擊雷射,注意冷卻防止爆射**
- **觀察雷射擊中敵人,敵人被移除**
- **確認銷毀物件完整刪除,避免殘留**
你已成功實作一套碰撞偵測系統,運用與太空船導航與機器人技術相同的數學原則。
### ⚡ **接下來 5 分鐘你可以做的事**
- [ ] 開啟瀏覽器開發者工具,在碰撞偵測函式設置斷點
- [ ] 嘗試調整雷射速度或敵人移動測試碰撞效果
- [ ] 嘗試不同冷卻時間,測試射擊速率控制
- [ ] 添加 `console.log` 陳述式以即時追蹤碰撞事件
### 🎯 **你這一小時可以達成的目標**
- [ ] 完成課後測驗並理解碰撞偵測演算法
- [ ] 在碰撞發生時加入爆炸等視覺效果
- [ ] 實作不同屬性的投射物種類
- [ ] 創建暫時增強玩家能力的強化道具
- [ ] 加入音效使碰撞更具滿足感
### 📅 **你這週的物理程式設計目標**
- [ ] 完成具備完善碰撞系統的太空遊戲
- [ ] 實作矩形以外的進階碰撞形狀(圓形、多邊形)
- [ ] 加入粒子系統以呈現真實爆炸效果
- [ ] 創建具備碰撞避讓的複雜敵人行為
- [ ] 優化大量物件下的碰撞偵測效能
- [ ] 加入動量與真實運動的物理模擬
### 🌟 **你這個月的遊戲物理大師之路**
- [ ] 建立使用先進物理引擎與真實模擬的遊戲
- [ ] 學習 3D 碰撞偵測與空間分割演算法
- [ ] 貢獻開源物理函式庫及遊戲引擎專案
- [ ] 精通高效能圖形應用程式的效能優化
- [ ] 製作遊戲物理與碰撞偵測的教學內容
- [ ] 建立展示先進物理程式技巧的作品集
## 🎯 你的碰撞偵測精通時間軸
```mermaid
timeline
title 碰撞偵測與遊戲物理學習進度
section 基礎 (10 分鐘)
Rectangle Math: 座標系統
: 邊界計算
: 位置追蹤
: 尺寸管理
section 演算法設計 (20 分鐘)
Intersection Logic: 分離測試
: 重疊偵測
: 效能優化
: 邊界案例處理
section 遊戲實作 (30 分鐘)
Object Systems: 生命週期管理
: 事件協調
: 狀態追蹤
: 記憶體清理
section 互動功能 (40 分鐘)
Combat Mechanics: 射擊系統
: 武器冷卻
: 傷害計算
: 視覺回饋
section 進階物理 (50 分鐘)
Real-time Systems: 幀率優化
: 空間劃分
: 碰撞反應
: 物理模擬
section 專業技術 (1 週)
Game Engine Concepts: 元件系統
: 物理流程線
: 效能分析
: 跨平台優化
section 產業應用 (1 個月)
Production Skills: 大規模優化
: 團隊協作
: 引擎開發
: 平台部署
```
### 🛠️ 你的遊戲物理工具箱摘要
完成本課程後,你已掌握:
- **碰撞數學**:矩形交集演算法與座標系統
- **效能優化**:實時應用的高效碰撞偵測
- **物件生命週期管理**:安全的物件建立、更新與銷毀模式
- **事件驅動架構**:解除耦合的碰撞回應系統
- **遊戲循環整合**:基於幀的物理更新與渲染協調
- **輸入系統**:具回饋的響應式控制與頻率限制
- **記憶體管理**:高效的物件池與清理策略
**實務應用範圍**:你的碰撞偵測技能直接應用於:
- **互動模擬**:科學模型與教育工具
- **使用者介面設計**:拖放交互與觸控偵測
- **資料可視化**:互動圖表與可點擊元素
- **行動開發**:觸控手勢識別與碰撞處理
- **機器人程式設計**:路徑規劃與障礙躲避
- **電腦圖學**:光線追蹤與空間演算法
**獲得的專業技能**:你現在能夠:
- **設計**實時碰撞偵測的高效演算法
- **實作**可橫向擴展的物理系統
- **除錯**基於數學原理的複雜互動系統
- **優化**適用於不同硬體與瀏覽器的效能
- **架構**使用成熟設計模式的可維護遊戲系統
到這裡,你的遊戲已經具備了一些基本功能!你可以使用方向鍵移動英雄,按下空白鍵發射雷射,並且當雷射擊中敵人時,敵人會消失。做得好!
**掌握的遊戲開發概念**
- **物理模擬**:實時碰撞偵測與回應
- **效能工程**:適用於互動應用的優化演算法
- **事件系統**:遊戲元件的解除耦合通訊
- **物件管理**:動態內容的高效生命週期模式
- **輸入處理**:具適當回饋的響應式控制
**下一階段**:你已準備好探索像 Matter.js 的進階物理引擎,實作 3D 碰撞偵測,或建構複雜粒子系統!
🌟 **成就解鎖**:你已建立一套具專業碰撞偵測的完整物理互動系統!
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
**描述:** 提升碰撞偵測系統,實作會隨機生成並在英雄太空船收集時提供暫時能力的強化道具。
**提示:** 創建一個繼承自 GameObject 的 PowerUp 類別,並實作英雄與強化道具間的碰撞偵測。至少加入兩種強化道具:一種提升射速(降低冷卻時間),另一種創建暫時護盾。包含在隨機間隔與位置生成強化道具的邏輯。
---
## 🚀 挑戰
新增爆炸效果!查看 [Space Art 資源庫](../../../../6-space-game/solution/spaceArt/readme.txt) 中的遊戲資產,嘗試在雷射擊中外星人時新增爆炸效果。
新增爆炸效果!查看 [Space Art repo](../../../../6-space-game/solution/spaceArt/readme.txt) 中的遊戲素材,嘗試在雷射碰撞外星人時添加爆炸效果
## 課後測驗
@ -299,7 +762,7 @@ npm start
## 回顧與自學
嘗試調整遊戲中的時間間隔,觀察會發生什麼變化?閱讀更多關於 [JavaScript 計時事件](https://www.freecodecamp.org/news/javascript-timing-events-settimeout-and-setinterval/) 的內容
嘗試調整你遊戲中目前的間隔時間。改變它們會發生什麼事?深入閱讀 [JavaScript 計時事件](https://www.freecodecamp.org/news/javascript-timing-events-settimeout-and-setinterval/)。
## 作業
@ -307,5 +770,7 @@ npm start
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 所翻譯。雖然我們致力於翻譯的準確性,但請注意,自動翻譯可能會包含錯誤或不準確之處。文件之原文版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯內容所導致之任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,64 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "8a0a097b45e7c75a611e2795e4013f16",
"translation_date": "2025-08-23T23:02:54+00:00",
"original_hash": "124efddbb65166cddb38075ad6dae324",
"translation_date": "2026-01-06T13:40:28+00:00",
"source_file": "6-space-game/4-collision-detection/assignment.md",
"language_code": "tw"
}
-->
# 探索碰撞
## 說明
## 指示
為了更好地理解碰撞的運作方式,建立一個包含少量物件的簡單遊戲,讓這些物件可以發生碰撞。透過按鍵或滑鼠點擊讓它們移動,並在其中一個物件被撞擊時觸發某些事件。這可以是像隕石撞擊地球,或者碰碰車之類的情境。發揮創意吧!
運用你的碰撞偵測知識,創建一個展示不同物件互動類型的自訂迷你遊戲。這個作業將透過創意實作與實驗,幫助你理解碰撞機制。
### 專案需求
**創建一個包含以下特色的小型互動遊戲:**
- **多個可透過鍵盤或滑鼠操作的移動物件**
- **使用課程中矩形交集原則的碰撞偵測系統**
- **碰撞發生時提供視覺回饋(物件消除、顏色變化、特效)**
- **具有使碰撞有意義且引人入勝的遊戲規則**
### 創意建議
**考慮實作以下情境之一:**
- **小行星帶**:駕駛太空船穿越危險的太空碎片
- **碰碰車**:建立基於物理的碰撞競技場
- **流星防禦**:保護地球免受太空隕石的攻擊
- **收集遊戲**:收集物品同時避開障礙物
- **領土爭奪**:競爭物件企圖佔領空間
### 技術實作
**你的解決方案應展示:**
- 矩形基礎碰撞偵測的正確運用
- 事件驅動的使用者輸入程式設計
- 物件生命週期管理(創建和銷毀)
- 使用適當類別結構的乾淨程式碼組織
### 加分挑戰
**為你的遊戲增添以下功能:**
- 碰撞時的粒子特效
- 不同碰撞類型的音效
- 基於碰撞結果的計分系統
- 多種碰撞種類且具有不同行為
- 隨時間增加的漸進式難度
## 評分標準
| 評分項目 | 卓越 | 合格 | 需要改進 |
| -------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------- |
| | 提供完整可運行的程式碼範例,物件成功繪製到畫布上,基本碰撞發生,並且有反應產生 | 程式碼在某些方面不完整 | 程式碼運行失敗 |
| 評分項目 | 優異 | 適當 | 需改進 |
|----------|-----------|----------|-------------------|
| **碰撞偵測** | 精確實作基於矩形的多物件碰撞偵測,且具有複雜互動規則 | 基本碰撞偵測正確,物件互動簡單 | 碰撞偵測有問題或不穩定 |
| **程式碼品質** | 程式碼乾淨且組織良好,使用恰當類別結構、具意義的變數名稱與適當註解 | 程式碼可運作,但組織或文件說明可改進 | 程式碼難以理解或結構混亂 |
| **使用者互動** | 操控反應良好,遊戲流暢,視覺回饋清晰且機制引人入勝 | 基本操作能用且回饋足夠 | 操控不敏感或混亂 |
| **創意表現** | 原創概念與獨特功能、視覺精緻與創新碰撞行為 | 標準實作,有部分創意元素 | 基本功能,無創意加強 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 所翻譯。雖然我們致力於翻譯的準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始語言文件應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所引起的任何誤解或曲解負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,89 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "adda95e02afa3fbee67b6e385b1109e1",
"translation_date": "2025-08-29T15:21:34+00:00",
"original_hash": "2ed9145a16cf576faa2a973dff84d099",
"translation_date": "2026-01-06T13:45:15+00:00",
"source_file": "6-space-game/5-keeping-score/README.md",
"language_code": "tw"
}
-->
# 建立太空遊戲第 5 部分:分數與生命值
# 建立太空遊戲 第五部分:計分與生命值
```mermaid
journey
title 你的遊戲設計旅程
section 玩家反饋
了解分數心理學: 3: Student
學習視覺傳達: 4: Student
設計獎勵系統: 4: Student
section 技術實作
Canvas 文字渲染: 4: Student
狀態管理: 5: Student
事件驅動更新: 5: Student
section 遊戲打磨
使用者體驗設計: 5: Student
平衡挑戰與獎勵: 5: Student
創造吸引人的遊戲玩法: 5: Student
```
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/37)
在這一課中,你將學習如何在遊戲中加入分數計算以及生命值機制。
準備好讓你的太空遊戲成為真正的遊戲了嗎?讓我們加入計分與生命值管理——這些早期街機遊戲如《太空侵略者》從簡單演示變成讓人上癮娛樂的核心機制。這是讓你的遊戲真正可玩的關鍵。
```mermaid
mindmap
root((遊戲反饋系統))
Visual Communication
Text Rendering
Icon Display
Color Psychology
Layout Design
Scoring Mechanics
Point Values
Reward Timing
Progress Tracking
Achievement Systems
Life Management
Risk vs Reward
Player Agency
Difficulty Balance
Recovery Mechanics
User Experience
Immediate Feedback
Clear Information
Emotional Response
Engagement Loops
Implementation
Canvas API
State Management
Event Systems
Performance
```
## 在畫面上繪製文字——你的遊戲之聲
## 在螢幕上繪製文字
要顯示分數,我們需要學會如何在畫布上繪製文字。`fillText()` 方法是你的主要工具——這也是經典街機遊戲用來顯示分數和狀態資訊的技術。
為了能夠在螢幕上顯示遊戲分數,你需要知道如何在螢幕上放置文字。答案是使用 canvas 物件的 `fillText()` 方法。你還可以控制其他方面,例如使用的字體、文字顏色,甚至是對齊方式(左對齊、右對齊、置中)。以下是一些在螢幕上繪製文字的程式碼。
```mermaid
flowchart LR
A["📝 文字內容"] --> B["🎨 樣式"]
B --> C["📍 位置"]
C --> D["🖼️ 畫布渲染"]
E["字體"] --> B
F["字體大小"] --> B
G["顏色"] --> B
H["對齊方式"] --> B
I["X 座標"] --> C
J["Y 座標"] --> C
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
```
你可以完全控制文字的外觀:
```javascript
ctx.font = "30px Arial";
@ -26,22 +92,74 @@ ctx.textAlign = "right";
ctx.fillText("show this on the screen", 0, 0);
```
閱讀更多關於[如何在 canvas 上添加文字](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_text)的內容,並隨意讓你的文字看起來更有特色
深入了解[在畫布上添加文字](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_text) — 你會驚訝於你在字型與樣式上能發揮多少創意
## 生命值作為遊戲概念
## 生命值——不只是一個數字
在遊戲中,生命值的概念只是一個數字。在太空遊戲的情境中,通常會分配一組生命值,當你的飛船受到傷害時,生命值會逐一減少。如果能用圖形化的方式來表示生命值,例如小型飛船或愛心,而不是單純的數字,會更直觀
在遊戲設計中,「生命」代表玩家犯錯的餘地。這個概念可追溯到彈球機,你會獲得多顆球來進行遊戲。在早期像《小行星》的遊戲中,生命讓玩家敢於冒險並從錯誤中學習
## 要實現的功能
```mermaid
flowchart TD
A["🎮 玩家行動"] --> B{"風險評估"}
B --> C["高風險,高回報"]
B --> D["安全策略"]
C --> E{"結果"}
D --> F["穩健進展"]
E -->|成功| G["🏆 大分數"]
E -->|失敗| H["💔 失去生命"]
H --> I{"剩餘生命?"}
I -->|是| J["🔄 再試一次"]
I -->|否| K["💀 遊戲結束"]
J --> B
G --> B
F --> B
style C fill:#ffebee
style D fill:#e8f5e8
style G fill:#e3f2fd
style H fill:#fff3e0
```
視覺呈現非常重要——顯示飛船圖示而不是僅標示「生命值3」能立即建立視覺認知類似早期街機機台利用圖示跨越語言障礙。
讓我們為你的遊戲新增以下功能:
## 建立你遊戲的獎勵系統
- **遊戲分數**:每摧毀一艘敵方飛船,英雄應該獲得一些分數,我們建議每艘飛船 100 分。遊戲分數應顯示在左下角。
- **生命值**:你的飛船有三條生命值。每當敵方飛船與你碰撞時,你會失去一條生命值。生命值應顯示在右下角,並以以下圖形表示 ![life image](../../../../translated_images/life.6fb9f50d53ee0413cd91aa411f7c296e10a1a6de5c4a4197c718b49bf7d63ebf.tw.png)。
現在我們將實現保持玩家投入的核心回饋系統:
```mermaid
sequenceDiagram
participant Player
participant GameEngine
participant ScoreSystem
participant LifeSystem
participant Display
Player->>GameEngine: 射擊敵人
GameEngine->>ScoreSystem: 獎勵分數
ScoreSystem->>ScoreSystem: +100 分
ScoreSystem->>Display: 更新分數
Player->>GameEngine: 跟敵人碰撞
GameEngine->>LifeSystem: 減少生命
LifeSystem->>LifeSystem: -1 生命
LifeSystem->>Display: 更新生命值
alt 生命值 > 0
LifeSystem->>Player: 繼續遊戲
else 生命值 = 0
LifeSystem->>GameEngine: 遊戲結束
end
```
- **計分系統**:每擊落一艘敵機獲得 100 分(整數分數讓玩家更容易心算)。分數顯示在左下角。
- **生命計數器**:你的英雄從三條命開始——這是早期街機遊戲為了挑戰與可玩性平衡而建立的標準。每碰撞一次敵人就損失一條命。我們會用飛船圖示在右下角顯示剩餘生命 ![life image](../../../../translated_images/life.6fb9f50d53ee0413.tw.png)。
## 建議步驟
## 開始動手做吧!
找到在 `your-work` 子資料夾中為你創建的檔案。它應包含以下內容:
首先,設定你的工作區。進入你的 `your-work` 子資料夾,你應該會看到這些檔案
```bash
-| assets
@ -53,24 +171,49 @@ ctx.fillText("show this on the screen", 0, 0);
-| package.json
```
你可以通過輸入以下指令啟動你的專案
要測試你的遊戲,從 `your_work` 資料夾啟動開發伺服器
```bash
cd your-work
npm start
```
上述指令會在地址 `http://localhost:5000` 啟動一個 HTTP 伺服器。打開瀏覽器並輸入該地址,現在應該會顯示英雄和所有敵人,當你按下左右方向鍵時,英雄會移動並能射擊敵人
這會在 `http://localhost:5000` 運行本機伺服器。打開瀏覽器進入該地址查看你的遊戲。用方向鍵測試控制,嘗試射擊敵人以確認一切運作正常
### 添加程式碼
```mermaid
flowchart TD
A["1. 資產加載"] --> B["2. 遊戲變數"]
B --> C["3. 碰撞檢測"]
C --> D["4. 英雄增強"]
D --> E["5. 顯示函式"]
E --> F["6. 事件處理函式"]
G["生命圖示圖片"] --> A
H["分數和生命追蹤"] --> B
I["英雄與敵人交集"] --> C
J["積分與生命方法"] --> D
K["文字與圖示渲染"] --> E
L["獎勵與懲罰邏輯"] --> F
F --> M["🎮 完整遊戲"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
style M fill:#e1f5fe
```
### 開始編碼!
1. **複製所需資源** 從 `solution/assets/` 資料夾複製到 `your-work` 資料夾;你需要添加一個 `life.png` 資源。在 `window.onload` 函數中添加 lifeImg
1. **取得你需要的視覺資源**。把 `solution/assets/` 資料夾中的 `life.png` 拷貝到你的 `your-work` 資料夾。然後將 lifeImg 加入你的 window.onload 函式
```javascript
lifeImg = await loadTexture("assets/life.png");
```
1. 將 `lifeImg` 添加到資源列表中:
1. 別忘了將 `lifeImg` 加入你的資源清單
```javascript
let heroImg,
@ -80,9 +223,9 @@ npm start
eventEmitter = new EventEmitter();
```
2. **添加變數**。新增程式碼來表示你的總分數0和剩餘生命值3並將這些分數顯示在螢幕上
2. **設定遊戲變數**。新增程式碼追蹤總分(起始為 0和剩餘生命起始為 3。我們會將這些資訊顯示在畫面上讓玩家隨時知道狀態
3. **擴展 `updateGameObjects()` 函數**。擴展 `updateGameObjects()` 函數以處理敵人碰撞:
3. **實作碰撞偵測**。擴充你的 `updateGameObjects()` 函式來偵測敵人與你的英雄碰撞:
```javascript
enemies.forEach(enemy => {
@ -93,19 +236,19 @@ npm start
})
```
4. **添加生命值和分數**。
1. **初始化變數**。在 `Hero` 類別中的 `this.cooldown = 0` 下,設置生命值和分數:
4. **為英雄新增生命與分數追蹤**。
1. **初始化計數器**。在你的 `Hero` 類別中,`this.cooldown = 0` 下面設定生命和分數:
```javascript
this.life = 3;
this.points = 0;
```
1. **在螢幕上繪製變數**。將這些值繪製到螢幕上
1. **將這些數值顯示給玩家**。建立函式將值繪製於畫面
```javascript
function drawLife() {
// TODO, 35, 27
// 待辦事項3527
const START_POS = canvas.width - 180;
for(let i=0; i < hero.life; i++ ) {
ctx.drawImage(
@ -128,18 +271,34 @@ npm start
```
1. **方法添加到遊戲循環中**。確保在 `window.onload` 函數中的 `updateGameObjects()` 下添加這些函數
1. **所有功能掛載到遊戲循環**。在 `updateGameObjects()` 後將這些函式加入你的 window.onload
```javascript
drawPoints();
drawLife();
```
1. **實現遊戲規則**。實現以下遊戲規則:
### 🔄 **教學檢查點**
**遊戲設計理解**:在實作後果之前,確認你理解:
- ✅ 視覺回饋如何向玩家傳達遊戲狀態
- ✅ UI 元件整齊擺放為何能提升易用性
- ✅ 分數值與生命管理背後的心理學原理
- ✅ 畫布文字渲染與 HTML 文字的差異
**快速自我測驗**:為何街機遊戲通常用整數分數?
*答案:整數分數玩家心算較容易,且帶來心理上滿足感獎勵*
**使用者體驗原則**:你目前應用:
- **視覺層級**:重要資訊放在醒目位置
- **即時回饋**:玩家行動即時更新
- **認知負荷**:簡潔清晰資訊呈現
- **情感設計**:用圖示與色彩建立玩家連結
1. **實現遊戲後果與獎勵系統**。現在加入讓玩家行動有意義的回饋系統:
1. **碰撞會損失生命**。每當英雄撞上敵人,就會失去一條命。
1. **每當英雄與敵人碰撞時**,扣除一條生命值。
擴展 `Hero` 類別以執行此扣除:
把此方法加入你的 `Hero` 類別:
```javascript
decrementLife() {
@ -150,17 +309,17 @@ npm start
}
```
2. **每當雷射擊中敵人時**,遊戲分數增加 100 分。
2. **射擊敵人會獲得分數**。每次成功擊中累積 100 分,為精準射擊帶來即時正向回饋。
擴充英雄類別新增分數增加方法:
擴展 `Hero` 類別以執行此加分:
```javascript
incrementPoints() {
this.points += 100;
}
```
將這些函數添加到你的碰撞事件觸發器中
現在將此功能與碰撞事件連結
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
@ -175,29 +334,175 @@ npm start
});
```
✅ 做一些研究,了解其他使用 JavaScript/Canvas 創建的遊戲。它們有哪些共同特點?
完成這些工作後,你應該能在右下角看到小型的「生命值」飛船,在左下角看到分數,並且當你與敵人碰撞時,生命值會減少;當你射擊敵人時,分數會增加。做得好!你的遊戲已接近完成。
✅ 想知道其他用 JavaScript 和 Canvas 建置的遊戲嗎?好好探索一番,你會驚艷於可能達成的效果!
實作完這些功能後,測試你的遊戲完整回饋系統。你會在右下角看到生命圖示,左下角看到分數,隨碰撞扣生命,成功射擊則增加分數。
你的遊戲現在擁有早期街機遊戲令人著迷的核心機制──明確目標、即時回饋與玩家行動後果。
### 🔄 **教學檢查點**
**完整遊戲設計系統**:驗證你已精通玩家回饋系統:
- ✅ 計分機制如何激發玩家動機與投入?
- ✅ 視覺一致性在界面設計中的重要性?
- ✅ 生命系統如何平衡挑戰與玩家留存?
- ✅ 即時回饋在創造滿意遊戲體驗中的作用?
**系統整合**:你的回饋系統展現:
- **使用者體驗設計**:清晰視覺溝通與資訊層級
- **事件驅動架構**:對玩家行動做即時回應
- **狀態管理**:追蹤並顯示動態遊戲數據
- **畫布技巧**:文字繪製與精靈定位
- **遊戲心理學**:理解玩家動機與投入
**專業設計模式**:你已實作:
- **MVC 架構**:遊戲邏輯、資料與呈現分離
- **觀察者模式**:事件驅動遊戲狀態更新
- **元件設計**:可重用渲染與邏輯函式
- **效能優化**:遊戲循環中高效渲染
### ⚡ **接下來五分鐘可以做的事情**
- [ ] 嘗試不同分數顯示的字型大小與顏色
- [ ] 改變分數值,感受遊戲節奏變化
- [ ] 增加 console.log 記錄分數與生命值變化時機
- [ ] 測試極限情況,如生命耗盡或達成高分
### 🎯 **這小時可達成目標**
- [ ] 完成課後答題,理解遊戲設計心理學
- [ ] 新增計分與失去生命的音效
- [ ] 實作使用 localStorage 的高分系統
- [ ] 為不同敵人設定不同點數
- [ ] 加入失去生命時畫面震動等視覺效果
### 📅 **你的周長遊戲設計之旅**
- [ ] 完成有完善回饋系統的完整太空遊戲
- [ ] 實現進階計分機制如連擊倍數
- [ ] 新增成就和可解鎖內容
- [ ] 建立難度進程與平衡系統
- [ ] 設計選單和遊戲結束畫面介面
- [ ] 研究其他遊戲理解玩家投入機制
### 🌟 **你的一個月遊戲開發修練**
- [ ] 建構具進階遊戲流程的完整作品
- [ ] 學習遊戲分析與玩家行為量化
- [ ] 參與開源遊戲開發專案
- [ ] 精通進階遊戲設計模式與營收策略
- [ ] 製作遊戲設計和使用者體驗教學內容
- [ ] 建立遊戲設計與開發作品集
## 🎯 你的遊戲設計掌握時程
```mermaid
timeline
title 遊戲設計與玩家回饋學習進度
section 基礎 (10分鐘)
視覺傳達:文字渲染
:圖示設計
:版面原則
:色彩心理學
section 玩家心理學 (20分鐘)
動機系統:點數價值
:風險與獎勵
:進度回饋
:成就設計
section 技術實作 (30分鐘)
畫布精通:文字定位
:圖像渲染
:狀態管理
:效能優化
section 遊戲平衡 (40分鐘)
難度設計:生命管理
:計分曲線
:玩家留存
:可及性
section 使用者體驗 (50分鐘)
介面設計:資訊階層
:回應反饋
:情感設計
:易用性測試
section 高級系統 (1週)
遊戲機制:進程系統
:分析整合
:營利設計
:社群功能
section 產業技能 (1個月)
專業發展:團隊合作
:設計文件
:玩家研究
:平台優化
```
### 🛠️ 你的遊戲設計工具摘要
完成本課程後,你已精通:
- **玩家心理學**:了解動機、風險/獎勵、與投入循環
- **視覺傳達**:用文字、圖示與排版提升 UI 效果
- **回饋系統**:對玩家行為及遊戲事件即時反應
- **狀態管理**:高效追蹤與呈現動態遊戲數據
- **畫布文字繪製**:專業文字顯示與樣式置中操作
- **事件整合**:將用戶操作連接到有意義的遊戲後果
- **遊戲平衡**:設計關卡難度與玩家成長系統
**實務應用**:你的遊戲設計能力可直接用於:
- **使用者介面設計**:打造吸引人且直覺的介面
- **產品開發**:理解用戶動機與回饋回圈
- **教育科技**:遊戲化與學習投入系統
- **資料視覺化**:讓複雜資訊變得易懂有趣
- **行動應用開發**:用戶留存機制與體驗設計
- **營銷科技**:理解用戶行為與轉換優化
**你已獲得的專業技能**
- **設計**出能激發動機且讓用戶投入的體驗
- **實作**引導用戶行為的回饋系統
- **平衡**互動系統的挑戰與可達性
- **創造**跨用戶群有效的視覺傳達
- **分析**用戶行為與迭代設計改進
**掌握的遊戲開發概念**
- **玩家動機**:了解促成參與與留存的關鍵
- **視覺設計**:打造清晰、吸引且實用的介面
- **系統整合**:結合多個遊戲系統提供完整體驗
- **效能優化**:高效畫面更新與狀態管理
- **無障礙設計**:適應不同技巧與玩家需求
**下一階段**:你已準備好探索進階遊戲設計模式、實作分析系統,或研究遊戲營收與玩家留存策略!
🌟 **成就解鎖**:你已建立完整的玩家回饋系統並掌握專業遊戲設計原則!
---
## 🚀 挑戰
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
**說明**:強化太空遊戲的計分系統,實作高分功能並加入持久儲存與連殺加分機制。
**提示**:建立高分系統,將玩家最高分數儲存到 localStorage。增加連續擊殺敵人連擊系統的獎勵分數並為不同敵人實作不同分數值。在玩家創造新高分時顯示視覺提示在遊戲畫面顯示目前最高分。
## 🚀 挑戰任務
你的程式碼已接近完成。你能想像下一步該做什麼嗎?
現在有一個具備計分與生命值的功能完整遊戲。想想看有哪些額外功能可以提升玩家體驗。
## 課後測驗
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/38)
## 回顧與自學
## 複習與自學
研究一些方法來增減遊戲分數和生命值。有一些有趣的遊戲引擎,例如 [PlayFab](https://playfab.com)。使用這些引擎如何提升你的遊戲體驗?
想要深入探索嗎?研究計分與生命系統的不同做法。市面上有些很棒的遊戲引擎如 [PlayFab](https://playfab.com) 負責計分、排行榜與玩家成長系統。整合這種方案會如何將你的遊戲推向新境界
## 作業
[建立一個計分遊戲](assignment.md)
[製作一款計分遊戲](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件由 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議採用專業人員的人工翻譯。我們不對因使用本翻譯而導致的任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,41 +1,163 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "05be6c37791668e3719c4fba94566367",
"translation_date": "2025-08-29T15:22:44+00:00",
"original_hash": "a4b78043f4d64bf3ee24e0689b8b391d",
"translation_date": "2026-01-06T13:42:46+00:00",
"source_file": "6-space-game/6-end-condition/README.md",
"language_code": "tw"
}
-->
# 建立太空遊戲第六部分:結束與重新開始
# 建立太空遊戲第六部:結束與重啟
```mermaid
journey
title 你的遊戲完成旅程
section 結束條件
定義勝負狀態: 3: Student
實作條件檢查: 4: Student
處理狀態轉換: 4: Student
section 玩家體驗
設計回饋系統: 4: Student
建立重新開始機制: 5: Student
打磨使用者介面: 5: Student
section 系統整合
管理遊戲生命週期: 5: Student
處理記憶體清理: 5: Student
創造完整體驗: 5: Student
```
每一款經典遊戲都需要明確的結束條件與順暢的重啟機制。你已經建立了一款有移動、戰鬥和得分功能的精彩太空遊戲——現在是時候加入最後的元素,讓遊戲更完整。
你的遊戲目前無限運行就像美國航太總署在1977年發射的旅行者探測器數十年後仍在太空中旅行。雖然對太空探索來說沒問題但遊戲需要有明確的終點才能創造令人滿意的體驗。
今天,我們將實作合適的勝利與失敗條件與重啟系統。課程結束時,你將擁有完成度高、玩家能結束並重玩的遊戲,就像定義了遊戲媒介的經典街機一樣。
```mermaid
mindmap
root((遊戲完成))
結束條件
勝利狀態
失敗條件
進度追蹤
狀態驗證
玩家反饋
視覺訊息
色彩心理學
清晰溝通
情感反應
狀態管理
遊戲循環控制
記憶清理
物件生命週期
事件處理
重啟系統
輸入處理
狀態重置
全新初始化
使用者體驗
精緻元素
訊息顯示
平滑過渡
防錯措施
無障礙
```
## 課前小測驗
[課前小測驗](https://ff-quizzes.netlify.app/web/quiz/39)
## 了解遊戲結束條件
## 課前測驗
遊戲應該何時結束?這個根本性問題自早期街機時代便影響遊戲設計。貪食蛇玩法是被鬼抓到或吃完所有點數便結束,太空侵略者是在外星人抵達底部或被全數擊毀時結束。
作為遊戲創作者,你定義勝利與失敗條件。針對我們的太空遊戲,以下是創造有趣玩法的經典方法:
```mermaid
flowchart TD
A["🎮 遊戲開始"] --> B{"檢查條件"}
B --> C["敵人數量"]
B --> D["英雄生命"]
B --> E["分數門檻"]
B --> F["關卡進度"]
C --> C1{"敵人 = 0?"}
D --> D1{"生命 = 0?"}
E --> E1{"分數 ≥ 目標?"}
F --> F1{"目標完成?"}
C1 -->|是| G["🏆 勝利"]
D1 -->|是| H["💀 失敗"]
E1 -->|是| G
F1 -->|是| G
C1 -->|否| B
D1 -->|否| B
E1 -->|否| B
F1 -->|否| B
G --> I["🔄 重新開始選項"]
H --> I
style G fill:#e8f5e8
style H fill:#ffebee
style I fill:#e3f2fd
```
- **摧毀 `N` 艘敵艦**:若遊戲分為多關,往往需要摧毀一定數量的敵艦才能過關
- **你的飛船被摧毀**:許多遊戲會在你的飛船被毀時判定失敗。另一種常見做法是有生命值概念,每次飛船毀滅扣一條命,生命耗盡則遊戲結束
- **收集了 `N` 點數**:另一種常見的結束條件是玩家須累積一定點數,點數可依各種行動獲取,如擊毀敵艦或收集敵艦被擊毀後掉落的物品
- **完成一關**:可能包含多種條件,例如摧毀 `X` 艘敵艦、收集 `Y` 點數,或是收集特定物品等
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/39)
## 實作遊戲重啟功能
在遊戲中,有多種方式可以表達*結束條件*。作為遊戲的創作者,您可以決定遊戲為什麼會結束。假設我們正在討論您目前正在構建的太空遊戲,以下是一些可能的原因:
優良遊戲透過順暢重啟機制鼓勵重玩。玩家完成遊戲(或失敗)後,往往喜歡立即重新嘗試,不論是為了破高分或改善表現。
- **摧毀了 `N` 艘敵方飛船**:如果您將遊戲分為不同的關卡,通常需要摧毀 `N` 艘敵方飛船才能完成一個關卡。
- **您的飛船被摧毀**:有些遊戲中,如果您的飛船被摧毀,您就會輸掉遊戲。另一種常見的方式是引入生命值的概念。每次飛船被摧毀時,扣除一條生命。一旦所有生命都耗盡,遊戲就結束。
- **收集了 `N` 分數**:另一個常見的結束條件是收集分數。如何獲得分數取決於您,但通常會將分數分配給各種活動,例如摧毀敵方飛船,或者收集敵方飛船被摧毀後掉落的物品。
- **完成一個關卡**:這可能涉及多種條件,例如摧毀 `X` 艘敵方飛船、收集 `Y` 分數,或者收集某個特定的物品。
```mermaid
stateDiagram-v2
[*] --> Playing: 遊戲開始
Playing --> Victory: 全部敵人被消滅
Playing --> Defeat: 生命值 = 0
Victory --> MessageDisplay: 顯示勝利訊息
Defeat --> MessageDisplay: 顯示失敗訊息
MessageDisplay --> WaitingRestart: 按下 Enter 提示
WaitingRestart --> Resetting: 按下 Enter 鍵
Resetting --> CleanupMemory: 清除間隔
CleanupMemory --> ClearEvents: 移除監聽器
ClearEvents --> InitializeGame: 全新開始
InitializeGame --> Playing: 新遊戲開始
note right of MessageDisplay
顏色編碼反饋:
綠色 = 勝利
紅色 = 失敗
end note
note right of Resetting
完整狀態重置
防止記憶體洩漏
end note
```
「俄羅斯方塊」就是完美例子:當方塊堆到頂端時,你可立刻開始新遊戲,無需瀏覽繁複選單。我們將建立類似的重啟系統,讓遊戲狀態乾淨重設,迅速帶玩家重返戰場。
## 重新開始
**思考**:想想你玩過的遊戲,它們在什麼條件會結束?如何提示你重啟?什麼讓重啟體驗順暢或令人沮喪?
如果玩家喜歡您的遊戲,他們可能會想要重新玩一次。無論遊戲因何種原因結束,您都應該提供重新開始的選項。
## 你將實作的內容
✅ 想一想,您認為遊戲在什麼條件下會結束,然後如何提示玩家重新開始。
你將完成最後功能,讓專案成為完整遊戲。這些元素決定遊戲的精緻度,而不只是基本原型
## 要構建的內容
**今天新增的是:**
您將為遊戲添加以下規則:
1. **勝利條件**:消滅所有敵人並展現恰當的慶祝(你值得擁有!)
2. **失敗條件**:生命耗盡,呈現失敗畫面
3. **重啟機制**:按 Enter 鍵立即重新開始 — 因為一場遊戲永遠不夠
4. **狀態管理**:每次都從乾淨狀態開始,不留敵人或奇怪的殘留錯誤
1. **贏得遊戲**。當所有敵方飛船被摧毀時,您贏得遊戲。此外,顯示某種勝利訊息。
2. **重新開始**。當所有生命耗盡或遊戲勝利時,您應該提供重新開始遊戲的方式。記住!您需要重新初始化遊戲,並清除之前的遊戲狀態。
## 開始前準備
## 建議步驟
讓我們準備開發環境。你應該已準備好之前課程的所有太空遊戲檔案。
找到在 `your-work` 子文件夾中為您創建的文件。它應該包含以下內容:
**你的專案看起來應該像這樣:**
```bash
-| assets
@ -48,189 +170,515 @@ CO_OP_TRANSLATOR_METADATA:
-| package.json
```
您可以通過輸入以下命令啟動 `your_work` 文件夾中的項目:
**啟動開發伺服器:**
```bash
cd your-work
npm start
```
上述命令將在地址 `http://localhost:5000` 上啟動一個 HTTP 伺服器。打開瀏覽器並輸入該地址。您的遊戲應該處於可玩狀態。
**此指令:**
- 在 `http://localhost:5000` 執行本地伺服器
- 正確提供你的檔案
- 檔案更動時自動刷新頁面
打開瀏覽器前往 `http://localhost:5000`,確認遊戲運作正常。你應該能移動、射擊並和敵人互動。確認無誤後,我們就可進行功能實作。
> 💡 **專業提示**:為避免 Visual Studio Code 中警告,請在檔案頂端宣告 `let gameLoopId;`,而非於 `window.onload` 函式內宣告。此做法符合現代 JavaScript 變數宣告最佳實踐。
```mermaid
flowchart TD
A["1. 狀態追蹤"] --> B["2. 事件處理器"]
B --> C["3. 訊息常數"]
C --> D["4. 重新啟動控制"]
D --> E["5. 訊息顯示"]
E --> F["6. 重置系統"]
G["isHeroDead()\nisEnemiesDead()"] --> A
H["碰撞事件\n結束遊戲事件"] --> B
I["GAME_END_WIN\nGAME_END_LOSS"] --> C
J["Enter 鍵\n重新啟動觸發"] --> D
K["勝利/失敗\n色彩標示文字"] --> E
L["狀態清理\n全新初始化"] --> F
F --> M["🎮 完整遊戲"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
style M fill:#e1f5fe
```
## 實作步驟
### 步驟 1建立結束條件追蹤函式
我們需要函式來監控遊戲何時該結束。就像國際太空站的感測器持續監控重要系統,這些函式會持續檢查遊戲狀態。
```javascript
function isHeroDead() {
return hero.life <= 0;
}
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
return enemies.length === 0;
}
```
> 提示:為了避免在 Visual Studio Code 中出現警告,編輯 `window.onload` 函數以直接調用 `gameLoopId`(不使用 `let`),並在文件頂部獨立聲明 `gameLoopId``let gameLoopId;`
**背後運作如下:**
- **檢查**主角是否已無生命(糟糕!)
- **計算**還有多少敵人存活並活躍
- **回傳**當敵場清空時為 `true`
- **使用**簡單的真假邏輯保持清晰
- **篩選**遊戲中的物件找出倖存者
### 添加程式碼
### 步驟 2更新事件處理器用於結束條件
1. **追蹤結束條件**。添加程式碼來追蹤敵方飛船的數量,或者英雄飛船是否被摧毀,通過添加以下兩個函數:
現在將結束條件判斷與遊戲事件系統連接。每次碰撞事件發生時,遊戲會評估是否觸發結束條件。如此可對重要事件給予即時回饋。
```javascript
function isHeroDead() {
return hero.life <= 0;
```mermaid
sequenceDiagram
participant Collision
participant GameLogic
participant Conditions
participant EventSystem
participant Display
Collision->>GameLogic: 雷射擊中敵人
GameLogic->>GameLogic: 摧毀物件
GameLogic->>Conditions: 檢查 isEnemiesDead()
alt 全部敵人被擊敗
Conditions->>EventSystem: 發出 GAME_END_WIN
EventSystem->>Display: 顯示勝利訊息
else 敵人尚存
Conditions->>GameLogic: 繼續遊戲
end
Collision->>GameLogic: 敵人撞擊英雄
GameLogic->>GameLogic: 減少生命值
GameLogic->>Conditions: 檢查 isHeroDead()
alt 生命值 = 0
Conditions->>EventSystem: 發出 GAME_END_LOSS
EventSystem->>Display: 顯示失敗訊息
else 生命值尚存
GameLogic->>Conditions: 檢查 isEnemiesDead()
alt 全部敵人被擊敗
Conditions->>EventSystem: 發出 GAME_END_WIN
end
end
```
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
hero.incrementPoints();
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
enemy.dead = true;
hero.decrementLife();
if (isHeroDead()) {
eventEmitter.emit(Messages.GAME_END_LOSS);
return; // 勝利之前的損失
}
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.GAME_END_WIN, () => {
endGame(true);
});
eventEmitter.on(Messages.GAME_END_LOSS, () => {
endGame(false);
});
```
**運作內容:**
- **雷射擊中敵人**:雙方消失,你得分,檢查是否勝利
- **敵人撞上你**:扣一條命並檢查是否存活
- **智能順序**:先檢查失敗條件(沒有人想同時贏又輸!)
- **即時反應**:重要事件一發生,遊戲立即得知
### 步驟 3新增訊息常數
你需要在 `Messages` 常數物件裡新增事件訊息類型。這些常數確保事件系統一致性與避免拼字錯誤。
```javascript
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
```
**以上更動包含:**
- **新增**與遊戲結束事件相關的常數,保持一致性
- **使用**清楚敘述事件目的的名稱
- **依循**既有訊息類型的命名慣例
### 步驟 4實作重啟控制
現在加入鍵盤控制允許玩家重啟遊戲。Enter 鍵是自然的選擇,因為它通常與確認動作和開始遊戲相關聯。
**在現有 keydown 事件監聽器中加入 Enter 鍵判斷:**
```javascript
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
```
**新增訊息常數:**
```javascript
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
```
**重要資訊:**
- **擴充**現有鍵盤事件處理系統
- **使用**Enter 鍵做為直覺的重啟觸發
- **發出**可被其他系統監聽的自訂事件
- **維持**和其他鍵盤控制相同模式
### 步驟 5建立訊息顯示系統
遊戲需清楚向玩家傳達結果。我們將建立訊息系統,用具有色彩標示的文字清楚表示勝利和失敗狀態,類似早期電腦終端機使用綠色表示成功、紅色表示錯誤。
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
return enemies.length === 0;
**建立 `displayMessage()` 函式:**
```javascript
function displayMessage(message, color = "red") {
ctx.font = "30px Arial";
ctx.fillStyle = color;
ctx.textAlign = "center";
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}
```
**細節說明:**
- **設定**字型大小與字體,提高可視性
- **使用**顏色參數,可預設為紅色警告色
- **讓**文字水平垂直置中呈現在畫布上
- **利用**現代 JavaScript 預設參數提供彈性
- **充分利用** canvas 2D context 實現直接文字渲染
**建立 `endGame()` 函式:**
```javascript
function endGame(win) {
clearInterval(gameLoopId);
// 設置延遲以確保所有待處理的渲染完成
setTimeout(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (win) {
displayMessage(
"Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
"green"
);
} else {
displayMessage(
"You died !!! Press [Enter] to start a new game Captain Pew Pew"
);
}
```
2. **添加邏輯到訊息處理器**。編輯 `eventEmitter` 以處理以下條件:
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
hero.incrementPoints();
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
enemy.dead = true;
hero.decrementLife();
if (isHeroDead()) {
eventEmitter.emit(Messages.GAME_END_LOSS);
return; // loss before victory
}
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.GAME_END_WIN, () => {
endGame(true);
});
eventEmitter.on(Messages.GAME_END_LOSS, () => {
endGame(false);
});
```
3. **添加新的訊息類型**。將以下訊息添加到常量對象中:
```javascript
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
```
4. **添加重新開始程式碼**,以便在按下選定按鈕時重新開始遊戲。
1. **監聽按鍵 `Enter`**。編輯窗口的事件監聽器以監聽此按鍵:
```javascript
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
```
2. **添加重新開始訊息**。將此訊息添加到您的訊息常量中:
```javascript
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
```
5. **實現遊戲規則**。實現以下遊戲規則:
1. **玩家勝利條件**。當所有敵方飛船被摧毀時,顯示勝利訊息。
1. 首先,創建一個 `displayMessage()` 函數:
```javascript
function displayMessage(message, color = "red") {
ctx.font = "30px Arial";
ctx.fillStyle = color;
ctx.textAlign = "center";
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}
```
2. 創建一個 `endGame()` 函數:
```javascript
function endGame(win) {
clearInterval(gameLoopId);
}, 200)
}
```
**該函式作用:**
- **凍結**所有活動:飛船與雷射停止移動
- **小暫停**(200 毫秒)讓上個畫面完成渲染
- **清空**畫面,並以黑色底顯示展現戲劇效果
- **對勝利與失敗者**顯示不同訊息
- **顏色區別**訊息:綠色代表好消息,紅色...代表不妙
- **指示**玩家如何重新開始遊戲
### 🔄 **教學檢核**
**遊戲狀態管理**:在實作重置功能前,請確保你了解:
- ✅ 結束條件如何創造明確遊戲目標
- ✅ 直觀視覺回饋為何對玩家理解非常重要
- ✅ 適當清理在防止記憶體洩漏上的重要性
- ✅ 事件驅動架構如何實現乾淨的狀態轉換
**自我測驗**:如果你不在重置時清除事件監聽器會發生什麼?
*答案:引起記憶體洩漏和事件監聽器重複,造成不可預測行為*
**遊戲設計原則**:你正執行以下重點:
- **明確目標**:玩家清楚何謂成功或失敗
- **即時回饋**:遊戲狀態變更能即刻傳達
- **用戶控制**:玩家能在準備好時重新開始
- **系統穩定**:適當清理避免 Bug 與性能問題
### 步驟 6實作遊戲重置功能
重置系統必須徹底清理現有遊戲狀態,並初始化全新遊戲環境。確保玩家每次從乾淨環境開始,沒有前場殘留資料。
**建立 `resetGame()` 函式:**
```javascript
function resetGame() {
if (gameLoopId) {
clearInterval(gameLoopId);
eventEmitter.clear();
initGame();
gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawPoints();
drawLife();
updateGameObjects();
drawGameObjects(ctx);
}, 100);
}
}
```
**逐段解析:**
- **檢查**是否已有進行中的遊戲迴圈
- **清除**現有迴圈,終止目前所有遊戲活動
- **移除**所有事件監聽器,避免記憶體洩漏
- **重新初始化**遊戲狀態,包括物件和變數
- **啟動**帶有必要遊戲功能的新遊戲迴圈
- **沿用**100 毫秒執行間隔,保持遊戲性能一致
**在 `initGame()` 函式中新增 Enter 鍵事件監聽:**
```javascript
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
```
**在 EventEmitter 類別新增 `clear()` 方法:**
```javascript
clear() {
this.listeners = {};
}
```
**記得關鍵點:**
- **將** Enter 鍵按下連結到重置遊戲功能
- **於遊戲初始化時**註冊此事件監聽
- **提供**一個方式在重置時移除所有事件監聽
- **避免**記憶體洩漏,重設遊戲間清理事件處理器
- **清空**listeners 物件,準備新初始化
## 恭喜!🎉
👽 💥 🚀 你成功從零打造出完整遊戲。就像1970年代創造第一批電子遊戲的程式設計師一樣你將程式碼轉成有完整遊戲機制與使用者回饋的互動體驗。🚀 💥 👽
**你已完成:**
- **實作**完整勝負條件及使用者回饋
- **創建**無縫重啟系統,讓遊戲持續進行
- **設計**清晰視覺顯示遊戲狀態
- **管理**複雜遊戲狀態轉換與清理
- **組合**所有元件成完整且可玩的遊戲
### 🔄 **教學檢核**
**完整遊戲開發系統**:慶祝你掌握全遊戲開發流程:
- ✅ 結束條件如何塑造讓玩家滿意的體驗?
- ✅ 為何正確狀態管理對遊戲穩定性關鍵?
- ✅ 視覺回饋如何強化玩家理解?
- ✅ 重啟系統在玩家留存中扮演什麼角色?
**系統掌握**:你打造的遊戲展現了:
- **全端遊戲開發**:涵蓋圖像、輸入及狀態管理
- **專業架構**:事件驅動、且具適當清理
- **使用者體驗設計**:清楚回饋與直覺操作
- **性能優化**:高效率渲染與記憶體管理
- **精緻與完整**:所有細節成就成熟遊戲感
**業界技能**:你已實作:
- **遊戲迴圈架構**:具一致性能的即時系統
- **事件驅動程式設計**:有效擴展的解耦系統
- **狀態管理**:複雜資料及生命週期處理
- **使用者界面設計**:明確溝通與回應式控制
- **測試與除錯**:反覆開發與問題解決能力
### ⚡ **接下來五分鐘可以做的事**
- [ ] 遊玩完成的遊戲並測試所有勝負條件
- [ ] 嘗試修改不同結束條件參數
- [ ] 加入 console.log 陳述追蹤遊戲狀態變化
- [ ] 分享遊戲給朋友並蒐集反饋
### 🎯 **這小時內能達成目標**
- [ ] 完成課後問答並反省遊戲開發歷程
- [ ] 為勝利與失敗狀態加入音效
- [ ] 實作更多結束條件,如限時或額外獎勵
- [ ] 製作不同難度關卡,調整敵人數量
- [ ] 美化視覺呈現,使用更佳字型與色彩
### 📅 **一週遊戲開發精通計畫**
- [ ] 完成改良版太空遊戲,含多關卡與進度
- [ ] 增加進階功能,如能量提升、敵人種類、多樣武器
- [ ] 建立持久化的排行榜系統
- [ ] 設計選單、設定和遊戲選項介面
- [ ] 優化不同裝置和瀏覽器的性能
- [ ] 將遊戲部署至網路並與社群分享
### 🌟 **你的一個月遊戲開發職涯**
- [ ] 製作多款完整遊戲,探索不同類型和機制
- [ ] 學習高階遊戲開發框架,如 Phaser 或 Three.js
- [ ] 參與開源遊戲開發專案
- [ ] 研究遊戲設計原則與玩家心理
- [ ] 建立作品集展示你的遊戲開發技能
- [ ] 與遊戲開發社群接軌並持續學習
## 🎯 你的完整遊戲開發精通時間軸
```mermaid
timeline
title 完整遊戲開發學習進度
section 基礎 (課程 1-2)
遊戲架構: 專案結構
: 資產管理
: 畫布基礎
: 事件系統
// set a delay so we are sure any paints have finished
setTimeout(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (win) {
displayMessage(
"Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
"green"
);
} else {
displayMessage(
"You died !!! Press [Enter] to start a new game Captain Pew Pew"
);
}
}, 200)
}
```
2. **重新開始邏輯**。當所有生命耗盡或玩家贏得遊戲時,顯示可以重新開始遊戲的提示。此外,當按下*重新開始*鍵時重新開始遊戲(您可以決定哪個鍵對應於重新開始)。
1. 創建 `resetGame()` 函數:
```javascript
function resetGame() {
if (gameLoopId) {
clearInterval(gameLoopId);
eventEmitter.clear();
initGame();
gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawPoints();
drawLife();
updateGameObjects();
drawGameObjects(ctx);
}, 100);
}
}
```
2. 在 `initGame()` 中添加一個調用 `eventEmitter` 重置遊戲的程式碼:
```javascript
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
```
3. 為 EventEmitter 添加一個 `clear()` 函數:
```javascript
clear() {
this.listeners = {};
}
```
👽 💥 🚀 恭喜您,艦長!您的遊戲已完成!幹得好!🚀 💥 👽
section 互動系統 (課程 3-4)
玩家控制: 輸入處理
: 移動機制
: 碰撞檢測
: 物理模擬
section 遊戲機制 (課程 5)
反饋系統: 計分機制
: 生命管理
: 視覺傳達
: 玩家動機
section 遊戲完成 (課程 6)
細節與流程: 結束條件
: 狀態管理
: 重新開始系統
: 使用者體驗
section 進階功能 (1 週)
強化技能: 音訊整合
: 視覺效果
: 關卡進度
: 性能優化
section 專業發展 (1 個月)
產業準備: 框架精通
: 團隊合作
: 作品集開發
: 社群參與
section 職涯提升 (3 個月)
專業化: 進階遊戲引擎
: 平台部署
: 營利策略
: 產業人脈
```
### 🛠️ 你的完整遊戲開發工具箱摘要
---
完成整個太空遊戲系列後,你已掌握:
- **遊戲架構**:事件驅動系統、遊戲循環及狀態管理
- **圖形程式設計**Canvas API、精靈繪製及視覺特效
- **輸入系統**:鍵盤處理、碰撞偵測及響應式控制
- **遊戲設計**:玩家反饋、進程系統及互動機制
- **效能優化**:高效渲染、記憶體管理及幀率控制
- **使用者體驗**:清楚溝通、直覺操作及細節修飾
- **專業範式**:乾淨程式碼、除錯技巧及專案組織
**實務應用領域**:你的遊戲開發技能可直接應用於:
- **互動式網頁應用**:動態介面與即時系統
- **資料視覺化**:動畫圖表與互動圖形
- **教育科技**:遊戲化與吸引人的學習體驗
- **行動裝置開發**:觸控互動與效能優化
- **模擬軟體**:物理引擎與即時建模
- **創意產業**:互動藝術、娛樂與數位體驗
**專業技能提升**:你現在能夠:
- **架構**複雜互動系統並從零開始打造
- **除錯**即時應用並運用系統化方法
- **優化**效能以實現流暢使用體驗
- **設計**引人入勝的使用者介面與互動模式
- **協作**於技術專案中有效組織程式碼
**遊戲開發核心概念精通**
- **即時系統**:遊戲循環、幀率管理及效能
- **事件驅動架構**:解耦系統與訊息傳遞
- **狀態管理**:複雜資料處理與生命週期管理
- **使用者介面程式設計**Canvas 繪圖與響應式設計
- **遊戲設計理論**:玩家心理與互動機制
**下一步**你已準備好探索進階遊戲框架、3D 圖形、多玩家系統,或轉向專業遊戲開發職涯!
🌟 **成就解鎖**:你完成了完整的遊戲開發旅程,並從零打造了一個專業品質的互動體驗!
**歡迎加入遊戲開發社群!** 🎮✨
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
**說明:** 透過實作關卡進度系統,並增加難度與額外功能,提升太空遊戲。
**提示:** 製作多關卡太空遊戲系統,每關擁有更多敵艦,速度與生命值提升。新增隨關卡增加的得分倍數,並實作道具(如連射或護盾),敵人被消滅時隨機出現。關卡完成時給予獎勵,並在畫面上顯示目前關卡,同時搭配既有得分和生命數。
進一步了解 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 選擇性強化挑戰
**為你的遊戲加入音效**:用音效增強遊戲體驗!考慮加入以下音效:
- 玩家發射時的 **雷射聲**
- 敌艦被摧毀時的 **爆炸聲**
- 玩家受傷時的 **受創聲**
- 遊戲勝利的 **勝利音樂**
- 遊戲失敗的 **失敗音效**
**音效實作範例:**
```javascript
// 建立音訊物件
const laserSound = new Audio('assets/laser.wav');
const explosionSound = new Audio('assets/explosion.wav');
// 在遊戲事件中播放聲音
function playLaserSound() {
laserSound.currentTime = 0; // 重設到開始位置
laserSound.play();
}
```
## 🚀 挑戰
**你需要知道:**
- **建立**不同音效的 Audio 物件
- **重設**currentTime 以實現連續快速播放音效
- **因應**瀏覽器自動播放政策,需從使用者互動觸發音效
- **管理**音量與時機,提升遊戲體驗
添加音效!您能否為遊戲添加音效來增強遊戲體驗,例如當激光命中、英雄死亡或勝利時播放音效?查看這個 [範例](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_audio_play) 來學習如何使用 JavaScript 播放音效。
> 💡 **學習資源**:探索此 [音效沙盒](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_audio_play),了解如何在 JavaScript 遊戲中實作音效。
## 課後測驗
## 課後測驗
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/40)
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/40)
## 回顧與自學
## 複習與自學
您的作業是創建一個全新的遊戲範例,因此請探索一些有趣的遊戲,看看您可能會構建哪種類型的遊戲。
你的作業是創建一個新的示範遊戲,請探索一些有趣的遊戲,看看你可能想做哪種類型的遊戲。
## 作業
[構建一個遊戲範例](assignment.md)
[製作示範遊戲](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對於因使用本翻譯而產生的任何誤解或錯誤解讀概不負責。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於翻譯的準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的原文版本應視為權威來源。針對重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所產生的任何誤解或誤釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,31 +1,173 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "24201cf428c7edba1ccec2a78a0dd8f8",
"translation_date": "2025-08-23T23:08:40+00:00",
"original_hash": "232d592791465c1678cab3a2bb6cd3e8",
"translation_date": "2026-01-06T13:44:48+00:00",
"source_file": "6-space-game/6-end-condition/assignment.md",
"language_code": "tw"
}
-->
# 建立一個範例遊戲
# 建立示範遊戲
## 指示
## 作業概述
嘗試建立一個小型遊戲,練習不同的結局條件。可以設計得分達到一定數量、英雄失去所有生命值或所有怪物被擊敗等情況。建立一個簡單的遊戲,例如基於控制台的冒險遊戲。以下的遊戲流程可以作為靈感:
現在你已經掌握了太空遊戲中的遊戲結束條件與重啟功能,是時候將這些概念應用到全新遊戲體驗中。你將設計並製作一款展示不同結束條件模式與重啟機制的遊戲。
本作業挑戰你在遊戲設計上的創意思考,同時練習你所學的技術技能。你將探索不同的勝利與失敗情境,實作玩家進度,並建立引人入勝的重啟體驗。
## 專案需求
### 核心遊戲功能
你的遊戲必須包含以下基本元素:
**結束條件多樣性**:實作至少兩種不同的遊戲結束方式:
- **積分勝利**:玩家達成目標分數或收集特定道具
- **生命值失敗**:玩家失去所有生命或血量
- **目標完成**:消滅所有敵人、收集特定物品或達成任務目標
- **時間限制**:遊戲在設定時間結束或倒數計時到零時終止
**重啟功能**
- **清除遊戲狀態**:移除所有先前的遊戲物件與重設變數
- **重置系統初始化**:以全新玩家狀態、敵人與目標重新開始
- **使用者友善的控制**:提供清楚的重啟遊戲說明
**玩家回饋**
- **勝利訊息**:慶祝玩家成就給予正向回饋
- **失敗訊息**:提供鼓勵語句激勵再玩
- **進度指標**:顯示當前分數、生命或目標狀態
### 遊戲點子與靈感
選擇以下遊戲概念之一或自行創作:
#### 1. 主控台冒險遊戲
製作帶有戰鬥機制的文字冒險:
```
Hero> Strikes with broadsword - orc takes 3p damage
Orc> Hits with club - hero takes 2p damage
Orc> Hits with club - hero takes 2p damage
Hero> Kicks - orc takes 1p damage
Game> Orc is defeated - Hero collects 2 coins
Game> ****No more monsters, you have conquered the evil fortress****
```
**需實作主要特色:**
- **回合制戰鬥**,包含不同攻擊選項
- 玩家與敵人皆有**血量**
- **物品欄系統**用於收集金幣或物品
- 多種敵人類型,難度不一
- **勝利條件**為消滅所有敵人
#### 2. 收集遊戲
- **目標**:收集指定物品並避開障礙物
- **結束條件**:達成收集目標數量或失去所有生命
- **進度**:隨著遊戲進行,物品越來越難取得
#### 3. 拼圖遊戲
- **目標**:解決逐漸增加難度的謎題
- **結束條件**:完成所有關卡或用盡移動次數/時間
- **重啟**:重置到第一關並清除進度
#### 4. 防禦遊戲
- **目標**:保護基地免受一波波敵人攻擊
- **結束條件**:存活所有波次(勝利)或基地被摧毀(失敗)
- **進度**:敵人波次難度與數量逐漸增加
## 實作指南
### 開始著手
1. **規劃遊戲設計**
- 草擬基本遊戲循環
- 清楚定義結束條件
- 確認重啟時需重置的資料
2. **建立專案架構**
```
my-game/
├── index.html
├── style.css
├── game.js
└── README.md
```
3. **寫出核心遊戲循環**
- 初始化遊戲狀態
- 處理使用者輸入
- 更新遊戲邏輯
- 檢查結束條件
- 繪製目前狀態
### 技術需求
**使用現代 JavaScript**
- 使用 `const``let` 宣告變數
- 適當時採用箭頭函式
- 實作 ES6+ 特性,如模板字串與解構賦值
**事件驅動架構**
- 建立事件處理器處理用戶互動
- 透過事件實作遊戲狀態變更
- 使用事件監聽器來實現重啟功能
**乾淨的程式碼實踐**
- 撰寫單一職責函式
- 採用描述性清楚的變數與函式名稱
- 撰寫註解解釋遊戲邏輯與規則
- 依邏輯區分程式碼區段
## 提交需求
### 交付物
1. **完整遊戲檔案**:所有可執行遊戲的 HTML、CSS 及 JavaScript 檔案
2. **README.md**:說明文件包含:
- 遊戲玩法說明
- 實作的結束條件
- 重啟指令說明
- 任何特殊功能或機制
3. **程式註解**:清楚說明遊戲邏輯與演算法
### 測試檢查清單
提交前請確認遊戲:
- [ ] **在瀏覽器控制台無錯誤執行**
- [ ] **實作多種指定的結束條件**
- [ ] **能正確重啟,狀態清空重設**
- [ ] **提供清楚的狀態回饋給玩家**
- [ ] **使用現代 JavaScript 語法與最佳實務**
- [ ] **README.md 有充分說明文件**
## 評分標準
| 評分標準 | 優秀表現 | 合格表現 | 需要改進 |
| -------- | --------------------- | --------------------------- | -------------------------- |
| | 完整的遊戲呈現 | 部分遊戲呈現 | 部分遊戲存在錯誤 |
| 標準 | 優異 (4) | 良好 (3) | 發展中 (2) | 初學 (1) |
|----------|---------------|----------------|----------------|--------------|
| **遊戲功能** | 遊戲完整有多重結束條件、重啟流暢與精緻遊玩體驗 | 完整遊戲含基本結束條件與重啟機制功能 | 部分結束條件實作完成,重啟可能有小問題 | 遊戲不完整,功能受限且含重大錯誤 |
| **程式碼品質** | 乾淨且良好組織,使用現代語法、詳細註解與結構優良 | 良好程式碼組織,現代語法適當,註解充足,結構清楚 | 基本組織,部分現代語法應用,註解有限 | 程式碼混亂,語法過時,缺乏註解與結構 |
| **使用者體驗** | 直覺玩法,清楚說明,優秀回饋與結束/重啟體驗 | 良好玩法,說明適當,回饋清楚,功能完整 | 基本玩法,說明有限,回饋較少 | 操作混亂,說明不足,使用者回饋差 |
| **技術實作** | 展現遊戲開發概念、事件處理及狀態管理精通 | 對遊戲概念有良好理解與實作 | 基本了解且可接受實作 | 理解有限,實作不佳 |
| **文件** | README 詳盡且清楚,程式碼註解豐富,測試全面 | 文件良好,說明清楚,註解足夠 | 文件簡單,說明與註解有限 | 文件缺乏或缺失 |
### 評分標準分數範圍
- **優異 (16-20 分)**:超越期待,有創意功能與精緻實作
- **良好 (12-15 分)**:符合所有需求,執行紮實
- **發展中 (8-11 分)**:大部分需求達成,有小幅缺失
- **初學 (4-7 分)**:部分需求符合,需大幅改進
## 其他學習資源
- [MDN 遊戲開發指南](https://developer.mozilla.org/en-US/docs/Games)
- [JavaScript 遊戲開發教學](https://developer.mozilla.org/en-US/docs/Games/Tutorials)
- [Canvas API 文件](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
- [遊戲設計原則](https://www.gamasutra.com/blogs/)
> 💡 **專家提示**:從簡單開始,逐步增加功能。經過精心打磨的簡單遊戲,比帶有錯誤的複雜遊戲更優秀!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤讀概不負責。
本文件經由 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻譯而成。儘管我們致力於提供準確的內容,但自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所造成的任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,31 +1,96 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "8a07db14e75ac62f013b7de5df05981d",
"translation_date": "2025-08-29T15:17:53+00:00",
"original_hash": "351678bece18f07d9daa987a881fb062",
"translation_date": "2026-01-06T14:00:46+00:00",
"source_file": "7-bank-project/1-template-route/README.md",
"language_code": "tw"
}
-->
# 建立銀行應用程式第一部分:網頁應用中的 HTML 模板與路由
# 建立銀行應用程式 第一部分HTML 模板與網頁應用程式中的路由
```mermaid
journey
title 您的銀行應用程式開發旅程
section SPA 基礎
了解單頁應用程式: 3: 學生
學習模板概念: 4: 學生
精通 DOM 操作: 4: 學生
section 路由系統
實作客戶端路由: 4: 學生
處理瀏覽器歷史紀錄: 5: 學生
建立導航系統: 5: 學生
section 專業模式
建立模組化架構: 5: 學生
應用最佳實務: 5: 學生
創建使用者體驗: 5: 學生
```
當阿波羅11號在1969年登月時其導航電腦必須在不同程式間切換卻不需重新啟動整個系統。現代網頁應用程式也類似 — 它們改變你所看到的內容,而非重新載入全部,這讓用戶體驗變得流暢且反應迅速。
不同於傳統網站每次互動都會重新載入整頁,現代網頁應用程式只更新需要改變的部分。這種作法就像任務控制中心在切換不同顯示畫面,同時保持持續通訊,帶來我們所期望的流暢體驗。
使差異如此顯著的原因如下:
| 傳統多頁應用程式 | 現代單頁應用程式 |
|-----------------|------------------|
| **導覽** | 每個畫面重新載入整頁 | 內容即時切換 |
| **效能** | 因為完整HTML下載較慢 | 部分更新較快 |
| **用戶體驗** | 頁面閃爍令人分心 | 流暢,像是原生應用程式的轉場 |
| **資料共享** | 頁面間共享困難 | 狀態管理容易 |
| **開發** | 需維護多個HTML文件 | 單一HTML搭配動態模板 |
**理解演變歷程:**
- **傳統應用程式** 每次導覽都需要向伺服器發送請求
- **現代SPA** 一次載入即可利用JavaScript動態更新內容
- **用戶期望** 現在偏好即時無縫的互動體驗
- **效能優勢** 包含降低頻寬使用與加快回應速度
在本課程中我們將建立一個銀行應用程式有多個畫面並且流暢銜接。就像科學家使用可模組化的儀器可依需求重新組合我們將用HTML模板作為可重複使用的元件必要時顯示。
你會操作HTML模板用於不同畫面重複使用的藍圖、JavaScript路由系統負責畫面切換、以及瀏覽器歷史API讓返回按鈕如預期運作。這些就是React、Vue、Angular等框架背後的基本技術。
最後,你將擁有一個功能完整且展現專業單頁應用原則的銀行應用程式。
```mermaid
mindmap
root((單頁應用程式))
Architecture
Template System
Client-side Routing
State Management
Event Handling
Templates
Reusable Components
Dynamic Content
DOM Manipulation
Content Switching
Routing
URL Management
History API
Navigation Logic
Browser Integration
User Experience
Fast Navigation
Smooth Transitions
Consistent State
Modern Interactions
Performance
Reduced Server Requests
Faster Page Transitions
Efficient Resource Usage
Better Responsiveness
```
## 課前測驗
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/41)
### 介紹
自從 JavaScript 在瀏覽器中出現以來,網站變得比以往更加互動且複雜。網頁技術現在常被用來創建完全功能的應用程式,直接在瀏覽器中運行,我們稱之為[網頁應用程式](https://en.wikipedia.org/wiki/Web_application)。由於網頁應用程式高度互動使用者不希望每次執行操作時都需要等待整個頁面重新載入。因此JavaScript 被用來直接使用 DOM 更新 HTML以提供更流暢的使用者體驗。
在本課程中,我們將建立銀行網頁應用程式的基礎,使用 HTML 模板創建多個畫面,這些畫面可以顯示並更新,而無需重新載入整個 HTML 頁面。
### 前置條件
### 所需準備
您需要一個本地網頁伺服器來測試我們在本課程中建立的網頁應用程式。如果您沒有,可以安裝 [Node.js](https://nodejs.org),並在您的專案資料夾中使用指令 `npx lite-server`。它將建立一個本地網頁伺服器並在瀏覽器中開啟您的應用程式。
我們需要一個本地網頁伺服器來測試銀行應用程式 — 不用擔心,這很簡單!如果你還沒設定好,安裝 [Node.js](https://nodejs.org) 之後,在專案目錄執行 `npx lite-server` 即可。此指令會啟動本地伺服器並自動打開瀏覽器顯示你的應用程式。
### 準備工作
在您的電腦上建立一個名為 `bank` 的資料夾,並在其中建立一個名為 `index.html` 的檔案。我們將從這個 HTML [樣板程式碼](https://en.wikipedia.org/wiki/Boilerplate_code)開始:
在電腦上建立一個資料夾名為 `bank`,裡面放一個 `index.html` 檔案。我們將從這個HTML [樣板](https://en.wikipedia.org/wiki/Boilerplate_code)開始:
```html
<!DOCTYPE html>
@ -41,30 +106,77 @@ CO_OP_TRANSLATOR_METADATA:
</html>
```
**此樣板提供了什麼:**
- **建立** 正確的HTML5文件結構及DOCTYPE宣告
- **設定** 字元編碼為UTF-8支援多國文字
- **啟用** 響應式設計的viewport標籤適用手機裝置
- **設置** 出現在瀏覽器分頁標題的描述性標題
- **創建** 一個乾淨的body區域讓我們構建應用程式
> 📁 **專案結構預覽**
>
> **本課結束時,你的專案將包含:**
> ```
> bank/
> ├── index.html <!-- Main HTML with templates -->
> ├── app.js <!-- Routing and navigation logic -->
> └── style.css <!-- (Optional for future lessons) -->
> ```
>
> **檔案職責分工:**
> - **index.html**:包含所有模板並提供應用架構
> - **app.js**:負責路由、導覽與模板管理
> - **模板**定義登入、儀表板及其他畫面UI
---
## HTML 模板
如果您想為網頁建立多個畫面,一種解決方案是為每個您想顯示的畫面建立一個 HTML 檔案。然而,這種解決方案有一些不便之處:
模板解決了網頁開發中的一個基本問題。當古騰堡在1440年代發明活字印刷時他發現不必雕刻整頁而是可製作可重複使用的字元塊並根據需要組合。HTML模板遵循同樣原理 — 不用為每個畫面建立單獨HTML檔而是定義可重用的結構並按需顯示。
```mermaid
flowchart TD
A["📋 範本定義"] --> B["💬 隱藏在 DOM 中"]
B --> C["🔍 JavaScript 尋找範本"]
C --> D["📋 複製範本內容"]
D --> E["🔗 附加到可見 DOM"]
E --> F["👁️ 使用者看到內容"]
G["登入範本"] --> A
H["儀表板範本"] --> A
I["未來範本"] --> A
style A fill:#e3f2fd
style D fill:#e8f5e8
style F fill:#fff3e0
style B fill:#f3e5f5
```
想像模板是應用程式不同部份的藍圖。就像建築師繪製一次藍圖並多次使用而不必重複畫相同房間一樣我們也只創建一次模板根據需要實例化。瀏覽器會將這些模板隱藏直到JavaScript啟用它們。
- 切換畫面時需要重新載入整個 HTML可能會很慢。
- 在不同畫面之間共享資料會變得困難。
如果你要建立多個網頁畫面一個解決方案是為每個畫面建立一個HTML文件但這有些不便
另一種方法是僅使用一個 HTML 檔案,並使用 `<template>` 元素定義多個 [HTML 模板](https://developer.mozilla.org/docs/Web/HTML/Element/template)。模板是一個可重複使用的 HTML 區塊,瀏覽器不會顯示它,必須使用 JavaScript 在運行時實例化。
- 在切換畫面時必須重新載入完整HTML速度會慢
- 不同畫面間共享資料較困難
### 任務
另一種作法是只用一個HTML檔`<template>` 元素定義多個 [HTML模板](https://developer.mozilla.org/docs/Web/HTML/Element/template)。模板是一段可重用而瀏覽器不會直接顯示的HTML區塊必須用JavaScript在執行時實例化。
我們將建立一個具有兩個畫面的銀行應用程式:登入頁面和儀表板。首先,在 HTML 主體中新增一個佔位元素,我們將用它來實例化應用程式的不同畫面:
### 讓我們開始打造
我們要做一個有兩個主要畫面的銀行應用登入頁與儀表板。先在HTML的body標籤內加一個佔位元素 — 所有不同畫面都將在這裡出現:
```html
<div id="app">Loading...</div>
```
我們給它一個 `id`,以便稍後使用 JavaScript 更容易定位它。
**此佔位元素說明:**
- **建立** 一個ID為 "app" 的容器,所有畫面將顯示在這裡
- **顯示** 加載中的訊息直到JavaScript初始化第一個畫面
- **提供** 一個動態內容的唯一載入點
- **方便** JavaScript用 `document.getElementById()` 操控
> 提示:由於此元素的內容將被替換,我們可以放置一個載入訊息或指示器,當應用程式載入時會顯示。
> 💡 **專家小技巧**:由於該元素內容會被替換,我們可以放置載入中消息或指示器,顯示應用程式正在載入中
接下來,在 HTML 中新增登入頁面的模板。目前我們只在其中放置一個標題和一個包含連結的區段,該連結將用於執行導航。
在HTML中加入登入頁的模板暫時只放標題和一個連結區讓我們用來導覽
```html
<template id="login">
@ -75,11 +187,17 @@ CO_OP_TRANSLATOR_METADATA:
</template>
```
然後,我們將新增另一個儀表板頁面的 HTML 模板。此頁面將包含不同的區段:
**分析這個登入模板:**
- **定義** 一個唯一ID為 "login" 的模板供JavaScript定位
- **包含** 顯示應用品牌的主標題
- **以** 語意 `<section>` 元素群組相關內容
- **提供** 一個連結幫助導向儀表板頁面
接著我們增加一個儀表板的HTML模板。這頁面包含不同區塊
- 一個包含標題和登出連結的標頭
- 銀行帳戶的當前餘額
- 一個以表格顯示的交易列表
- 一個標題列含頁面標題和登出連結
- 顯示銀行帳戶目前餘額
- 一份交易記錄,以表格形式呈現
```html
<template id="dashboard">
@ -106,31 +224,88 @@ CO_OP_TRANSLATOR_METADATA:
</template>
```
> 提示:在建立 HTML 模板時,如果您想查看它的外觀,可以將 `<template>``</template>` 行用 `<!-- -->` 註解掉。
✅ 您認為我們為什麼使用 `id` 屬性來標識模板?我們是否可以使用其他方法,例如類別?
## 使用 JavaScript 顯示模板
如果您在瀏覽器中嘗試目前的 HTML 檔案,您會看到它停留在顯示 `Loading...`。這是因為我們需要新增一些 JavaScript 程式碼來實例化並顯示 HTML 模板。
實例化模板通常分為三個步驟:
1. 在 DOM 中檢索模板元素,例如使用 [`document.getElementById`](https://developer.mozilla.org/docs/Web/API/Document/getElementById)。
2. 使用 [`cloneNode`](https://developer.mozilla.org/docs/Web/API/Node/cloneNode) 複製模板元素。
3. 將其附加到 DOM 中的可見元素,例如使用 [`appendChild`](https://developer.mozilla.org/docs/Web/API/Node/appendChild)。
**了解儀表板模板各部分:**
- **用** 語意 `<header>` 元素構造頁首並含導覽連結
- **統一顯示** 應用名稱品牌
- **包含** 一個登出連結,路由回登入頁
- **顯示** 專門區塊呈現當前帳戶餘額
- **以** 正確結構HTML表格組織交易資料
- **定義** 表格標題列分為日期、物件及金額欄
- **將** 表格主體留空,待動態注入內容
> 💡 **專家小技巧**:想預覽模板實際呈現,可將 `<template>``</template>` 標籤包在 `<!-- -->` 註解內,即會顯示裡面內容。
### 🔄 **教學檢視點**
**模板系統理解**在寫JavaScript前請確定你知道
- ✅ 模板與普通HTML元素的差異
- ✅ 模板為何會隱藏直到JavaScript啟用
- ✅ 模板中語意HTML結構的重要性
- ✅ 模板如何實現UI元件重複使用
**快速自我測驗**:如果把 `<template>` 標籤移除,會怎麼樣?
*答案:內容會馬上可見,失去模板功能*
**架構優勢**:模板提供:
- **重用性**:單一定義,多次實例
- **效能**避免重複HTML解析
- **維護性**UI結構集中管理
- **彈性**:動態切換內容
✅ 為什麼我們在模板上使用 `id` 屬性我們能改用類別class
## 用JavaScript讓模板活起來
現在我們要把模板變成可用的介面。就像3D印表機以數位藍圖實體化物件JavaScript會從我們隱藏的模板創建可見且互動的元素。
這流程遵循三個一致的步驟,是現代網頁開發的基石。理解後,你會在許多框架及函式庫中看到相同模式。
若你嘗試將現有HTML載入瀏覽器會看到只顯示 `Loading...`因為我們尚未寫JavaScript來實例化並顯示模板。
執行模板實例化通常分3步
1. 透過 [`document.getElementById`](https://developer.mozilla.org/docs/Web/API/Document/getElementById) 取得DOM中的模板元素。
2. 用 [`cloneNode`](https://developer.mozilla.org/docs/Web/API/Node/cloneNode) 複製模板元素。
3. 把複製品附加到DOM中可見的元素下例如用 [`appendChild`](https://developer.mozilla.org/docs/Web/API/Node/appendChild)。
```mermaid
flowchart TD
A[🔍 步驟 1尋找範本] --> B[📋 步驟 2複製範本]
B --> C[🔗 步驟 3附加到 DOM]
A1["document.getElementById('login')"] --> A
B1["template.content.cloneNode(true)"] --> B
C1["app.appendChild(view)"] --> C
C --> D[👁️ 範本呈現在使用者面前]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
```
**此流程視覺解析:**
- **步驟1** 定位DOM中隱藏的模板元素
- **步驟2** 製作可安全修改的可用複本
- **步驟3** 將複本插入可見的頁面區域
- **結果** 是一個用戶可互動的功能畫面
✅ 為什麼我們需要在附加到 DOM 之前複製模板?如果跳過這一步,您認為會發生什麼?
✅ 為何要先複製模板再附加進DOM如果沒這步驟會怎樣
### 任務
在您的專案資料夾中建立一個名為 `app.js` 的新檔案,並在 HTML 的 `<head>` 區段中匯入該檔案:
專案資料夾新增 `app.js` 文件並在HTML `<head>` 區塊引入
```html
<script src="app.js" defer></script>
```
現在在 `app.js` 中,我們將建立一個新函數 `updateRoute`
**理解這個腳本引入:**
- **連結** JavaScript檔案至HTML文件
- **使用** `defer` 屬性確保腳本在HTML解析完後執行
- **確保** DOM元素皆已載入才執行腳本
- **遵循** 現代最佳腳本載入與效能慣例
接著,在 `app.js` 中創建一個新函式 `updateRoute`
```js
function updateRoute(templateId) {
@ -142,19 +317,71 @@ function updateRoute(templateId) {
}
```
我們在這裡執行的正是上述的三個步驟。我們使用 `templateId` 實例化模板,並將其複製的內容放入應用程式的佔位元素中。請注意,我們需要使用 `cloneNode(true)` 來複製模板的整個子樹。
**步驟說明:**
- **用ID定位** 相應的模板元素
- **`cloneNode(true)`** 深度複製模板內容
- **找出** app容器元素顯示區域
- **清空** app容器現有內容
- **將複製內容** 插入至可見DOM中
現在使用其中一個模板呼叫此函數並查看結果。
現在呼叫此函式並輸入一個模板ID看結果。
```js
updateRoute('login');
```
✅ 這段程式碼 `app.innerHTML = '';` 的目的是什麼?如果沒有它會發生什麼?
## 建立路由
**此函式呼叫所達成:**
- **啟用** 登入模板傳入其ID作為參數
- **展示** 程式切換應用畫面的方式
- **將** 登入頁取代原先的「Loading...」訊息
✅ 這段程式碼 `app.innerHTML = '';` 作用為何?不寫會怎樣?
## 建立路由Routes
路由本質是將網址(URL)對應到正確內容。想像早期電話接線員以交換臺將通話連接至正確電話號碼 — 網路路由作用類似接收URL請求並決定顯示哪些內容。
```mermaid
flowchart LR
A["🌐 URL 路徑<br/>/dashboard"] --> B["🗺️ 路由物件<br/>查詢"]
B --> C["🎯 範本 ID<br/>'dashboard'"]
C --> D["📌 找到範本<br/>getElementById"]
D --> E["👁️ 顯示畫面<br/>複製並附加"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ 找不到"]
I --> J["🔄 重新導向到 /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
```
傳統網頁伺服器根據不同URL回傳不同HTML文件。因為我們做的是單頁應用程式必須用JavaScript自己處理路由這讓我們能更靈活控管用戶體驗與效能。
```mermaid
flowchart LR
A["🌐 URL 路徑<br/>/dashboard"] --> B["🗺️ 路由物件<br/>查找"]
B --> C["🎯 範本 ID<br/>'dashboard'"]
C --> D["📄 找範本<br/>getElementById"]
D --> E["👁️ 顯示畫面<br/>複製並附加"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ 找不到"]
I --> J["🔄 重新導向到 /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
```
**了解路由流程:**
- **URL變更** 觸發路由對照查詢
- **有效路由** 對應特定模板ID以渲染畫面
- **無效路由** 觸發預設行為以避免顯示錯誤狀態
- **模板渲染** 跟先前學的三步驟處理一致
在談論網頁應用程式時,我們稱 *路由* 為將 **URL** 映射到應顯示的特定畫面的意圖。在具有多個 HTML 檔案的網站中,這是自動完成的,因為檔案路徑會反映在 URL 上。例如,在您的專案資料夾中有以下檔案:
提到網頁應用,我們稱「路由」是映射 **URLs** 到應該顯示的特定畫面。在有多個HTML文件的網站中這會根據檔案路徑自動完成。例如專案中有以下檔案:
```
mywebsite/index.html
@ -162,7 +389,7 @@ mywebsite/login.html
mywebsite/admin/index.html
```
如果您以 `mywebsite` 作為根建立一個網頁伺服器URL 映射將是
若你用 `mywebsite` 當作根目錄設置網頁伺服器URL會對應為
```
https://site.com --> mywebsite/index.html
@ -170,11 +397,11 @@ https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/ --> mywebsite/admin/index.html
```
然而,對於我們的網頁應用程式,我們使用的是包含所有畫面的單一 HTML 檔案,因此這種預設行為對我們沒有幫助。我們必須手動建立此映射並使用 JavaScript 更新顯示的模板。
但我們的網頁應用只有一個HTML檔包含全部畫面因此這種預設行為不適用。我們必須自己建立對照表並用JavaScript更新顯示的模板。
### 任務
我們將使用一個簡單的物件來實現 [映射](https://en.wikipedia.org/wiki/Associative_array) URL 路徑與模板之間的關係。在 `app.js` 檔案的頂部新增此物件
我們將使用一個簡單物件實作 [映射](https://en.wikipedia.org/wiki/Associative_array) 將URL路徑對應至模板。把這個物件加在 `app.js` 頂端
```js
const routes = {
@ -183,7 +410,12 @@ const routes = {
};
```
現在稍微修改一下 `updateRoute` 函數。我們不再直接將 `templateId` 作為參數傳遞,而是希望先查看當前的 URL然後使用我們的映射來獲取對應的模板 ID 值。我們可以使用 [`window.location.pathname`](https://developer.mozilla.org/docs/Web/API/Location/pathname) 來僅獲取 URL 的路徑部分。
**理解此路由設定:**
- **定義** URL路徑與模板識別碼的對應映射
- **用** 物件語法關鍵字是URL路徑值包含模板資訊
- **方便** 查找對應URL該顯示哪個模板
- **建立** 擴展性良好的架構以便未來新增路由
現在讓我們稍微修改一下 `updateRoute` 函式。我們不直接將 `templateId` 作為參數傳入,而是先從當前 URL 中擷取,然後透過之前建立的對應表取得相應的模板 ID 值。我們可以使用 [`window.location.pathname`](https://developer.mozilla.org/docs/Web/API/Location/pathname) 來取得 URL 中的路徑部分。
```js
function updateRoute() {
@ -198,26 +430,100 @@ function updateRoute() {
}
```
在這裡,我們將宣告的路由映射到對應的模板。您可以嘗試手動更改瀏覽器中的 URL檢查它是否正確運作。
✅ 如果您在 URL 中輸入未知的路徑會發生什麼?我們如何解決這個問題?
## 新增導航功能
我們應用程式的下一步是新增在頁面之間導航的功能,而不需要手動更改 URL。這涉及到兩件事
1. 更新當前 URL
2. 根據新的 URL 更新顯示的模板
第二部分我們已經使用 `updateRoute` 函數處理了,因此我們需要弄清楚如何更新當前 URL。
我們需要使用 JavaScript特別是 [`history.pushState`](https://developer.mozilla.org/docs/Web/API/History/pushState),它允許更新 URL 並在瀏覽歷史中建立新條目,而不重新載入 HTML。
> 注意:雖然 HTML 錨點元素 [`<a href>`](https://developer.mozilla.org/docs/Web/HTML/Element/a) 本身可以用來建立指向不同 URL 的超連結,但它預設會使瀏覽器重新載入 HTML。在使用自訂 JavaScript 處理路由時,必須使用 `preventDefault()` 函數來防止此行為。
**拆解這裡發生的事情:**
- **擷取** 瀏覽器 URL 中的目前路徑,使用 `window.location.pathname`
- **查詢** routes 物件中相對應的路由設定
- **取出** 路由設定中的模板 ID
- **沿用** 之前的模板渲染流程
- **建立** 一個根據 URL 變更動態回應的系統
這裡我們將宣告的路由映射到對應的模板。你可以透過手動變更瀏覽器的 URL 來測試它是否正確運作。
✅ 如果你輸入一個未知的路徑會發生什麼?我們該怎麼解決?
## 新增導航
當路由機制建置完成後,用戶需要一種方法在應用程式中導航。傳統網站點擊連結會重新載入整個頁面,而我們想要在不重新整理頁面的情況下更新 URL 和內容。這會創造出更流暢的體驗,類似桌面應用程式在不同檢視間切換的感覺。
我們需要協調兩件事:更新瀏覽器的 URL讓使用者可以書籤及分享連結以及顯示相對應的內容。正確實作下這將建構出使用者對現代應用程式所期望的無縫導航體驗。
```mermaid
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: 點擊「登入」連結
Browser->>App: onclick 事件觸發
App->>App: preventDefault() 並導向('/dashboard')
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: URL 更新為 /dashboard
App->>App: 呼叫 updateRoute()
App->>Template: 找到並複製儀表板模板
Template->>App: 回傳複製內容
App->>Browser: 用模板替換應用內容
Browser->>User: 顯示儀表板畫面
Note over User,Template: 使用者點擊瀏覽器返回按鈕
User->>Browser: 點擊返回按鈕
Browser->>Browser: 歷史記錄回到 /login
Browser->>App: popstate 事件觸發
App->>App: 自動呼叫 updateRoute()
App->>Template: 找到並複製登入模板
Template->>App: 回傳複製內容
App->>Browser: 用模板替換應用內容
Browser->>User: 顯示登入畫面
```
### 🔄 **教學核對點**
**單頁應用程式架構**:檢視你對整體系統的理解:
- ✅ 客戶端路由與傳統伺服器端路由有何不同?
- ✅ 為什麼 History API 對 SPA 的導航至關重要?
- ✅ 模板如何在不重新整理的情況下實現動態內容?
- ✅ 事件處理在攔截導航上扮演什麼角色?
**系統整合**:你的 SPA 展現了:
- **模板管理**:可重複使用的 UI 元件與動態內容
- **客戶端路由**:不透過伺服器請求管理 URL
- **事件驅動架構**:響應式導航與使用者互動
- **瀏覽器整合**:正確支援歷史紀錄及前進後退鍵
- **效能優化**:快速轉場與降低伺服器負載
**專業模式**:你已實作:
- **模型-視圖分離**:模板與應用邏輯分開
- **狀態管理**URL 狀態與顯示內容同步
- **漸進式增強**JavaScript 強化基本 HTML 功能
- **使用者體驗**:流暢且類 App 的無刷新導航
> <20> **架構洞察**:導航系統元件
>
> **你正在建構:**
> - **🔄 URL 管理**:更新瀏覽器位址欄且不重新整理頁面
> - **📋 模板系統**:根據當前路由動態切換內容
> - **📚 歷史整合**:維持瀏覽器前進/後退按鈕功能
> - **🛡️ 錯誤處理**:對無效或缺失路由提供優雅備援
>
> **元件如何協作:**
> - **監聽** 導航事件(點擊、歷史變動)
> - **更新** 使用 History API 設定 URL
> - **渲染** 對應路由的模板
> - **保持** 用戶體驗的連續性
我們應用的下一步是加入在頁面間導航的功能,不需手動更改 URL。這包含兩件事
1. 更新當前 URL
2. 根據新 URL 更新顯示模板
第二部分我們已用 `updateRoute` 函式解決,現在要處理如何更新當前 URL。
我們得使用 JavaScript特別是 [`history.pushState`](https://developer.mozilla.org/docs/Web/API/History/pushState),它允許更新 URL 並在瀏覽歷史中新增紀錄,但不會重新載入 HTML。
> ⚠️ **重要提示**:雖然 HTML 錨點元素 [`<a href>`](https://developer.mozilla.org/docs/Web/HTML/Element/a) 可用於不同 URL 的超鏈結,但預設會導致瀏覽器重新載入。使用自訂 JavaScript 控制路由時,需要在點擊事件中透過 `preventDefault()` 防止此行為。
### 任務
讓我們建立一個新函數,可以用來在應用程式中導航:
讓我們建立一個可以用來在應用程式中導航的新函式
```js
function navigate(path) {
@ -226,9 +532,15 @@ function navigate(path) {
}
```
此方法首先根據給定的路徑更新當前 URL然後更新模板。屬性 `window.location.origin` 返回 URL 根,允許我們從給定的路徑重建完整的 URL。
**理解這個導航函式:**
- **使用** `history.pushState` 更新瀏覽器 URL 到新路徑
- **新增** 瀏覽器歷史紀錄堆疊的紀錄,以支援前進/後退按鈕
- **觸發** `updateRoute()` 函式,顯示相對應模板
- **維持** 單頁應用無重新整理的使用體驗
此方法先根據指定路徑更新目前 URL再更新模板。`window.location.origin` 屬性會回傳 URL 根部,可用來從路徑重建完整 URL。
現在我們有了這個函數,可以解決當路徑不符合任何定義的路由時的問題。我們將通過新增回退到現有路由之一來修改 `updateRoute` 函數。
現在我們擁有此函式後,針對找不到匹配路由的情況,我們會在 `updateRoute` 函式裡加入回退方案,轉向現有路由中的其中一頁
```js
function updateRoute() {
@ -239,12 +551,23 @@ function updateRoute() {
return navigate('/login');
}
...
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
```
如果找不到路由,我們現在會重定向到 `login` 頁面。
**記住這些重點:**
- **檢查** 當前路徑是否存在路由
- **無效路由時** 重新導向至登入頁
- **提供** 備援機制避免導致導航破裂
- **確保** 使用者即使輸入錯誤 URL 也看得到有效頁面
現在讓我們建立一個函數來獲取點擊連結時的 URL並防止瀏覽器的預設連結行為
若找不到路由,我們會重定向至 `login` 頁面。
接著建立一個函式,在點擊連結時取得該 URL 並阻止瀏覽器預設行為:
```js
function onLinkClick(event) {
@ -253,7 +576,11 @@ function onLinkClick(event) {
}
```
讓我們通過新增 HTML 中 *登入**登出* 連結的綁定來完成導航系統。
**拆解此點擊處理器:**
- **透過 `preventDefault()`** 防止瀏覽器預設的連結行為
- **擷取** 被點擊連結元素的目標 URL
- **呼叫** 我們的自訂導航函式取代重新載入頁面
- **保持** 順暢的單頁應用體驗
```html
<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
@ -261,56 +588,237 @@ function onLinkClick(event) {
<a href="/login" onclick="onLinkClick(event)">Logout</a>
```
上述的 `event` 物件捕捉 `click` 事件並將其傳遞給我們的 `onLinkClick` 函數。
使用 [`onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick) 屬性將 `click` 事件綁定到 JavaScript 程式碼,這裡是呼叫 `navigate()` 函數。
嘗試點擊這些連結,您現在應該能夠在應用程式的不同畫面之間導航。
`history.pushState` 方法是 HTML5 標準的一部分,並在[所有現代瀏覽器](https://caniuse.com/?search=pushState)中實現。如果您正在為舊版瀏覽器建立網頁應用程式,可以使用一個技巧來替代此 API使用 [hash (`#`)](https://en.wikipedia.org/wiki/URI_fragment) 作為路徑,您可以實現與常規錨點導航相容且不重新載入頁面的路由,因為它的目的是在頁面內建立內部連結。
## 處理瀏覽器的返回與前進按鈕
**此 onclick 綁定達成:**
- **將** 每個連結接入我們的自訂導航系統
- **將** 點擊事件傳給 `onLinkClick` 函式處理
- **實現** 無刷新頁面的流暢導航
- **維持** 使用者能書籤或分享的正確 URL 結構
[`onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick) 屬性綁定了 `click` 事件的 JavaScript 代碼,這裡是呼叫 `navigate()` 函式。
試試點擊這些連結,你應能在不同畫面間成功切換。
`history.pushState` 方法是 HTML5 標準的一部分,且[所有現代瀏覽器](https://caniuse.com/?search=pushState)均有實作。如需支援舊版瀏覽器,有個技巧可用:利用路徑前的 [hash (`#`)](https://en.wikipedia.org/wiki/URI_fragment) 實作路由,這樣可以使用傳統錨點導航且不會重新載入頁面,因為 hash 主要用於頁面內部連結。
## 支援前進與後退按鈕
前進與後退按鈕是網頁瀏覽的根本,就像太空任務中的 NASA 控制員可以檢視先前系統狀態一般。使用者期望這些按鈕能正常工作,若不行就會破壞瀏覽體驗。
我們的單頁應用需要額外設定才支援此功能。瀏覽器會維護歷史堆疊(我們透過 `history.pushState` 持續新增),但使用者在歷史中移動時,我們的應用必須回應並更新顯示內容。
```mermaid
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: 點擊「登入」連結
Browser->>App: onclick 事件觸發
App->>App: preventDefault() 並導航至 '/dashboard'
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: URL 更新至 /dashboard
App->>App: 呼叫 updateRoute()
App->>Template: 找到並複製 dashboard 模板
Template->>App: 回傳複製的內容
App->>Browser: 以模板取代應用內容
Browser->>User: 顯示 dashboard 畫面
Note over User,Template: 使用者點擊瀏覽器返回鍵
User->>Browser: 點擊返回鍵
Browser->>Browser: 歷史紀錄退回到 /login
Browser->>App: popstate 事件觸發
App->>App: 自動呼叫 updateRoute()
App->>Template: 找到並複製登入模板
Template->>App: 回傳複製的內容
App->>Browser: 以模板取代應用內容
Browser->>User: 顯示登入畫面
```
**重要互動點:**
- **使用者行動**:點擊或瀏覽器按鈕觸發導航
- **應用攔截**:連結點擊事件防止頁面刷新
- **歷史 API**:管理 URL 變化及歷史堆疊
- **模板**:為每個畫面提供內容架構
- **事件監聽**:確保任何導航類型均有反應
使用 `history.pushState` 會在瀏覽器的導航歷史中建立新條目。您可以通過按住瀏覽器的*返回按鈕*檢查,它應顯示類似以下內容:
使用 `history.pushState` 會在瀏覽器導覽歷史新增紀錄。你可以長按瀏覽器的 *後退鍵* 查看,應該會顯示類似以下內容:
![導航歷史的截圖](../../../../translated_images/history.7fdabbafa521e06455b738d3dafa3ff41d3071deae60ead8c7e0844b9ed987d8.tw.png)
![Screenshot of navigation history](../../../../translated_images/history.7fdabbafa521e064.tw.png)
如果您嘗試多次點擊返回按鈕,您會看到當前 URL 改變且歷史被更新,但顯示的模板保持不變。
若嘗試點擊後退鍵幾次,你會看到 URL 變更且歷史紀錄更新,但畫面模板不變。
這是因為應用程式不知道每次歷史改變時需要呼叫 `updateRoute()`。如果您查看 [`history.pushState` 的文件](https://developer.mozilla.org/docs/Web/API/History/pushState),您會看到如果狀態改變——意味著我們移動到不同的 URL——[`popstate`](https://developer.mozilla.org/docs/Web/API/Window/popstate_event) 事件會被觸發。我們將使用它來修正此問題。
這是因為應用無法偵測每次歷史堆疊變動時應呼叫 `updateRoute()`。查看 [`history.pushState` 文件](https://developer.mozilla.org/docs/Web/API/History/pushState) 可知,當狀態發生改變(即網址轉換)時,會觸發 [`popstate`](https://developer.mozilla.org/docs/Web/API/Window/popstate_event) 事件。我們會利用這點來修正問題。
### 任務
為了確保當瀏覽器歷史改變時顯示的模板被更新,我們將附加一個新函數來呼叫 `updateRoute()`。我們會在 `app.js` 檔案的底部完成此操作:
確保瀏覽器歷史發生變動時模板同步更新,我們將新增函式呼叫 `updateRoute()`,並放在 `app.js` 檔案底部
```js
window.onpopstate = () => updateRoute();
updateRoute();
```
> 注意:我們在這裡使用了一個[箭頭函數](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions)來宣告 `popstate` 事件處理器以簡化程式碼,但普通函數也可以正常運作。
**理解此歷史整合:**
- **監聽** 使用者用瀏覽器前後鈕時觸發的 `popstate` 事件
- **使用** 箭頭函式簡潔宣告事件處理器
- **自動** 呼叫 `updateRoute()` 更新模板內容
- **初始化** 頁面載入時先呼叫 `updateRoute()` 顯示初始畫面
- **確保** 無論如何導航均顯示正確模板
> 💡 **專家小技巧**:此處使用 [箭頭函式](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 宣告 `popstate` 事件處理器,簡潔明了;若改用傳統函式同樣有效。
這裡有一段箭頭函式教學影片複習:
[![Arrow Functions](https://img.youtube.com/vi/OP6eEbOj2sc/0.jpg)](https://youtube.com/watch?v=OP6eEbOj2sc "Arrow Functions")
> 🎥 點擊上方圖片觀看箭頭函式說明影片。
現在試著使用瀏覽器的前進與後退按鈕,確認這次顯示的路由是否隨之正確更新。
### ⚡ **你可以在接下來 5 分鐘完成的事項**
- [ ] 測試你的銀行應用在瀏覽器前後按鈕下的導航功能
- [ ] 嘗試在位址欄手動輸入不同 URL 測試路由機制
- [ ] 開啟瀏覽器開發工具,檢查模板如何被克隆並插入 DOM
- [ ] 動手加入 console.log 追蹤路由流程
### 🎯 **你可以在這一小時內達成的目標**
- [ ] 完成課後測驗,了解 SPA 架構概念
- [ ] 為銀行應用模板加入 CSS 美化
- [ ] 實作 404 錯誤頁面挑戰並完善錯誤處理
- [ ] 建立製作頁面挑戰並新增路由功能
- [ ] 在模板切換間新增載入狀態與過場動畫
### 📅 **你的週度 SPA 開發歷程**
- [ ] 完成完整銀行應用,涵蓋表單、資料管理與持久化
- [ ] 增加進階路由功能,如參數路由與巢狀路由
- [ ] 實作導航守衛與基於認證的路由控制
- [ ] 建立可重用模板元件與元件庫
- [ ] 新增動畫及過場提升使用者體驗流暢度
- [ ] 將 SPA 部署到主機平台並正確設定路由配置
### 🌟 **你一個月內的前端架構大師養成**
- [ ] 使用 React、Vue 或 Angular 建置複雜 SPA
- [ ] 學習進階狀態管理模式與函式庫
- [ ] 精通建置工具及 SPA 開發工作流程
- [ ] 實作漸進式網頁應用 (PWA) 與離線功能
- [ ] 研究大型 SPA 的效能優化技術
- [ ] 貢獻開源 SPA 專案並分享知識
## 🎯 你的單頁應用掌握時程
```mermaid
timeline
title SPA 開發與現代網頁架構學習進度
section 基礎 (20 分鐘)
模板系統: HTML 範本元素
: DOM 操作
: 內容複製
: 動態渲染
section 路由基礎 (30 分鐘)
用戶端導覽: URL 管理
: History API
: 路由映射
: 事件處理
section 用戶體驗 (40 分鐘)
導覽精進: 瀏覽器整合
: 返回按鈕支援
: 錯誤處理
: 流暢轉場
section 架構模式 (50 分鐘)
專業 SPA: 元件系統
: 狀態管理
: 效能優化
: 錯誤邊界
section 進階技術 (1 週)
框架整合: React Router
: Vue Router
: Angular Router
: 狀態庫
section 生產技能 (1 個月)
企業開發: 建置系統
: 測試策略
: 部署流程
: 效能監控
```
### 🛠️ 你的 SPA 開發工具總覽
完成本課後,你已精通:
- **模板架構**:可重複使用的 HTML 元件與動態內容渲染
- **客戶端路由**:無刷新頁面切換的 URL 管理與導航
- **瀏覽器整合**History API 使用及前進/後退支援
- **事件驅動系統**:導航處理與使用者互動管理
- **DOM 操作**:模板克隆、內容切換與元素管理
- **錯誤處理**:對無效路由及缺失內容的優雅處理
- **效能模式**:高效內容載入與渲染策略
**實務應用**:你的 SPA 技能可直接應用於:
- **現代網頁應用**React、Vue、Angular 等框架開發
- **漸進式網頁應用**:具備離線能力與類 App 體驗
- **企業儀表板**:多視圖複雜商業應用
- **電商平台**:產品目錄、購物車及結帳流程
- **內容管理**:動態內容建立與編輯介面
- **行動開發**:使用網路技術的混合應用程式
**所獲專業技能**:你現在能夠:
- **架構** 單頁應用程式並維持適當的關注點分離
- **實作** 隨應用複雜度可擴充的客戶端路由系統
- **除錯** 複雜的導覽流程,利用瀏覽器開發者工具
- **優化** 透過有效的模板管理提升應用程式效能
- **設計** 原生且具回應性的使用者體驗
**掌握的前端開發概念**
- **元件架構**:可重複使用的 UI 範式和模板系統
- **狀態同步**:網址狀態管理與瀏覽器歷史紀錄
- **事件驅動程式設計**:使用者互動處理與導覽
- **效能優化**:高效的 DOM 操控與內容載入
- **使用者體驗設計**:流暢過場與直覺性導覽
**下一步**:你已準備好探索現代前端框架、進階狀態管理,或打造複雜的企業級應用程式!
🌟 **成就解鎖**:你已建立具有現代網路架構模式的專業單頁應用基礎!
以下是箭頭函數的影片回顧:
---
[![箭頭函數](https://img.youtube.com/vi/OP6eEbOj2sc/0.jpg)](https://youtube.com/watch?v=OP6eEbOj2sc "箭頭函數")
## GitHub Copilot Agent 挑戰 🚀
> 🎥 點擊上方圖片觀看有關箭頭函數的影片。
使用 Agent 模式完成以下挑戰:
現在嘗試使用瀏覽器的返回與前進按鈕,檢查這次顯示的路由是否正確更新。
**說明:** 強化銀行應用程式,實作錯誤處理及針對無效路徑的 404 頁面模板,改善使用者瀏覽不存在頁面時的體驗
---
**提示:** 建立一個新的 HTML 模板id 為 "not-found",以顯示具友善提示的 404 錯誤頁面並包含樣式。接著修改 JavaScript 路由邏輯,在使用者瀏覽無效網址時顯示此模板,並新增一個「回首頁」按鈕,可導回登入頁面。
更多關於[agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)的資訊。
## 🚀 挑戰
新增一個模板和路由,用於顯示此應用程式的製作人員名單的第三個頁面。
為此應用程式新增第三頁的模板與路由,該頁展示製作人員名單。
**挑戰目標:**
- **建立** 一個新的 HTML 模板並具合適內容結構
- **加入** 新路由至路由配置物件
- **包含** 導覽連結以往返製作人員頁面
- **測試** 確認所有導覽功能正常並符合瀏覽器歷史紀錄運作
## 課後小測驗
## 課後測驗
[課後小測驗](https://ff-quizzes.netlify.app/web/quiz/42)
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/42)
## 複習與自學
## 回顧與自學
路由是 Web 開發中意外地棘手部分,尤其當 Web 從頁面重新整理行為轉向單頁應用程式的頁面刷新時。閱讀一點有關 [Azure 靜態網站服務](https://docs.microsoft.com/azure/static-web-apps/routes/?WT.mc_id=academic-77807-sagibbon) 如何處理路由。你能解釋該文件中描述的某些決策為什麼是必要的嗎?
路由是網頁開發中令人驚訝的棘手部分之一,特別是當網頁從頁面刷新行為轉向單頁應用程式的頁面刷新時。閱讀一些有關 [Azure 靜態網頁應用程式服務](https://docs.microsoft.com/azure/static-web-apps/routes/?WT.mc_id=academic-77807-sagibbon) 如何處理路由的資料。您能否解釋為什麼文件中描述的一些決策是必要的?
**額外學習資源:**
- **探索** React Router 和 Vue Router 等熱門框架如何實作客戶端路由
- **研究** 基於 hash 的路由與 history API 路由的差異
- **了解** 伺服器端渲染SSR及其對路由策略的影響
- **調查** 漸進式網路應用程式PWA如何處理路由與導覽
## 作業
@ -318,5 +826,7 @@ updateRoute();
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們雖致力於提供準確的翻譯,但請注意,機器翻譯可能存在錯誤或不準確之處。原始語言版本的文件應視為權威來源。對於重要資訊,建議委託專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或錯誤詮釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,26 +1,60 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "8223e429218befa731dd5bfd22299520",
"translation_date": "2025-08-24T00:09:49+00:00",
"original_hash": "df0dcecddcd28ea8cbf6ede0ad57d673",
"translation_date": "2026-01-06T14:03:09+00:00",
"source_file": "7-bank-project/1-template-route/assignment.md",
"language_code": "tw"
}
-->
# 改善路由
## 說明
## 指示
目前的路由宣告僅包含模板 ID但在顯示新頁面時有時需要更多功能。讓我們透過以下兩個額外功能來改進路由實現
現在你已經建立了基本的路由系統,是時候用專業功能來增強它,以改善使用者體驗並提供更好的開發工具。實際應用程式需要的不僅是模板切換-它們需要動態頁面標題、生命週期鉤子和可擴充的架構。
- 為每個模板指定標題,並在模板變更時更新窗口標題為新標題。
- 增加一個選項,在模板變更後執行一些程式碼。我們希望每次顯示儀表板頁面時,在開發者主控台中打印 `'Dashboard is shown'`
在此作業中,你將擴展你的路由實現,加入兩個在生產網頁應用中常見的基本功能。這些增強將讓你的銀行應用感覺更完善,並為未來功能打下基礎。
## 評分標準
路由宣告目前只包含要使用的模板 ID但在顯示新頁面時有時需要更多資訊。讓我們用兩個額外功能來改善我們的路由實作
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| | 兩個功能均已實現並正常運作。標題和程式碼新增功能也適用於在 `routes` 宣告中新增的路由。 | 兩個功能均正常運作,但行為是硬編碼的,無法透過 `routes` 宣告進行配置。新增第三個具有標題和程式碼新增功能的路由無法正常運作或僅部分運作。 | 缺少其中一個功能或功能未正常運作。 |
### 功能 1動態頁面標題
**目標:** 為每個模板指定標題,並在模板變更時動態更新視窗標題。
**重要性:**
- **提升**使用者體驗,顯示具描述性的瀏覽器分頁標題
- **增強**輔助技術如螢幕閱讀器的可用性
- **提供**更好的書籤和瀏覽器歷史記錄上下文
- **遵循**專業網頁開發最佳實務
**實作方向:**
- **擴充** routes 物件以包含每個路由的標題資訊
- **修改** `updateRoute()` 函式,使其動態更新 `document.title`
- **測試**在切換不同畫面時標題是否正確變更
### 功能 2路由生命週期鉤子
**目標:** 新增選項可在模板變更後執行某段程式碼。我們希望每次顯示「Dashboard」頁面時都在開發者主控台印出 `'Dashboard is shown'`
**重要性:**
- **允許**在特定路由載入時執行自定義邏輯
- **提供**分析、紀錄或初始化程式碼的鉤子
- **建立**更複雜路由行為的基礎
- **展現**網頁開發中的觀察者模式
**實作方向:**
- **加入**選用的回呼函式屬性至路由設定
- **在**模板渲染完成後執行該回呼函式(若有定義)
- **確保**此功能對所有帶回呼的路由有效
- **測試**訪問 Dashboard 時,主控台訊息是否顯示
## 評量標準
| 標準 | 優異 | 及格 | 需改進 |
| -------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| | 兩項功能皆已實作且可運作。對 `routes` 宣告新增的路由也適用標題及程式碼加入功能。 | 兩項功能可運作,但行為為硬編碼,且無法透過 `routes` 宣告設定。新增第三個有標題及程式碼的路由時,功能無法或部分運作。 | 有一項功能缺失或無法正常運作。 |
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們努力追求準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或誤譯承擔任何責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because it is too large Load Diff

@ -1,25 +1,166 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "474f3ab1ee755ca980fc9104a0316e17",
"translation_date": "2025-08-24T00:01:01+00:00",
"original_hash": "efb01fcafd2ef40c593a6e662fc938a8",
"translation_date": "2026-01-06T14:00:19+00:00",
"source_file": "7-bank-project/2-forms/assignment.md",
"language_code": "tw"
}
-->
# 為您的銀行應用程式設計樣式
# 使用現代 CSS 美化您的銀行應用程式
## 專案概述
將您的功能性銀行應用程式轉變為視覺吸引且專業的網頁應用程式,使用現代 CSS 技術。您將建立一個一致的設計系統,提升使用者體驗,同時維持無障礙與響應式設計原則。
此作業挑戰您應用當代網頁設計模式,實現一致的視覺識別,創造出吸引且直觀易用的使用者介面。
## 指示
建立一個新的 `styles.css` 檔案,並在您目前的 `index.html` 檔案中加入連結。在您剛建立的 CSS 檔案中,添加一些樣式,使 *登入**儀表板* 頁面看起來整潔美觀。嘗試創建一個色彩主題,為您的應用程式打造自己的品牌形象。
### 第 1 步:設定您的樣式表
**建立您的 CSS 基礎:**
1. **建立** 一個名為 `styles.css` 的新檔案於您的專案根目錄
2. **在** `index.html` 文件中連結此樣式表:
```html
<link rel="stylesheet" href="styles.css">
```
3. **從** CSS 重置和現代預設開始:
```css
/* Modern CSS reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
}
```
### 第 2 步:設計系統需求
**實作以下核心設計元素:**
#### 色彩調色盤
- **主色調**:選擇專業色彩用於按鈕與重點標示
- **次色調**:互補色用於點綴和次要操作
- **中性色**:灰色用於文字、邊框和背景
- **成功/錯誤色彩**:綠色表示成功狀態,紅色表示錯誤
#### 字體排版
- **標題層級**:清楚區分 H1、H2 和 H3 元素
- **正文文字**:可讀字體大小(最小 16px與適當行高
- **表單標籤**:清晰且易讀的文字樣式
#### 版面配置與間距
- **一致的間距**使用間距刻度8px、16px、24px、32px
- **格線系統**:表單與內容區域的有序布局
- **響應式設計**:採用行動優先策略與斷點
### 第 3 步:組件樣式
**設計以下特定組件樣式:**
#### 表單
- **輸入欄位**:專業邊框、聚焦狀態與驗證樣式
- **按鈕**:滑鼠懸停效果、禁用狀態與載入指示
- **標籤**:清晰定位及必填欄位標示
- **錯誤訊息**:可見的錯誤樣式與友善提示
#### 導航
- **頁首**:簡潔且具有品牌風格的導航區域
- **連結**:清楚的懸停狀態與作用中指示
- **商標/標題**:獨特的品牌元素
#### 內容區域
- **區塊分隔**:不同區域間明確的視覺分隔
- **卡片**:若使用卡片式佈局,包含陰影與邊框
- **背景**:適度留白和細膩背景運用
### 第 4 步:進階功能(選擇性)
> 提示:如果需要,您可以修改 HTML並添加新的元素和類別。
**可考慮實作以下進階功能:**
- **深色模式**:亮色與暗色主題切換
- **動畫效果**:細微的過渡與微互動
- **載入狀態**:表單提交時的視覺回饋
- **響應式圖片**:針對不同螢幕尺寸優化的圖片
## 設計靈感
**現代銀行應用程式特徵:**
- **乾淨、簡約設計**,大量留白
- **專業色彩方案**(藍色、綠色或高雅中性色)
- **清楚視覺層級**,具有醒目的動作呼籲按鈕
- **無障礙對比度** 符合 WCAG 指南
- **行動響應式佈局** 適用於所有裝置
## 技術需求
### CSS 組織
```css
/* 1. CSS Custom Properties (Variables) */
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
/* Add more variables */
}
/* 2. Base Styles */
/* Reset, typography, general elements */
/* 3. Layout */
/* Grid, flexbox, positioning */
/* 4. Components */
/* Forms, buttons, cards */
/* 5. Utilities */
/* Helper classes, responsive utilities */
/* 6. Media Queries */
/* Responsive breakpoints */
```
### 無障礙需求
- **色彩對比**:確保一般文字至少有 4.5:1 的對比度
- **聚焦指示**:鍵盤導覽時可見的聚焦狀態
- **表單標籤**:正確關聯輸入欄位
- **響應式設計**:可用於寬度介於 320px 到 1920px 的螢幕
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| | 所有頁面看起來乾淨且易於閱讀,具有一致的色彩主題,不同的區塊能夠清楚地突出。 | 頁面有樣式,但缺乏主題或區塊未清楚劃分。 | 頁面缺乏樣式,區塊看起來雜亂無章,資訊難以閱讀。 |
| 標準 | 優異 (A) | 良好 (B) | 需改進 (C) | 不及格 (F) |
|----------|---------------|----------------|----------------|----------------------|
| **設計系統** | 實作完整設計系統,整體色彩、字體與間距一致 | 使用一致樣式,清楚設計模式與良好視覺層級 | 基本樣式,有部分一致性問題或缺少設計元素 | 樣式簡陋且不一致或衝突 |
| **使用者體驗** | 建立直觀專業介面,具優秀可用性與視覺吸引力 | 提供良好使用體驗,清楚導覽與易讀內容 | 基本可用性,需改進 UX | 可用性差,難以導航或閱讀 |
| **技術實作** | 採用現代 CSS 技術,組織良好,符合最佳實踐 | 有效運用 CSS組織良好、技術合適 | CSS 正確工作,可能缺乏組織或現代技術 | CSS 實作差,有技術問題或瀏覽器相容問題 |
| **響應式設計** | 完整響應式設計,完美適用各種裝置大小 | 良好響應式行為,少數螢幕尺寸有問題 | 基本響應式,部分佈局有問題 | 不響應式,行動裝置有顯著問題 |
| **無障礙** | 符合 WCAG鍵盤導航與螢幕閱讀器支持優秀 | 良好無障礙實務,恰當對比與聚焦指示 | 基本無障礙,少部分元素缺失 | 無障礙差,行動不便者難以使用 |
## 提交指南
**請一併提交:**
- **styles.css**:完整樣式表
- **更新的 HTML**:您修改的任何 HTML
- **截圖**:桌面與行動裝置上的設計畫面
- **README**:簡述您的設計選擇與色彩調色盤
**加分項目:**
- **CSS 自訂屬性**,維護便利的主題化
- **先進 CSS 功能**,如 Grid、Flexbox 或 CSS 動畫
- **效能優化**,如精簡 CSS 與檔案大小
- **跨瀏覽器測試**,確保各瀏覽器兼容性
> 💡 **專家秘訣**:先從行動裝置設計開始,再針對較大螢幕強化。此行動優先策略確保您的應用在所有裝置上良好運作,並符合現代網頁開發最佳實踐。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤讀概不負責。
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於確保準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為具權威性的來源。對於重要資訊,建議聘請專業人工翻譯。我們對因使用本翻譯而產生的任何誤解或誤譯不承擔任何責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because it is too large Load Diff

@ -1,27 +1,144 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a4abf305ede1cfaadd56a8fab4b4c288",
"translation_date": "2025-08-24T00:05:59+00:00",
"original_hash": "d0a02cb117e91a5b5f24178080068a3d",
"translation_date": "2026-01-06T14:06:29+00:00",
"source_file": "7-bank-project/3-data/assignment.md",
"language_code": "tw"
}
-->
# 重構並添加註解到你的程式碼
# 程式碼重構與文件撰寫作業
## 指導方針
## 學習目標
隨著程式碼庫的擴展,定期重構程式碼以保持其可讀性和可維護性是非常重要的。請添加註解並重構你的 `app.js` 以提升程式碼品質:
完成此作業後,您將練習專業開發人員每日使用的重要軟體開發技能。您將學會組織程式碼以利於維護,透過抽象化減少重複,並為未來的開發者(包括您自己)撰寫文件。
- 提取常數,例如伺服器 API 的基礎 URL
- 將相似的程式碼進行統一:例如,你可以建立一個 `sendRequest()` 函數,將 `createAccount()``getAccount()` 中使用的程式碼整合起來
- 重新組織程式碼,使其更易於閱讀,並添加註解
乾淨且良好記錄的程式碼對於多位開發者協作且程式碼庫隨時間演進的真實網頁開發專案至關重要。
## 評分標準
## 作業概述
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| | 程式碼有註解,分成不同的區塊且易於閱讀。常數已提取,並建立了統一的 `sendRequest()` 函數。 | 程式碼乾淨,但仍可透過添加更多註解、提取常數或統一程式碼進一步改善。 | 程式碼混亂,沒有註解,常數未提取,程式碼未統一。 |
您的銀行應用程式的 `app.js` 檔案因登入、註冊與主控台功能而變得相當龐大。現在是時候依據專業開發實務重構這段程式碼,以提升可讀性、維護性並減少重複。
## 指示
請使用下列三項核心重構技巧,對您目前的 `app.js` 進行改寫:
### 1. 擷取設定常數
**任務**:在檔案頂端建立一個設定區段,定義可重複使用的常數。
**實作指導:**
- 擷取多處硬編碼的伺服器 API 基底 URL
- 為多個函式中出現的錯誤訊息建立常數
- 考慮抽取多次使用的路由路徑及元素 ID
**範例結構:**
```javascript
// 配置常數
const API_BASE_URL = 'http://localhost:5000/api';
const ROUTES = {
LOGIN: '/login',
DASHBOARD: '/dashboard'
};
```
### 2. 建立統一的請求函式
**任務**:建立一個可重複使用的 `sendRequest()` 函式,消除 `createAccount()``getAccount()` 間的重複程式碼。
**需求:**
- 處理 GET 與 POST 請求
- 包含適當的錯誤處理
- 支援不同的 URL 端點
- 接受可選的請求主體資料
**函式簽名指導:**
```javascript
async function sendRequest(endpoint, method = 'GET', data = null) {
// 請在此處實作您的程式碼
}
```
### 3. 新增專業程式碼文件
**任務**:以清楚且有助於理解的註解,說明邏輯背後的「為什麼」。
**文件標準:**
- 為函式添加說明其目的、參數與回傳值的文件註解
- 對較複雜的邏輯或商業規則加入內嵌說明
- 將相關函式以區段標題進行群組
- 解釋任何不明顯的程式碼模式或瀏覽器特定解法
**範例文件風格:**
```javascript
/**
* Authenticates user and redirects to dashboard
* @param {Event} event - Form submission event
* @returns {Promise<void>} - Resolves when login process completes
*/
async function login(event) {
// 防止預設表單提交,以便使用 JavaScript 處理
event.preventDefault();
// 您的實作...
}
```
## 成功標準
您的重構程式碼應展現以下專業開發實務:
### 優秀實作
- ✅ **常數**:所有魔術字串與 URL 已抽取成明確命名的常數
- ✅ **DRY 原則**:共通請求邏輯已整合為可重複使用的 `sendRequest()` 函式
- ✅ **文件**:函式具備清楚的 JSDoc 註解,說明目的與參數
- ✅ **組織**:程式碼以區段標題並配合一致格式邏輯分組
- ✅ **錯誤處理**:使用新請求函式提升錯誤處理
### 適當實作
- ✅ **常數**:大部分重複值已被抽取,少許硬編碼仍存在
- ✅ **重構**:已建立基本 `sendRequest()` 函式,但可能未涵蓋所有邊界情況
- ✅ **註解**:主要函式已有文件說明,但部分解釋尚嫌不完整
- ✅ **可讀性**:程式碼整體良好,部分區域仍有改進空間
### 待改進
- ❌ **常數**:許多魔術字串與 URL 仍硬編碼於檔案內
- ❌ **重複**:相似函式間尚有大量重複程式碼
- ❌ **文件**:缺乏或不足夠的註解,無法清楚說明程式碼目的
- ❌ **組織**:程式碼缺少清晰結構和邏輯分組
## 測試您的重構程式碼
重構後,確保您的銀行應用程式依然正常運作:
1. **測試所有使用者流程**:註冊、登入、主控台顯示及錯誤處理
2. **驗證 API 呼叫**:確認 `sendRequest()` 函式能執行帳戶建立與讀取
3. **檢查錯誤情境**:測試無效驗證資料及網路錯誤
4. **檢視主控台輸出**:確認重構期間未產生新錯誤
## 投稿規範
請提交已重構的 `app.js` 檔案,包含:
- 清晰的區段標題組織各功能
- 一致的程式碼格式與縮排
- 完整的 JSDoc 文件於所有函式
- 檔案頂部附簡短註解說明您的重構策略
**加分挑戰**:建立一份簡易程式碼文件 `CODE_STRUCTURE.md`,說明您的應用架構及各函式如何協同運作。
## 真實世界關聯
此作業模擬專業開發人員經常進行的程式碼維護工作。在業界:
- **程式碼審查** 會評估可讀性與維護性,類似此作業
- **技術債務** 若未定期重構與文件記錄就會累積
- **團隊協作** 依賴清晰且良好記錄的程式碼,方便新成員理解
- **錯誤修復** 在有妥善抽象與組織的程式碼庫中更為容易
您此處練習的技能──擷取常數、消除重複與撰寫清楚文件──是專業軟體開發的基本功。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。
本文件由 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們力求準確,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件之母語版本應視為權威來源。對於重要資訊,建議聘請專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或曲解負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,73 +1,242 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "b46acf79da8550d76445eed00b06c878",
"translation_date": "2025-10-03T12:51:24+00:00",
"original_hash": "b807b09df716dc48a2b750835bf8e933",
"translation_date": "2026-01-06T14:06:54+00:00",
"source_file": "7-bank-project/4-state-management/README.md",
"language_code": "tw"
}
-->
# 建立銀行應用程式第4部分:狀態管理概念
# 建立銀行應用程式第部分:狀態管理概念
## 課前測驗
## ⚡ 接下來五分鐘你可以做什麼
[課前測驗](https://ff-quizzes.netlify.app/web/quiz/47)
**忙碌開發者的快速入門路徑**
### 簡介
```mermaid
flowchart LR
A[⚡ 5 分鐘] --> B[診斷狀態問題]
B --> C[建立中央狀態對象]
C --> D[新增 updateState 函式]
D --> E[立即看到改進]
```
- **第1分鐘**:測試目前的狀態問題 - 登入,刷新頁面,觀察是否登出
- **第2分鐘**:將 `let account = null` 替換為 `let state = { account: null }`
- **第3分鐘**:建立一個簡單的 `updateState()` 函式以進行控制更新
- **第4分鐘**:更新一個函式以使用新的模式
- **第5分鐘**:測試改良後的可預測性和除錯能力
**快速診斷測試**
```javascript
// 之前:分散狀態
let account = null; // 重新整理時會遺失!
// 之後:集中式狀態
let state = Object.freeze({ account: null }); // 可控且可追蹤!
```
**為什麼重要**在5分鐘內你將體驗從混亂的狀態管理到可預測、易除錯模式的轉變。這是讓複雜應用可維護的基礎。
## 🗺️ 你在狀態管理精通的學習之旅
```mermaid
journey
title 從分散狀態到專業架構
section 診斷問題
識別狀態遺失問題: 3: You
理解分散更新: 4: You
認識架構需求: 6: You
section 集中控制
建立統一狀態物件: 5: You
實作受控更新: 7: You
新增不可變模式: 8: You
section 增加持久性
實作 localStorage: 6: You
處理序列化: 7: You
建立會話連續性: 9: You
section 平衡新鮮度
處理資料陳舊問題: 5: You
建構刷新系統: 8: You
達成最佳平衡: 9: You
```
**你的旅程終點**:本課結束時,你將建立一個專業級的狀態管理系統,處理持久化、資料鮮度與可預測更新——這些是生產環境應用使用的相同模式。
## 講前測驗
[講前測驗](https://ff-quizzes.netlify.app/web/quiz/47)
## 介紹
狀態管理就像航行者太空船上的導航系統——當一切運作順利時,你幾乎感受不到它存在。但當事情出錯時,它就是區分能否抵達星際空間或迷失在宇宙虛空中的關鍵。在網頁開發中,狀態代表應用程式需要記得的所有資訊:使用者登入狀態、表單資料、導航歷史及臨時介面狀態。
隨著你的銀行應用從簡單的登入表單演變為更複雜的應用,你很可能遇到一些常見問題。刷新頁面時,使用者意外被登出。關閉瀏覽器後,所有進度消失。除錯問題時,你需要在多個以不同方式修改相同資料的函式中穿梭。
這些不是糟糕程式碼的表徵——而是當應用達到某個複雜度門檻時,自然產生的成長痛。每個開發者在應用從「概念驗證」過渡至「生產準備」階段都會面對這些挑戰。
在本課,我們將實作一個集中式狀態管理系統,將你的銀行應用轉變為可靠且專業的應用。你將學會可預測地管理資料流、適當持續使用者會話,並打造現代網頁應用所需的流暢使用者體驗。
## 預備知識
隨著網頁應用程式的規模增大,追蹤所有資料流變得越來越困難。哪些程式碼獲取資料、哪些頁面使用資料、資料需要在何時何地更新……很容易導致程式碼混亂且難以維護。尤其是當需要在應用程式的不同頁面之間共享資料時,例如使用者資料。*狀態管理*的概念一直存在於各類程式中,但隨著網頁應用程式的複雜性不斷增加,狀態管理現在已成為開發過程中的關鍵點。
在深入狀態管理概念之前,你需要將開發環境妥善設置,且銀行應用基礎已經完成。本課直接基於本系列前幾部分的概念與程式碼
在這最後一部分,我們將重新審視我們建立的應用程式,重新思考如何管理狀態,支持瀏覽器在任何時候刷新,並在使用者會話之間持續保存資料。
請確認你已準備好以下元件後再繼續:
### 前置條件
**所需設置:**
- 完成 [資料取得課程](../3-data/README.md) — 應用應能成功載入並顯示帳戶資料
- 在系統安裝 [Node.js](https://nodejs.org) 以執行後端 API
- 啟動本機的 [伺服器 API](../api/README.md) 以處理帳戶資料操作
您需要完成本課程的[資料擷取](../3-data/README.md)部分。此外,您需要安裝 [Node.js](https://nodejs.org) 並[在本地運行伺服器 API](../api/README.md),以便管理帳戶資料。
**測試你的環境:**
您可以通過在終端執行以下命令來測試伺服器是否正常運行:
在終端機執行此指令確認 API 伺服器運作正常
```sh
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
# -> 應該回傳 "Bank API v1.0.0" 作為結果
```
**此指令的作用:**
- **發送** GET 請求至本機 API 伺服器
- **測試** 連線並確認伺服器回應
- **回傳** API 版本資訊,若一切正常
## 🧠 狀態管理架構概述
```mermaid
mindmap
root((狀態管理))
Current Problems
Session Loss
Page Refresh Issues
Browser Close Impact
Variable Reset Problems
Scattered Updates
Multiple Modification Points
Debugging Challenges
Unpredictable Behavior
Incomplete Cleanup
Logout State Issues
Memory Leaks
Security Concerns
Centralized Solutions
Unified State Object
Single Source of Truth
Predictable Structure
Scalable Foundation
Controlled Updates
Immutable Patterns
Object.freeze Usage
Function-Based Changes
State Tracking
History Management
Debug Visibility
Change Auditing
Persistence Strategies
localStorage Integration
Session Continuity
JSON Serialization
Automatic Sync
Data Freshness
Server Refresh
Stale Data Handling
Balance Optimization
Storage Optimization
Minimal Data
Performance Focus
Security Considerations
```
**核心原則**:專業狀態管理平衡可預測性、持久性與效能,打造可靠的使用者體驗,從簡單互動到複雜應用流程都能擴展。
---
## 重新思考狀態管理
## 診斷當前的狀態問題
在[上一課程](../3-data/README.md)中,我們在應用程式中引入了基本的狀態概念,使用全域變數 `account` 來保存當前登入使用者的銀行資料。然而,我們目前的實現存在一些缺陷。嘗試在儀表板頁面刷新瀏覽器。會發生什麼?
就像福爾摩斯檢視犯罪現場一樣,我們需要了解目前實作到底發生了什麼,才能解開消失使用者會話之謎。
目前程式碼有三個問題:
讓我們做個簡單實驗,揭露潛藏的狀態管理挑戰
- 狀態未持久化,瀏覽器刷新後會返回登入頁面。
- 有多個函數修改狀態。隨著應用程式的增長,這可能使追蹤變更變得困難,並且容易忘記更新某些部分。
- 狀態未清理,因此當您點擊*登出*時,帳戶資料仍然存在,即使您已經回到登入頁面。
**🧪 嘗試此診斷測試:**
1. 登入你的銀行應用並進入儀表板
2. 刷新瀏覽器頁面
3. 觀察你的登入狀態會有什麼變化
我們可以逐一更新程式碼來解決這些問題,但這會導致程式碼重複並使應用程式更加複雜且難以維護。或者,我們可以花幾分鐘重新思考策略。
如果你被重新導向回登入頁,就是發現了經典的狀態持久化問題。此行為發生是因為我們目前的實作將使用者資料儲存在會隨頁面載入重置的 JavaScript 變數內
> 我們真正試圖解決的問題是什麼?
**目前實作的問題:**
[狀態管理](https://en.wikipedia.org/wiki/State_management)的核心在於找到一個良好的方法來解決以下兩個特定問題:
來自我們[前課程](../3-data/README.md)的簡單 `account` 變數導致三個重大問題,影響使用者體驗與程式碼維護
- 如何使應用程式中的資料流易於理解?
- 如何確保狀態資料始終與使用者介面保持同步(反之亦然)?
| 問題 | 技術原因 | 使用者影響 |
|---------|--------|----------------|
| **會話流失** | 頁面刷新會清除 JavaScript 變數 | 使用者需經常重新認證 |
| **更新分散** | 多個函式直接修改狀態 | 除錯難度提高 |
| **清理不完全** | 登出未清除所有狀態引用 | 可能有安全與隱私風險 |
一旦解決了這些問題,您可能已經解決了其他問題,或者使它們更容易解決。有許多方法可以解決這些問題,但我們將採用一種常見的解決方案,即**集中化資料及其變更方式**。資料流將如下所示:
**架構挑戰:**
![顯示 HTML、使用者操作和狀態之間資料流的架構圖](../../../../translated_images/data-flow.fa2354e0908fecc89b488010dedf4871418a992edffa17e73441d257add18da4.tw.png)
就像鐵達尼號艙室的分隔設計,乍看堅固,但多個艙室同時淹水時仍難以挽救,單獨修復這些問題無法解決底層架構缺陷。我們需要一個全面的狀態管理方案。
> 我們在此不會涵蓋資料自動觸發視圖更新的部分,因為這涉及到更高級的[反應式程式設計](https://en.wikipedia.org/wiki/Reactive_programming)概念。如果您有興趣深入研究,這是一個很好的後續主題。
> 💡 **我們真正想達成什麼?**
✅ 市面上有許多不同方法的狀態管理庫,[Redux](https://redux.js.org) 是一個受歡迎的選擇。了解其概念和模式通常是學習大型網頁應用程式可能面臨的潛在問題以及如何解決這些問題的好方法。
[狀態管理](https://en.wikipedia.org/wiki/State_management) 其實是解決兩個根本謎題:
### 任務
1. **我的資料在哪裡?**:追蹤擁有哪些資訊以及來源
2. **所有人都有相同認知嗎?**:確保使用者看到的介面與實際狀態一致
**我們的策略:**
不用再東奔西跑,我們要建立一個**集中式狀態管理**系統。想像它是一位非常有組織的人,負責所有重要事項:
![Schema showing the data flows between the HTML, user actions and state](../../../../translated_images/data-flow.fa2354e0908fecc8.tw.png)
```mermaid
flowchart TD
A[使用者操作] --> B[事件處理器]
B --> C[更新狀態函式]
C --> D{狀態驗證}
D -->|有效| E[建立新狀態]
D -->|無效| F[錯誤處理]
E --> G[Object.freeze]
G --> H[更新 localStorage]
H --> I[觸發介面更新]
I --> J[使用者看到變更]
F --> K[使用者看到錯誤]
subgraph "狀態管理層"
C
E
G
end
subgraph "持久層"
H
L[localStorage]
H -.-> L
end
```
**理解此資料流:**
- **將**所有應用狀態集中於一處
- **導引**所有狀態變更通過控制函式
- **確保**使用者介面與當前狀態同步
- **提供**清晰、可預測的資料管理模式
> 💡 **專業提示**:本課專注基礎概念。對複雜應用,像是[Redux](https://redux.js.org)等庫提供更進階的狀態管理功能。理解這些核心原則將協助你掌握任何狀態管理函式庫。
> ⚠️ **進階主題**:我們不涵蓋由狀態變更自動觸發的 UI 更新,此涉[反應式程式設計](https://en.wikipedia.org/wiki/Reactive_programming)概念。這是你學習旅程中的優秀後續課題!
### 任務:集中狀態結構
讓我們開始將分散的狀態管理轉變成集中式系統。這第一步建立所有改進的基礎。
我們將從一些重構開始。替換 `account` 宣告:
**步驟1建立中央狀態物件**
替換簡單的 `account` 宣告:
```js
let account = null;
```
改為:
改為結構化的狀態物件
```js
let state = {
@ -75,31 +244,112 @@ let state = {
};
```
這個想法是將我們的應用程式資料*集中化*到一個單一的狀態物件中。目前狀態中只有 `account`,因此變化不大,但這為未來的擴展奠定了基礎。
**此變更重要原因:**
- **集中**所有應用資料在一處
- **為未來新增更多狀態屬性做好準備**
- **建立**狀態與其他變數的明確邊界
- **創造**隨應用成長可擴充的模式
**步驟2更新狀態存取模式**
更新函式以使用新狀態結構:
我們還需要更新使用它的函數。在 `register()``login()` 函數中,將 `account = ...` 替換為 `state.account = ...`;
**在 `register()``login()` 函式中**,替換:
```js
account = ...
```
`updateDashboard()` 函數的頂部,添加以下行:
為:
```js
state.account = ...
```
**在 `updateDashboard()` 函式中**,於頂部新增此行:
```js
const account = state.account;
```
這次重構本身並未帶來太多改進,但其目的是為接下來的變更奠定基礎。
**這些改動達成:**
- **保持**現有功能並改善結構
- **為更複雜的狀態管理準備代碼**
- **建立**存取狀態資料的一致模式
- **奠定**集中式狀態更新基礎
> 💡 **注意**:此重構尚未立即解決問題,但它打造了強大改善方案的核心基礎!
### 🎯 教學檢查點:集中原則
**暫停並反思**:你剛完成了集中式狀態管理的基礎實作。這是關鍵的架構決策。
**快速自我評估**
- 你能解釋為何將狀態集中在一個物件比分散變數好嗎?
- 如果忘記更新某函式以使用 `state.account` 會發生什麼?
- 這模式如何讓你的程式碼準備好迎接更進階功能?
**現實世界連結**:你學到的集中模式是現代框架如 Redux、Vuex、React Context 的基礎。你正在建立大型應用使用的相同架構思維。
## 追蹤資料變更
**挑戰問題**:如果需要加入使用者偏好(主題、語言)到應用中,你會將它們加入狀態結構何處?這樣做如何擴充?
現在我們已經設置了 `state` 物件來存儲資料,下一步是集中更新。目標是使追蹤任何變更及其發生時間變得更容易。
## 實作受控狀態更新
為了避免對 `state` 物件進行更改,考慮將其視為[*不可變*](https://en.wikipedia.org/wiki/Immutable_object)是一個良好的做法,這意味著它完全不能被修改。這也意味著如果您想更改其中的任何內容,必須創建一個新的狀態物件。通過這樣做,您可以防止潛在的[副作用](https://en.wikipedia.org/wiki/Side_effect_(computer_science)),並為應用程式的新功能(例如實現撤銷/重做)打開可能性,同時也使調試更容易。例如,您可以記錄對狀態所做的每次更改,並保留更改的歷史記錄,以了解錯誤的來源。
在狀態集中後,接著要建立對資料修改的控制機制。這確保狀態變化可預測、易於除錯
在 JavaScript 中,您可以使用 [`Object.freeze()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) 創建物件的不可變版本。如果嘗試更改不可變物件,將引發異常。
核心原則類似空中交通管制:不允許多個函式獨立改變狀態,而是將所有變更經由單一受控函式。此模式提供清晰監管,掌握資料何時、如何變更
✅ 您知道*淺層*和*深層*不可變物件的區別嗎?您可以在[這裡](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze)閱讀相關內容。
**不可變狀態管理:**
我們將視 `state` 物件為 [*不可變*](https://en.wikipedia.org/wiki/Immutable_object),意即不直接修改它。每次變更都產生一個新的狀態物件,包含更新後的資料。
雖然此方式初看似較不效率,較直接修改費時,但對除錯、測試與保持應用可預測性有重大優勢。
**不可變狀態管理的好處:**
| 好處 | 說明 | 影響 |
|---------|-------------|--------|
| **可預測性** | 狀態變更僅透過受控函式 | 除錯和測試更容易 |
| **歷史追蹤** | 每次變動產生新物件 | 支援復原/重做功能 |
| **防止副作用** | 防止意外修改 | 避免神祕錯誤 |
| **效能優化** | 易於偵測狀態實際變更 | 支援高效 UI 更新 |
**JavaScript 使用 `Object.freeze()` 實現不可變:**
JavaScript 提供 [`Object.freeze()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) 來防止物件修改:
```js
const immutableState = Object.freeze({ account: userData });
// 任何嘗試修改 immutableState 的行為都會拋出錯誤
```
**逐步解讀此處:**
- **防止**直接修改或刪除屬性
- **於嘗試修改時**拋出例外
- **確保**狀態必須經由受控函式更新
- **建立**明確規定如何更新狀態
> 💡 **深入瞭解**:閱讀 [MDN 文件](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze) 了解 *淺層**深層* 不可變物件的差異。掌握該區分對複雜狀態結構至關重要。
```mermaid
stateDiagram-v2
[*] --> StateV1: 初始狀態
StateV1 --> StateV2: updateState('account', newData)
StateV2 --> StateV3: updateState('account', anotherUpdate)
StateV3 --> StateV4: updateState('preferences', userSettings)
note right of StateV1
Object.freeze()
不可變
可除錯
end note
note right of StateV2
新物件已建立
保留先前狀態
可預測的變更
end note
```
### 任務
讓我們創建一個新的 `updateState()` 函數:
讓我們建立新的 `updateState()` 函式
```js
function updateState(property, newData) {
@ -110,9 +360,9 @@ function updateState(property, newData) {
}
```
在此函數中,我們創建了一個新的狀態物件,並使用[*展開運算符 (`...`)*](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals)從先前的狀態中複製資料。然後,我們使用[方括號表示法](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties) `[property]` 覆蓋狀態物件的特定屬性。最後,我們使用 `Object.freeze()` 鎖定物件以防止修改。目前狀態中僅存儲 `account` 屬性,但使用此方法,您可以在狀態中添加任意多的屬性
此函式中,我們使用 [擴展運算子(`...`)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) 從先前狀態複製資料至新物件,接著使用 [中括號符號](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties) `[property]` 指派指定屬性新的資料。最後,使用 `Object.freeze()` 鎖定物件防止修改。目前狀態中僅有 `account` 屬性,但你可以依需求新增更多
我們還需要更新 `state` 的初始化,以確保初始狀態也是不可變的:
同時我們也會更新 `state` 初始化,確保初始狀態也是被鎖定的:
```js
let state = Object.freeze({
@ -120,21 +370,21 @@ let state = Object.freeze({
});
```
之後,更新 `register` 函數,將 `state.account = result;` 替換為:
接著更新 `register` 函式,將 `state.account = result;` 取代為:
```js
updateState('account', result);
```
`login` 函數進行相同的更新,將 `state.account = data;` 替換為
`login` 函式也同理,將 `state.account = data;` 替換成
```js
updateState('account', data);
```
現在我們可以順便修復使用者點擊*登出*時帳戶資料未清除的問題。
我們現在順便修正用戶點擊 *登出* 時帳戶資料未清除的問題。
創建一個新的函數 `logout()`
建立新的 `logout()` 函式
```js
function logout() {
@ -143,49 +393,123 @@ function logout() {
}
```
`updateDashboard()` 中,將重定向 `return navigate('/login');` 替換為 `return logout()`;
`updateDashboard()` 中,把導向 `return navigate('/login');` 改成 `return logout()`
嘗試註冊新帳戶,登出並再次登入,檢查是否一切正常
試著註冊新帳號,登出後再登入,確認一切正常運作
> 提示:您可以通過在 `updateState()` 的底部添加 `console.log(state)` 並打開瀏覽器開發工具中的控制台來查看所有狀態變更。
> 小提示:你可以在 `updateState()` 函式底部加上 `console.log(state)`,並啟用瀏覽器開發工具的主控台來查看所有狀態變更。
## 持久化狀態
## 實作資料持久化
大多數網頁應用程式需要持久化資料才能正常工作。所有關鍵資料通常存儲在資料庫中,並通過伺服器 API 訪問,例如我們的使用者帳戶資料。但有時,將某些資料存儲在瀏覽器中的客戶端應用程式中也是有益的,這可以改善使用者體驗或提高加載性能
我們先前發現的會話流失問題需要持久化方案,保持使用者狀態跨瀏覽器會話。這使應用從暫時體驗轉變成可靠的專業工具
當您想在瀏覽器中持久化資料時,有幾個重要問題需要問自己:
想像原子鐘即使停電也能維持精確時間,因為它將關鍵狀態儲存在非揮發性記憶體。類似地,網頁應用需要持久儲存機制以保留重要使用者資料,跨會話及刷新。
- *資料是否敏感?* 您應避免在客戶端存儲任何敏感資料,例如使用者密碼。
- *您需要保存這些資料多久?* 您是僅在當前會話中訪問這些資料,還是希望永久保存?
**資料持久化的策略性問題:**
根據您的需求,有多種方法可以在網頁應用程式中存儲資訊。例如,您可以使用 URL 存儲搜尋查詢,並使其可在使用者之間共享。您還可以使用 [HTTP cookies](https://developer.mozilla.org/docs/Web/HTTP/Cookies) 如果需要與伺服器共享資料,例如[身份驗證](https://en.wikipedia.org/wiki/Authentication)資訊。
實作持久化之前,請考慮這些關鍵因素:
另一個選擇是使用瀏覽器提供的多種 API 來存儲資料。其中有兩個特別值得注意:
| 問題 | 銀行應用脈絡 | 決策影響 |
|----------|-------------------|----------------|
| **資料是否敏感?** | 帳戶餘額、交易紀錄 | 選擇安全的儲存方式 |
| **應該持續多久?** | 登入狀態 vs. 臨時的 UI 偏好設定 | 選擇適當的儲存期限 |
| **伺服器需要它嗎?** | 認證令牌 vs. UI 設定 | 判斷是否需要分享 |
- [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage):一個[鍵值存儲](https://en.wikipedia.org/wiki/Key%E2%80%93value_database),允許跨不同會話持久化特定於當前網站的資料。存儲在其中的資料永不過期。
- [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage):其工作方式與 `localStorage` 相同,但存儲的資料在會話結束(瀏覽器關閉時)後會被清除。
**瀏覽器儲存選項:**
請注意,這兩個 API 只允許存儲[字串](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)。如果您想存儲複雜物件,則需要使用 [`JSON.stringify()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) 將其序列化為 [JSON](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON) 格式。
現代瀏覽器提供多種儲存機制,各自針對不同使用情境設計:
✅ 如果您想創建一個不依賴伺服器的網頁應用程式,也可以使用 [`IndexedDB` API](https://developer.mozilla.org/docs/Web/API/IndexedDB_API) 在客戶端創建資料庫。這適用於高級用例或需要存儲大量資料的情況,因為它使用起來更為複雜。
**主要儲存 API**
### 任務
1. **[`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage)**:持久的[鍵/值儲存](https://zh.wikipedia.org/wiki/键值数据库)
- **資料持續**跨瀏覽器工作階段無限期
- **瀏覽器重新啟動及電腦重啟時依然保持**
- **限定**於特定網站網域
- **完美**適用於使用者偏好和登入狀態
2. **[`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage)**:臨時會話儲存
- 在活躍會話中功能與 localStorage 相同
- 瀏覽器分頁關閉時自動清除
- 適合不應持續保留的臨時資料
我們希望使用者在明確點擊*登出*按鈕之前保持登入狀態,因此我們將使用 `localStorage` 存儲帳戶資料。首先,定義一個用於存儲資料的鍵。
3. **[HTTP Cookies](https://developer.mozilla.org/docs/Web/HTTP/Cookies)**:伺服器共享儲存
- 每次伺服器請求時自動附加
- 適合[認證](https://zh.wikipedia.org/wiki/身份验证)令牌
- 容量有限且可影響效能
**資料序列化需求:**
`localStorage``sessionStorage` 皆只儲存[字串](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
```js
// 將物件轉換為 JSON 字串以便儲存
const accountData = { user: 'john', balance: 150 };
localStorage.setItem('account', JSON.stringify(accountData));
// 取得資料時,將 JSON 字串解析回物件
const savedAccount = JSON.parse(localStorage.getItem('account'));
```
**序列化解說:**
- **將** JavaScript 物件轉換成使用 [`JSON.stringify()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) 的 JSON 字串
- **使用** [`JSON.parse()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) 從 JSON 重建物件
- **自動**處理複雜巢狀物件與陣列
- **無法**處理函式、未定義值及循環參考
> 💡 **進階選項**:對於複雜的離線應用與大量資料,建議考慮 [`IndexedDB` API](https://developer.mozilla.org/docs/Web/API/IndexedDB_API)。它提供完整的客戶端資料庫,但實作較為複雜。
```mermaid
quadrantChart
title 瀏覽器儲存選項
x-axis 低複雜度 --> 高複雜度
y-axis 短時長 --> 長時長
quadrant-1 專業工具
quadrant-2 簡單持久化
quadrant-3 臨時儲存
quadrant-4 進階系統
localStorage: [0.3, 0.8]
sessionStorage: [0.2, 0.2]
HTTP Cookies: [0.6, 0.7]
IndexedDB: [0.9, 0.9]
Memory Variables: [0.1, 0.1]
```
### 任務:實作 localStorage 的持久化
讓我們實作持久化儲存,使使用者能維持登入狀態直到主動登出。我們將使用 `localStorage` 來跨瀏覽器工作階段儲存帳戶資料。
**步驟 1定義儲存設定**
```js
const storageKey = 'savedAccount';
```
然後在 `updateState()` 函數的末尾添加以下行:
**此常數的作用:**
- **建立**穩定且一致的儲存資料識別碼
- **避免**儲存金鑰拼寫錯誤
- **便於**日後修改儲存金鑰
- **遵守**維護性佳的最佳實踐
**步驟 2加入自動持久化**
`updateState()` 函式結尾加入此行:
```js
localStorage.setItem(storageKey, JSON.stringify(state.account));
```
有了這個,使用者帳戶資料將被持久化並始終保持最新,因為我們之前已集中化所有狀態更新。這就是我們開始從之前的重構中受益的地方 🙂。
**這裡發生了什麼:**
- **將**帳戶物件轉換成 JSON 字串以便儲存
- **使用**前面定義的儲存金鑰保存資料
- **在**狀態改變時自動執行
- **確保**儲存資料永遠與當前狀態同步
由於資料已保存,我們還需要在應用程式加載時恢復它。由於我們將開始擁有更多初始化程式碼,創建一個新的 `init` 函數可能是一個好主意,並將其包括在 `app.js` 的底部:
> 💡 **架構優勢**:因為所有狀態更新集中在 `updateState()`,只需加一行就完成持久化,展現良好架構設計的威力!
**步驟 3在應用載入時還原狀態**
建立初始化函式來還原儲存的資料:
```js
function init() {
@ -194,7 +518,7 @@ function init() {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
// 我們之前的初始化程式碼
window.onpopstate = () => updateRoute();
updateRoute();
}
@ -202,17 +526,63 @@ function init() {
init();
```
在這裡,我們檢索保存的資料,如果有任何資料,我們相應地更新狀態。重要的是在更新路由*之前*執行此操作,因為在頁面更新期間可能有程式碼依賴於狀態。
**初始化流程說明:**
- **從** localStorage 取回先前保存的帳戶資料(如有)
- **解析** JSON 字串,還原為 JavaScript 物件
- **使用**受控更新函式更新狀態
- **自動**還原使用者的會話
- **於**路由更新前執行確保狀態可用
**步驟 4優化預設路由**
更新預設路由以利用持久化優勢:
`updateRoute()` 中替換:
```js
// 替換return navigate('/login');
return navigate('/dashboard');
```
**本變更的合理性:**
- **有效利用**新加入的持久化系統
- **讓**儀表板處理認證檢查
- **無會話時**自動導向登入頁
- **營造**更順暢的使用者體驗
**測試你的實作:**
1. 登入你的銀行應用
2. 重新整理瀏覽器頁面
3. 確認你仍保持登入且位於儀表板
4. 關閉再重新開啟瀏覽器
5. 返回你的應用並確認依舊登入
🎉 **成就達成**:你已成功實作持久狀態管理!你的應用已具備專業網頁應用行為。
### 🎯 教學檢核:持久化架構
我們還可以將*儀表板*頁面設為應用程式的預設頁面,因為我們現在正在持久化帳戶資料。如果未找到任何資料,儀表板會負責重定向到*登入*頁面。在 `updateRoute()` 中,將回退 `return navigate('/login');` 替換為 `return navigate('/dashboard');`
**架構理解**:你實作了一個平衡使用者體驗與資料管理複雜度的高階持久化層
現在登入應用程式並嘗試刷新頁面。您應該停留在儀表板上。通過這次更新,我們已解決所有初始問題...
**精通概念:**
- **JSON 序列化**:複雜物件轉存字串
- **自動同步**:狀態變動即觸發儲存
- **會話復原**:可於中斷後還原使用者上下文
- **集中持久化**:單一更新函式掌管所有儲存
## 刷新資料
**產業連結**這種持久化模式是漸進式網頁應用PWA、離線優先應用以及現代行動網頁體驗的根基。你正在建立具備生產力水準的功能。
...但我們可能也創造了一個新問題。糟糕!
**反思問題**:如何修改此系統,以便同一台裝置能管理多個使用者帳戶?要考慮隱私與安全性影響。
使用 `test` 帳戶進入儀表板,然後在終端執行以下命令以創建新交易:
## 持久化與資料新鮮度的平衡
我們的持久化系統成功維持使用者會話,但帶來新挑戰:資料陳舊。當多位使用者或應用修改伺服器資料時,本地快取資訊可能已過時。
此情況類似維京航海師同時依賴存有的星圖與即時天象觀察。星圖提供一致參考,但航海師必須以新觀測補強。類似地,我們的應用需要持久的使用者狀態和最新的伺服器資料。
**🧪 探索資料新鮮度問題:**
1. 使用 `test` 帳號登入儀表板
2. 用終端機執行此指令以模擬其他來源的交易:
```sh
curl --request POST \
@ -221,15 +591,47 @@ curl --request POST \
http://localhost:5000/api/accounts/test/transactions
```
現在嘗試在瀏覽器中刷新儀表板頁面。會發生什麼?您是否看到新交易?
由於 `localStorage`,狀態被無限期持久化,但這也意味著在您登出應用程式並再次登入之前,它永遠不會更新!
解決此問題的一種策略是每次加載儀表板時重新載入帳戶資料,以避免資料過時。
3. 於瀏覽器重新整理儀表板頁面
4. 觀察是否看到新的交易紀錄
**此測試說明:**
- **示範**本地儲存可能變陳舊
- **模擬**真實世界資料於應用外部改動情境
- **揭示**持久化與資料新鮮的張力衝突
**資料陳舊挑戰:**
| 問題 | 成因 | 對使用者影響 |
|---------|-------|-------------|
| **資料過時** | localStorage 不會自動過期 | 使用者看到陳舊資訊 |
| **伺服器變更** | 其他應用或使用者改動相同資料 | 跨平台檢視不一致 |
| **快取與真實差異** | 本地快取與伺服器狀態不符 | 使用者體驗差異與混淆 |
**解決策略:**
我們將實作「載入時刷新」模式,在維持持久化優勢下確保資料新鮮,兼顧流暢體驗與精確資料。
```mermaid
sequenceDiagram
participant U as 使用者
participant A as 應用程式
participant L as 本地儲存
participant S as 伺服器
U->>A: 開啟應用程式
A->>L: 載入儲存狀態
L-->>A: 回傳快取資料
A->>U: 立即顯示介面
A->>S: 取得最新資料
S-->>A: 回傳目前資料
A->>L: 更新快取
A->>U: 使用最新資料更新介面
```
### 任務:實作資料刷新系統
### 任務
建立透過持久狀態管理同時自動從伺服器抓取新資料的系統。
創建一個新的函數 `updateAccountData`
**步驟 1建立帳戶資料更新器**
```js
async function updateAccountData() {
@ -247,9 +649,15 @@ async function updateAccountData() {
}
```
此方法檢查我們當前是否已登入,然後從伺服器重新載入帳戶資料。
**此函式邏輯說明:**
- **檢查**目前是否有使用者登入state.account 是否存在)
- **無有效會話時**導向登出
- **利用既有 `getAccount()` 函式**從伺服器取得最新帳戶資料
- **優雅處理**伺服器錯誤,無效會話時登出
- **使用控制更新系統**同步更新帶新資料的狀態
- **透過 `updateState()`**函式觸發自動 localStorage 持久化
創建另一個名為 `refresh` 的函數:
**步驟 2建立儀表板刷新處理器**
```js
async function refresh() {
@ -258,7 +666,15 @@ async function refresh() {
}
```
此函數更新帳戶資料,然後負責更新儀表板頁面的 HTML。這是我們需要在加載儀表板路由時調用的函數。使用以下程式碼更新路由定義
**此刷新函式達成目標:**
- **協調**資料刷新及 UI 更新流程
- **等待**新資料載入完成後才更新顯示
- **確保**儀表板呈現最新資訊
- **維持**資料管理與 UI 更新分離明確
**步驟 3整合路由系統**
更新路由設定以自動觸發刷新:
```js
const routes = {
@ -267,28 +683,126 @@ const routes = {
};
```
現在嘗試刷新儀表板,它應顯示更新的帳戶資料。
**此整合如何發揮作用:**
- **每次載入儀表板路由時執行刷新函式**
- **確保使用者導向儀表板時總是顯示新資料**
- **維持既有路由結構同時加入資料新鮮度**
- **提供一致的路由專屬初始化模式**
**測試資料刷新系統:**
1. 登入你的銀行應用
2. 執行前述 curl 指令新增交易
3. 重新整理儀表板頁面或切換再回來
4. 確認新交易即刻顯示
🎉 **完美平衡實現**:你的應用現已兼具持久狀態的流暢體驗與新鮮伺服器資料的準確度!
## 📈 你的狀態管理精通時程表
```mermaid
timeline
title 專業狀態管理旅程
section 問題識別
State Issues Diagnosis
: 識別會話遺失問題
: 了解分散更新問題
: 認識架構需求
section 架構基礎
Centralized State Design
: 創建統一狀態物件
: 實施受控更新模式
: 建立不可變原則
Predictable Updates
: 精通 Object.freeze() 用法
: 建構除錯友善系統
: 創建可擴充模式
section 持久化精通
localStorage Integration
: 處理 JSON 序列化
: 實施自動同步
: 建立會話連續性
Data Freshness Balance
: 解決陳舊問題
: 建構刷新機制
: 優化效能與精準度
section 專業模式
Production-Ready Systems
: 實施錯誤處理
: 創建可維護架構
: 遵循產業最佳實踐
Advanced Capabilities
: 準備框架整合
: 應對複雜狀態需求
: 即時功能基礎
```
**🎓 畢業里程碑**:你已成功打造完整狀態管理系統,採用 Redux、Vuex 等專業狀態庫背後相同原理。這些模式可從簡單應用擴展至企業級。
---
**🔄 下一階段能力:**
- 准備掌握狀態管理框架Redux、Zustand、Pinia
- 準備實作以 WebSocket 為基礎的即時功能
- 配備建置離線優先漸進式網頁應用能力
- 建立狀態機與觀察者等進階模式基礎
## GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
**說明:**為銀行應用實作具備復原與重做undo/redo功能的完整狀態管理系統。此挑戰將協助你練習先進狀態管理概念包括歷史狀態追蹤、不可變更新、與用戶介面同步。
**提示:**建構強化版的狀態管理系統包含1) 追蹤所有先前狀態的歷史狀態陣列2) 可回復至先前狀態的 undo/redo 函式3) 儀表板上的 undo/redo 操作按鈕4) 限制最多儲存 10 筆歷史狀態以避免記憶體問題5) 使用者登出時適當清理歷史。確保 undo/redo 功能能搭配帳戶餘額變更,且能跨瀏覽器刷新持續運作。
想了解更多請見 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑戰:儲存優化
你現有的實作有效處理使用者會話、資料刷新與狀態管理。然而,思考我們目前方法是否在儲存效率與功能性間達到最佳平衡。
猶如象棋高手會區分必要棋子與可犧牲卒子,有效狀態管理需判斷哪些資料必須持續保存,哪些則必須保持最新且直接取自伺服器。
**優化分析:**
評估你現有的 localStorage 實作,思考以下策略問題:
- 維持使用者認證最少需要哪些資訊?
- 哪些資料變化頻繁,當地快取益處不大?
- 如何優化儲存提升效能同時不損失使用者體驗?
這類架構分析是區分具經驗開發者,能兼顧功能與效率的關鍵。
**實作策略:**
- **識別**必須持續儲存的關鍵資料(可能僅為使用者識別資訊)
- **修改** localStorage 實作僅存放關鍵會話資料
- **確保**在儀表板訪問時總是從伺服器載入新資料
- **測試**優化後仍能維持相同使用者體驗
## 🚀 挑戰
**進階考量:**
- **比較**儲存完整帳戶資料與僅存認證令牌的利弊
- **記錄**你的決策過程與原因以便團隊參考
現在我們每次加載儀表板時都重新載入帳戶資料,您認為我們是否仍需要持久化*所有帳戶*資料?
此挑戰將訓練你如專業開發者般全盤考量使用者體驗與應用效率。慢慢試驗各種方法吧!
嘗試合作更改 `localStorage` 中保存和加載的內容,只包括應用程式正常運行所需的絕對必要資料。
## 講義後測驗
## 課後測驗
[課後測驗](https://ff-quizzes.netlify.app/web/quiz/48)
[講義後測驗](https://ff-quizzes.netlify.app/web/quiz/48)
## 作業
[實作「新增交易」對話框](assignment.md)
以下是完成作業後的範例結果:
完成作業後範例呈現
![螢幕截圖顯示範例「新增交易」對話框](../../../../translated_images/dialog.93bba104afeb79f12f65ebf8f521c5d64e179c40b791c49c242cf15f7e7fab15.tw.png)
![截圖顯示範例「新增交易」對話框](../../../../translated_images/dialog.93bba104afeb79f1.tw.png)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於追求準確性,但請注意,自動化翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議採用專業人工翻譯。我們不對因使用本翻譯而引起的任何誤解或曲解承擔責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,37 +1,164 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "f23a868536c07da991b1d4e773161e25",
"translation_date": "2025-08-24T00:15:03+00:00",
"original_hash": "50a7783473b39a2e0f133e271a102231",
"translation_date": "2026-01-06T14:09:12+00:00",
"source_file": "7-bank-project/4-state-management/assignment.md",
"language_code": "tw"
}
-->
# 實「新增交易」對話框
# 實「新增交易」對話框
## 說明
## 概覽
我們的銀行應用程式仍然缺少一個重要功能:輸入新交易的可能性。
使用您在前四節課中學到的所有內容,實現一個「新增交易」對話框:
你的銀行應用程式現在已有穩健的狀態管理和資料持久化功能,但缺少一個真實銀行應用程式必備的關鍵功能:使用者能夠新增自己的交易。在這個作業中,你將實作一個完整的「新增交易」對話框,能無縫整合到你現有的狀態管理系統中。
- 在儀表板頁面新增一個「新增交易」按鈕
- 可以選擇建立一個帶有 HTML 模板的新頁面,或者使用 JavaScript 顯示/隱藏對話框的 HTML而不離開儀表板頁面您可以使用 [`hidden`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/hidden) 屬性或 CSS 類別來完成此操作)
- 確保處理好對話框的[鍵盤和螢幕閱讀器的可訪問性](https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/)
- 實現一個 HTML 表單以接收輸入數據
- 從表單數據創建 JSON 數據並將其發送到 API
- 使用新數據更新儀表板頁面
這個作業結合了你在四堂銀行課中所學的所有內容HTML 範本、表單處理、API 整合與狀態管理。
查看 [伺服器 API 規範](../api/README.md),了解需要調用的 API 以及預期的 JSON 格式。
## 學習目標
以下是完成作業後的示例結果:
完成此作業後,你將能:
- **建立**使用者友善的資料輸入對話框介面
- **實作**可存取的表單設計,支援鍵盤與螢幕閱讀器
- **整合**新功能與你現有的狀態管理系統
- **練習**API 通訊與錯誤處理
- **應用**現代網頁開發模式到真實功能
![顯示「新增交易」對話框的示例截圖](../../../../7-bank-project/4-state-management/images/dialog.png)
## 指示
### 步驟 1新增交易按鈕
**建立**一個「新增交易」按鈕,放在儀表板頁面上,讓使用者能輕鬆找到並存取。
**需求:**
- **將**按鈕放在儀表板的合適位置
- **使用**明確且具行動導向的按鈕文字
- **套用**與你現有 UI 設計一致的按鈕樣式
- **確保**按鈕可用鍵盤操作
### 步驟 2對話框實作
從以下兩種方法選擇一種實作你的對話框:
**選項 A獨立頁面**
- **建立**交易表單的新 HTML 範本
- **新增**路由到你的路由系統
- **實作**前往及返回表單頁面的導航
**選項 B模態對話框推薦**
- **使用**JavaScript 在不離開儀表板的情況下顯示/隱藏對話框
- **利用**[`hidden` 屬性](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/hidden)或 CSS 類別實作
- **創造**順暢的使用者體驗,並妥善管理焦點
### 步驟 3無障礙實作
**確保**你的對話框符合[模態對話框無障礙標準](https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/)
**鍵盤導航:**
- **支援**按 Esc 鍵關閉對話框
- **限制**當對話框開啟時焦點只在對話框內移動
- **關閉**後焦點回到觸發按鈕
**螢幕閱讀器支援:**
- **加入**適當的 ARIA 標籤和角色
- **向**螢幕閱讀器宣告對話框的開啟與關閉
- **提供**清楚的表單欄位標籤與錯誤訊息
### 步驟 4表單建立
**設計**一個收集交易資料的 HTML 表單:
**必填欄位:**
- **日期**:交易發生的時間
- **描述**:交易用途
- **金額**:交易金額(收入為正數,支出為負數)
**表單功能:**
- **提交前**驗證使用者輸入
- **提供**無效資料的清楚錯誤訊息
- **包含**有用的 placeholder 文字與標籤
- **樣式**與你現有設計保持一致
### 步驟 5API 整合
**將**你的表單連接到後端 API
**實作步驟:**
- **參考**[伺服器 API 規格](../api/README.md)了解正確的端點與資料格式
- **從**表單輸入建立 JSON 資料
- **送出**資料至 API並妥善處理錯誤
- **向**使用者顯示成功或失敗訊息
- **優雅地**處理網路錯誤
### 步驟 6狀態管理整合
**以新交易更新你的儀表板:**
**整合需求:**
- **交易新增成功後**重新整理帳戶資料
- **更新**儀表板畫面,不需重新載入頁面
- **確保**新交易立即顯示
- **維持**整個流程中的狀態一致性
## 技術規格
**API 端點詳情:**
請參考[伺服器 API 文件](../api/README.md)了解:
- 交易資料所需的 JSON 格式
- HTTP 方法與端點 URL
- 預期的回應格式
- 錯誤回應處理
**預期成果:**
完成此作業後,你的銀行應用程式應該擁有一個外觀專業且功能完整的「新增交易」功能:
![顯示範例「新增交易」對話框截圖](../../../../translated_images/dialog.93bba104afeb79f1.tw.png)
## 測試你的實作
**功能測試:**
1. **確認**「新增交易」按鈕明顯且可存取
2. **測試**對話框是否能正常開啟與關閉
3. **驗證**所有必填欄位的表單驗證功能
4. **確認**成功新增的交易能立即出現在儀表板
5. **確保**無效資料與網路問題會正確處理錯誤
**無障礙測試:**
1. **僅用鍵盤**瀏覽整個操作流程
2. **搭配**螢幕閱讀器測試宣告是否正確
3. **驗證**焦點管理是否正常
4. **檢查**所有表單元素都有適當標籤
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| | 完全按照課程中看到的所有最佳實踐實現新增交易功能。 | 新增交易功能已實現,但未完全遵循課程中看到的最佳實踐,或者僅部分運作。 | 新增交易功能完全無法運作。 |
| 評分標準 | 優異 | 適當 | 需改進 |
| -------- | ------ | ------ | ---------- |
| **功能性** | 新增交易功能運作流暢,使用者體驗優秀且遵循課程最佳實務 | 新增交易功能正常,但可能未完全遵循部分最佳實務或有些微易用性問題 | 新增交易功能部分可用或有重大易用性問題 |
| **程式碼品質** | 程式碼組織良好,遵循既有模式,具備良好錯誤處理,與現有狀態管理完美整合 | 程式碼可用,但可能有組織問題或與現有程式碼基底不一致 | 程式碼結構有重大問題,且未與既有模式良好整合 |
| **無障礙** | 完整鍵盤導航支援,螢幕閱讀器相容,符合 WCAG 指南,焦點管理優異 | 實作基礎無障礙功能,但可能缺少部分鍵盤導航或螢幕閱讀器支援 | 無或極少無障礙考量 |
| **使用者體驗** | 介面直覺且有質感,包含明確回饋、流暢互動與專業外觀 | 使用者體驗良好,但回饋或視覺設計有小幅提升空間 | 使用者介面混亂,缺少明確回饋 |
## 額外挑戰(選擇性)
完成基本需求後,考慮以下增強功能:
**進階功能:**
- **新增**交易類別(食物、交通、娛樂等)
- **實作**輸入即時驗證與回饋
- **建立**進階使用者的快捷鍵
- **加入**交易編輯與刪除功能
**高階整合:**
- **實作**最近新增交易的復原功能
- **增加**CSV 檔案批次匯入交易
- **建立**交易搜尋與篩選功能
- **實作**資料匯出功能
這些選擇性功能能幫助你練習更進階的網頁開發概念,打造更完整的銀行應用程式!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。
本文件由 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於準確性,但請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所產生的任何誤解或誤釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,195 +1,639 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "f8d4b0284f3fc1de7eb65073d8338cca",
"translation_date": "2025-10-03T08:59:31+00:00",
"original_hash": "a9a3bcc037a447e2d8994d99e871cd9f",
"translation_date": "2026-01-06T13:36:12+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/README.md",
"language_code": "tw"
}
-->
***
# 使用程式碼編輯器:掌握 [VSCode.dev](https://vscode.dev)
**歡迎!**
本課程將帶您從基礎到進階使用 [VSCode.dev](https://vscode.dev)——這是一款功能強大的基於網頁的程式碼編輯器。您將學習如何自信地編輯程式碼、管理專案、追蹤變更、安裝擴充功能,以及像專業人士一樣進行協作——全部都能直接在瀏覽器中完成,無需安裝。
***
## 學習目標
完成本課程後,您將能夠:
- 高效地在任何專案上使用程式碼編輯器,隨時隨地
- 使用內建版本控制無縫追蹤您的工作
- 透過編輯器自訂和擴充功能個性化並提升您的開發工作流程
***
## 先決條件
開始之前,請**註冊一個免費的 [GitHub](https://github.com) 帳戶**,這將幫助您管理程式碼倉庫並與全球開發者協作。如果您尚未擁有帳戶,請[在此建立](https://github.com/)。
***
## 為什麼使用基於網頁的程式碼編輯器?
像 VSCode.dev 這樣的**程式碼編輯器**是您撰寫、編輯和管理程式碼的指揮中心。它擁有直觀的介面、豐富的功能,並且可以直接透過瀏覽器訪問,您可以:
- 在任何設備上編輯專案
- 避免安裝的麻煩
- 即時協作和貢獻
一旦熟悉 VSCode.dev您就能隨時隨地處理程式碼任務。
***
## 開始使用 VSCode.dev
前往 **[VSCode.dev](https://vscode.dev)**——無需安裝,無需下載。使用 GitHub 登錄可解鎖完整功能,包括同步您的設定、擴充功能和倉庫。如果系統提示,請連接您的 GitHub 帳戶。
載入後,您的工作區將如下所示:
![Default VSCode.dev](../../../../8-code-editor/images/default-vscode-dev)
工作區分為三個核心區域,從左到右:
- **活動欄:** 包括 🔎(搜尋)、⚙️(設定)、檔案、版本控制等圖示。
- **側邊欄:** 根據選擇的活動欄圖示改變上下文(預設為 *Explorer* 顯示檔案)。
- **編輯器/程式碼區域:** 最大的右側區域——您將在此編輯和查看程式碼。
# 使用程式碼編輯器:掌握 VSCode.dev
還記得在《駭客任務》中,尼歐必須連接到一個巨大的電腦終端機才能進入數位世界嗎?現今的網頁開發工具則是完全相反的故事 — 強大的功能隨時隨地皆可使用。VSCode.dev 是一個基於瀏覽器的程式碼編輯器,將專業開發工具帶到任何有網路連線的裝置上。
就像印刷術讓書籍普及不再只是修道院裡的抄寫員專享VSCode.dev 也讓程式碼編寫民主化。你可以在圖書館電腦、學校實驗室,或任何能開瀏覽器的地方工作。免安裝,沒有「我需要特定開發環境」的限制。
本課程結束時,你將學會如何在 VSCode.dev 中導航,直接在瀏覽器中開啟 GitHub 倉庫,並使用 Git 進行版本控管 — 這些都是專業開發者每日倚賴的技能。
## ⚡ 你接下來五分鐘能做什麼
**忙碌開發者的快速入門路徑**
```mermaid
flowchart LR
A[⚡ 5 分鐘] --> B[造訪 vscode.dev]
B --> C[連接 GitHub 帳戶]
C --> D[開啟任意儲存庫]
D --> E[立即開始編輯]
```
- **第 1 分鐘**:前往 [vscode.dev](https://vscode.dev) — 完全免安裝
- **第 2 分鐘**:使用 GitHub 登入,連結你的倉庫
- **第 3 分鐘**:試試 URL 技巧:將任何倉庫 URL 的 `github.com` 改成 `vscode.dev/github`
- **第 4 分鐘**:建立新檔案,並觀察語法高亮自動生效
- **第 5 分鐘**:修改檔案並經由版本控制面板提交變更
**快速測試網址**
```
# Transform this:
github.com/microsoft/Web-Dev-For-Beginners
# Into this:
vscode.dev/github/microsoft/Web-Dev-For-Beginners
```
**為何這很重要**5 分鐘內,你將體驗從任何地方使用專業工具編碼的自由。這正是開發的未來 — 開放、強大且即時。
## 🗺️ 你的雲端開發學習旅程
```mermaid
journey
title 從本地設置到雲端開發精通之路
section 了解平台
發現基於網頁的編輯: 4: You
連接到 GitHub 生態系統: 6: You
精通介面導航: 7: You
section 檔案管理技能
建立並組織檔案: 5: You
使用語法高亮編輯: 7: You
導覽專案結構: 8: You
section 版本控制精通
了解 Git 整合: 6: You
練習提交工作流程: 8: You
精通協作模式: 9: You
section 專業自訂化
安裝強大擴充功能: 7: You
配置開發環境: 8: You
建立個人工作流程: 9: You
```
**你的學習目標**:課程結束時,你將能熟練使用一套專業的雲端開發環境,無論任何裝置皆可操作,使用與頂尖科技公司開發者相同的工具來編寫程式。
## 你將學會什麼
完成本課程後,你能:
- 像在家一樣自在瀏覽 VSCode.dev — 輕鬆找到所需功能不迷路
- 直接在瀏覽器中打開任何 GitHub 倉庫,立即開始編輯(很神奇!)
- 使用 Git 追蹤變更,專業儲存你的進度
- 利用擴充功能強化編輯器,讓編碼更快速有趣
- 有信心地建立與整理專案檔案
## 你需要準備什麼
需求簡單明確:
- 一個免費的 [GitHub 帳號](https://github.com)(若無,我們會帶你註冊)
- 基本的瀏覽器使用經驗
- GitHub 基礎課程提供有用背景知識,非必要但建議閱讀
> 💡 **GitHub 新手看過來**註冊帳號免費且快速。就像圖書證讓你能借用全球的書籍GitHub 帳號讓你進入全球各地的程式碼倉庫。
## 🧠 雲端開發生態系統概述
```mermaid
mindmap
root((VSCode.dev 精通))
Platform Benefits
Accessibility
裝置獨立性
無需安裝
即時更新
通用存取
Integration
GitHub 連接
儲存庫同步
設定持久化
協作準備
Development Workflow
File Management
專案結構
語法高亮
多標籤編輯
自動儲存功能
Version Control
Git 整合
提交工作流程
分支管理
變更追蹤
Customization Power
Extensions Ecosystem
生產力工具
語言支援
主題選項
自訂快捷鍵
Environment Setup
個人偏好
工作區配置
工具整合
工作流程優化
Professional Skills
Industry Standards
版本控制
程式碼品質
協作
文件撰寫
Career Readiness
遠端工作
雲端開發
團隊專案
開源
```
**核心理念**:基於雲端的開發環境是程式編寫的未來 — 提供專業、可協作且平台無關的開發工具。
## 為何網頁型程式碼編輯器重要
在網路普及之前不同大學的科學家無法輕易共享研究資料。1960 年代的 ARPANET 連結了遠距電腦。網頁型程式碼編輯器遵循同樣理念 — 讓強大工具不受地點或裝置限制。
程式碼編輯器是你的開發工作空間,用於撰寫、修改、整理程式碼檔案。與簡單的文字編輯器不同,專業編輯器有語法高亮、錯誤偵測與專案管理功能。
VSCode.dev 將這些能力帶到瀏覽器中:
**網頁編輯優勢:**
| 功能 | 說明 | 實用好處 |
|---------|-------------|----------|
| **平台無關** | 可於任何具瀏覽器的裝置使用 | 無縫在不同電腦間工作 |
| **免安裝** | 透過網頁 URL 直接存取 | 避免軟體安裝限制 |
| **自動更新** | 永遠運行最新版本 | 享受新功能不需手動更新 |
| **倉庫整合** | 直接連結 GitHub | 編輯程式無需本地管理檔案 |
**實際效益:**
- 在不同環境間保持工作連續性
- 操作介面跨作業系統一致
- 立即啟用協作功能
- 降低本機儲存需求
## 探索 VSCode.dev
就如同居禮夫人實驗室中擁有先進設備且空間簡潔VSCode.dev 也將專業開發工具整合到瀏覽器介面中。本網頁應用具有與桌面版編輯器相同的核心功能。
首先在瀏覽器開啟 [vscode.dev](https://vscode.dev),介面立即載入,無需下載或安裝系統 — 充分展現雲端運算精神。
### 連結你的 GitHub 帳戶
正如貝爾的電話連結遠方,連結 GitHub 帳戶則橋接 VSCode.dev 與你的程式碼倉庫。提示登錄 GitHub 時,建議接受此連結。
**GitHub 整合提供:**
- 編輯器中直接訪問你的倉庫
- 在裝置間同步設定和擴充功能
- 簡化將變更推送至 GitHub 的流程
- 個人化開發環境
### 認識你的新工作區
完成載入後,你將看到一個潔淨、專注於程式碼的工作環境!
![Default VSCode.dev interface](../../../../translated_images/default-vscode-dev.5d06881d65c1b323.tw.png)
**社區導覽:**
- **活動列**(左側那條):主導航,有檔案總管 📁、搜尋 🔍、版本控制 🌿、擴充功能 🧩 和設定 ⚙️
- **側邊欄**(旁邊面板):視所選項顯示相應資訊
- **編輯區域**(中間大片區域):這是編碼的主要場域
**花點時間探索:**
- 點擊活動列圖示並了解它們功能
- 注意側邊欄如何根據選擇動態變化 — 很酷吧?
- 檔案總管(📁)大概是你會花最多時間的地方,熟悉它吧!
```mermaid
flowchart TB
subgraph "VSCode.dev 介面架構"
A[活動列] --> B[檔案總管 📁]
A --> C[搜尋 🔍]
A --> D[原始碼管理 🌿]
A --> E[擴充功能 🧩]
A --> F[設定 ⚙️]
B --> G[檔案樹]
C --> H[尋找與取代]
D --> I[Git 狀態]
E --> J[擴充商店]
F --> K[組態]
L[側邊欄] --> M[內容面板]
N[編輯區域] --> O[程式碼檔案]
P[終端機/輸出] --> Q[命令列]
end
```
## 開啟 GitHub 倉庫
點擊圖示探索功能,但請返回 _Explorer_ 以保持位置。
在網際網路尚未普及前研究人員必須親自到圖書館翻閱資料。GitHub 倉庫類似遠端存放的程式碼集合。VSCode.dev 則省去下載到本機才編輯的繁瑣步驟
***
這功能讓你能立刻打開任何公開倉庫,查看、編輯或貢獻。以下兩種開啟倉庫方式:
## 開啟 GitHub 倉庫
### 方法 1點擊介面操作
### 方法 1透過編輯器
適合剛開始使用 VSCode.dev 想打開指定倉庫的新手。簡單易懂:
1. 前往 [VSCode.dev](https://vscode.dev)。點擊 **"Open Remote Repository"**。
**操作步驟:**
![Open remote repository](../../../../8-code-editor/images/open-remote-repository)
1. 若還沒開啟,先前往 [vscode.dev](https://vscode.dev)
2. 在歡迎畫面按「Open Remote Repository」開啟遠端倉庫按鈕
或使用 _命令面板_Ctrl-Shift-P或 Mac 上的 Cmd-Shift-P
![Open remote repository](../../../../translated_images/open-remote-repository.bd9c2598b8949e7f.tw.png)
![Palette Menu](../../../../translated_images/palette-menu.4946174e07f426226afcdad707d19b8d5150e41591c751c45b5dee213affef91.tw.png)
3. 貼上任意 GitHub 倉庫網址(例如:`https://github.com/microsoft/Web-Dev-For-Beginners`
4. 按 Enter驚喜等著你
- 選擇該選項。
- 貼上您的 GitHub 倉庫 URL例如 `https://github.com/microsoft/Web-Dev-For-Beginners`),然後按 Enter。
**高手小技巧 — 命令選單快捷鍵:**
如果成功,您將看到整個專案已載入並準備好編輯!
想像自己是程式大師?用 Ctrl+Shift+PMac 版是 Cmd+Shift+P開啟命令選單
***
![Command Palette](../../../../translated_images/palette-menu.4946174e07f42622.tw.png)
### 方法 2透過 URL 即時開啟
**命令選單就像萬能搜索引擎:**
- 輸入「open remote」可快速找到打開遠端倉庫功能
- 它會記住你最近打開的倉庫(超方便!)
- 用熟了後,你編程速度爆棚
- VSCode.dev 的「嘿 Siri但為編碼而生」
將任何 GitHub 倉庫 URL 替換 `github.com``vscode.dev/github`,即可直接在 VSCode.dev 中開啟。
例如:
### 方法 2URL 修改法
- GitHub: `https://github.com/microsoft/Web-Dev-For-Beginners`
- VSCode.dev: `https://vscode.dev/github/microsoft/Web-Dev-For-Beginners`
就像 HTTP 和 HTTPS 使用不同協定但網址一樣VSCode.dev 遵循一套與 GitHub 相似的 URL 規則。任何 GitHub 倉庫網址均可改寫成 VSCode.dev 形式。
此功能能快速訪問任何專案。
**網址轉換範例:**
***
| 倉庫類型 | GitHub 網址 | VSCode.dev 網址 |
|----------------|---------------------|----------------|
| **公開倉庫** | `github.com/microsoft/Web-Dev-For-Beginners` | `vscode.dev/github/microsoft/Web-Dev-For-Beginners` |
| **個人專案** | `github.com/your-username/my-project` | `vscode.dev/github/your-username/my-project` |
| **任何可訪問倉庫** | `github.com/their-username/awesome-repo` | `vscode.dev/github/their-username/awesome-repo` |
## 編輯專案中的檔案
**使用方法:**
- 將 URL 中的 `github.com` 替換成 `vscode.dev/github`
- 其餘網址結構不變
- 支援任何公開可訪問的倉庫
- 立刻打開編輯介面
倉庫開啟後,您可以:
> 💡 **改變人生的小秘訣**:將你常用的倉庫 VSCode.dev URL 加入書籤。我有「編輯個人作品集」和「修正說明文件」的書籤,直接進入編輯頁面超便利!
### 1. **建立新檔案**
- 在 *Explorer* 側邊欄中,導航至您想要的資料夾或使用根目錄。
- 點擊 _New file ..._ 圖示。
- 命名您的檔案,按 **Enter**,檔案會立即出現。
**怎麼選擇方法?**
- **介面方式**:適合探索或不確定準確倉庫名稱時
- **URL 技巧**:知道確切路徑時,享受疾速存取
![Create a new file](../../../../8-code-editor/images/create-new-file)
### 🎯 教學反思:雲端開發存取
### 2. **編輯並儲存檔案**
**暫停思考**:你已學會兩種透過瀏覽器存取程式碼倉庫的方法。這是一場開發方式的根本革新。
- 點擊 *Explorer* 中的檔案以在程式碼區域中開啟。
- 根據需要進行修改。
- VSCode.dev 會自動儲存您的變更,但您也可以按 Ctrl+S 手動儲存。
**快速自我檢視**
- 能否解釋為何網頁編輯免去了傳統「開發環境安裝」?
- URL 修改技術相比本地 git 克隆有何優勢?
- 這種方式如何改變你貢獻開源專案的可能?
![Edit a file](../../../../translated_images/edit-a-file.52c0ee665ef19f08119d62d63f395dfefddc0a4deb9268d73bfe791f52c5807a.tw.png)
**實務連結**GitHub、GitLab、Replit 等大公司已建構基於雲端的開發平台。你正在學習全球專業團隊使用的開發流程。
### 3. **使用版本控制追蹤並提交變更**
**挑戰問題**:雲端開發如何改變學校程式教學?請考慮裝置需求、軟體管理和協作可能性。
VSCode.dev 集成了 **Git** 版本控制!
## 操作檔案與專案
- 點擊 _'Source Control'_ 圖示以查看所有已做的變更。
- `Changes` 資料夾中的檔案顯示新增(綠色)和刪除(紅色)。
![View changes](../../../../translated_images/working-tree.c58eec08e6335c79cc708c0c220c0b7fea61514bd3c7fb7471905a864aceac7c.tw.png)
現在你已開啟一個倉庫我們開始建構VSCode.dev 提供所有必備工具來創建、編輯及整理程式碼檔案,把它當成你的數位工作坊 — 所有工具盡在掌握。
- 點擊檔案旁的 `+` 以準備提交變更。
- 點擊撤銷圖示以**丟棄**不需要的變更。
- 輸入清晰的提交訊息,然後點擊勾選符號以提交並推送。
讓我們看看將構成你日常編碼流程的基本任務。
要返回 GitHub 倉庫,請選擇左上角的漢堡菜單。
### 建立新檔案
![Stage & commit changes](../../../../8-code-editor/images/edit-vscode.dev)
如同建築師辦公室中整理藍圖VSCode.dev 中的檔案創建同樣有條理。系統支援所有標準網頁開發檔案類型。
***
**建立流程:**
## 使用擴充功能提升工作效率
1. 在檔案總管側邊欄找到目標資料夾
2. 將游標移至該資料夾名稱,顯示「新檔案」圖標 (📄+)
3. 輸入檔名並包含適當副檔名(如 `style.css`、`script.js`、`index.html`
4. 按 Enter 建立檔案
擴充功能可讓您為 VSCode.dev 添加語言、主題、除錯工具和生產力工具——使您的程式碼編輯更輕鬆、更有趣。
![Creating a new file](../../../../translated_images/create-new-file.2814e609c2af9aeb.tw.png)
### 瀏覽和管理擴充功能
**命名規範:**
- 使用描述性名稱便於辨識檔案用途
- 包含副檔名以啟用正確語法高亮
- 專案內保持命名一致性
- 儘量使用小寫及短橫線,避免空白
- 點擊活動欄中的 **擴充功能圖示**。
- 在 _'Search Extensions in Marketplace'_ 框中搜尋擴充功能。
### 編輯與儲存檔案
![Extension details](../../../../8-code-editor/images/extension-details)
真正的樂趣就在這裡開始VSCode.dev 的編輯器內建豐富功能,讓編碼順暢直覺。就像有個超聰明的寫作助理,只不過它是為程式碼服務。
- **已安裝:** 您已添加的所有擴充功能
- **熱門:** 行業最受歡迎的擴充功能
- **推薦:** 根據您的工作流程量身定制
**你的編輯流程:**
![View extensions](
1. 點擊檔案總管中的任一檔案,於主區域打開
2. 開始輸入,觀察 VSCode.dev 用顏色、建議與錯誤偵測協助你
3. 使用 Ctrl+SWindows/Linux或 Cmd+SMac儲存 — 編輯器也會自動儲存!
![Editing files in VSCode.dev](../../../../translated_images/edit-a-file.52c0ee665ef19f08.tw.png)
***
**編碼中的貼心功能:**
- 程式碼自動色彩標記,閱讀清晰
- 輸入時會建議程式碼補全(像更智慧的自動更正)
- 儲存前能發現錯誤和拼字問題
- 可同時開啟多個檔案分頁,像瀏覽器一樣
- 背景自動儲存功能隨時保護你的進度
### 1. **安裝擴充功能**
> ⚠️ **小提醒**:儘管有自動儲存,養成按 Ctrl+S 或 Cmd+S 的習慣仍很重要。能立即儲存並觸發額外的錯誤檢查等幫助功能。
- 在搜尋框中輸入擴充功能名稱,點擊它,並在編輯器中查看詳細資訊。
- 點擊側邊欄或程式碼區域中的 **藍色安裝按鈕**。
### Git 版本控制
![Install extensions](../../../../8-code-editor/images/install-extension)
就像考古學家詳細紀錄挖掘層次Git 追蹤程式碼隨時間的變更。這系統保存專案歷史必要時還能回復舊版本。VSCode.dev 內建 Git 功能。
### 2. **自訂擴充功能**
**版本控制介面:**
- 找到您已安裝的擴充功能。
- 點擊 **齒輪圖示** → 選擇 _Extension Settings_ 以微調行為。
1. 點選活動列的 🌿 圖示開啟版本控制面板
2. 有修改的檔案會出現在「變更 (Changes)」中
3. 顏色代表變更種類:新增為綠色,刪除為紅色
![Viewing changes in Source Control](../../../../translated_images/working-tree.c58eec08e6335c79.tw.png)
**保存進度(提交流程):**
```mermaid
flowchart TD
A[對檔案進行更改] --> B[在原始碼管理中查看更改]
B --> C[點擊 + 來暫存更改]
C --> D[撰寫描述性提交訊息]
D --> E[點擊勾選標記提交]
E --> F[更改推送至 GitHub]
```
```mermaid
stateDiagram-v2
[*] --> Modified: 編輯檔案
Modified --> Staged: 點擊 + 來暫存
Staged --> Modified: 點擊 - 來取消暫存
Staged --> Committed: 新增留言並提交
Committed --> [*]: 同步到 GitHub
state Committed {
[*] --> LocalCommit
LocalCommit --> RemotePush: 自動同步
}
```
**一步步作法:**
- 點擊要保存檔案旁的「+」圖示(即暫存區)
- 再次確認你對所有已暫存的變更感到滿意
- 撰寫一則簡短說明,解釋你做了什麼(這就是你的「提交訊息」)
- 點擊勾選按鈕,將所有內容儲存到 GitHub
- 如果改變主意,點擊復原圖示即可放棄變更
**撰寫好提交訊息(比你想像的簡單!):**
- 只要描述你做了什麼,例如「新增聯絡表單」或「修正壞掉的導覽列」
- 保持簡短有力 — 想像成推特長度,不是長篇大論
- 以動詞為開頭,如「新增」、「修正」、「更新」或「移除」
- **好範例**:「新增響應式導覽選單」、「修正行動裝置版版面問題」、「更新色彩以提升無障礙性」
> 💡 **快速導覽提示**:使用左上角的漢堡選單 (☰) 快速跳回你的 GitHub 倉庫,查看你已提交的變更。這就像你編輯環境與專案 github 主頁間的傳送門!
## 使用擴充功能提升功能性
就像工匠的工作坊擁有專門工具針對不同任務VSCode.dev 也能透過擴充功能自訂,為你添加特定能力。這些社群開發的插件解決了常見開發需求,如程式碼格式化、即時預覽,以及加強的 Git 整合。
擴充功能市集匯聚了來自全球開發者的數千款免費工具。每個擴充功能解決特定工作流程挑戰,讓你打造適合自己需求和喜好的個人化開發環境。
```mermaid
mindmap
root((擴充生態系統))
Essential Categories
Productivity
Live Server
Auto Rename Tag
Bracket Pair Colorizer
GitLens
Code Quality
Prettier
ESLint
Spell Checker
Error Lens
Language Support
HTML CSS Support
JavaScript ES6
Python Extension
Markdown Preview
Themes & UI
Dark+ Modern
Material Icon Theme
Peacock
Rainbow Brackets
Discovery Methods
Popular Rankings
Download Counts
User Ratings
Recent Updates
Community Reviews
Recommendations
Workspace Suggestions
Language-based
Workflow-specific
Team Standards
```
### 找到你的完美擴充功能
擴充功能市集組織得非常完善,不會讓你在尋找所需工具時迷路。它設計用來幫助你發現特定工具,也有一些你之前沒察覺的酷東西!
**進入市集方式:**
1. 點選活動欄的擴充功能圖示 (🧩)
2. 瀏覽或搜尋特定功能
3. 點擊任何看起來有趣的項目,查看更多資訊
![Extension marketplace interface](../../../../translated_images/extensions.eca0e0c7f59a10b5.tw.png)
**你將看到的內容:**
| 區塊 | 內容 | 為何有用 |
|----------|---------|----------|
| **已安裝** | 你已添加的擴充功能 | 你的個人編程工具箱 |
| **熱門** | 大家喜愛的擴充功能 | 多數開發者推薦的工具 |
| **推薦** | 對你的專案有智慧推薦 | VSCode.dev 的貼心建議 |
**讓瀏覽更方便:**
- 每個擴充功能都會顯示評分、下載數及真實用戶評論
- 有截圖和清楚說明其功能
- 清楚標註相容性資訊
- 推薦相似擴充功能方便比對選擇
### 安裝擴充功能(超簡單!)
為你的編輯器添加新功能,只要點按一下。擴充功能幾秒鐘內安裝完成並立即生效 — 不需重啟或等待。
**你只需做這些:**
1. 搜尋你想要的功能(試試搜尋 "live server" 或 "prettier"
2. 點選看起來不錯的擴充功能,查看詳細資訊
3. 閱讀功能介紹並檢視評價
4. 按下藍色「安裝」按鈕,就完成了!
![Installing extensions](../../../../8-code-editor/images/install-extension.gif)
**幕後發生什麼:**
- 擴充功能自動下載並設定好
- 新功能立刻顯現在介面中
- 立即開始工作(真的這麼快!)
- 若你已登入,擴充功能會同步至所有裝置
**我推薦你先試試:**
- **Live Server**:邊寫程式碼邊看到網站實時更新(神奇!)
- **Prettier**:自動讓你的程式碼看起來乾淨又專業
- **Auto Rename Tag**:修改一個 HTML 標籤,夥伴標籤會自動配對改變
- **Bracket Pair Colorizer**:用顏色標示括號,讓你不迷失
- **GitLens**:大幅強化 Git 功能,提供豐富資訊
### 自訂你的擴充功能
多數擴充功能提供設定供你調整,使其完全符合你的需求。就像調整車座和後視鏡 — 每個人都有自己的喜好!
**調整擴充功能設定:**
1. 在擴充功能面板找到你已安裝的擴充功能
2. 找尋名稱旁的齒輪圖示 (⚙️) 點擊它
3. 從下拉選單選擇「擴充功能設定」
4. 調整設定直到符合你的工作流程需求
![Customizing extension settings](../../../../translated_images/extension-settings.21c752ae4f4cdb78.tw.png)
**常見你可能想調整的項目:**
- 程式碼格式化方式tab 或空格、行寬等等)
- 觸發不同功能的鍵盤快捷鍵
- 擴充功能應作用的檔案類型
- 開啟或關閉特定功能保持整潔
### 維持擴充功能的組織有序
當你發現更多酷炫擴充功能時想必會希望保持收藏乾淨且順暢運作。VSCode.dev 提供非常方便的管理方式。
**你的擴充功能管理選項:**
| 可操作項目 | 何時有用 | 專家小撇步 |
|--------|---------|----------|
| **停用** | 測試是否是擴充功能出錯 | 比卸載更方便,方便後續再啟用 |
| **卸載** | 完全移除不需要的擴充功能 | 保持環境乾淨且執行速度快 |
| **更新** | 獲得最新功能與修正 | 通常自動,但值得留意是否有更新 |
**我喜歡的管理作法:**
- 每隔數月檢視已安裝的擴充功能,移除不再使用的
- 保持擴充功能更新,獲取最新改良和安全修補
- 遇到速度變慢時暫時停用擴充功能,找出元凶
- 閱讀重大更新說明,有時會有超棒的新功能!
> ⚠️ **性能建議**:擴充功能很棒,但太多會拖慢速度。集中使用真正幫助你的擴充功能,不用怕刪除從未使用過的。
### 🎯 教學反思檢核:開發環境客製化
**架構理解**:你已學會使用社群製作的擴充功能,客製化專業的開發環境。這也反映企業開發團隊建立標準化工具鏈的作法。
**掌握的關鍵概念**
- **擴充功能發掘**:尋找可解決開發痛點的工具
- **環境設定**:依據個人或團隊喜好調整工具
- **效能優化**:在功能和系統效能間取得平衡
- **社群合作**:利用全球開發者創造的工具
**產業連結**:擴充功能生態系統是 VS Code、Chrome DevTools 及現代 IDE 等主要平臺的動力。懂得如何評估、安裝與設定擴充功能,是專業工作流程的基礎。
**反思問題**:你會怎麼為一組 10 人的開發團隊設置標準化開發環境?考慮一致性、效能以及個人偏好。
## 📈 你的雲端開發精通時間表
```mermaid
timeline
title 專業雲端開發旅程
section 平台基礎
Cloud Development Understanding
: 精通基於網頁的編輯概念
: 連接 GitHub 整合模式
: 操作專業介面
section 工作流程精通
File & Project Management
: 建立有組織的專案架構
: 精通語法高亮優點
: 處理多檔案編輯工作流程
Version Control Integration
: 理解 Git 視覺化
: 練習提交訊息標準
: 精通變更追蹤工作流程
section 環境自訂
Extension Ecosystem
: 探索生產力擴充功能
: 配置開發偏好設定
: 優化效能與功能
Professional Setup
: 建立一致的工作流程
: 建立可重用的設定
: 制定團隊標準
section 產業準備
Cloud-First Development
: 精通遠端開發實務
: 理解協作工作流程
: 建立跨平台技能
Professional Practices
: 遵循產業標準
: 創建可維護的工作流程
: 為團隊環境做好準備
```
**🎓 畢業里程碑**:你成功掌握了使用大型科技公司專業開發者相同工具和流程的雲端開發技能。這些技能代表軟體開發的未來。
**🔄 下一層能力:**
- 準備探索進階雲端開發平台Codespaces、GitPod
- 準備分散式開發團隊合作
- 有能力全球貢獻開源專案
- 為現代 DevOps 與持續整合奠定基礎
## GitHub Copilot Agent 挑戰 🚀
就像 NASA 執行太空任務的系統化方法,此挑戰要求你系統性地運用 VSCode.dev 技能完成完整工作流程。
**目標:** 以 Agent 模式協助下,展示你對 VSCode.dev 的熟練度,建立完善的網站開發工作流程。
**專案要求:** 使用代理模式完成以下任務:
1. 派生現有儲存庫或建立新儲存庫
2. 建立包含 HTML、CSS 及 JavaScript 檔案的功能性專案結構
3. 安裝並設定三個開發強化擴充功能
4. 使用有描述性的提交訊息實踐版本控管
5. 嘗試建立並修改功能分支
6. 在 README.md 文件中記錄過程及學習心得
此練習匯集了所有 VSCode.dev 概念,讓你應用於未來開發專案的實務工作流程中。
在此了解更多[agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
![Modify extension settings](../../../../8-code-editor/images/extension-settings)
## 作業
### 3. **管理擴充功能**
您可以:
是時候實戰一番!我有個親自操作的專案,讓你練習所有我們涵蓋的內容:[使用 VSCode.dev 製作履歷網站](./assignment.md)
- **停用:** 暫時關閉擴充功能但保留安裝
- **卸載:** 如果不再需要,永久移除擴充功能
此作業引導你在瀏覽器內建置專業履歷網站。你會用到所有我們探討過的 VSCode.dev 功能,結束時將擁有一個令人滿意的網站和紮實的工作流程信心。
找到擴充功能點擊齒輪圖示選擇DisableUninstall或使用程式碼區域中的藍色按鈕。
## 繼續探索並提升你的技能
***
你已有堅實基礎,但還有更多精彩等著你去發掘!這裡有些資源和想法,助你把 VSCode.dev 技能提升到下一階段:
## 作業
**官方文件推薦收藏:**
- [VSCode Web 文件](https://code.visualstudio.com/docs/editor/vscode-web?WT.mc_id=academic-0000-alfredodeza) — 瀏覽器編輯的完整指南
- [GitHub Codespaces](https://docs.github.com/en/codespaces) — 想要雲端更強大時的選擇
測試您的技能:[使用 vscode.dev 建立履歷網站](https://github.com/microsoft/Web-Dev-For-Beginners/blob/main/8-code-editor/1-using-a-code-editor/assignment.md)
**值得下一步試試的酷功能:**
- **鍵盤快捷鍵**:學會組合鍵,讓你變身編碼高手
- **工作區設定**:為不同類型專案設置獨立環境
- **多根目錄工作區**:同時在多個儲存庫工作(超方便!)
- **終端機整合**:直接在瀏覽器中使用命令列工具
***
**練習點子:**
- 加入開源專案,用 VSCode.dev 貢獻代碼 — 很好的回饋方式!
- 嘗試各種擴充功能,找到你的完美組合
- 為你常建置的網站類型製作專案範本
- 練習 Git 工作流程,如分支和合併 — 團隊合作中極為珍貴的技能
## 進一步探索與自學
---
- 深入了解 [官方 VSCode Web 文件](https://code.visualstudio.com/docs/editor/vscode-web?WT.mc_id=academic-0000-alfredodeza)。
- 探索進階工作區功能、鍵盤快捷鍵和設定。
**你已精通瀏覽器編程!** 🎉 就像便攜式儀器讓科學家能在偏遠地區進行研究VSCode.dev 讓你能從任何連網裝置進行專業程式設計。
***
這些技能反映當今產業實務 — 許多專業開發者使用雲端開發環境,因其彈性與可及性。你學到的工作流程可以從個人專案擴展至大型團隊合作。
**現在您已準備好使用 VSCode.dev 隨時隨地進行程式碼編輯、創建和協作!**
將這些技巧應用到你的下一個開發專案吧! 🚀
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的內容,但請注意,自動翻譯結果可能包含錯誤或不準確之處。原始文件的母語版本應視為具權威性的依據。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯內容而產生的任何誤解或誤譯負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,247 +1,591 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "bd3aa6d2b879c30ea496c43aec1c49ed",
"translation_date": "2025-08-29T15:27:56+00:00",
"original_hash": "effe56ba51c38d7bdfad1ea38288666b",
"translation_date": "2026-01-06T13:37:51+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/assignment.md",
"language_code": "tw"
}
-->
# 使用 vscode.dev 建立履歷網站
# 使用 VSCode.dev 建立履歷網站
_有沒有想過當招聘人員要求你的履歷時你可以直接給他們一個網址_ 😎
透過建立一個專業的履歷網站,以互動且現代化的方式展示你的技能與經驗,徹底改變你的職涯前景。想像一下,不再是傳統的 PDF而是提供給招募人員一個時尚且響應式的網站不僅展現你的資格也同時展現你的網頁開發能力。
## 目標
這個動手作業讓你將所有 VSCode.dev 技能付諸實踐,並打造出對你的職涯真正有用的東西。你將體驗完整的網頁開發工作流程——從建立程式庫到部署——全部都在瀏覽器中完成。
完成這項任務後,你將學會:
完成此專案後,你將擁有一個專業的線上形象,能輕鬆分享給潛在雇主,隨著技能成長隨時更新,並可自訂以符合你的個人品牌。這正是能展現實務網頁開發技能的理想專案。
- 建立一個網站來展示你的履歷
## 學習目標
### 先決條件
完成此作業後,你將能:
1. 一個 GitHub 帳戶。如果你還沒有帳戶,請前往 [GitHub](https://github.com/) 註冊。
- **使用 VSCode.dev** 創建並管理完整的網頁開發專案
- **使用語義化 HTML 元素** 結構化專業網站
- **使用現代 CSS 技術** 設計響應式佈局
- **運用基礎網頁技術** 實作互動功能
- **部署** 可透過分享連結存取的網站
- **示範版本控制最佳實踐**,貫穿開發流程
## 步驟
## 先備條件
**步驟 1** 建立一個新的 GitHub 儲存庫,並命名為 `my-resume`
開始本作業前,請確認你已具備:
**步驟 2** 在你的儲存庫中建立一個 `index.html` 文件。我們需要在 github.com 上至少新增一個文件,因為空的儲存庫無法在 vscode.dev 中打開。
- 一個 GitHub 帳號(如需建立,請至 [github.com](https://github.com/)
- 完成 VSCode.dev 介面導覽與基本操作課程
- 基本的 HTML 結構與 CSS 樣式概念
點擊 `creating a new file` 連結,輸入文件名稱 `index.html`,然後選擇 `Commit new file` 按鈕。
## 專案設定與程式庫建立
![在 github.com 上建立新文件](../../../../translated_images/new-file-github.com.c886796d800e8056561829a181be1382c5303da9d902d8b2dd82b68a4806e21f.tw.png)
讓我們先打造專案基礎。此流程與現實開發工作流程相符,從適當初始化程式庫和規劃專案結構開始。
**步驟 3** 打開 [VSCode.dev](https://vscode.dev),選擇 `Open Remote Repository` 按鈕。
### 步驟 1建立 GitHub 程式庫
複製你剛剛為履歷網站建立的儲存庫網址,並將其貼到輸入框中:
設立專屬儲存庫可確保專案從一開始就具備良好的組織與版本控制。
_將 `your-username` 替換為你的 GitHub 使用者名稱_
1. **前往** [GitHub.com](https://github.com) 並登入帳號
2. **點擊** 右上角綠色「New」按鈕或「+」圖示
3. **命名** 你的程式庫為 `my-resume`(或依個人喜好,如 `john-smith-resume`
4. **新增** 簡短描述:「以 HTML 與 CSS 建立的專業履歷網站」
5. **選擇** 公開Public使履歷網頁對潛在雇主可見
6. **勾選** 「Add a README file」創建專案初始說明檔
7. **點擊** 「Create repository」完成設定
> 💡 **儲存庫命名小撇步**:使用描述性且專業的名稱,明確指出專案用途,有助於分享給雇主或作品集檢視。
### 步驟 2初始化專案結構
因為 VSCode.dev 至少要有一個檔案才能開啟專案,我們先在 GitHub 上直接建立主要 HTML 檔。
1. 在新建立的程式庫中,**點擊**「creating a new file」連結
2. **輸入** 檔名為 `index.html`
3. **新增** 以下初始 HTML 結構:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Name - Professional Resume</title>
</head>
<body>
<h1>Your Name</h1>
<p>Professional Resume Website</p>
</body>
</html>
```
https://github.com/your-username/my-resume
```
✅ 如果成功,你將在瀏覽器中的文字編輯器看到你的專案和 `index.html` 文件。
4. **填寫** commit 訊息「Add initial HTML structure」
5. **點擊**「Commit new file」儲存變更
![在 GitHub 建立初始檔案](../../../../translated_images/new-file-github.com.c886796d800e8056.tw.png)
**這個初始設定完成了:**
- **建立** 正確的 HTML5 文件結構並使用語義元素
- **包含** viewport meta 標籤支援響應式設計
- **設定** 可在瀏覽器分頁顯示的描述性頁面標題
- **奠定** 專業內容組織基礎
## 在 VSCode.dev 中工作
程式庫基礎建立後,接著切換到 VSCode.dev 進行主要開發工作。這款網頁版編輯器提供專業網頁開發所需的所有工具。
### 步驟 3在 VSCode.dev 開啟專案
1. **在新分頁** 開啟 [vscode.dev](https://vscode.dev)
2. **在歡迎畫面點選**「Open Remote Repository」
3. **從 GitHub 複製** 程式庫網址並貼上輸入框
格式:`https://github.com/your-username/my-resume`
*將 `your-username` 替換成你的 GitHub 使用者名稱*
4. **按下 Enter 載入專案**
**成功指標**:你將在 Explorer 側欄看到專案檔案,並在主編輯區可以編輯 `index.html`
![VSCode.dev 中載入專案](../../../../translated_images/project-on-vscode.dev.e79815a9a95ee7fe.tw.png)
![在 vscode.dev 中打開專案](../../../../translated_images/project-on-vscode.dev.e79815a9a95ee7feac72ebe5c941c91279716be37c575dbdbf2f43bea2c7d8b6.tw.png)
**介面會顯示:**
- **Explorer 側欄****呈現** 程式庫檔案與資料夾結構
- **編輯區****顯示** 選取檔案內容供編輯
- **活動列****提供** 原始碼控管與擴充功能
- **狀態列****顯示** 連線狀態與目前分支資訊
**步驟 4** 打開 `index.html` 文件,將以下代碼貼到你的代碼區域並保存。
### 步驟 4構建履歷內容
`index.html` 中的範例內容替換為完整的履歷結構。此 HTML 是專業履歷呈現的基礎。
<details>
<summary><b>HTML 代碼負責履歷網站的內容。</b></summary>
<summary><b>完整 HTML 履歷結構</b></summary>
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<title>Your Name - Professional Resume</title>
</head>
<body>
<header id="header">
<h1>Your Full Name</h1>
<hr>
<p class="role">Your Professional Title</p>
<hr>
</header>
<html>
<head>
<link href="style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<title>你的名字在這裡!</title>
</head>
<body>
<header id="header">
<!-- 履歷標題,包含你的名字和職稱 -->
<h1>你的名字在這裡!</h1>
<hr>
你的角色!
<hr>
</header>
<main>
<article id="mainLeft">
<section>
<h2>聯絡方式</h2>
<!-- 聯絡資訊,包括社交媒體 -->
<p>
<i class="fa fa-envelope" aria-hidden="true"></i>
<a href="mailto:username@domain.top-level domain">在這裡填寫你的電子郵件</a>
</p>
<p>
<i class="fab fa-github" aria-hidden="true"></i>
<a href="github.com/yourGitHubUsername">在這裡填寫你的 GitHub 使用者名稱!</a>
</p>
<p>
<i class="fab fa-linkedin" aria-hidden="true"></i>
<a href="linkedin.com/yourLinkedInUsername">在這裡填寫你的 LinkedIn 使用者名稱!</a>
</p>
</section>
<section>
<h2>技能</h2>
<!-- 你的技能 -->
<ul>
<li>技能 1</li>
<li>技能 2</li>
<li>技能 3</li>
<li>技能 4</li>
</ul>
</section>
<section>
<h2>教育背景</h2>
<!-- 你的教育背景 -->
<h3>在這裡填寫你的課程!</h3>
<p>
在這裡填寫你的學校名稱!
</p>
<p>
開始日期 - 結束日期
</p>
</section>
</article>
<article id="mainRight">
<section>
<h2>關於我</h2>
<!-- 關於你的簡介 -->
<p>在這裡寫一些關於自己的簡介!</p>
</section>
<section>
<h2>工作經驗</h2>
<!-- 你的工作經驗 -->
<h3>職位名稱</h3>
<p>
在這裡填寫公司名稱 | 開始月份 結束月份
</p>
<ul>
<li>任務 1 - 在這裡填寫你做了什麼!</li>
<li>任務 2 - 在這裡填寫你做了什麼!</li>
<li>在這裡填寫你的貢獻成果/影響</li>
</ul>
<h3>職位名稱 2</h3>
<p>
在這裡填寫公司名稱 | 開始月份 結束月份
</p>
<ul>
<li>任務 1 - 在這裡填寫你做了什麼!</li>
<li>任務 2 - 在這裡填寫你做了什麼!</li>
<li>在這裡填寫你的貢獻成果/影響</li>
</ul>
</section>
</article>
</main>
</body>
</html>
<main>
<article id="mainLeft">
<section>
<h2>CONTACT</h2>
<p>
<i class="fa fa-envelope" aria-hidden="true"></i>
<a href="mailto:your.email@domain.com">your.email@domain.com</a>
</p>
<p>
<i class="fab fa-github" aria-hidden="true"></i>
<a href="https://github.com/your-username">github.com/your-username</a>
</p>
<p>
<i class="fab fa-linkedin" aria-hidden="true"></i>
<a href="https://linkedin.com/in/your-profile">linkedin.com/in/your-profile</a>
</p>
</section>
<section>
<h2>SKILLS</h2>
<ul>
<li>HTML5 & CSS3</li>
<li>JavaScript (ES6+)</li>
<li>Responsive Web Design</li>
<li>Version Control (Git)</li>
<li>Problem Solving</li>
</ul>
</section>
<section>
<h2>EDUCATION</h2>
<h3>Your Degree or Certification</h3>
<p>Institution Name</p>
<p>Start Date - End Date</p>
</section>
</article>
<article id="mainRight">
<section>
<h2>ABOUT</h2>
<p>Write a compelling summary that highlights your passion for web development, key achievements, and career goals. This section should give employers insight into your personality and professional approach.</p>
</section>
<section>
<h2>WORK EXPERIENCE</h2>
<div class="job">
<h3>Job Title</h3>
<p class="company">Company Name | Start Date End Date</p>
<ul>
<li>Describe a key accomplishment or responsibility</li>
<li>Highlight specific skills or technologies used</li>
<li>Quantify impact where possible (e.g., "Improved efficiency by 25%")</li>
</ul>
</div>
<div class="job">
<h3>Previous Job Title</h3>
<p class="company">Previous Company | Start Date End Date</p>
<ul>
<li>Focus on transferable skills and achievements</li>
<li>Demonstrate growth and learning progression</li>
<li>Include any leadership or collaboration experiences</li>
</ul>
</div>
</section>
<section>
<h2>PROJECTS</h2>
<div class="project">
<h3>Project Name</h3>
<p>Brief description of what the project accomplishes and technologies used.</p>
<a href="#" target="_blank">View Project</a>
</div>
</section>
</article>
</main>
</body>
</html>
```
</details>
將你的履歷細節替換掉 HTML 代碼中的 _佔位文字_
**自訂建議:**
- **替換** 所有預留文字為你的真實資訊
- **依經驗與職涯重點** 調整章節內容
- **加入或刪除** 章節(例如:證照、志工經驗、語言能力)
- **包含** 實際的個人連結和專案展示
### 步驟 5建立支援檔案
**步驟 5** 將滑鼠移到 My-Resume 資料夾上,點擊 `New File ...` 圖標,並在你的專案中建立兩個新文件:`style.css` 和 `codeswing.json`
專業網站需要有組織的檔案結構。創建 CSS 樣式表與設定檔以完成專案
**步驟 6** 打開 `style.css` 文件,將以下代碼貼上並保存。
1. **將滑鼠停留** 在 Explorer 側欄的專案資料夾名稱上
2. **點擊** 出現的「新增檔案」圖示(📄+
3. **依序建立** 這些檔案:
- `style.css`(負責樣式與佈局)
- `codeswing.json`(用於預覽擴充設定)
**建立 CSS 樣式檔 (`style.css`)**
<details>
<summary><b>CSS 代碼負責網站的佈局格式。</b></summary>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 16px;
max-width: 960px;
margin: auto;
}
h1 {
font-size: 3em;
letter-spacing: .6em;
padding-top: 1em;
padding-bottom: 1em;
}
h2 {
font-size: 1.5em;
padding-bottom: 1em;
}
h3 {
font-size: 1em;
padding-bottom: 1em;
}
main {
display: grid;
grid-template-columns: 40% 60%;
margin-top: 3em;
}
header {
text-align: center;
margin: auto 2em;
}
section {
margin: auto 1em 4em 2em;
}
i {
margin-right: .5em;
}
p {
margin: .2em auto
}
hr {
border: none;
background-color: lightgray;
height: 1px;
}
h1, h2, h3 {
font-weight: 100;
margin-bottom: 0;
}
#mainLeft {
border-right: 1px solid lightgray;
}
<summary><b>專業 CSS 樣式</b></summary>
```css
/* Modern Resume Styling */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 16px;
line-height: 1.6;
max-width: 960px;
margin: 0 auto;
padding: 20px;
color: #333;
background-color: #f9f9f9;
}
/* Header Styling */
header {
text-align: center;
margin-bottom: 3em;
padding: 2em;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 3em;
letter-spacing: 0.1em;
margin-bottom: 0.2em;
font-weight: 300;
}
.role {
font-size: 1.3em;
font-weight: 300;
margin: 1em 0;
}
/* Main Content Layout */
main {
display: grid;
grid-template-columns: 35% 65%;
gap: 3em;
margin-top: 3em;
background: white;
padding: 2em;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* Typography */
h2 {
font-size: 1.4em;
font-weight: 600;
margin-bottom: 1em;
color: #667eea;
border-bottom: 2px solid #667eea;
padding-bottom: 0.3em;
}
h3 {
font-size: 1.1em;
font-weight: 600;
margin-bottom: 0.5em;
color: #444;
}
/* Section Styling */
section {
margin-bottom: 2.5em;
}
#mainLeft {
border-right: 1px solid #e0e0e0;
padding-right: 2em;
}
/* Contact Links */
section a {
color: #667eea;
text-decoration: none;
transition: color 0.3s ease;
}
section a:hover {
color: #764ba2;
text-decoration: underline;
}
/* Icons */
i {
margin-right: 0.8em;
width: 20px;
text-align: center;
color: #667eea;
}
/* Lists */
ul {
list-style: none;
padding-left: 0;
}
li {
margin: 0.5em 0;
padding: 0.3em 0;
position: relative;
}
li:before {
content: "▸";
color: #667eea;
margin-right: 0.5em;
}
/* Work Experience */
.job, .project {
margin-bottom: 2em;
padding-bottom: 1.5em;
border-bottom: 1px solid #f0f0f0;
}
.company {
font-style: italic;
color: #666;
margin-bottom: 0.5em;
}
/* Responsive Design */
@media (max-width: 768px) {
main {
grid-template-columns: 1fr;
gap: 2em;
}
#mainLeft {
border-right: none;
border-bottom: 1px solid #e0e0e0;
padding-right: 0;
padding-bottom: 2em;
}
h1 {
font-size: 2.2em;
}
body {
padding: 10px;
}
}
/* Print Styles */
@media print {
body {
background: white;
color: black;
font-size: 12pt;
}
header {
background: none;
color: black;
box-shadow: none;
}
main {
box-shadow: none;
}
}
```
</details>
**步驟 6** 打開 `codeswing.json` 文件,將以下代碼貼上並保存。
**建立設定檔 (`codeswing.json`)**
{
```json
{
"scripts": [],
"styles": []
}
}
```
**CSS 特性說明:**
- **採用** CSS Grid 打造響應式、專業版面結構
- **實作** 現代漸層配色的頁首設計
- **包含** 滑鼠懸停效果與平滑過渡互動體驗
- **提供** 適用各種裝置尺寸的韌性設計
- **添加** 友善列印的樣式方便產生 PDF
### 步驟 6安裝與設定擴充功能
擴充功能能提升開發體驗如即時預覽與流程優化。CodeSwing 擴充是網頁專案的實用工具。
**安裝 CodeSwing 擴充:**
1. **點擊** 活動列的擴充功能圖示(🧩)
2. **在市場搜尋框** 輸入「CodeSwing」
3. **在結果中選擇** CodeSwing 擴充
4. **點擊** 藍色「Install」按鈕安裝
![安裝 CodeSwing 擴充](../../../../8-code-editor/images/install-extension.gif)
**CodeSwing 可提供:**
- **即時預覽**,編輯時同步顯示網站變更
- **無需手動重新整理**,即時反映內容修改
- **支援多檔案格式**,含 HTML、CSS、JavaScript
- **整合開發環境** 預覽體驗
**安裝後立即呈現成果:**
CodeSwing 安裝完成後,你會在編輯器看到履歷網站的即時預覽,能直接觀看網站實際效果。
**步驟 7** 安裝 `Codeswing 擴展` 以在代碼區域中預覽履歷網站。
![CodeSwing 擴充即時預覽](../../../../translated_images/after-codeswing-extension-pb.0ebddddcf73b5509.tw.png)
點擊活動欄上的 _`Extensions`_ 圖標,輸入 Codeswing。點擊擴展活動欄上的 _藍色安裝按鈕_ 或在選擇擴展後出現的代碼區域安裝按鈕來安裝。安裝擴展後,觀察你的代碼區域,看看專案的變化 😃
**加強版介面說明:**
- **分割視窗**:同時呈現程式碼與實時預覽
- **即時更新**:輸入時變更立刻反映
- **互動預覽**:可測試連結與互動功能
- **行動裝置模擬**:便於測試響應式設計
![安裝擴展](../../../../8-code-editor/images/install-extension.gif)
### 步驟 7版本控制與發佈
安裝擴展後,你的螢幕上將看到以下內容。
履歷網站完成後,使用 Git 提交你的工作,並讓他人能在線上存取
![Codeswing 擴展效果](../../../../translated_images/after-codeswing-extension-pb.0ebddddcf73b550994947a9084e35e2836c713ae13839d49628e3c764c1cfe83.tw.png)
**提交變更:**
如果你對所做的更改感到滿意,將滑鼠移到 `Changes` 資料夾上,點擊 `+` 按鈕以暫存更改。
1. **點擊** 活動列的原始碼控管圖示(🌿)
2. **檢視**「變更」區塊的所有新增與修改檔案
3. **分別點擊** 每個檔案旁的「+」圖示加入暫存區
4. **輸入** 描述性提交訊息,例如:
- 「Add complete resume website with responsive design」
- 「Implement professional styling and content structure」
5. **點擊** 右上勾選符號 (✓) 送出並推送變更
輸入提交訊息 _(描述你對專案所做的更改)_,並點擊 `check` 提交更改。完成專案後,選擇左上角的漢堡菜單圖標返回 GitHub 上的儲存庫。
**高效提交訊息示例:**
- 「Add professional resume content and styling」
- 「Implement responsive design for mobile compatibility」
- 「Update contact information and project links」
恭喜 🎉 你已經使用 vscode.dev 在幾個步驟內建立了你的履歷網站。
> 💡 **專業提示**:良好提交訊息有助於追蹤專案進展,也展示細節把控,是雇主重視的品質
## 🚀 挑戰
**存取你的線上網站:**
提交後,利用左上角漢堡選單 (☰) 回到 GitHub 程式庫。你的履歷網站已受版本控制,隨時可部署或分享。
打開一個你有權限進行更改的遠端儲存庫,更新一些文件。接下來,嘗試建立一個包含更改的新分支並提交 Pull Request。
## 結果與後續步驟
## 回顧與自學
**恭喜!🎉** 你已成功使用 VSCode.dev 建立專業履歷網站。你的專案展現了:
**示範的技術能力:**
- **程式庫管理**:建立完備專案結構與組織
- **網頁開發**:使用現代 HTML5 及 CSS3 建立響應式網站
- **版本控制**:落實符合標準流程且具意義的提交
- **工具熟練**:有效運用 VSCode.dev 介面及擴充系統
**達成的職業成果:**
- **網路形象**:具有可分享的網址展現專業資格
- **現代格式**:取代傳統 PDF 的互動式替代方案
- **技能證明**:具體展現你的網頁開發實力
- **輕鬆更新**:建立可持續改良與客製化的基礎
### 部署選項
讓你的履歷能被雇主輕鬆存取,請考慮以下托管方案:
**GitHub Pages推薦**
1. 進入 GitHub 程式庫設定Settings
2. 向下滾動到「Pages」區塊
3. 選擇「Deploy from a branch」並選擇「main」
4. 網站即會透過 `https://your-username.github.io/my-resume` 上線
**其他替代平台:**
- **Netlify**:自動部署並支援自訂網域
- **Vercel**:快速部署及現代化主機解決方案
- **GitHub Codespaces**:內建預覽的雲端開發環境
### 強化建議
持續發展你的技能,可考慮新增這些功能:
**技術升級:**
- **JavaScript 互動功能**:增加順暢滾動或動態元素
- **深色模式切換器**:實作主題更換功能以符合使用者偏好
- **聯絡表單**:開啟潛在雇主直接聯繫通路
- **SEO 優化**:加入 meta 標籤與結構化資料提升搜尋曝光度
**內容提升:**
- **專案作品集**:連結 GitHub 倉庫與線上示範
- **技能視覺化**:製作進度條或技能評分系統
- **推薦語區塊**:收錄同事或教師的推薦內容
- **部落格整合**:新增部落格展示學習歷程
## GitHub Copilot Agent 挑戰 🚀
運用 Agent 模式完成以下挑戰:
**描述:** 強化你的履歷網站,加入展現專業網頁開發能力與現代設計理念的進階功能。
**提示:** 在現有履歷網站基礎上,實作這些進階功能:
1. 增加深色/淺色主題切換並配合平滑過渡
2. 製作互動式技能區段,包含動畫進度條
3. 實作帶有表單驗證的聯絡表單
4. 新增專案作品集區,包含懸停效果與模態彈窗
5. 加入至少三篇部落格文章,分享你的學習旅程
6. 進行 SEO 優化,包括適當 meta 標籤、結構化資料與效能調校
7. 使用 GitHub Pages 或 Netlify 部署強化後網站
8. 在 README.md 中加入所有新增功能說明與截圖
你的增強網站應展現現代網頁開發技術包括響應式設計、JavaScript 互動功能與專業部署流程。
## 挑戰延伸
想挑戰更高難度?嘗試以下進階挑戰:
**📱 行動優先重構:** 使用 CSS Grid 與 Flexbox 徹底以行動裝置優先方式重建網站
**🔍 SEO 優化:** 完整實作 SEO包括 meta 標籤、結構化資料與效能提升
**🌐 多語系支援:** 加入國際化功能,支援多種語言呈現
**📊 分析整合:** 加入 Google Analytics 追蹤訪客行為與優化內容
**🚀 效能優化:** 全面達成 Lighthouse 各項目滿分
## 複習與自學
擴展你的知識,參考下列資源:
**進階 VSCode.dev 功能:**
- [VSCode.dev 文件](https://code.visualstudio.com/docs/editor/vscode-web?WT.mc_id=academic-0000-alfredodeza) - 全面導覽網頁版編輯
- [GitHub Codespaces](https://docs.github.com/en/codespaces) - 雲端開發環境說明
**網頁開發最佳實踐:**
- **響應式設計**:深入學習 CSS Grid 與 Flexbox 現代布局技術
- **無障礙設計**:學習 WCAG 指南以實現包容性網頁設計
- **效能**:探索 Lighthouse 等工具以進行優化
- **SEO**:了解搜尋引擎優化基本原則
**專業發展:**
- **作品集建立**:創建更多專案以展示多元技能
- **開源貢獻**:參與現有專案以獲取協作經驗
- **社群交流**:在開發者社群分享你的履歷網站以獲得反饋
- **持續學習**:保持對網頁開發趨勢和技術的更新
---
閱讀更多關於 [VSCode.dev](https://code.visualstudio.com/docs/editor/vscode-web?WT.mc_id=academic-0000-alfredodeza) 及其其他功能的資訊。
**你的下一步:** 與朋友、家人或導師分享你的履歷網站以獲得反饋。利用他們的建議反覆調整並改進你的設計。請記住,這個專案不只是履歷——它是你作為網頁開發者成長的展現!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們力求準確,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們不對因使用此翻譯而產生的任何誤解或誤釋承擔責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because it is too large Load Diff

@ -1,15 +1,15 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "537f02a36d73db093cbb8b9b44867645",
"translation_date": "2025-09-01T15:46:27+00:00",
"original_hash": "0aaa930f076f2d83cc872ad157f8ffd3",
"translation_date": "2026-01-06T14:29:33+00:00",
"source_file": "9-chat-project/solution/backend/python/README.md",
"language_code": "tw"
}
-->
# 執行程式碼
## 設環境
## 設環境
建立虛擬環境
@ -18,23 +18,31 @@ python -m venv venv
source ./venv/bin/activate
```
## 安裝依賴項
## 安裝相依性
```sh
pip install openai flask flask-cors
pip install openai fastapi uvicorn python-dotenv
```
## 啟動 API
## 執行 API
```sh
# 方法一:直接執行
python api.py
# 方法二:使用 uvicorn
uvicorn api:app --host 0.0.0.0 --port 5000 --reload
```
## 啟動前端
## 測試 API
造訪互動式 API 文件:`http://localhost:5000/docs`
## 執行前端
確保你位於前端資料夾中
請確認您位於 frontend 資料夾中
找到 *app.js*,將 `BASE_URL` 更改為你的後端 URL
找到 *app.js*,將 `BASE_URL` 改為您的後端 URL
執行它
@ -42,13 +50,15 @@ python api.py
npx http-server -p 8000
```
嘗試在聊天中輸入訊息,你應該會看到回應(前提是你在 Codespace 中執行此操作或已設置存取權杖)。
嘗試在聊天中輸入訊息,您應該會看到回應(前提是您在 Codespace 執行此程式或已設定了存取權杖)。
## 設置存取權杖(如果你不是在 Codespace 中執行)
## 設定存取權杖(如果您不是在 Codespace 執行)
請參閱 [設置 PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
請參考 [設定 PAT](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或誤釋負任何責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,8 +1,8 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "caf2ca695e9d259153d24a5cf3e07ef5",
"translation_date": "2025-10-11T10:52:28+00:00",
"original_hash": "fea3a0fceb8ad86fd640c09cf63a2aac",
"translation_date": "2026-01-06T13:17:17+00:00",
"source_file": "README.md",
"language_code": "tw"
}
@ -17,220 +17,259 @@ CO_OP_TRANSLATOR_METADATA:
[![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-Beginners.svg?style=social&label=Fork&maxAge=2592000)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/network/)
[![GitHub stars](https://img.shields.io/github/stars/microsoft/Web-Dev-For-Beginners.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/stargazers/)
[![](https://dcbadge.vercel.app/api/server/ByRwuEEgH4)](https://discord.gg/zxKYvhSnVp?WT.mc_id=academic-000002-leestott)
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
# 初學者的網頁開發課程 - 一套完整的教學計畫
# Web Development for Beginners - 課程大綱
透過 Microsoft Cloud Advocates 提供的 12 週完整課程,學習網頁開發的基礎知識。課程包含 24 節課,透過實作專案如生態瓶、瀏覽器擴充功能及太空遊戲,深入學習 JavaScript、CSS 和 HTML。課程還包含測驗、討論及實際作業幫助你提升技能並加強知識記憶。立即開始你的程式設計旅程吧
透過 Microsoft 雲端宣導者精心策劃的為期十二週綜合課程學習網頁開發的基礎知識。24 節課程深入探討 JavaScript、CSS 與 HTML並透過實作專案如生態瓶、瀏覽器擴充功能和太空遊戲培養動手能力。積極參與小測驗、討論與實務作業。利用我們高效的專案導向教學法提升技能並優化知識保留。立即開始你的程式設計旅程
加入 Azure AI Foundry Discord 社群
[![Microsoft Azure AI Foundry Discord](https://dcbadge.limes.pink/api/server/ByRwuEEgH4)](https://discord.com/invite/ByRwuEEgH4)
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
按照以下步驟開始使用這些資源:
1. **Fork 儲存庫**:點擊 [![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/fork)
2. **Clone 儲存庫** `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
3. [**加入 Azure AI Foundry Discord與專家及其他開發者交流**](https://discord.com/invite/ByRwuEEgH4)
遵循以下步驟開始使用這些資源:
1. **派生此儲存庫**:點擊 [![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/fork)
2. **複製儲存庫** `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
3. [**加入 Azure AI Foundry Discord與專家及開發者交流**](https://discord.com/invite/ByRwuEEgH4)
### 🌐 多語言支援
#### 透過 GitHub Action 支援(自動化且隨時保持最新)
#### 透過 GitHub Action 支援 (自動且隨時更新)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START -->
[阿拉伯文](../ar/README.md) | [孟加拉文](../bn/README.md) | [保加利亞文](../bg/README.md) | [緬甸文](../my/README.md) | [簡體中文](../zh/README.md) | [繁體中文(香港)](../hk/README.md) | [繁體中文(澳門)](../mo/README.md) | [繁體中文(台灣)](./README.md) | [克羅埃西亞文](../hr/README.md) | [捷克文](../cs/README.md) | [丹麥文](../da/README.md) | [荷蘭文](../nl/README.md) | [愛沙尼亞文](../et/README.md) | [芬蘭文](../fi/README.md) | [法文](../fr/README.md) | [德文](../de/README.md) | [希臘文](../el/README.md) | [希伯來文](../he/README.md) | [印地文](../hi/README.md) | [匈牙利文](../hu/README.md) | [印尼文](../id/README.md) | [義大利文](../it/README.md) | [日文](../ja/README.md) | [韓文](../ko/README.md) | [立陶宛文](../lt/README.md) | [馬來文](../ms/README.md) | [馬拉地文](../mr/README.md) | [尼泊爾文](../ne/README.md) | [挪威文](../no/README.md) | [波斯文](../fa/README.md) | [波蘭文](../pl/README.md) | [葡萄牙文(巴西)](../br/README.md) | [葡萄牙文(葡萄牙)](../pt/README.md) | [旁遮普文](../pa/README.md) | [羅馬尼亞文](../ro/README.md) | [俄文](../ru/README.md) | [塞爾維亞文(西里爾字母)](../sr/README.md) | [斯洛伐克文](../sk/README.md) | [斯洛維尼亞文](../sl/README.md) | [西班牙文](../es/README.md) | [斯瓦希里文](../sw/README.md) | [瑞典文](../sv/README.md) | [他加祿文(菲律賓)](../tl/README.md) | [泰米爾文](../ta/README.md) | [泰文](../th/README.md) | [土耳其文](../tr/README.md) | [烏克蘭文](../uk/README.md) | [烏爾都文](../ur/README.md) | [越南文](../vi/README.md)
[阿拉伯文](../ar/README.md) | [孟加拉文](../bn/README.md) | [保加利亞文](../bg/README.md) | [緬甸文 (Myanmar)](../my/README.md) | [中文 (簡體)](../zh/README.md) | [中文 (繁體, 香港)](../hk/README.md) | [中文 (繁體, 澳門)](../mo/README.md) | [中文 (繁體, 台灣)](./README.md) | [克羅地亞文](../hr/README.md) | [捷克文](../cs/README.md) | [丹麥文](../da/README.md) | [荷蘭文](../nl/README.md) | [愛沙尼亞文](../et/README.md) | [芬蘭文](../fi/README.md) | [法文](../fr/README.md) | [德文](../de/README.md) | [希臘文](../el/README.md) | [希伯來文](../he/README.md) | [印地文](../hi/README.md) | [匈牙利文](../hu/README.md) | [印尼文](../id/README.md) | [義大利文](../it/README.md) | [日文](../ja/README.md) | [坎納達文](../kn/README.md) | [韓文](../ko/README.md) | [立陶宛文](../lt/README.md) | [馬來文](../ms/README.md) | [馬拉雅拉姆文](../ml/README.md) | [馬拉地文](../mr/README.md) | [尼泊爾文](../ne/README.md) | [奈及利亞皮欽文](../pcm/README.md) | [挪威文](../no/README.md) | [波斯文 (Farsi)](../fa/README.md) | [波蘭文](../pl/README.md) | [葡萄牙文 (巴西)](../br/README.md) | [葡萄牙文 (葡萄牙)](../pt/README.md) | [旁遮普文 (Gurmukhi)](../pa/README.md) | [羅馬尼亞文](../ro/README.md) | [俄文](../ru/README.md) | [塞爾維亞文 (西里爾字母)](../sr/README.md) | [斯洛伐克文](../sk/README.md) | [斯洛維尼亞文](../sl/README.md) | [西班牙文](../es/README.md) | [斯瓦希里文](../sw/README.md) | [瑞典文](../sv/README.md) | [塔加洛語 (菲律賓語)](../tl/README.md) | [泰米爾文](../ta/README.md) | [泰盧固文](../te/README.md) | [泰文](../th/README.md) | [土耳其文](../tr/README.md) | [烏克蘭文](../uk/README.md) | [烏爾都文](../ur/README.md) | [越南文](../vi/README.md)
> **喜歡在本地端複製嗎?**
> 本儲存庫包含 50 多種語言翻譯會大幅增加下載大小。若要不下載翻譯檔案請使用稀疏簽出sparse checkout
> ```bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/Web-Dev-For-Beginners.git
> cd Web-Dev-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
> ```
> 如此即可用更快速的速度下載,並取得完成課程所需的所有內容。
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
**如果希望支援更多語言,請參考 [此處](https://github.com/Azure/co-op-translator/blob/main/getting_started/supported-languages.md)**
**若您希望支援更多翻譯語言,請參考此處列出的語言:[here](https://github.com/Azure/co-op-translator/blob/main/getting_started/supported-languages.md)**
[![Open in Visual Studio Code](https://img.shields.io/static/v1?logo=visualstudiocode&label=&message=Open%20in%20Visual%20Studio%20Code&labelColor=2c2c32&color=007acc&logoColor=007acc)](https://open.vscode.dev/microsoft/Web-Dev-For-Beginners)
#### 🧑‍🎓 _你是學生嗎_
造訪 [**學生中心頁面**](https://docs.microsoft.com/learn/student-hub/?WT.mc_id=academic-77807-sagibbon),在這裡你可以找到初學者資源、學生套件,甚至有機會獲得免費證書兌換券。這是你值得收藏並定期查看的頁面,因為我們每月都會更新內容。
請造訪 [**學生專區頁面**](https://docs.microsoft.com/learn/student-hub/?WT.mc_id=academic-77807-sagibbon),這裡提供入門資源、學生包,甚至還有獲得免費證書優惠券的方法。這是你應該加入書籤並不時回訪的頁面,我們每月都會更新內容。
### 📣 公告 - 新增 GitHub Copilot Agent 模式挑戰!
新增挑戰請於多數章節中尋找「GitHub Copilot Agent Challenge 🚀」。這是一項全新挑戰,讓你使用 GitHub Copilot 與 Agent 模式完成。如果你以前沒用過 Agent 模式,它不僅能生成文字,也可以創建和編輯檔案、執行指令等功能。
### 📣 公告 - _使用生成式 AI 建立新專案_
### 📣 公告 - _新增利用生成式 AI 建置的專案_
新增了 AI 助理專案,快來看看 [專案](./09-chat-project/README.md)
AI 助理專案剛加入,請查看 [project](./9-chat-project/README.md)
### 📣 公告 - _新課程_ 關於 JavaScript 的生成式 AI 已正式推出
### 📣 公告 - _全新 JavaScript 生成式 AI 課程剛發布_
不要錯過我們的生成式 AI 課程!
不要錯過我們全新的生成式 AI 課程!
造訪 [https://aka.ms/genai-js-course](https://aka.ms/genai-js-course) 開始學習!
![Background](../../translated_images/background.148a8d43afde57303419a663f50daf586681bc2fabf833f66ef6954073983c66.tw.png)
![Background](../../translated_images/background.148a8d43afde5730.tw.png)
- 課程涵蓋從基礎到 RAG 的所有內容
- 使用生成式 AI 和我們的配套應用程式與歷史人物互動。
- 有趣且引人入勝的故事情節,帶你穿越時空
- 授課內容涵蓋從基礎至 RAG
- 使用生成式 AI 與我們的伴隨應用程式與歷史人物互動。
- 有趣且引人入勝的敘事,你會穿越時光
![character](../../translated_images/character.5c0dd8e067ffd693c16e2c5b7412ab075a2215ce31f998305639fa3a05e14fbe.tw.png)
![character](../../translated_images/character.5c0dd8e067ffd693.tw.png)
節課都包含作業、知識檢測及挑戰,幫助你學習以下主題
- 提示設計及提示工程
- 文本及圖像應用程式生成
- 搜應用程式
堂課皆含作業、知識測驗及挑戰,引導你學習
- 提示語和提示工程
- 文字與圖像應用程式生成
- 搜應用程式
造訪 [https://aka.ms/genai-js-course](../../[https:/aka.ms/genai-js-course) 開始學習!
## 🌱 開始使用
> **教師們**,我們已 [提供一些建議](for-teachers.md) 關於如何使用這套課程。我們期待在 [討論論壇](https://github.com/microsoft/Web-Dev-For-Beginners/discussions/categories/teacher-corner) 中收到您的回饋!
**[學習者](https://aka.ms/student-page/?WT.mc_id=academic-77807-sagibbon)**,每節課都從課前測驗開始,接著閱讀課程內容,完成各種活動,並透過課後測驗檢查你的理解程度。
## 🌱 入門指南
為了提升學習效果,與同儕一起合作完成專案吧!我們鼓勵在 [討論論壇](https://github.com/microsoft/Web-Dev-For-Beginners/discussions) 中進行交流,我們的版主團隊會在那裡回答你的問題。
> **教師們**,我們已在 [包含了一些建議](for-teachers.md) 關於如何使用此課程。歡迎你在 [討論區](https://github.com/microsoft/Web-Dev-For-Beginners/discussions/categories/teacher-corner) 分享你的回饋!
為了進一步提升你的教育水平,我們強烈建議探索 [Microsoft Learn](https://learn.microsoft.com/users/wirelesslife/collections/p1ddcy5jwy0jkm?WT.mc_id=academic-77807-sagibbon) 以獲取更多學習資源
**[學習者](https://aka.ms/student-page/?WT.mc_id=academic-77807-sagibbon)**,每堂課開始前請先完成課前小測驗,再閱讀課程內容,完成各種活動,最後用課後小測驗檢驗你的理解
### 📋 設置你的環境
為了提升學習效果,建議你與同儕一同合作完成專案!請善用我們的 [討論區](https://github.com/microsoft/Web-Dev-For-Beginners/discussions),這裡有專門的版主團隊隨時回答你的問題。
這套課程已準備好開發環境!你可以選擇在 [Codespace](https://github.com/features/codespaces/)(基於瀏覽器,無需安裝的環境)中運行課程,或在本地電腦上使用像 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 的文字編輯器。
若想進一步學習,我們強烈推薦參考 [Microsoft Learn](https://learn.microsoft.com/users/wirelesslife/collections/p1ddcy5jwy0jkm?WT.mc_id=academic-77807-sagibbon) 以獲取更多學習資料。
### 📋 建立你的開發環境
本課程已準備好開發環境!開始時,你可以選擇在 [Codespace](https://github.com/features/codespaces/)(一個基於瀏覽器且免安裝的環境)執行此課程,或是在本機使用像是 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 的文字編輯器。
#### 建立你的儲存庫
為了方便保存你的學習成果,建議你建立自己的儲存庫副本。你可以點擊頁面頂部的 **Use this template** 按鈕,這將在你的 GitHub 帳戶中建立一個包含課程副本的新儲存庫。
方便保存你的作品,建議你建立此儲存庫的個人副本。你可以點擊上方的 **Use this template** 按鈕,系統將於你的 GitHub 帳號上建立一個包含課程內容的新儲存庫。
按照以下步驟:
1. **Fork 儲存庫**:點擊頁面右上角的 "Fork" 按鈕。
2. **Clone 儲存庫** `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
請依照下列步驟:
1. **派生儲存庫**點擊本頁右上方的「Fork」按鈕。
2. **複製儲存庫** `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
#### 在 Codespace 中運行課程
#### 在 Codespace 行課程
在你建立的儲存庫副本中,點擊 **Code** 按鈕並選擇 **Open with Codespaces**。這將為你建立一個新的 Codespace 以供使用
在你建立的儲存庫副本中,點擊 **Code** 按鈕,並選擇 **Open with Codespaces**,系統將為你建立一個新的 Codespace 讓你作業
![Codespace](../../translated_images/createcodespace.0238bbf4d7a8d955fa8fa7f7b6602a3cb6499a24708fbee589f83211c5a613b7.tw.png)
![Codespace](../../translated_images/createcodespace.0238bbf4d7a8d955.tw.png)
#### 在本地電腦上運行課程
#### 在本機執行課程
要在本地電腦上運行課程,你需要一個文字編輯器、瀏覽器及命令行工具。我們的第一節課 [程式語言及工具介紹](../../1-getting-started-lessons/1-intro-to-programming-languages) 將引導你選擇最適合你的工具
想於本機執行此課程,你需要一個文字編輯器、瀏覽器和命令列工具。第一堂課 [程式語言與開發工具入門](../../1-getting-started-lessons/1-intro-to-programming-languages) 將帶你認識各種工具選擇,幫助你挑選最合適自己的
我們推薦使用 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 作為編輯器,它還內建了 [終端機](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon)。你可以在 [這裡](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 下載 Visual Studio Code
我們推薦使用 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 作為編輯器,它內建有 [終端機](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon)。你可從 [此處下載 Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon)。
1. 將你的儲存庫克隆到電腦。點擊 **Code** 按鈕並複製 URL
1. 將儲存庫複製到你的電腦。你可以點擊 **Code** 按鈕並複製網址
[CodeSpace](./images/createcodespace.png)
然後,在 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 的 [終端機](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) 中運行以下命令,將 `<your-repository-url>` 替換為你剛複製的 URL
然後,在 [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) 中開啟 [終端機](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) 並執行以下命令,將 `<your-repository-url>` 替換為您剛剛複製的 URL
```bash
git clone <your-repository-url>
```
2. 在 Visual Studio Code 中打開資料夾。點擊 **File** > **Open Folder**,選擇你剛克隆的資料夾。
2. 在 Visual Studio Code 中開啟資料夾。您可以點擊 **檔案** > **開啟資料夾** 並選取您剛剛複製的資料夾。
> 推薦的 Visual Studio Code 擴充功能:
> 推薦的 Visual Studio Code 擴充功能:
>
> * [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) - 在 Visual Studio Code 中預覽 HTML 頁面
> * [Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot&WT.mc_id=academic-77807-sagibbon) - 幫助更快撰寫程式碼
## 📂 每節課包含
- 可選的手繪筆記
- 可選的補充影片
- 課前暖身測驗
- 書面課程
- 針對專案型課程,提供逐步指南教您如何建立專案
- 知識檢
- 挑戰
- 補充閱讀
- 作業
- [課後測驗](https://ff-quizzes.netlify.app/web/)
> **關於測驗的注意事項**:所有測驗都包含在 Quiz-app 資料夾中,共有 48 個測驗,每個測驗包含三個問題。您可以在[這裡](https://ff-quizzes.netlify.app/web/)找到測驗,測驗應用程式可以在本地運行或部署到 Azure請按照 `quiz-app` 資料夾中的指示進行操作。
## 🗃️ 課程
| | 專案名稱 | 教授概念 | 學習目標 | 相關課程 | 作者 |
| :-: | :--------------------------------------------------: | :------------------------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------: | :-------------------: |
| 01 | 入門篇 | 程式設計入門及工具介紹 | 學習大多數程式語言的基本原理以及幫助專業開發者完成工作的軟體 | [程式語言入門及工具介紹](./1-getting-started-lessons/1-intro-to-programming-languages/README.md) | Jasmine |
| 02 | 入門篇 | GitHub 基礎,包含團隊合作 | 如何在專案中使用 GitHub如何與他人協作程式碼庫 | [GitHub 基礎介紹](./1-getting-started-lessons/2-github-basics/README.md) | Floor |
| 03 | 入門篇 | 無障礙設計 | 學習網頁無障礙設計的基礎 | [無障礙設計基礎](./1-getting-started-lessons/3-accessibility/README.md) | Christopher |
| 04 | JS 基礎 | JavaScript 資料型別 | JavaScript 資料型別的基礎 | [資料型別](./2-js-basics/1-data-types/README.md) | Jasmine |
| 05 | JS 基礎 | 函數與方法 | 學習如何使用函數和方法來管理應用程式的邏輯流程 | [函數與方法](./2-js-basics/2-functions-methods/README.md) | Jasmine 和 Christopher |
| 06 | JS 基礎 | 使用 JS 做出決策 | 學習如何使用決策方法在程式碼中創建條件 | [做出決策](./2-js-basics/3-making-decisions/README.md) | Jasmine |
| 07 | JS 基礎 | 陣列與迴圈 | 使用 JavaScript 中的陣列和迴圈處理資料 | [陣列與迴圈](./2-js-basics/4-arrays-loops/README.md) | Jasmine |
| 08 | [生態瓶](./3-terrarium/solution/README.md) | HTML 實作 | 建立 HTML 以創建線上生態瓶,專注於建立佈局 | [HTML 入門](./3-terrarium/1-intro-to-html/README.md) | Jen |
| 09 | [生態瓶](./3-terrarium/solution/README.md) | CSS 實作 | 建立 CSS 以設計線上生態瓶,專注於 CSS 的基礎,包括使頁面響應式 | [CSS 入門](./3-terrarium/2-intro-to-css/README.md) | Jen |
| 10 | [生態瓶](./3-terrarium/solution/README.md) | JavaScript 閉包、DOM 操作 | 建立 JavaScript 使生態瓶具備拖放介面功能,專注於閉包和 DOM 操作 | [JavaScript 閉包、DOM 操作](./3-terrarium/3-intro-to-DOM-and-closures/README.md) | Jen |
| 11 | [打字遊戲](./4-typing-game/solution/README.md) | 建立打字遊戲 | 學習如何使用鍵盤事件來驅動 JavaScript 應用程式的邏輯 | [事件驅動程式設計](./4-typing-game/typing-game/README.md) | Christopher |
| 12 | [綠色瀏覽器擴充功能](./5-browser-extension/solution/README.md) | 瀏覽器操作 | 學習瀏覽器的工作原理、歷史,以及如何搭建瀏覽器擴充功能的初始元素 | [關於瀏覽器](./5-browser-extension/1-about-browsers/README.md) | Jen |
| 13 | [綠色瀏覽器擴充功能](./5-browser-extension/solution/README.md) | 建立表單、呼叫 API 並將變數儲存於本地存儲 | 建立瀏覽器擴充功能的 JavaScript 元素,使用儲存在本地存儲中的變數呼叫 API | [API、表單與本地儲](./5-browser-extension/2-forms-browsers-local-storage/README.md) | Jen |
| 14 | [綠色瀏覽器擴充功能](./5-browser-extension/solution/README.md) | 瀏覽器的背景處理、網頁效能 | 使用瀏覽器的背景處理來管理擴充功能的圖示;學習網頁效能及一些優化方法 | [背景任務與效能](./5-browser-extension/3-background-tasks-and-performance/README.md) | Jen |
| 15 | [太空遊戲](./6-space-game/solution/README.md) | 更進階的 JavaScript 遊戲開發 | 學習使用類別和組合進行繼承以及 Pub/Sub 模式,為建立遊戲做準備 | [進階遊戲開發入門](./6-space-game/1-introduction/README.md) | Chris |
| 16 | [太空遊戲](./6-space-game/solution/README.md) | 繪製到畫布 | 學習 Canvas API用於將元素繪製到螢幕 | [繪製到畫布](./6-space-game/2-drawing-to-canvas/README.md) | Chris |
| 17 | [太空遊戲](./6-space-game/solution/README.md) | 在螢幕上移動元素 | 探索如何使用笛卡爾座標和 Canvas API 使元素獲得運動 | [移動元素](./6-space-game/3-moving-elements-around/README.md) | Chris |
| 18 | [太空遊戲](./6-space-game/solution/README.md) | 碰撞檢測 | 使用按鍵使元素碰撞並相互作用,並提供冷卻功能以確保遊戲效能 | [碰撞檢測](./6-space-game/4-collision-detection/README.md) | Chris |
| 19 | [太空遊戲](./6-space-game/solution/README.md) | 計分 | 根據遊戲的狀態和效能進行數學計算 | [計分](./6-space-game/5-keeping-score/README.md) | Chris |
| 20 | [太空遊戲](./6-space-game/solution/README.md) | 結束與重新開始遊戲 | 學習如何結束和重新開始遊戲,包括清理資源和重置變數值 | [結束條件](./6-space-game/6-end-condition/README.md) | Chris |
| 21 | [銀行應用程式](./7-bank-project/solution/README.md) | HTML 模板與網頁應用程式的路由 | 學習如何使用路由和 HTML 模板建立多頁網站的架構 | [HTML 模板與路由](./7-bank-project/1-template-route/README.md) | Yohan |
| 22 | [銀行應用程式](./7-bank-project/solution/README.md) | 建立登入與註冊表單 | 學習建立表單及處理驗證程序 | [表單](./7-bank-project/2-forms/README.md) | Yohan |
| 23 | [銀行應用程式](./7-bank-project/solution/README.md) | 獲取與使用資料的方法 | 資料如何在應用程式中流動,如何獲取、儲存及處理 | [資料](./7-bank-project/3-data/README.md) | Yohan |
| 24 | [銀行應用程式](./7-bank-project/solution/README.md) | 狀態管理概念 | 學習應用程式如何保留狀態以及如何以程式方式管理它 | [狀態管理](./7-bank-project/4-state-management/README.md) | Yohan |
| 25 | [瀏覽器/VScode 編輯器](../../8-code-editor) | 使用 VScode | 學習如何使用程式碼編輯器| [使用 VScode 編輯器](./8-code-editor/1-using-a-code-editor/README.md) | Chris |
| 26 | [AI 助手](./9-chat-project/README.md) | 使用 AI | 學習如何建立自己的 AI 助手 | [AI 助手專案](./9-chat-project/README.md) | Chris |
> * [Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot&WT.mc_id=academic-77807-sagibbon) - 幫助更快撰寫程式碼
## 📂 每堂課包括
- 選擇性筆記
- 選擇性補充影片
- 課前熱身小測驗
- 書面課程內容
- 專案導向課程,包含專案逐步指南
- 知識檢
- 挑戰任務
- 補充閱讀
- 作業
- [課後測驗](https://ff-quizzes.netlify.app/web/)
> **關於小測驗的說明**:所有小測驗集中在 Quiz-app 資料夾中,共 48 個小測驗,每個小測驗包含三個問題。可透過 [此處](https://ff-quizzes.netlify.app/web/) 使用該小測驗應用程式,該應用程式可在本機執行或部署到 Azure請依 `quiz-app` 資料夾中的說明操作。
## 🗃️ 課程列表
| | 專案名稱 | 教授概念 | 學習目標 | 連結課程 | 作者 |
| :-: | :--------------------------------------------------: | :--------------------------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------: | :-------------------: |
| 01 | 入門篇 | 程式設計入門及開發工具簡介 | 了解大多數程式語言的基本原理及專業開發者使用的軟體工具 | [程式設計語言與開發工具介紹](./1-getting-started-lessons/1-intro-to-programming-languages/README.md) | Jasmine |
| 02 | 入門篇 | GitHub 基礎與團隊協作 | 如何在專案中使用 GitHub以及如何與其他人協作共同維護程式碼庫 | [GitHub 入門](./1-getting-started-lessons/2-github-basics/README.md) | Floor |
| 03 | 入門篇 | 無障礙設計 | 學習網頁無障礙設計的基礎概念 | [無障礙設計基礎](./1-getting-started-lessons/3-accessibility/README.md) | Christopher |
| 04 | JS 基礎 | JavaScript 資料型別 | JavaScript 資料型別的基礎 | [資料型別](./2-js-basics/1-data-types/README.md) | Jasmine |
| 05 | JS 基礎篇 | 函式與方法 | 學習函式與方法以管理應用程式的邏輯流程 | [函式與方法](./2-js-basics/2-functions-methods/README.md) | Jasmine 和 Christopher |
| 06 | JS 基礎篇 | 使用 JS 做出決策 | 學習如何使用條件判斷方法撰寫程式碼 | [決策判斷](./2-js-basics/3-making-decisions/README.md) | Jasmine |
| 07 | JS 基礎篇 | 陣列與迴圈 | 使用 JavaScript 陣列與迴圈操作資料 | [陣列與迴圈](./2-js-basics/4-arrays-loops/README.md) | Jasmine |
| 08 | [Terrarium](./3-terrarium/solution/README.md) | HTML 實作 | 製作線上生態箱的 HTML著重於版面配置 | [HTML 入門](./3-terrarium/1-intro-to-html/README.md) | Jen |
| 09 | [Terrarium](./3-terrarium/solution/README.md) | CSS 實作 | 製作線上生態箱的 CSS著重於 CSS 基本與製作響應式網頁 | [CSS 入門](./3-terrarium/2-intro-to-css/README.md) | Jen |
| 10 | [Terrarium](./3-terrarium/solution/README.md) | JavaScript 閉包與 DOM 操作 | 編寫 JavaScript 使生態箱具備拖放功能,重點是閉包與 DOM 操作 | [JavaScript 閉包與 DOM 操作](./3-terrarium/3-intro-to-DOM-and-closures/README.md) | Jen |
| 11 | [Typing Game](./4-typing-game/solution/README.md) | 製作打字遊戲 | 學習如何使用鍵盤事件來驅動 JavaScript 應用的邏輯 | [事件驅動程式設計](./4-typing-game/typing-game/README.md) | Christopher |
| 12 | [Green Browser Extension](./5-browser-extension/solution/README.md) | 瀏覽器運作原理 | 了解瀏覽器如何運作、發展史及如何建立瀏覽器擴充功能的基礎元素 | [瀏覽器介紹](./5-browser-extension/1-about-browsers/README.md) | Jen |
| 13 | [Green Browser Extension](./5-browser-extension/solution/README.md) | 表單建立、API 呼叫與本地儲存變數 | 製作瀏覽器擴充功能的 JavaScript 元件,使用本地儲存的變數呼叫 API | [API、表單與本地](./5-browser-extension/2-forms-browsers-local-storage/README.md) | Jen |
| 14 | [Green Browser Extension](./5-browser-extension/solution/README.md) | 瀏覽器背景工作程序與網頁效能優化 | 使用瀏覽器背景工作程序管理擴充功能圖示,並學習網頁效能及優化方法 | [背景工作程序與效能](./5-browser-extension/3-background-tasks-and-performance/README.md) | Jen |
| 15 | [Space Game](./6-space-game/solution/README.md) | 使用 JavaScript 進行進階遊戲開發 | 學習類別與組合Class 和 Composition的繼承以及發布/訂閱模式 (Pub/Sub),為製作遊戲做準備 | [進階遊戲開發導論](./6-space-game/1-introduction/README.md) | Chris |
| 16 | [Space Game](./6-space-game/solution/README.md) | 畫布繪圖 | 了解 Canvas API用於繪製螢幕上的元件 | [畫布繪圖](./6-space-game/2-drawing-to-canvas/README.md) | Chris |
| 17 | [Space Game](./6-space-game/solution/README.md) | 移動螢幕上的元件 | 學習如何使用笛卡爾座標與 Canvas API 來使元素動起來 | [移動螢幕元素](./6-space-game/3-moving-elements-around/README.md) | Chris |
| 18 | [Space Game](./6-space-game/solution/README.md) | 碰撞偵測 | 讓元素碰撞並能反應,使用按鍵事件並設計冷卻功能確保遊戲效能 | [碰撞偵測](./6-space-game/4-collision-detection/README.md) | Chris |
| 19 | [Space Game](./6-space-game/solution/README.md) | 計分管理 | 根據遊戲狀態及表現進行數學計算 | [計分管理](./6-space-game/5-keeping-score/README.md) | Chris |
| 20 | [Space Game](./6-space-game/solution/README.md) | 遊戲結束與重新開始 | 了解遊戲結束與重新開始,包括清理資源和重設變數值 | [結束條件](./6-space-game/6-end-condition/README.md) | Chris |
| 21 | [Banking App](./7-bank-project/solution/README.md) | 網頁應用的 HTML 模板及路由 | 學習如何透過路由與 HTML 模板建立多頁面網站的架構 | [HTML 模板與路由](./7-bank-project/1-template-route/README.md) | Yohan |
| 22 | [Banking App](./7-bank-project/solution/README.md) | 製作登入與註冊表單 | 學習表單構建與驗證流程 | [表單](./7-bank-project/2-forms/README.md) | Yohan |
| 23 | [Banking App](./7-bank-project/solution/README.md) | 取用與使用資料的方法 | 了解資料如何進入及流出應用程式,如何取得、儲存與釋放 | [資料](./7-bank-project/3-data/README.md) | Yohan |
| 24 | [Banking App](./7-bank-project/solution/README.md) | 狀態管理概念 | 學習應用程式如何保持狀態及如何程式化管理 | [狀態管理](./7-bank-project/4-state-management/README.md) | Yohan |
| 25 | [Browser/VScode Code](../../8-code-editor) | 使用 VScode | 學習如何使用程式碼編輯器 | [使用 VScode 程式碼編輯器](./8-code-editor/1-using-a-code-editor/README.md) | Chris |
| 26 | [AI Assistants](./9-chat-project/README.md) | 使用 AI | 學習如何建立自己的 AI 助手 | [AI 助手專案](./9-chat-project/README.md) | Chris |
## 🏫 教學法
我們的課程設計基於兩個關鍵的教學原則:
* 專案導向學習
* 頻繁的測驗
我們的課程設計基於兩大教學原則:
* 專案導向學習
* 頻繁的測驗
本課程教授 JavaScript、HTML 和 CSS 的基礎知識,以及當今網頁開發者使用的最新工具和技術。學生將有機會通過建立打字遊戲、虛擬生態瓶、環保瀏覽器擴充功能、太空侵略者風格的遊戲以及商業銀行應用程式來獲得實際操作經驗。完成課程後,學生將對網頁開發有扎實的理解
課程教授 JavaScript、HTML 及 CSS 的基礎,並介紹現今網頁開發者所使用的最新工具和技術。學生將有機會透過製作打字遊戲、虛擬生態箱、環保瀏覽器擴充功能、太空侵略者風格遊戲與銀行業務應用程式來累積實務經驗。完成此系列課程後,學生將具備穩固的網頁開發基礎知識
> 🎓 您可以在 Microsoft Learn 上以 [學習路徑](https://docs.microsoft.com/learn/paths/web-development-101/?WT.mc_id=academic-77807-sagibbon) 的形式學習本課程的前幾節
> 🎓 您可以將此課程的前幾堂課程視為 [Microsoft Learn 上的學習路徑](https://docs.microsoft.com/learn/paths/web-development-101/?WT.mc_id=academic-77807-sagibbon)
通過確保內容與專案相符,學習過程對學生來說更具吸引力,概念的記憶也會得到增強。我們還撰寫了幾個 JavaScript 基礎課程作為入門,並搭配 "[JavaScript 初學者系列](https://channel9.msdn.com/Series/Beginners-Series-to-JavaScript/?WT.mc_id=academic-77807-sagibbon)" 視頻教程,其中一些作者也參與了本課程的編寫
確保內容與專案對應,讓學生學習過程更有趣且能提升概念記憶。我們也撰寫了數個 JavaScript 基礎入門課程,搭配「[JavaScript 初學者系列](https://channel9.msdn.com/Series/Beginners-Series-to-JavaScript/?WT.mc_id=academic-77807-sagibbon)」影片教學,其中部分作者也曾為本課程做出貢獻
此外,課前的低壓力測驗可以幫助學生集中注意力學習主題,而課後的第二次測驗則能進一步加強記憶。本課程設計靈活有趣,可以完整學習,也可以選擇部分內容。專案從簡單開始,並在 12 週的課程結束時逐漸變得更加複雜
此外,課前的一次低壓力小測驗有助於學生設定學習目標,課後第二次小測驗則幫助加深學習印象。本課程設計靈活且富趣味性,您可以選擇全部或部分修習。專案從簡單開始,並在 12 週課程結束時逐步增加難度
雖然我們刻意避免介紹 JavaScript 框架,以便專注於作為網頁開發者在採用框架之前所需的基本技能,但完成本課程後的下一步可以是通過另一系列視頻學習 Node.js"[Node.js 初學者系列](https://channel9.msdn.com/Series/Beginners-Series-to-Nodejs/?WT.mc_id=academic-77807-sagibbon)"
我們刻意不引入 JavaScript 框架,專注於網頁開發者在採用框架之前需要學習的基本技能。完成本課程後,學習 Node.js 是個良好後續,相關內容可參考另一套影片系列:「[Node.js 初學者系列](https://channel9.msdn.com/Series/Beginners-Series-to-Nodejs/?WT.mc_id=academic-77807-sagibbon)
> 請參閱我們的 [行為準則](CODE_OF_CONDUCT.md) 和 [貢獻指南](CONTRIBUTING.md)。我們歡迎您的建設性反饋!
> 請參閱我們的 [行為準則](CODE_OF_CONDUCT.md) 及 [貢獻指南](CONTRIBUTING.md)。歡迎您提出建設性回饋!
## 🧭 離線存取
您可以使用 [Docsify](https://docsify.js.org/#/) 離線運行此文件。Fork 此存儲庫,在本地機器上[安裝 Docsify](https://docsify.js.org/#/quickstart),然後在此存儲庫的根目錄中輸入 `docsify serve`。網站將在本地端的 3000 埠上運行:`localhost:3000`
您可以使用 [Docsify](https://docsify.js.org/#/) 離線瀏覽此文件。複製此儲存庫,於本機安裝 [Docsify](https://docsify.js.org/#/quickstart),然後在儲存庫根目錄輸入 `docsify serve`。網站將於本機端口 3000 (localhost:3000) 提供服務
## 📘 PDF
所有課程的 PDF 可在[這裡](https://microsoft.github.io/Web-Dev-For-Beginners/pdf/readme.pdf)找到
所有課程的 PDF 可於 [此處](https://microsoft.github.io/Web-Dev-For-Beginners/pdf/readme.pdf) 下載
## 🎒 其他課程
我們團隊還有製作其他課程!歡迎查看:
我們的團隊還製作了其他課程!請查看:
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
### LangChain
[![LangChain4j for Beginners](https://img.shields.io/badge/LangChain4j%20for%20Beginners-22C55E?style=for-the-badge&&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchain4j-for-beginners)
[![LangChain.js for Beginners](https://img.shields.io/badge/LangChain.js%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchainjs-for-beginners?WT.mc_id=m365-94501-dwahlin)
- [MCP 初學者課程](https://aka.ms/mcp-for-beginners)
- [邊緣 AI 初學者課程](https://aka.ms/edgeai-for-beginners)
- [AI 助手初學者課程](https://aka.ms/ai-agents-beginners)
- [生成式 AI 初學者課程 .NET](https://github.com/microsoft/Generative-AI-for-beginners-dotnet)
- [使用 JavaScript 的生成式 AI](https://github.com/microsoft/generative-ai-with-javascript)
- [使用 Java 的生成式 AI](https://github.com/microsoft/Generative-AI-for-beginners-java)
- [AI 初學者課程](https://aka.ms/ai-beginners)
- [資料科學初學者課程](https://aka.ms/datascience-beginners)
- [機器學習初學者課程](https://aka.ms/ml-beginners)
- [網路安全初學者課程](https://github.com/microsoft/Security-101)
- [網頁開發初學者課程](https://aka.ms/webdev-beginners)
- [物聯網初學者課程](https://aka.ms/iot-beginners)
- [XR 初學者開發指南](https://github.com/microsoft/xr-development-for-beginners)
- [GitHub Copilot 高效使用指南](https://github.com/microsoft/Mastering-GitHub-Copilot-for-Paired-Programming)
- [GitHub Copilot C#/.NET 開發者進階指南](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers)
- [選擇你的 Copilot 冒險之旅](https://github.com/microsoft/CopilotAdventures)
---
### Azure / Edge / MCP / Agents
[![AZD for Beginners](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Edge AI for Beginners](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![MCP for Beginners](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst)
[![AI Agents for Beginners](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### 生成式 AI 系列
[![Generative AI for Beginners](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Generative AI (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst)
[![Generative AI (Java)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst)
[![Generative AI (JavaScript)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst)
---
### 核心學習
[![ML for Beginners](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst)
[![Data Science for Beginners](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst)
[![AI for Beginners](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst)
[![Cybersecurity for Beginners](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung)
[![Web Dev for Beginners](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst)
[![IoT for Beginners](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst)
[![XR Development for Beginners](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### Copilot 系列
[![Copilot for AI Paired Programming](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst)
[![Copilot for C#/.NET](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst)
[![Copilot Adventure](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst)
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
## 獲取幫助
## 尋求協
如果您遇到困難或對構建 AI 應用有任何疑問,請加入:
如果您在建立 AI 應用程式時遇到困難或有任何問題,歡迎加入學習夥伴與資深開發者的討論,分享 MCP 的相關主題。這是一個充滿支持的社群,熱忱歡迎提問並自由分享知識。
[![Azure AI Foundry Discord](https://img.shields.io/badge/Discord-Azure_AI_Foundry_Community_Discord-blue?style=for-the-badge&logo=discord&color=5865f2&logoColor=fff)](https://aka.ms/foundry/discord)
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
如果您有產品反饋或在構建過程中遇到錯誤,請訪問:
若您在開發過程中有產品回饋或遇到錯誤,請造訪
[![Azure AI Foundry Developer Forum](https://img.shields.io/badge/GitHub-Azure_AI_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
[![Microsoft Foundry Developer Forum](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
## 授權
## 授權條款
此存儲庫基於 MIT 授權。請參閱 [LICENSE](../../LICENSE) 文件以了解更多信息。
資源庫採用 MIT 授權。更多資訊請參閱 [LICENSE](../../LICENSE) 檔案
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於追求準確性,但請注意,機器翻譯可能包含錯誤或不準確之處。原始文件以其原文版本為權威依據。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯版本而產生之任何誤解或誤釋負責。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -42,10 +42,10 @@ CO_OP_TRANSLATOR_METADATA:
- Moodle Cloud 對 Common Cartridge 的支持有限。建議使用上述 Moodle 文件,該文件也可上傳到 Canvas。
- 導入後,請檢查模組、截止日期和測驗設置,以匹配您的學期安排。
![Moodle](../../translated_images/moodle.94eb93d714a50cb2c97435b408017dee224348b61bc86203ffd43a4f4e57b95f.tw.png)
![Moodle](../../translated_images/moodle.94eb93d714a50cb2.tw.png)
> Moodle 課堂中的課程內容
![Canvas](../../translated_images/canvas.fbd605ff8e5b8aff567d398528ce113db304446b90b9cad55c654de3fdfcda34.tw.png)
![Canvas](../../translated_images/canvas.fbd605ff8e5b8aff.tw.png)
> Canvas 課堂中的課程內容
### 直接使用倉庫(不使用 Classroom

@ -17,7 +17,7 @@ CO_OP_TRANSLATOR_METADATA:
آج، ہم ان حیرت انگیز ٹولز کو دریافت کرنے جا رہے ہیں جو جدید ویب ڈیولپمنٹ کو نہ صرف ممکن بناتے ہیں بلکہ واقعی دلچسپ بناتے ہیں۔ میں ان ایڈیٹرز، براؤزرز، اور ورک فلو کے بارے میں بات کر رہا ہوں جو نیٹ فلکس، اسپاٹیفائی، اور آپ کے پسندیدہ انڈی ایپ اسٹوڈیو کے ڈیولپرز ہر روز استعمال کرتے ہیں۔ اور یہاں وہ حصہ ہے جو آپ کو خوشی سے جھومنے پر مجبور کر دے گا: ان میں سے زیادہ تر پروفیشنل گریڈ، انڈسٹری اسٹینڈرڈ ٹولز مکمل طور پر مفت ہیں!
![پروگرامنگ کا تعارف](../../../../translated_images/webdev101-programming.d6e3f98e61ac4bff0b27dcbf1c3f16c8ed46984866f2d29988929678b0058fde.ur.png)
![پروگرامنگ کا تعارف](../../../../translated_images/webdev101-programming.d6e3f98e61ac4bff.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
```mermaid

@ -17,7 +17,7 @@ CO_OP_TRANSLATOR_METADATA:
ہم یہ سفر ایک ساتھ کریں گے، ایک قدم بہ ایک قدم۔ کوئی جلدی نہیں، کوئی دباؤ نہیں بس آپ، میں، اور کچھ واقعی زبردست ٹولز جو آپ کے نئے بہترین دوست بننے والے ہیں!
![GitHub کا تعارف](../../../../translated_images/webdev101-github.8846d7971abef6f947909b4f9d343e2a23778aa716ca6b9d71df7174ee5009ac.ur.png)
![GitHub کا تعارف](../../../../translated_images/webdev101-github.8846d7971abef6f9.ur.png)
> اسکیچ نوٹ از [Tomomi Imura](https://twitter.com/girlie_mac)
```mermaid
@ -583,7 +583,7 @@ flowchart TD
✅ 'beginner-friendly' ریپوزٹریز تلاش کرنے کا ایک اچھا طریقہ [tag 'good-first-issue' کے ذریعے تلاش کرنا](https://github.blog/2020-01-22-browse-good-first-issues-to-start-contributing-to-open-source/) ہے۔
![ریپو کو لوکل کاپی کریں](../../../../translated_images/clone_repo.5085c48d666ead57664f050d806e325d7f883be6838c821e08bc823ab7c66665.ur.png)
![ریپو کو لوکل کاپی کریں](../../../../translated_images/clone_repo.5085c48d666ead57.ur.png)
کوڈ کو کاپی کرنے کے کئی طریقے ہیں۔ ایک طریقہ یہ ہے کہ ریپوزٹری کے مواد کو "کلون" کریں، HTTPS، SSH، یا GitHub CLI (کمانڈ لائن انٹرفیس) کا استعمال کرتے ہوئے۔

@ -9,7 +9,7 @@ CO_OP_TRANSLATOR_METADATA:
-->
# قابل رسائی ویب صفحات بنانا
![سب کچھ قابل رسائی کے بارے میں](../../../../translated_images/webdev101-a11y.8ef3025c858d897a403a1a42c0897c76e11b724d9a8a0c0578dd4316f7507622.ur.png)
![سب کچھ قابل رسائی کے بارے میں](../../../../translated_images/webdev101-a11y.8ef3025c858d897a.ur.png)
> اسکیچ نوٹ از [ٹومومی ایمورا](https://twitter.com/girlie_mac)
```mermaid

@ -9,7 +9,7 @@ CO_OP_TRANSLATOR_METADATA:
-->
# جاوا اسکرپٹ کی بنیادی باتیں: ڈیٹا کی اقسام
![جاوا اسکرپٹ کی بنیادی باتیں - ڈیٹا کی اقسام](../../../../translated_images/webdev101-js-datatypes.4cc470179730702c756480d3ffa46507f746e5975ebf80f99fdaaf1cff09a7f4.ur.png)
![جاوا اسکرپٹ کی بنیادی باتیں - ڈیٹا کی اقسام](../../../../translated_images/webdev101-js-datatypes.4cc470179730702c.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
```mermaid

@ -9,7 +9,7 @@ CO_OP_TRANSLATOR_METADATA:
-->
# جاوا اسکرپٹ کی بنیادی باتیں: طریقے اور فنکشنز
![جاوا اسکرپٹ کی بنیادی باتیں - فنکشنز](../../../../translated_images/webdev101-js-functions.be049c4726e94f8b7605c36330ac42eeb5cd8ed02bcdd60fdac778174d6cb865.ur.png)
![جاوا اسکرپٹ کی بنیادی باتیں - فنکشنز](../../../../translated_images/webdev101-js-functions.be049c4726e94f8b.ur.png)
> اسکیچ نوٹ از [Tomomi Imura](https://twitter.com/girlie_mac)
```mermaid

@ -9,7 +9,7 @@ CO_OP_TRANSLATOR_METADATA:
-->
# جاوا اسکرپٹ کی بنیادی باتیں: فیصلے کرنا
![جاوا اسکرپٹ کی بنیادی باتیں - فیصلے کرنا](../../../../translated_images/webdev101-js-decisions.69e1b20f272dd1f0b1cb2f8adaff3ed2a77c4f91db96d8a0594132a353fa189a.ur.png)
![جاوا اسکرپٹ کی بنیادی باتیں - فیصلے کرنا](../../../../translated_images/webdev101-js-decisions.69e1b20f272dd1f0.ur.png)
> اسکیچ نوٹ از [Tomomi Imura](https://twitter.com/girlie_mac)

@ -9,7 +9,7 @@ CO_OP_TRANSLATOR_METADATA:
-->
# جاوا اسکرپٹ کی بنیادی باتیں: Arrays اور Loops
![جاوا اسکرپٹ کی بنیادی باتیں - Arrays](../../../../translated_images/webdev101-js-arrays.439d7528b8a294558d0e4302e448d193f8ad7495cc407539cc81f1afe904b470.ur.png)
![جاوا اسکرپٹ کی بنیادی باتیں - Arrays](../../../../translated_images/webdev101-js-arrays.439d7528b8a29455.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
```mermaid

@ -26,7 +26,7 @@ journey
Build terrarium: 5: Student
```
![HTML کا تعارف](../../../../translated_images/webdev101-html.4389c2067af68e98280c1bde52b6c6269f399eaae3659b7c846018d8a7b0bbd9.ur.png)
![HTML کا تعارف](../../../../translated_images/webdev101-html.4389c2067af68e98.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
HTML، یا HyperText Markup Language، ہر ویب سائٹ کی بنیاد ہے جو آپ نے کبھی دیکھی ہے۔ HTML کو ویب صفحات کا ڈھانچہ سمجھیں یہ بتاتا ہے کہ مواد کہاں جائے گا، کیسے منظم ہوگا، اور ہر حصہ کیا ظاہر کرتا ہے۔ جبکہ CSS بعد میں آپ کے HTML کو رنگوں اور لے آؤٹ کے ساتھ "سجائے گا"، اور JavaScript اسے انٹرایکٹیویٹی کے ساتھ زندہ کرے گا، HTML وہ بنیادی ڈھانچہ فراہم کرتا ہے جو باقی سب کچھ ممکن بناتا ہے۔
@ -88,7 +88,7 @@ HTML کوڈ میں جانے سے پہلے، آئیے آپ کے ٹیریریم پ
4. Explorer پین میں، "New File" آئیکن پر کلک کریں
5. اپنی فائل کا نام `index.html` رکھیں
![VS Code Explorer میں نئی فائل بنانے کا عمل](../../../../translated_images/vs-code-index.e2986cf919471eb984a0afef231380c8b132b000635105f2397bd2754d1b689c.ur.png)
![VS Code Explorer میں نئی فائل بنانے کا عمل](../../../../translated_images/vs-code-index.e2986cf919471eb9.ur.png)
**آپشن 2: ٹرمینل کمانڈز کا استعمال**
```bash

@ -30,7 +30,7 @@ journey
Glass reflections: 5: Student
```
![CSS کا تعارف](../../../../translated_images/webdev101-css.3f7af5991bf53a200d79e7257e5e450408d8ea97f5b531d31b2e3976317338ee.ur.png)
![CSS کا تعارف](../../../../translated_images/webdev101-css.3f7af5991bf53a20.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
یاد ہے آپ کا HTML ٹیریریم کتنا سادہ نظر آ رہا تھا؟ CSS وہ جگہ ہے جہاں ہم اس سادہ ڈھانچے کو بصری طور پر دلکش چیز میں تبدیل کرتے ہیں۔
@ -205,7 +205,7 @@ body {
اپنے براؤزر کے ڈیولپر ٹولز (F12) کھولیں، ایلیمنٹس ٹیب پر جائیں، اور اپنے `<h1>` عنصر کا معائنہ کریں۔ آپ دیکھیں گے کہ یہ باڈی سے فونٹ فیملی وراثت میں لیتا ہے:
![وراثت میں لیا گیا فونٹ](../../../../translated_images/1.cc07a5cbe114ad1d4728c35134584ac1b87db688eff83cf75985cf31fe0ed95c.ur.png)
![وراثت میں لیا گیا فونٹ](../../../../translated_images/1.cc07a5cbe114ad1d.ur.png)
**تجربہ کا وقت**: باڈی پر دیگر وراثت میں ملنے والی پراپرٹیز جیسے `color`, `line-height`, یا `text-align` سیٹ کرنے کی کوشش کریں۔ آپ کے ہیڈنگ اور دیگر عناصر کے ساتھ کیا ہوتا ہے؟
@ -561,7 +561,7 @@ Agent mode کا استعمال کرتے ہوئے درج ذیل چیلنج مکم
آپ ہلکے سفید یا ہلکے رنگ کے بیضوی شکلیں بنائیں گے جو شیشے کی عکاسی کی نقل کرتے ہیں۔ یہ طریقہ اس طرح ہے جیسے Renaissance کے مصور جیسے Jan van Eyck نے روشنی اور عکاسی کا استعمال کرتے ہوئے پینٹ شدہ شیشے کو تین جہتی ظاہر کیا۔ آپ کا مقصد یہ ہے:
![finished terrarium](../../../../translated_images/terrarium-final.2f07047ffc597d0a06b06cab28a77801a10dd12fdb6c7fc630e9c40665491c53.ur.png)
![finished terrarium](../../../../translated_images/terrarium-final.2f07047ffc597d0a.ur.png)
**آپ کا چیلنج:**
- **بنائیں** ہلکے سفید یا روشنی والے بیضوی شکلیں شیشے کی عکاسی کے لیے

@ -26,7 +26,7 @@ journey
Complete terrarium: 5: Student
```
![DOM اور ایک کلوزر](../../../../translated_images/webdev101-js.10280393044d7eaaec7e847574946add7ddae6be2b2194567d848b61d849334a.ur.png)
![DOM اور ایک کلوزر](../../../../translated_images/webdev101-js.10280393044d7eaa.ur.png)
> اسکیچ نوٹ [Tomomi Imura](https://twitter.com/girlie_mac) کی طرف سے
ویب ڈیولپمنٹ کے سب سے دلچسپ پہلو میں خوش آمدید - چیزوں کو انٹرایکٹو بنانا! دستاویز آبجیکٹ ماڈل (DOM) آپ کے HTML اور جاوا اسکرپٹ کے درمیان ایک پل کی طرح ہے، اور آج ہم اسے آپ کے ٹیریریم کو زندہ کرنے کے لیے استعمال کریں گے۔ جب ٹم برنرز لی نے پہلا ویب براؤزر بنایا، تو انہوں نے ایک ایسی ویب کا تصور کیا جہاں دستاویزات متحرک اور انٹرایکٹو ہو سکیں - DOM اس تصور کو ممکن بناتا ہے۔
@ -105,7 +105,7 @@ flowchart TD
style Q fill:#ffebee
```
![DOM درخت کی نمائندگی](../../../../translated_images/dom-tree.7daf0e763cbbba9273f9a66fe04c98276d7d23932309b195cb273a9cf1819b42.ur.png)
![DOM درخت کی نمائندگی](../../../../translated_images/dom-tree.7daf0e763cbbba92.ur.png)
> DOM اور HTML مارک اپ کی نمائندگی جو اس کا حوالہ دیتا ہے۔ [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites) کی طرف سے
@ -150,7 +150,7 @@ flowchart LR
> 💡 **کلوزرز کو سمجھنا**: کلوزرز جاوا اسکرپٹ میں ایک اہم موضوع ہیں، اور بہت سے ڈیولپرز انہیں سالوں تک استعمال کرتے ہیں اس سے پہلے کہ وہ تمام نظریاتی پہلوؤں کو مکمل طور پر سمجھ سکیں۔ آج، ہم عملی اطلاق پر توجہ مرکوز کر رہے ہیں - آپ دیکھیں گے کہ کلوزرز قدرتی طور پر ابھرتے ہیں جب ہم اپنی انٹرایکٹو خصوصیات بناتے ہیں۔ سمجھنا اس وقت ترقی کرے گا جب آپ دیکھیں گے کہ وہ حقیقی مسائل کو کیسے حل کرتے ہیں۔
![DOM درخت کی نمائندگی](../../../../translated_images/dom-tree.7daf0e763cbbba9273f9a66fe04c98276d7d23932309b195cb273a9cf1819b42.ur.png)
![DOM درخت کی نمائندگی](../../../../translated_images/dom-tree.7daf0e763cbbba92.ur.png)
> DOM اور HTML مارک اپ کی نمائندگی جو اس کا حوالہ دیتا ہے۔ [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites) کی طرف سے
@ -554,7 +554,7 @@ function stopElementDrag() {
- **کراس ڈیوائس سپورٹ**: ڈیسک ٹاپ اور موبائل پر کام کرتا ہے
- **پرفارمنس کا خیال**: کوئی میموری لیکس یا غیر ضروری حسابات نہیں
![مکمل شدہ ٹیریریم](../../../../translated_images/terrarium-final.0920f16e87c13a84cd2b553a5af9a3ad1cffbd41fbf8ce715d9e9c43809a5e2c.ur.png)
![مکمل شدہ ٹیریریم](../../../../translated_images/terrarium-final.0920f16e87c13a84.ur.png)
---

@ -1,43 +1,30 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "7965cd2bc5dc92ad888dc4c6ab2ab70a",
"translation_date": "2025-08-25T21:04:01+00:00",
"original_hash": "bc5c5550f79d10add90ce419ee34abb3",
"translation_date": "2026-01-06T11:01:29+00:00",
"source_file": "3-terrarium/README.md",
"language_code": "ur"
}
-->
# میرا ٹیریریم: HTML، CSS، اور جاوا اسکرپٹ کے ذریعے DOM مینپولیشن سیکھنے کا ایک پروجیکٹ 🌵🌱
## اپنا ٹیریریم تعینات کریں
ایک چھوٹا سا ڈریگ اینڈ ڈراپ کوڈ میڈیٹیشن۔ تھوڑے سے HTML، JS اور CSS کے ساتھ، آپ ایک ویب انٹرفیس بنا سکتے ہیں، اسے اسٹائل دے سکتے ہیں، اور اپنی پسند کے مطابق مختلف تعاملات شامل کر سکتے ہیں۔
![میرا ٹیریریم](../../../translated_images/screenshot_gray.0c796099a1f9f25e40aa55ead81f268434c00af30d7092490759945eda63067d.ur.png)
# اسباق
1. [HTML کا تعارف](./1-intro-to-html/README.md)
2. [CSS کا تعارف](./2-intro-to-css/README.md)
3. [DOM اور JS کلوزرز کا تعارف](./3-intro-to-DOM-and-closures/README.md)
## کریڈٹس
یہ ♥️ کے ساتھ [Jen Looper](https://www.twitter.com/jenlooper) نے لکھا ہے۔
CSS کے ذریعے بنایا گیا ٹیریریم Jakub Mandra کے گلاس جار [کوڈپین](https://codepen.io/Rotarepmi/pen/rjpNZY) سے متاثر ہے۔
آرٹ ورک [Jen Looper](http://jenlooper.com) نے Procreate کی مدد سے ہاتھ سے بنایا ہے۔
## اپنا ٹیریریم شائع کریں
آپ Azure Static Web Apps کا استعمال کرتے ہوئے اپنے ٹیریریم کو ویب پر شائع کر سکتے ہیں۔
آپ اپنی ٹیریریم کو ویب پر **Azure Static Web Apps** استعمال کرتے ہوئے تعینات یا شائع کر سکتے ہیں۔
1. اس ریپو کو فورک کریں
2. یہ بٹن دبائیں
2. اس بٹن کو دبائیں 👇
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.StaticApp)
[![Azure پر شائع کریں بٹن](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/?feature.customportal=false&WT.mc_id=academic-77807-sagibbon#create/Microsoft.StaticApp)
3. اپنی ایپ بنانے کے لیے سیٹ اپ وزرڈ کی پیروی کریں۔
- **App root** کو `/solution` یا آپ کے کوڈبیس کی روٹ پر سیٹ کریں۔
- اس ایپ میں کوئی API نہیں ہے، اس لیے آپ API کنفیگریشن کو نظرانداز کر سکتے ہیں۔
- ایک `.github` فولڈر خودبخود بنایا جائے گا جو Azure Static Web Apps کو آپ کی ایپ بنانے اور شائع کرنے میں مدد دے گا۔
3. وزرڈ کے ذریعے اپنی ایپ بنائیں۔ یقینی بنائیں کہ آپ ایپ روٹ کو `/solution` یا اپنے کوڈ بیس کی روٹ پر سیٹ کریں۔ اس ایپ میں کوئی API نہیں ہے، اس لیے اس کی فکر نہ کریں۔ ایک گٹ ہب فولڈر آپ کی فورک کی گئی ریپوزٹری میں بنایا جائے گا جو Azure Static Web Apps کی بلڈ سروسز کو آپ کی ایپ کو ایک نئے URL پر بنانے اور شائع کرنے میں مدد دے گا۔
---
**ڈسکلیمر**:
یہ دستاویز AI ترجمہ سروس [Co-op Translator](https://github.com/Azure/co-op-translator) کا استعمال کرتے ہوئے ترجمہ کی گئی ہے۔ ہم درستگی کے لیے کوشش کرتے ہیں، لیکن براہ کرم آگاہ رہیں کہ خودکار ترجمے میں غلطیاں یا غیر درستیاں ہو سکتی ہیں۔ اصل دستاویز کو اس کی اصل زبان میں مستند ذریعہ سمجھا جانا چاہیے۔ اہم معلومات کے لیے، پیشہ ور انسانی ترجمہ کی سفارش کی جاتی ہے۔ ہم اس ترجمے کے استعمال سے پیدا ہونے والی کسی بھی غلط فہمی یا غلط تشریح کے ذمہ دار نہیں ہیں۔
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**دلعضا**:
یہ دستاویز AI ترجمہ سروس [Co-op Translator](https://github.com/Azure/co-op-translator) کے ذریعے ترجمہ کی گئی ہے۔ اگرچہ ہم درستگی کے لیے کوشاں ہیں، براہِ کرم اس بات سے آگاہ رہیں کہ خودکار تراجم میں غلطیاں یا غیر یقینی باتیں ہو سکتی ہیں۔ اصل دستاویز اپنی مادری زبان میں معتبر ماخذ شمار کی جانی چاہیے۔ اہم معلومات کے لیے پیشہ ور انسانی ترجمہ کی سفارش کی جاتی ہے۔ اس ترجمے کے استعمال سے پیدا ہونے والی کسی بھی غلط فہمی یا غلط تشریح کی ذمہ داری ہم پر عائد نہیں ہوتی۔
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
ایک چھوٹا سا ڈریگ اینڈ ڈراپ کوڈ-میڈیٹیشن۔ تھوڑے سے HTML، JS اور CSS کے ساتھ، آپ ایک ویب انٹرفیس بنا سکتے ہیں، اسے اسٹائل دے سکتے ہیں، اور اس میں انٹریکشن شامل کر سکتے ہیں۔
![میرا ٹیریریم](../../../../translated_images/screenshot_gray.0c796099a1f9f25e40aa55ead81f268434c00af30d7092490759945eda63067d.ur.png)
![میرا ٹیریریم](../../../../translated_images/screenshot_gray.0c796099a1f9f25e.ur.png)
## کریڈٹس

@ -26,7 +26,7 @@ journey
Polish experience: 5: Student
```
![براؤزر اسکیچ نوٹ](../../../../translated_images/browser.60317c9be8b7f84adce43e30bff8d47a1ae15793beab762317b2bc6b74337c1a.ur.jpg)
![براؤزر اسکیچ نوٹ](../../../../translated_images/browser.60317c9be8b7f84a.ur.jpg)
> اسکیچ نوٹ از [وسیم چگم](https://dev.to/wassimchegham/ever-wondered-what-happens-when-you-type-in-a-url-in-an-address-bar-in-a-browser-3dob)
## لیکچر سے پہلے کا کوئز
@ -79,7 +79,7 @@ mindmap
**تھوڑا سا تاریخ کے بارے میں**: پہلا براؤزر 'ورلڈ وائڈ ویب' کہلاتا تھا اور اسے سر ٹموتھی برنرز لی نے 1990 میں بنایا تھا۔
![ابتدائی براؤزرز](../../../../translated_images/earlybrowsers.d984b711cdf3a42ddac919d46c4b5ca7232f68ccfbd81395e04e5a64c0015277.ur.jpg)
![ابتدائی براؤزرز](../../../../translated_images/earlybrowsers.d984b711cdf3a42d.ur.jpg)
> کچھ ابتدائی براؤزرز، از [کیرن میکگرین](https://www.slideshare.net/KMcGrane/week-4-ixd-history-personal-computing)
### براؤزرز ویب مواد کو کیسے پروسیس کرتے ہیں
@ -198,7 +198,7 @@ quadrantChart
ایکسٹینشن انسٹالیشن کے عمل کو سمجھنا آپ کو صارف کے تجربے کی پیش گوئی کرنے میں مدد دیتا ہے جب لوگ آپ کا ایکسٹینشن انسٹال کرتے ہیں۔ انسٹالیشن کا عمل جدید براؤزرز میں معیاری ہے، انٹرفیس ڈیزائن میں معمولی فرق کے ساتھ۔
![ایج براؤزر کا اسکرین شاٹ جس میں edge://extensions صفحہ اور سیٹنگز مینو کھلا ہوا دکھایا گیا ہے](../../../../translated_images/install-on-edge.d68781acaf0b3d3dada8b7507cde7a64bf74b7040d9818baaa9070668e819f90.ur.png)
![ایج براؤزر کا اسکرین شاٹ جس میں edge://extensions صفحہ اور سیٹنگز مینو کھلا ہوا دکھایا گیا ہے](../../../../translated_images/install-on-edge.d68781acaf0b3d3d.ur.png)
> **اہم**: جب آپ اپنے ایکسٹینشنز کی جانچ کر رہے ہوں تو ڈویلپر موڈ کو آن کریں اور دوسرے اسٹورز سے ایکسٹینشنز کی اجازت دیں۔

@ -268,7 +268,7 @@ stateDiagram-v2
ClearStorage --> FirstTime: Back to setup
```
![لوکل اسٹوریج پین](../../../../translated_images/localstorage.472f8147b6a3f8d141d9551c95a2da610ac9a3c6a73d4a1c224081c98bae09d9.ur.png)
![لوکل اسٹوریج پین](../../../../translated_images/localstorage.472f8147b6a3f8d1.ur.png)
> ⚠️ **سیکیورٹی غور و فکر**: پروڈکشن ایپلیکیشنز میں، لوکل اسٹوریج میں API کلیدوں کو محفوظ کرنا سیکیورٹی خطرات پیدا کرتا ہے کیونکہ جاوا اسکرپٹ اس ڈیٹا تک رسائی حاصل کر سکتا ہے۔ سیکھنے کے مقاصد کے لیے، یہ طریقہ ٹھیک کام کرتا ہے، لیکن حقیقی ایپلیکیشنز کو حساس اسناد کے لیے محفوظ سرور سائیڈ اسٹوریج استعمال کرنا چاہیے۔

@ -126,7 +126,7 @@ flowchart LR
آئیے اسے آزمائیں۔ ایک ویب سائٹ کھولیں (Microsoft.com اس کے لیے اچھی ہے) اور 'ریکارڈ' بٹن پر کلک کریں۔ اب صفحہ کو ریفریش کریں اور پروفائلر کو ہر وہ چیز کیپچر کرتے ہوئے دیکھیں جو ہو رہی ہے۔ جب آپ ریکارڈنگ بند کریں گے، تو آپ کو ایک تفصیلی تجزیہ نظر آئے گا کہ براؤزر سائٹ کو 'اسکرپٹ'، 'رینڈر'، اور 'پینٹ' کیسے کرتا ہے۔ یہ بالکل مشن کنٹرول کی طرح ہے جو راکٹ لانچ کے دوران ہر سسٹم کی نگرانی کرتا ہے - آپ کو بالکل معلوم ہوتا ہے کہ کیا ہو رہا ہے اور کب۔
![ایج پروفائلر](../../../../translated_images/profiler.5a4a62479c5df01cfec9aab74173dba13f91d2c968e1a1ae434c26165792df15.ur.png)
![ایج پروفائلر](../../../../translated_images/profiler.5a4a62479c5df01c.ur.png)
✅ [Microsoft Documentation](https://docs.microsoft.com/microsoft-edge/devtools-guide/performance/?WT.mc_id=academic-77807-sagibbon) میں مزید تفصیلات موجود ہیں اگر آپ مزید گہرائی میں جانا چاہتے ہیں۔
@ -136,11 +136,11 @@ flowchart LR
پروفائل ٹائم لائن کے ایک حصے کو منتخب کرکے اور خلاصہ پین کو دیکھ کر اپنے صفحے کی کارکردگی کا اسنیپ شاٹ حاصل کریں:
![ایج پروفائلر اسنیپ شاٹ](../../../../translated_images/snapshot.97750180ebcad73794a3594b36925eb5c8dbaac9e03fec7f9b974188c9ac63c7.ur.png)
![ایج پروفائلر اسنیپ شاٹ](../../../../translated_images/snapshot.97750180ebcad737.ur.png)
ایونٹ لاگ پین کو چیک کریں تاکہ دیکھ سکیں کہ آیا کوئی ایونٹ 15 ملی سیکنڈ سے زیادہ وقت لے رہا ہے:
![ایج ایونٹ لاگ](../../../../translated_images/log.804026979f3707e00eebcfa028b2b5a88cec6292f858767bb6703afba65a7d9c.ur.png)
![ایج ایونٹ لاگ](../../../../translated_images/log.804026979f3707e0.ur.png)
✅ اپنے پروفائلر کو جانیں! اس سائٹ پر ڈیولپر ٹولز کھولیں اور دیکھیں کہ کیا کوئی رکاوٹیں ہیں۔ سب سے سست لوڈ ہونے والا اثاثہ کون سا ہے؟ سب سے تیز؟

@ -23,7 +23,7 @@ CO_OP_TRANSLATOR_METADATA:
### کریڈٹس
![ایک سبز براؤزر ایکسٹینشن](../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایک سبز براؤزر ایکسٹینشن](../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## کریڈٹس

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کے C02 Signal API کا استعمال کرتے ہوئے بجلی کے استعمال کو ٹریک کریں اور ایک براؤزر ایکسٹینشن بنائیں تاکہ آپ کے براؤزر میں یاد دہانی ہو کہ آپ کے علاقے میں بجلی کا استعمال کتنا زیادہ ہے۔ اس ایکسٹینشن کو استعمال کرنے سے آپ کو اپنی سرگرمیوں کے بارے میں بہتر فیصلے کرنے میں مدد ملے گی۔
![ایکسٹینشن اسکرین شاٹ](../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن اسکرین شاٹ](../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات کرنا
@ -31,7 +31,7 @@ npm run build
Edge پر انسٹال کرنے کے لیے، براؤزر کے اوپر دائیں کونے میں موجود 'تین نقطے' والے مینو کا استعمال کریں تاکہ ایکسٹینشنز پینل تک پہنچ سکیں۔ وہاں سے 'Load Unpacked' کو منتخب کریں تاکہ ایک نیا ایکسٹینشن لوڈ کیا جا سکے۔ جب پرامپٹ آئے تو 'dist' فولڈر کھولیں اور ایکسٹینشن لوڈ ہو جائے گا۔ اسے استعمال کرنے کے لیے آپ کو CO2 Signal کے API کے لیے ایک API key کی ضرورت ہوگی ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2signal.com/) - اس صفحے پر اپنا ای میل درج کریں) اور اپنے علاقے کے لیے [Electricity Map](https://www.electricitymap.org/map) کے مطابق [کوڈ](http://api.electricitymap.org/v3/zones) کی ضرورت ہوگی (مثال کے طور پر، بوسٹن میں، میں 'US-NEISO' استعمال کرتا ہوں)۔
![انسٹال کرنا](../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹال کرنا](../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
جب API key اور علاقائی کوڈ ایکسٹینشن انٹرفیس میں درج کر دیے جائیں، تو براؤزر ایکسٹینشن بار میں موجود رنگین نقطہ آپ کے علاقے کے توانائی کے استعمال کو ظاہر کرے گا اور آپ کو یہ مشورہ دے گا کہ کون سی توانائی سے متعلق سرگرمیاں آپ کے لیے مناسب ہوں گی۔ اس 'نقطہ' سسٹم کا تصور مجھے [Energy Lollipop ایکسٹینشن](https://energylollipop.com/) سے ملا تھا جو کیلیفورنیا کے اخراجات کے لیے بنایا گیا ہے۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کی CO2 Signal API کا استعمال کرتے ہوئے بجلی کی کھپت کو ٹریک کریں اور ایک براؤزر ایکسٹینشن بنائیں تاکہ آپ کو اپنے براؤزر میں براہ راست اپنی علاقے کی بجلی کی کھپت کا یاد دہانی مل سکے۔ اس ایڈہاک ایکسٹینشن کا استعمال آپ کو ان معلومات کی بنیاد پر اپنی سرگرمیوں کے بارے میں بہتر فیصلہ کرنے میں مدد دے گا۔
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات
@ -31,7 +31,7 @@ npm run build
Edge پر انسٹال کرنے کے لیے، براؤزر کے اوپری دائیں کونے میں 'تین نقطے' والے مینو کا استعمال کریں تاکہ ایکسٹینشنز کا پینل تلاش کریں۔ وہاں سے، 'غیر کمپریسڈ ایکسٹینشن لوڈ کریں' کو منتخب کریں تاکہ ایک نئی ایکسٹینشن لوڈ کی جا سکے۔ پرامپٹ پر 'dist' فولڈر کھولیں اور ایکسٹینشن لوڈ ہو جائے گی۔ استعمال کے لیے، آپ کو CO2 Signal API کے لیے ایک API کلید کی ضرورت ہوگی ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2signal.com/) - اس صفحے پر دیے گئے باکس میں اپنا ای میل درج کریں) اور اپنے علاقے کے لیے [کوڈ](http://api.electricitymap.org/v3/zones) جو [الیکٹریسٹی میپ](https://www.electricitymap.org/map) سے مطابقت رکھتا ہو (مثال کے طور پر، بوسٹن میں، میں 'US-NEISO' استعمال کرتا ہوں)۔
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
ایک بار جب API کلید اور علاقہ ایکسٹینشن کے انٹرفیس میں درج ہو جائیں، تو براؤزر کی ایکسٹینشن بار میں رنگین نقطہ آپ کے علاقے کی توانائی کی کھپت کو ظاہر کرنے کے لیے تبدیل ہو جانا چاہیے اور آپ کو توانائی کے زیادہ استعمال والی سرگرمیوں کے بارے میں اشارہ دینا چاہیے جو آپ کے لیے مناسب ہو سکتی ہیں۔ اس 'نقطہ' سسٹم کے پیچھے تصور مجھے [Energy Lollipop ایکسٹینشن](https://energylollipop.com/) سے ملا، جو کیلیفورنیا کے اخراجات کے لیے بنایا گیا ہے۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کے C02 سگنل API کا استعمال کرتے ہوئے بجلی کے استعمال کو ٹریک کرنے کے لیے ایک براؤزر ایکسٹینشن بنائیں تاکہ آپ کے براؤزر میں آپ کے علاقے کی بجلی کے استعمال کی شدت کے بارے میں آپ کو یاد دہانی مل سکے۔ اس ایکسٹینشن کا استعمال آپ کو اس معلومات کی بنیاد پر اپنی سرگرمیوں کے بارے میں فیصلے کرنے میں مدد دے گا۔
![ایکسٹینشن اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات کرنا
@ -31,7 +31,7 @@ npm run build
ایج پر انسٹال کرنے کے لیے، براؤزر کے اوپری دائیں کونے میں 'تین ڈاٹ' مینو کا استعمال کرتے ہوئے ایکسٹینشن پینل تلاش کریں۔ وہاں سے، ایک نیا ایکسٹینشن لوڈ کرنے کے لیے 'لوڈ ان پیکڈ' کا انتخاب کریں۔ پرامپٹ پر 'dist' فولڈر کھولیں اور ایکسٹینشن لوڈ ہو جائے گا۔ اس کا استعمال کرنے کے لیے، آپ کو CO2 سگنل API ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2snal.com/)) کے لیے ایک API کلید کی ضرورت ہوگی - اس صفحے پر باکس میں اپنا ای میل درج کریں) اور [اپنے علاقے کے لیے کوڈ](http://api.electricitymap.org/v3/zones) [الیکٹریسٹی میپ](https://www.electricitymap.org/map) سے حاصل کریں (مثال کے طور پر، بوسٹن میں، میں 'US-NEISO' استعمال کرتا ہوں)۔
![انسٹال کرنا](../../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹال کرنا](../../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
ایک بار جب API کلید اور علاقہ ایکسٹینشن انٹرفیس میں درج ہو جائیں، تو براؤزر ایکسٹینشن بار میں رنگین ڈاٹ آپ کے علاقے کی توانائی کے استعمال کی عکاسی کرنے کے لیے تبدیل ہو جانا چاہیے اور آپ کو یہ اشارہ دینا چاہیے کہ توانائی سے بھرپور سرگرمیاں آپ کے لیے کب موزوں ہوں گی۔ اس 'ڈاٹ' سسٹم کے پیچھے کا تصور مجھے کیلیفورنیا کے اخراج کے لیے [انرجی لالی پاپ ایکسٹینشن](https://energylollipop.com/) سے ملا تھا۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
آپ tmrow کی Signal CO2 API کا استعمال کریں گے تاکہ بجلی کے استعمال کی نگرانی کی جا سکے اور ایک براؤزر ایکسٹینشن بنائی جا سکے، جس سے آپ کو اپنے براؤزر میں براہ راست یاد دہانی ملے کہ آپ کے علاقے میں بجلی کا استعمال کتنا زیادہ ہے۔ اس خاص ایکسٹینشن کا استعمال آپ کو اپنی سرگرمیوں کا جائزہ لینے میں مدد دے گا، ان معلومات کی بنیاد پر۔
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات کے لیے
@ -31,7 +31,7 @@ npm run build
Edge پر انسٹال کرنے کے لیے، براؤزر کے اوپری دائیں کونے میں "تین نقطے" والے مینو کا استعمال کریں تاکہ ایکسٹینشنز کا پینل تلاش کیا جا سکے۔ اگر پہلے سے فعال نہیں ہے، تو ڈویلپر موڈ کو فعال کریں (نیچے بائیں جانب)۔ "غیر کمپریسڈ لوڈ کریں" کو منتخب کریں تاکہ ایک نئی ایکسٹینشن لوڈ کی جا سکے۔ پرامپٹ پر "dist" فولڈر کھولیں، اور ایکسٹینشن لوڈ ہو جائے گی۔ استعمال کے لیے، آپ کو CO2 Signal API کے لیے ایک API کلید کی ضرورت ہوگی (آپ اسے [یہاں ای میل کے ذریعے حاصل کر سکتے ہیں](https://www.co2signal.com/) - اس صفحے پر موجود باکس میں اپنا ای میل درج کریں) اور اپنی [بجلی کی نقشے](https://www.electricitymap.org/map) کے مطابق [علاقے کا کوڈ](http://api.electricitymap.org/v3/zones) (مثال کے طور پر، بوسٹن میں "US-NEISO")۔
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
ایک بار جب API کلید اور علاقہ ایکسٹینشن کے انٹرفیس میں درج کر دیے جائیں، تو براؤزر کی ایکسٹینشن بار میں رنگین نقطہ علاقے کے توانائی کے استعمال کی عکاسی کرنے کے لیے تبدیل ہو جانا چاہیے اور یہ اشارہ فراہم کرے گا کہ کون سی زیادہ توانائی استعمال کرنے والی سرگرمیاں انجام دینے کے لیے موزوں ہوں گی۔ اس "نقطہ" سسٹم کا تصور [Energy Lollipop ایکسٹینشن](https://energylollipop.com/) سے لیا گیا ہے، جو کیلیفورنیا کی اخراجات کے لیے بنایا گیا تھا۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کے CO2 سگنل API کا استعمال کرتے ہوئے، آپ کے علاقے میں بجلی کے استعمال کی مقدار کو ٹریک کرنے کے لیے ایک براؤزر ایکسٹینشن بنایا گیا ہے جو آپ کے براؤزر پر ایک یاد دہانی کے طور پر ظاہر ہوتا ہے۔ اس ایکسٹینشن کو استعمال کرتے ہوئے، آپ اپنی سرگرمیوں کا فیصلہ اس معلومات کی بنیاد پر کر سکتے ہیں۔
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات کریں
@ -31,7 +31,7 @@ npm run build
Edge میں انسٹال کرنے کے لیے، براؤزر کے اوپر دائیں کونے میں موجود "تین نقطے" والے مینو سے "ایکسٹینشنز" پینل کو تلاش کریں۔ وہاں سے "Load Unpacked" کو منتخب کریں اور نئی ایکسٹینشن لوڈ کریں۔ جب پرامپٹ آئے تو "dist" فولڈر کو کھولیں، اور ایکسٹینشن لوڈ ہو جائے گی۔ استعمال کے لیے، آپ کو CO2 سگنل API کی API کلید ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2signal.com/) - اس صفحے کے باکس میں اپنا ای میل درج کریں) اور [Electricity Map](https://www.electricitymap.org/map) کے مطابق اپنے علاقے کا [کوڈ](http://api.electricitymap.org/v3/zones) درکار ہوگا (مثال کے طور پر، بوسٹن کے لیے 'US-NEISO' استعمال کیا جاتا ہے)۔
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹالیشن](../../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
جب آپ API کلید اور علاقہ ایکسٹینشن انٹرفیس میں درج کریں گے، تو براؤزر کے ایکسٹینشن بار میں ظاہر ہونے والا رنگین ڈاٹ آپ کے علاقے کی توانائی کے استعمال کی عکاسی کرے گا اور یہ بتائے گا کہ کس قسم کی توانائی کی ضرورت والی سرگرمیاں انجام دینا مناسب ہے۔ اس "ڈاٹ" سسٹم کا تصور مجھے کیلیفورنیا کے اخراجات کے لیے [Energy Lollipop extension](https://energylollipop.com/) سے ملا۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کے CO2 سگنل API کا استعمال کرتے ہوئے بجلی کے استعمال کا پتہ لگائیں اور ایک براؤزر ایکسٹینشن بنائیں تاکہ آپ کو اپنے علاقے میں بجلی کے استعمال کی شدت کے بارے میں براؤزر میں الرٹس مل سکیں۔ اس ایکسٹینشن کا استعمال خاص طور پر آپ کو اپنی سرگرمیوں کے بارے میں بہتر فیصلے کرنے میں مدد دے گا۔
![براؤزر ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![براؤزر ایکسٹینشن کا اسکرین شاٹ](../../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات یہاں سے کریں
@ -31,7 +31,7 @@ npm run build
Edge میں انسٹال کرنے کے لیے، براؤزر کے دائیں اوپری کونے میں 'تین نقطے' والے مینو کا استعمال کریں تاکہ ایکسٹینشن پینل تلاش کریں۔ وہاں سے، 'Load Unpacked' کو منتخب کریں تاکہ نیا ایکسٹینشن لوڈ کیا جا سکے۔ درخواست پر 'dist' فولڈر کھولیں اور ایکسٹینشن لوڈ ہو جائے گی۔ اسے استعمال کرنے کے لیے، آپ کو CO2 سگنل API کے لیے ایک API کلید کی ضرورت ہوگی ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2signal.com/) - اس صفحے پر اپنے ای میل کو باکس میں ڈالیں) اور [اپنے علاقے کے لیے کوڈ](http://api.electricitymap.org/v3/zones) جو [الیکٹریسٹی میپ](https://www.electricitymap.org/map) سے مطابقت رکھتا ہو (مثال کے طور پر، بوسٹن میں، میں 'US-NEISO' استعمال کرتا ہوں)۔
![ڈاؤن لوڈ ہو رہا ہے](../../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![ڈاؤن لوڈ ہو رہا ہے](../../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
ایک بار جب API کلید اور علاقہ ایکسٹینشن کے انٹرفیس میں ڈال دیا جائے، تو براؤزر ایکسٹینشن بار میں رنگین نقطہ آپ کے علاقے کے توانائی کے استعمال کی عکاسی کرنے کے لیے بدل جائے گا اور آپ کو یہ مشورہ دے گا کہ کون سی بھاری سرگرمیاں آپ کے لیے مناسب ہیں۔ اس 'ڈاٹ' سسٹم کا تصور مجھے [انرجی لالی پاپ براؤزر ایکسٹینشن](https://energylollipop.com/) سے ملا، جو کیلیفورنیا کے اخراجات کے لیے بنایا گیا ہے۔

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
tmrow کے C02 Signal API کا استعمال کرتے ہوئے بجلی کے استعمال کو ٹریک کریں اور ایک براؤزر ایکسٹینشن بنائیں تاکہ آپ کے براؤزر میں یاد دہانی ہو کہ آپ کے علاقے میں بجلی کا استعمال کتنا زیادہ ہے۔ اس ایکسٹینشن کو وقتی طور پر استعمال کرنے سے آپ کو اپنی سرگرمیوں کے بارے میں بہتر فیصلے کرنے میں مدد ملے گی۔
![ایکسٹینشن اسکرین شاٹ](../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3875e1bc9405edd45a3d2e02963e48900adb91926a62a5807.ur.png)
![ایکسٹینشن اسکرین شاٹ](../../../../translated_images/extension-screenshot.0e7f5bfa110e92e3.ur.png)
## شروعات کریں
@ -31,7 +31,7 @@ npm run build
Edge پر انسٹال کرنے کے لیے، براؤزر کے اوپر دائیں کونے میں موجود 'تین نقطے' والے مینو کا استعمال کریں تاکہ ایکسٹینشنز پینل تک پہنچ سکیں۔ وہاں سے 'Load Unpacked' کو منتخب کریں تاکہ نئی ایکسٹینشن لوڈ کی جا سکے۔ جب پرامپٹ آئے تو 'dist' فولڈر کھولیں اور ایکسٹینشن لوڈ ہو جائے گی۔ اسے استعمال کرنے کے لیے، آپ کو CO2 Signal کے API کے لیے ایک API key ([یہاں ای میل کے ذریعے حاصل کریں](https://www.co2signal.com/) - اس صفحے پر موجود باکس میں اپنا ای میل درج کریں) اور اپنے علاقے کے لیے [Electricity Map](https://www.electricitymap.org/map) کے مطابق [کوڈ](http://api.electricitymap.org/v3/zones) کی ضرورت ہوگی (مثال کے طور پر، بوسٹن میں، میں 'US-NEISO' استعمال کرتا ہوں)۔
![انسٹال کرنا](../../../../translated_images/install-on-edge.78634f02842c48283726c531998679a6f03a45556b2ee99d8ff231fe41446324.ur.png)
![انسٹال کرنا](../../../../translated_images/install-on-edge.78634f02842c4828.ur.png)
جب API key اور علاقائی کوڈ ایکسٹینشن انٹرفیس میں درج کر دیے جائیں، تو براؤزر ایکسٹینشن بار میں موجود رنگین نقطہ آپ کے علاقے کے توانائی کے استعمال کو ظاہر کرے گا اور آپ کو یہ مشورہ دے گا کہ کون سی توانائی سے متعلق سرگرمیاں آپ کے لیے مناسب ہوں گی۔ اس 'نقطہ' نظام کا تصور مجھے [Energy Lollipop ایکسٹینشن](https://energylollipop.com/) سے ملا تھا جو کیلیفورنیا کے اخراجات کے لیے بنایا گیا ہے۔

@ -108,7 +108,7 @@ quadrantChart
UI Elements: [0.9, 0.1]
```
![کینوس کا گرڈ](../../../../translated_images/canvas_grid.5f209da785ded492a01ece440e3032afe51efa500cc2308e5ea4252487ceaf0b.ur.png)
![کینوس کا گرڈ](../../../../translated_images/canvas_grid.5f209da785ded492.ur.png)
> تصویر [MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes) سے
کینوس عنصر پر ڈرائنگ کرنے کے لیے، آپ وہی تین قدمی عمل اپنائیں گے جو تمام کینوس گرافکس کی بنیاد بناتا ہے۔ ایک بار جب آپ یہ چند بار کریں گے، تو یہ آپ کے لیے آسان ہو جائے گا:
@ -181,7 +181,7 @@ ctx.fillRect(0, 0, 200, 200); // x, y, width, height
حتمی نتیجہ کچھ اس طرح نظر آنا چاہیے:
![کالا اسکرین جس پر ایک ہیرو اور 5*5 مونسٹرز ہیں](../../../../translated_images/partI-solution.36c53b48c9ffae2a5e15496b23b604ba5393433e4bf91608a7a0a020eb7a2691.ur.png)
![کالا اسکرین جس پر ایک ہیرو اور 5*5 مونسٹرز ہیں](../../../../translated_images/partI-solution.36c53b48c9ffae2a.ur.png)
## حل

@ -160,7 +160,7 @@ sequenceDiagram
```
- **اسکورنگ سسٹم**: ہر تباہ شدہ دشمن جہاز 100 پوائنٹس دیتا ہے (گول نمبر کھلاڑیوں کے لیے ذہنی طور پر حساب لگانا آسان بناتے ہیں)۔ اسکور نیچے بائیں کونے میں دکھایا جاتا ہے۔
- **زندگی کا کاؤنٹر**: آپ کا ہیرو تین زندگیوں کے ساتھ شروع ہوتا ہے - ابتدائی آرکیڈ گیمز کے ذریعہ چیلنج اور کھیلنے کی صلاحیت کو متوازن کرنے کے لیے قائم کردہ معیار۔ دشمن کے ساتھ ہر تصادم ایک زندگی کی قیمت پر ہوتا ہے۔ ہم نیچے دائیں کونے میں جہاز کے آئیکنز کے ذریعے باقی زندگیوں کو دکھائیں گے ![زندگی کی تصویر](../../../../translated_images/life.6fb9f50d53ee0413cd91aa411f7c296e10a1a6de5c4a4197c718b49bf7d63ebf.ur.png)۔
- **زندگی کا کاؤنٹر**: آپ کا ہیرو تین زندگیوں کے ساتھ شروع ہوتا ہے - ابتدائی آرکیڈ گیمز کے ذریعہ چیلنج اور کھیلنے کی صلاحیت کو متوازن کرنے کے لیے قائم کردہ معیار۔ دشمن کے ساتھ ہر تصادم ایک زندگی کی قیمت پر ہوتا ہے۔ ہم نیچے دائیں کونے میں جہاز کے آئیکنز کے ذریعے باقی زندگیوں کو دکھائیں گے ![زندگی کی تصویر](../../../../translated_images/life.6fb9f50d53ee0413.ur.png)۔
## آئیے تعمیر شروع کریں!

@ -616,7 +616,7 @@ sequenceDiagram
`history.pushState` براؤزر کے نیویگیشن history میں نئے entries بناتا ہے۔ آپ اسے چیک کر سکتے ہیں براؤزر کے *back button* کو دبائے رکھ کر، یہ کچھ اس طرح دکھائے گا:
![نیویگیشن history کا اسکرین شاٹ](../../../../translated_images/history.7fdabbafa521e06455b738d3dafa3ff41d3071deae60ead8c7e0844b9ed987d8.ur.png)
![نیویگیشن history کا اسکرین شاٹ](../../../../translated_images/history.7fdabbafa521e064.ur.png)
اگر آپ back button پر چند بار کلک کرنے کی کوشش کریں، تو آپ دیکھیں گے کہ موجودہ URL تبدیل ہوتا ہے اور history اپ ڈیٹ ہوتی ہے، لیکن وہی template ظاہر ہوتا رہتا ہے۔

@ -295,7 +295,7 @@ graph TD
2. اپنے براؤزر کے ایڈریس بار میں تبدیلیوں کا مشاہدہ کریں
3. دیکھیں کہ صفحہ کیسے ری لوڈ ہوتا ہے اور ڈیٹا URL میں ظاہر ہوتا ہے
![رجسٹر بٹن پر کلک کرنے کے بعد براؤزر کے URL میں تبدیلی کا اسکرین شاٹ](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.ur.png)
![رجسٹر بٹن پر کلک کرنے کے بعد براؤزر کے URL میں تبدیلی کا اسکرین شاٹ](../../../../translated_images/click-register.e89a30bf0d4bc9ca.ur.png)
### HTTP طریقوں کا موازنہ
@ -350,7 +350,7 @@ graph TD
2. **"اکاؤنٹ بنائیں" بٹن پر کلک کریں**
3. **اپنے براؤزر میں سرور کے جواب کا مشاہدہ کریں**
![براؤزر ونڈو ایڈریس localhost:5000/api/accounts پر، صارف کے ڈیٹا کے ساتھ JSON اسٹرنگ دکھا رہا ہے](../../../../translated_images/form-post.61de4ca1b964d91a9e338416e19f218504dd0af5f762fbebabfe7ae80edf885f.ur.png)
![براؤزر ونڈو ایڈریس localhost:5000/api/accounts پر، صارف کے ڈیٹا کے ساتھ JSON اسٹرنگ دکھا رہا ہے](../../../../translated_images/form-post.61de4ca1b964d91a.ur.png)
**آپ کو کیا دیکھنا چاہیے:**
- **براؤزر ری ڈائریکٹ** API اینڈ پوائنٹ URL پر
@ -554,7 +554,7 @@ async function register() {
3. **"اکاؤنٹ بنائیں" پر کلک کریں**
4. **کنسول پیغامات اور صارف تاثرات کا مشاہدہ کریں**
![براؤزر کنسول میں لاگ پیغام دکھانے والا اسکرین شاٹ](../../../../translated_images/browser-console.efaf0b51aaaf67782a29e1a0bb32cc063f189b18e894eb5926e02f1abe864ec2.ur.png)
![براؤزر کنسول میں لاگ پیغام دکھانے والا اسکرین شاٹ](../../../../translated_images/browser-console.efaf0b51aaaf6778.ur.png)
**آپ کو کیا دیکھنا چاہیے:**
- **لوڈنگ اسٹیٹ** جمع کرانے کے بٹن پر ظاہر ہوتا ہے
@ -729,7 +729,7 @@ input:focus:invalid {
3. **صارف نام کے فیلڈ میں خصوصی کردار آزمائیں**
4. **منفی بیلنس کی رقم درج کریں**
![فارم جمع کرانے کی کوشش کرتے وقت توثیق کی خرابی دکھانے والا اسکرین شاٹ](../../../../translated_images/validation-error.8bd23e98d416c22f80076d04829a4bb718e0e550fd622862ef59008ccf0d5dce.ur.png)
![فارم جمع کرانے کی کوشش کرتے وقت توثیق کی خرابی دکھانے والا اسکرین شاٹ](../../../../translated_images/validation-error.8bd23e98d416c22f.ur.png)
**آپ کیا مشاہدہ کریں گے:**
- **براؤزر دکھاتا ہے** مقامی توثیق کے پیغامات
@ -858,7 +858,7 @@ timeline
یہاں ایک مثال ہے کہ CSS اسٹائلز شامل کرنے کے بعد حتمی لاگ ان صفحہ کیسا نظر آ سکتا ہے:
![CSS اسٹائلز شامل کرنے کے بعد لاگ ان صفحہ کا اسکرین شاٹ](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.ur.png)
![CSS اسٹائلز شامل کرنے کے بعد لاگ ان صفحہ کا اسکرین شاٹ](../../../../translated_images/result.96ef01f607bf856a.ur.png)
## لیکچر کے بعد کا کوئز

@ -160,7 +160,7 @@ sequenceDiagram
Browser->>User: Displays new page (flash/reload)
```
![ملٹی پیج ایپلیکیشن میں اپ ڈیٹ ورک فلو](../../../../translated_images/mpa.7f7375a1a2d4aa779d3f928a2aaaf9ad76bcdeb05cfce2dc27ab126024050f51.ur.png)
![ملٹی پیج ایپلیکیشن میں اپ ڈیٹ ورک فلو](../../../../translated_images/mpa.7f7375a1a2d4aa77.ur.png)
**یہ طریقہ کیوں بھاری محسوس ہوتا تھا:**
- ہر کلک کا مطلب پورے صفحے کو شروع سے دوبارہ تعمیر کرنا تھا
@ -187,7 +187,7 @@ sequenceDiagram
Browser->>User: Shows updated content (no reload)
```
![سنگل پیج ایپلیکیشن میں اپ ڈیٹ ورک فلو](../../../../translated_images/spa.268ec73b41f992c2a21ef9294235c6ae597b3c37e2c03f0494c2d8857325cc57.ur.png)
![سنگل پیج ایپلیکیشن میں اپ ڈیٹ ورک فلو](../../../../translated_images/spa.268ec73b41f992c2.ur.png)
**SPA کیوں بہتر محسوس ہوتی ہیں:**
- صرف وہ حصے جو واقعی تبدیل ہوئے ہیں اپ ڈیٹ ہوتے ہیں (سمارٹ، ہے نا؟)
@ -508,7 +508,7 @@ if (data.error) {
اب جب آپ کسی غلط اکاؤنٹ کے ساتھ ٹیسٹ کریں گے، تو آپ صفحے پر ایک مددگار غلطی کا پیغام دیکھیں گے!
![لاگ ان کے دوران دکھائے جانے والے غلطی کے پیغام کا اسکرین شاٹ](../../../../translated_images/login-error.416fe019b36a63276764c2349df5d99e04ebda54fefe60c715ee87a28d5d4ad0.ur.png)
![لاگ ان کے دوران دکھائے جانے والے غلطی کے پیغام کا اسکرین شاٹ](../../../../translated_images/login-error.416fe019b36a6327.ur.png)
#### مرحلہ 4: رسائی کے ساتھ شامل ہونا
@ -891,7 +891,7 @@ Agent موڈ کے بارے میں مزید جانیں [یہاں](https://code.vi
یہاں ایک پالش شدہ ڈیش بورڈ کی مثال کی طرح نظر آ سکتا ہے:
![ڈیش بورڈ کے اسٹائلنگ کے بعد کے نتیجے کی مثال کا اسکرین شاٹ](../../../../translated_images/screen2.123c82a831a1d14ab2061994be2fa5de9cec1ce651047217d326d4773a6348e4.ur.png)
![ڈیش بورڈ کے اسٹائلنگ کے بعد کے نتیجے کی مثال کا اسکرین شاٹ](../../../../translated_images/screen2.123c82a831a1d14a.ur.png)
ایسا محسوس نہ کریں کہ آپ کو اسے بالکل اسی طرح سے ملانا ہے - اسے بطور تحریک استعمال کریں اور اسے اپنا بنائیں!

@ -190,7 +190,7 @@ mindmap
اپنے دماغ کو الجھانے کے بجائے، ہم ایک **مرکزی اسٹیٹ مینجمنٹ** سسٹم بنائیں گے۔ اسے ایسے سمجھیں جیسے ایک بہت ہی منظم شخص تمام اہم چیزوں کا انچارج ہو:
![HTML، صارف کے اعمال اور اسٹیٹ کے درمیان ڈیٹا کے بہاؤ کو ظاہر کرنے والی اسکیمہ](../../../../translated_images/data-flow.fa2354e0908fecc89b488010dedf4871418a992edffa17e73441d257add18da4.ur.png)
![HTML، صارف کے اعمال اور اسٹیٹ کے درمیان ڈیٹا کے بہاؤ کو ظاہر کرنے والی اسکیمہ](../../../../translated_images/data-flow.fa2354e0908fecc8.ur.png)
```mermaid
flowchart TD

@ -112,7 +112,7 @@ CO_OP_TRANSLATOR_METADATA:
**متوقع نتیجہ:**
اس اسائنمنٹ کو مکمل کرنے کے بعد، آپ کی بینکنگ ایپ میں ایک مکمل طور پر فعال "ٹرانزیکشن شامل کریں" فیچر ہونا چاہیے جو پیشہ ورانہ نظر آئے اور کام کرے:
![ایک مثال "ٹرانزیکشن شامل کریں" ڈائیلاگ دکھانے والا اسکرین شاٹ](../../../../translated_images/dialog.93bba104afeb79f12f65ebf8f521c5d64e179c40b791c49c242cf15f7e7fab15.ur.png)
![ایک مثال "ٹرانزیکشن شامل کریں" ڈائیلاگ دکھانے والا اسکرین شاٹ](../../../../translated_images/dialog.93bba104afeb79f1.ur.png)
## اپنی نافذ کردہ چیز کی جانچ

@ -11,7 +11,7 @@ CO_OP_TRANSLATOR_METADATA:
اس پروجیکٹ میں، آپ ایک خیالی بینک بنانے کا طریقہ سیکھیں گے۔ یہ اسباق آپ کو ویب ایپ کی ترتیب اور راستے فراہم کرنے، فارم بنانے، اسٹیٹ کو منظم کرنے، اور API سے ڈیٹا حاصل کرنے کے طریقے سکھائیں گے جس سے آپ بینک کا ڈیٹا حاصل کر سکتے ہیں۔
| ![Screen1](../../../translated_images/screen1.baccbba0f1f93364672eb250d2fbd21574bb1caf79a2155022dc098a741cbdfe.ur.png) | ![Screen2](../../../translated_images/screen2.123c82a831a1d14ab2061994be2fa5de9cec1ce651047217d326d4773a6348e4.ur.png) |
| ![Screen1](../../../translated_images/screen1.baccbba0f1f93364.ur.png) | ![Screen2](../../../translated_images/screen2.123c82a831a1d14a.ur.png) |
|--------------------------------|--------------------------------|
## اسباق

@ -185,7 +185,7 @@ VSCode.dev یہ صلاحیتیں آپ کے براؤزر میں لاتا ہے:
جب سب کچھ لوڈ ہو جائے، تو آپ ایک خوبصورت صاف ورک اسپیس دیکھیں گے جو آپ کو اس پر مرکوز رکھنے کے لیے ڈیزائن کیا گیا ہے جو اہم ہے آپ کا کوڈ!
![ڈیفالٹ VSCode.dev انٹرفیس](../../../../translated_images/default-vscode-dev.5d06881d65c1b3234ce50cd9ed3b0028e6031ad5f5b441bcbed96bfa6311f6d0.ur.png)
![ڈیفالٹ VSCode.dev انٹرفیس](../../../../translated_images/default-vscode-dev.5d06881d65c1b323.ur.png)
**یہاں آپ کے علاقے کا دورہ ہے:**
- **ایکٹیویٹی بار** (بائیں طرف کی پٹی): آپ کی مرکزی نیویگیشن جس میں ایکسپلورر 📁، سرچ 🔍، سورس کنٹرول 🌿، ایکسٹینشنز 🧩، اور سیٹنگز ⚙️ شامل ہیں
@ -233,7 +233,7 @@ flowchart TB
1. [vscode.dev](https://vscode.dev) پر جائیں اگر آپ پہلے سے وہاں نہیں ہیں
2. ویلکم اسکرین پر "اوپن ریموٹ ریپوزیٹری" بٹن تلاش کریں اور اس پر کلک کریں
![اوپن ریموٹ ریپوزیٹری](../../../../translated_images/open-remote-repository.bd9c2598b8949e7fc283cdfc8f4050c6205a7c7c6d3f78c4b135115d037d6fa2.ur.png)
![اوپن ریموٹ ریپوزیٹری](../../../../translated_images/open-remote-repository.bd9c2598b8949e7f.ur.png)
3. کسی بھی GitHub ریپوزیٹری URL کو پیسٹ کریں (اسے آزمائیں: `https://github.com/microsoft/Web-Dev-For-Beginners`)
4. انٹر دبائیں اور جادو دیکھیں!
@ -242,7 +242,7 @@ flowchart TB
کیا آپ کوڈنگ کے جادوگر کی طرح محسوس کرنا چاہتے ہیں؟ یہ کی بورڈ شارٹ کٹ آزمائیں: Ctrl+Shift+P (یا Mac پر Cmd+Shift+P) کمانڈ پیلیٹ کھولنے کے لیے:
![کمانڈ پیلیٹ](../../../../translated_images/palette-menu.4946174e07f426226afcdad707d19b8d5150e41591c751c45b5dee213affef91.ur.png)
![کمانڈ پیلیٹ](../../../../translated_images/palette-menu.4946174e07f42622.ur.png)
**کمانڈ پیلیٹ ایسا ہے جیسے آپ کے پاس ہر چیز کے لیے سرچ انجن ہو:**
- "اوپن ریموٹ" ٹائپ کریں اور یہ آپ کے لیے ریپوزیٹری اوپنر تلاش کرے گا
@ -304,7 +304,7 @@ flowchart TB
3. مناسب ایکسٹینشن سمیت فائل کا نام درج کریں (`style.css`, `script.js`, `index.html`)
4. فائل بنانے کے لیے انٹر دبائیں
![نئی فائل بنانا](../../../../translated_images/create-new-file.2814e609c2af9aeb6c6fd53156c503ac91c3d538f9cac63073b2dd4a7631f183.ur.png)
![نئی فائل بنانا](../../../../translated_images/create-new-file.2814e609c2af9aeb.ur.png)
**نام رکھنے کے اصول:**
- وضاحتی نام استعمال کریں جو فائل کے مقصد کی نشاندہی کریں
@ -387,7 +387,7 @@ mindmap
2. ارد گرد براؤز کریں یا کسی خاص چیز کی تلاش کریں
3. جو دلچسپ لگے اس پر کلک کریں تاکہ اس کے بارے میں مزید جان سکیں
![ایکسٹینشن مارکیٹ پلیس انٹرفیس](../../../../translated_images/extensions.eca0e0c7f59a10b5c88be7fe24b3e32cca6b6058b35a49026c3a9d80b1813b7c.ur.png)
![ایکسٹینشن مارکیٹ پلیس انٹرفیس](../../../../translated_images/extensions.eca0e0c7f59a10b5.ur.png)
**آپ کو وہاں کیا نظر آئے گا:**
@ -440,7 +440,7 @@ mindmap
3. ڈراپ ڈاؤن سے "ایکسٹینشن سیٹنگز" منتخب کریں
4. چیزوں کو ایڈجسٹ کریں جب تک کہ وہ آپ کے ورک فلو کے لیے بالکل صحیح محسوس نہ ہوں
![ایکسٹینشن سیٹنگز کو حسب ضرورت بنانا](../../../../translated_images/extension-settings.21c752ae4f4cdb78a867f140ccd0680e04619d0c44bb4afb26373e54b829d934.ur.png)
![ایکسٹینشن سیٹنگز کو حسب ضرورت بنانا](../../../../translated_images/extension-settings.21c752ae4f4cdb78.ur.png)
**عام چیزیں جو آپ ایڈجسٹ کرنا چاہیں گے:**
- آپ کا کوڈ کیسے فارمیٹ ہوتا ہے (ٹیبز بمقابلہ اسپیسز، لائن کی لمبائی، وغیرہ)

@ -78,7 +78,7 @@ CO_OP_TRANSLATOR_METADATA:
4. ایک کمیٹ میسج لکھیں: "Add initial HTML structure"
5. "Commit new file" پر کلک کریں تاکہ آپ کی تبدیلیاں محفوظ ہو جائیں
![گٹ ہب پر ابتدائی فائل بنانا](../../../../translated_images/new-file-github.com.c886796d800e8056561829a181be1382c5303da9d902d8b2dd82b68a4806e21f.ur.png)
![گٹ ہب پر ابتدائی فائل بنانا](../../../../translated_images/new-file-github.com.c886796d800e8056.ur.png)
**یہ ابتدائی سیٹ اپ کیا حاصل کرتا ہے:**
- **مناسب ایچ ٹی ایم ایل 5 دستاویز کی ساخت قائم کرتا ہے** سیمینٹک عناصر کے ساتھ
@ -104,7 +104,7 @@ CO_OP_TRANSLATOR_METADATA:
**کامیابی کا اشارہ**: آپ کو اپنے پروجیکٹ فائلز ایکسپلورر سائیڈ بار میں اور `index.html` کو مرکزی ایڈیٹر ایریا میں ایڈیٹنگ کے لیے دستیاب دیکھنا چاہیے۔
![وی ایس کوڈ ڈاٹ ڈی وی میں پروجیکٹ لوڈ ہوا](../../../../translated_images/project-on-vscode.dev.e79815a9a95ee7feac72ebe5c941c91279716be37c575dbdbf2f43bea2c7d8b6.ur.png)
![وی ایس کوڈ ڈاٹ ڈی وی میں پروجیکٹ لوڈ ہوا](../../../../translated_images/project-on-vscode.dev.e79815a9a95ee7fe.ur.png)
**انٹرفیس میں آپ کیا دیکھیں گے:**
- **ایکسپلورر سائیڈ بار**: **آپ کے ریپوزیٹری فائلز اور فولڈر کی ساخت دکھاتا ہے**
@ -448,7 +448,7 @@ li:before {
**انسٹالیشن کے بعد فوری نتائج:**
ایک بار کوڈ سوئنگ انسٹال ہو جائے، آپ کو اپنے ریزیوم ویب سائٹ کا لائیو پریویو ایڈیٹر میں نظر آئے گا۔ یہ آپ کو بالکل دکھاتا ہے کہ آپ کی سائٹ کیسی لگتی ہے جیسے آپ تبدیلیاں کرتے ہیں۔
![کوڈ سوئنگ ایکسٹینشن لائیو پریویو دکھا رہا ہے](../../../../translated_images/after-codeswing-extension-pb.0ebddddcf73b550994947a9084e35e2836c713ae13839d49628e3c764c1cfe83.ur.png)
![کوڈ سوئنگ ایکسٹینشن لائیو پریویو دکھا رہا ہے](../../../../translated_images/after-codeswing-extension-pb.0ebddddcf73b5509.ur.png)
**بہتر انٹرفیس کو سمجھنا:**
- **سپلٹ ویو**: **آپ کے کوڈ کو ایک طرف اور لائیو پریویو کو دوسری طرف دکھاتا ہے**

@ -61,7 +61,7 @@ print(response.choices[0].message.content)
یہ ہے کہ آپ کا مکمل شدہ پروجیکٹ کیسا نظر آئے گا:
![چیٹ ایپ انٹرفیس جو صارف اور AI اسسٹنٹ کے درمیان گفتگو دکھا رہا ہے](../../../translated_images/screenshot.0a1ee0d123df681b4501eb53ffb267519fcc20aa653eabecef1e7561ddfb1cab.ur.png)
![چیٹ ایپ انٹرفیس جو صارف اور AI اسسٹنٹ کے درمیان گفتگو دکھا رہا ہے](../../../translated_images/screenshot.0a1ee0d123df681b.ur.png)
## 🗺️ AI ایپلیکیشن ڈویلپمنٹ کے ذریعے آپ کا سیکھنے کا سفر
@ -194,7 +194,7 @@ mindmap
**بنیادی اصول**: AI ایپلیکیشن ڈویلپمنٹ روایتی ویب ڈویلپمنٹ کی مہارتوں کو AI سروس انٹیگریشن کے ساتھ جوڑتا ہے، ذہین ایپلیکیشنز تخلیق کرتا ہے جو صارفین کے لیے قدرتی اور جوابدہ محسوس ہوتی ہیں۔
![GitHub Models AI Playground انٹرفیس ماڈل کے انتخاب اور ٹیسٹنگ ایریا کے ساتھ](../../../translated_images/playground.d2b927122224ff8ff4028fc842176e353c339147d8925455f36c92fb1655c477.ur.png)
![GitHub Models AI Playground انٹرفیس ماڈل کے انتخاب اور ٹیسٹنگ ایریا کے ساتھ](../../../translated_images/playground.d2b927122224ff8f.ur.png)
**یہاں ہے کہ پلے گراؤنڈ کو اتنا مفید کیا بناتا ہے:**
- **مختلف AI ماڈلز آزمائیں** جیسے GPT-4o-mini، Claude، اور دیگر (سب مفت!)
@ -204,7 +204,7 @@ mindmap
جب آپ تھوڑا سا کھیل چکے ہوں، تو بس "کوڈ" ٹیب پر کلک کریں اور اپنی پروگرامنگ زبان منتخب کریں تاکہ آپ کو وہ نفاذی کوڈ ملے جس کی آپ کو ضرورت ہے۔
![پلے گراؤنڈ کا انتخاب مختلف پروگرامنگ زبانوں کے لیے کوڈ جنریشن کے اختیارات دکھا رہا ہے](../../../translated_images/playground-choice.1d23ba7d407f47584c9f446c77f0bcf70cae794cc9c8d7849a3cca4a3693e6c4.ur.png)
![پلے گراؤنڈ کا انتخاب مختلف پروگرامنگ زبانوں کے لیے کوڈ جنریشن کے اختیارات دکھا رہا ہے](../../../translated_images/playground-choice.1d23ba7d407f4758.ur.png)
## Python بیک اینڈ انٹیگریشن سیٹ اپ کرنا
@ -1930,14 +1930,14 @@ mindmap
- [Web Dev For Beginners repository](https://github.com/microsoft/Web-Dev-For-Beginners) پر جائیں
- اوپر دائیں کونے میں "Use this template" پر کلک کریں (یقینی بنائیں کہ آپ GitHub میں لاگ ان ہیں)
![ٹیمپلیٹ انٹرفیس دکھا رہا ہے جس میں سبز "Use this template" بٹن ہے](../../../translated_images/template.67ad477109d29a2b04599a83c964c87fcde041256d4f04d3589cbb00c696f76c.ur.png)
![ٹیمپلیٹ انٹرفیس دکھا رہا ہے جس میں سبز "Use this template" بٹن ہے](../../../translated_images/template.67ad477109d29a2b.ur.png)
**مرحلہ 2: Codespaces لانچ کریں**
- اپنی نئی بنائی گئی repository کھولیں
- سبز "Code" بٹن پر کلک کریں اور "Codespaces" منتخب کریں
- "Create codespace on main" منتخب کریں تاکہ آپ کا ڈیولپمنٹ ماحول شروع ہو سکے
![Codespace انٹرفیس دکھا رہا ہے جس میں کلاؤڈ ڈیولپمنٹ ماحول لانچ کرنے کے اختیارات ہیں](../../../translated_images/codespace.bcecbdf5d2747d3d17da67a78ad911c8853d68102e34748ec372cde1e9236e1d.ur.png)
![Codespace انٹرفیس دکھا رہا ہے جس میں کلاؤڈ ڈیولپمنٹ ماحول لانچ کرنے کے اختیارات ہیں](../../../translated_images/codespace.bcecbdf5d2747d3d.ur.png)
**مرحلہ 3: ماحول کی ترتیب**
جب آپ کا Codespace لوڈ ہو جائے، آپ کو رسائی حاصل ہوگی:

@ -1,255 +1,263 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "63e29f5a308b533df9d70336bbb2e2b8",
"translation_date": "2025-11-25T11:48:04+00:00",
"original_hash": "fea3a0fceb8ad86fd640c09cf63a2aac",
"translation_date": "2026-01-06T10:59:15+00:00",
"source_file": "README.md",
"language_code": "ur"
}
-->
[![GitHub license](https://img.shields.io/github/license/microsoft/Web-Dev-For-Beginners.svg)](https://github.com/microsoft/Web-Dev-For-Beginners/blob/master/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors/microsoft/Web-Dev-For-Beginners.svg)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/graphs/contributors/)
[![GitHub issues](https://img.shields.io/github/issues/microsoft/Web-Dev-For-Beginners.svg)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/issues/)
[![GitHub pull-requests](https://img.shields.io/github/issues-pr/microsoft/Web-Dev-For-Beginners.svg)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/pulls/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
# ویب ڈویلپمنٹ برائے مبتدئین - ایک نصاب
[![GitHub watchers](https://img.shields.io/github/watchers/microsoft/Web-Dev-For-Beginners.svg?style=social&label=Watch&maxAge=2592000)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/watchers/)
[![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-Beginners.svg?style=social&label=Fork&maxAge=2592000)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/network/)
[![GitHub stars](https://img.shields.io/github/stars/microsoft/Web-Dev-For-Beginners.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/stargazers/)
مائیکروسافٹ کلاؤڈ ایڈووکیٹس کے ذریعہ ہمارا 12 ہفتوں کا جامع کورس کے ساتھ ویب ڈیولپمنٹ کے بنیادی اصول سیکھیں۔ 24 اسباق میں ہر ایک جاوا اسکرپٹ، CSS، اور HTML کو ٹیراریئمز، براؤزر ایکسٹینشنز، اور اسپیس گیمز جیسے عملی منصوبوں کے ذریعے جانچا گیا ہے۔ کوئزز، مباحثوں، اور عملی اسائنمنٹ میں حصہ لیں۔ اپنی مہارتوں کو بہتر بنائیں اور ہمارے مؤثر پروجیکٹ پر مبنی تدریسی طریقہ کار کے ساتھ اپنی معلومات کو بہتر طور پر یاد رکھیں۔ آج ہی اپنی کوڈنگ کی سفر شروع کریں!
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
ایژور AI فاؤنڈری ڈسکارڈ کمیونٹی میں شامل ہوں
# ویب ڈیولپمنٹ برائے ابتدائی - ایک نصاب
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
مائیکروسافٹ کلاؤڈ ایڈووکیٹس کے 12 ہفتوں کے جامع کورس کے ساتھ ویب ڈیولپمنٹ کی بنیادی باتیں سیکھیں۔ 24 اسباق میں سے ہر ایک جاوا اسکرپٹ، سی ایس ایس، اور ایچ ٹی ایم ایل کو عملی منصوبوں جیسے ٹیراریئمز، براؤزر ایکسٹینشنز، اور اسپیس گیمز کے ذریعے سکھاتا ہے۔ کوئزز، مباحثے، اور عملی اسائنمنٹس کے ساتھ شامل ہوں۔ اپنی مہارتوں کو بہتر بنائیں اور ہمارے مؤثر پروجیکٹ پر مبنی طریقہ کار کے ساتھ اپنے علم کو بہتر بنائیں۔ آج ہی اپنے کوڈنگ کے سفر کا آغاز کریں!
ان وسائل کو استعمال کرنے کے لیے یہ اقدامات کریں:
1. **ریفوزیٹری کو فورک کریں**: کلک کریں [![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/fork)
2. **ریفوزیٹری کو کلون کریں**: `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
3. [**ایژور AI فاؤنڈری ڈسکارڈ میں شامل ہوں اور ماہرین اور دیگر ڈویلپرز سے ملیں**](https://discord.com/invite/ByRwuEEgH4)
Azure AI Foundry Discord کمیونٹی میں شامل ہوں
### 🌐 متعدد زبانوں کی حمایت
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
#### گیٹ ہب ایکشن کے ذریعہ سپورٹ (خودکار اور ہمیشہ تازہ ترین)
ان وسائل کو استعمال کرنے کے لیے ان اقدامات پر عمل کریں:
1. **ریپوزٹری کو فورک کریں**: کلک کریں [![GitHub forks](https://img.shields.io/github/forks/microsoft/Web-Dev-For-beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/Web-Dev-For-Beginners/fork)
2. **ریپوزٹری کو کلون کریں**: `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
3. [**Azure AI Foundry Discord میں شامل ہوں اور ماہرین اور دیگر ڈیولپرز سے ملیں**](https://discord.com/invite/ByRwuEEgH4)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START -->
[Arabic](../ar/README.md) | [Bengali](../bn/README.md) | [Bulgarian](../bg/README.md) | [Burmese (Myanmar)](../my/README.md) | [Chinese (Simplified)](../zh/README.md) | [Chinese (Traditional, Hong Kong)](../hk/README.md) | [Chinese (Traditional, Macau)](../mo/README.md) | [Chinese (Traditional, Taiwan)](../tw/README.md) | [Croatian](../hr/README.md) | [Czech](../cs/README.md) | [Danish](../da/README.md) | [Dutch](../nl/README.md) | [Estonian](../et/README.md) | [Finnish](../fi/README.md) | [French](../fr/README.md) | [German](../de/README.md) | [Greek](../el/README.md) | [Hebrew](../he/README.md) | [Hindi](../hi/README.md) | [Hungarian](../hu/README.md) | [Indonesian](../id/README.md) | [Italian](../it/README.md) | [Japanese](../ja/README.md) | [Kannada](../kn/README.md) | [Korean](../ko/README.md) | [Lithuanian](../lt/README.md) | [Malay](../ms/README.md) | [Malayalam](../ml/README.md) | [Marathi](../mr/README.md) | [Nepali](../ne/README.md) | [Nigerian Pidgin](../pcm/README.md) | [Norwegian](../no/README.md) | [Persian (Farsi)](../fa/README.md) | [Polish](../pl/README.md) | [Portuguese (Brazil)](../br/README.md) | [Portuguese (Portugal)](../pt/README.md) | [Punjabi (Gurmukhi)](../pa/README.md) | [Romanian](../ro/README.md) | [Russian](../ru/README.md) | [Serbian (Cyrillic)](../sr/README.md) | [Slovak](../sk/README.md) | [Slovenian](../sl/README.md) | [Spanish](../es/README.md) | [Swahili](../sw/README.md) | [Swedish](../sv/README.md) | [Tagalog (Filipino)](../tl/README.md) | [Tamil](../ta/README.md) | [Telugu](../te/README.md) | [Thai](../th/README.md) | [Turkish](../tr/README.md) | [Ukrainian](../uk/README.md) | [Urdu](./README.md) | [Vietnamese](../vi/README.md)
### 🌐 کثیر لسانی معاونت
> **مقامی طور پر کلون کرنا پسند کریں؟**
#### GitHub Action کے ذریعے معاونت (خودکار اور ہمیشہ اپ ڈیٹ)
> یہ ریپوزیٹری 50+ زبانوں کے تراجم شامل کرتی ہے جو ڈاؤن لوڈ سائز کو نمایاں طور پر بڑھاتے ہیں۔ بغیر تراجم کے کلون کرنے کے لیے اسپارس چیک آؤٹ استعمال کریں:
> ```bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/Web-Dev-For-Beginners.git
> cd Web-Dev-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
> ```
> اس کے ذریعے آپ کو کورس مکمل کرنے کے لیے سب کچھ مل جائے گا اور ڈاؤن لوڈ بہت تیز ہوگا۔
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
[Arabic](../ar/README.md) | [Bengali](../bn/README.md) | [Bulgarian](../bg/README.md) | [Burmese (Myanmar)](../my/README.md) | [Chinese (Simplified)](../zh/README.md) | [Chinese (Traditional, Hong Kong)](../hk/README.md) | [Chinese (Traditional, Macau)](../mo/README.md) | [Chinese (Traditional, Taiwan)](../tw/README.md) | [Croatian](../hr/README.md) | [Czech](../cs/README.md) | [Danish](../da/README.md) | [Dutch](../nl/README.md) | [Estonian](../et/README.md) | [Finnish](../fi/README.md) | [French](../fr/README.md) | [German](../de/README.md) | [Greek](../el/README.md) | [Hebrew](../he/README.md) | [Hindi](../hi/README.md) | [Hungarian](../hu/README.md) | [Indonesian](../id/README.md) | [Italian](../it/README.md) | [Japanese](../ja/README.md) | [Korean](../ko/README.md) | [Lithuanian](../lt/README.md) | [Malay](../ms/README.md) | [Marathi](../mr/README.md) | [Nepali](../ne/README.md) | [Norwegian](../no/README.md) | [Persian (Farsi)](../fa/README.md) | [Polish](../pl/README.md) | [Portuguese (Brazil)](../br/README.md) | [Portuguese (Portugal)](../pt/README.md) | [Punjabi (Gurmukhi)](../pa/README.md) | [Romanian](../ro/README.md) | [Russian](../ru/README.md) | [Serbian (Cyrillic)](../sr/README.md) | [Slovak](../sk/README.md) | [Slovenian](../sl/README.md) | [Spanish](../es/README.md) | [Swahili](../sw/README.md) | [Swedish](../sv/README.md) | [Tagalog (Filipino)](../tl/README.md) | [Tamil](../ta/README.md) | [Thai](../th/README.md) | [Turkish](../tr/README.md) | [Ukrainian](../uk/README.md) | [Urdu](./README.md) | [Vietnamese](../vi/README.md)
**اگر آپ اضافی ترجمہ شدہ زبانوں کی حمایت چاہتے ہیں تو وہ یہاں [دیکھیے](https://github.com/Azure/co-op-translator/blob/main/getting_started/supported-languages.md) دستیاب ہیں**
**اگر آپ اضافی زبانوں میں ترجمہ چاہتے ہیں تو معاون زبانوں کی فہرست [یہاں](https://github.com/Azure/co-op-translator/blob/main/getting_started/supported-languages.md) موجود ہے۔**
[![Open in Visual Studio Code](https://img.shields.io/static/v1?logo=visualstudiocode&label=&message=Open%20in%20Visual%20Studio%20Code&labelColor=2c2c32&color=007acc&logoColor=007acc)](https://open.vscode.dev/microsoft/Web-Dev-For-Beginners)
[![Open in Visual Studio Code](https://img.shields.io/static/v1?logo=visualstudiocode&label=&message=Open%20in%20Visual%20Studio%20Code&labelColor=2c2c32&color=007acc&logoColor=007acc)](https://open.vscode.dev/microsoft/Web-Dev-For-Beginners)
#### 🧑‍🎓 _کیا آپ طالب علم ہیں؟_
#### 🧑‍🎓 _کیا آپ طالب علم ہیں؟_
[**اسٹوڈنٹ ہب صفحہ**](https://docs.microsoft.com/learn/student-hub/?WT.mc_id=academic-77807-sagibbon) پر جائیں جہاں آپ کو ابتدائی مواد، طالب علم پیک اور مفت سرٹیفکیٹ واؤچر حاصل کرنے کے طریقے ملیں گے۔ یہ صفحہ آپ کو بک مارک کرنا چاہیے اور وقتاً فوقتاً چیک کرنا چاہیے کیونکہ ہم ہر مہینہ مواد کو تبدیل کرتے رہتے ہیں۔
[**اسٹوڈنٹ ہب صفحہ**](https://docs.microsoft.com/learn/student-hub/?WT.mc_id=academic-77807-sagibbon) پر جائیں جہاں آپ کو ابتدائی وسائل، اسٹوڈنٹ پیک اور مفت سرٹیفکیٹ واؤچر حاصل کرنے کے طریقے ملیں گے۔ یہ وہ صفحہ ہے جسے آپ بک مارک کریں اور وقتاً فوقتاً چیک کریں کیونکہ ہم ماہانہ مواد تبدیل کرتے ہیں۔
### 📣 اعلان - نئے GitHub Copilot ایجنٹ موڈ چیلنجز مکمل کریں!
### 📣 اعلان - نئے GitHub Copilot Agent موڈ چیلنجز مکمل کریں!
نیا چیلنج شامل کیا گیا ہے، زیادہ تر ابواب میں "GitHub Copilot Agent Challenge 🚀" تلاش کریں۔ یہ آپ کے لیے ایک نیا چیلنج ہے جو آپ GitHub Copilot اور ایجنٹ موڈ استعمال کرتے ہوئے مکمل کریں گے۔ اگر آپ نے پہلے ایجنٹ موڈ استعمال نہیں کیا تو یہ صرف متن بنانے کے قابل نہیں بلکہ فائلیں بنانے، ترمیم کرنے، کمانڈیں چلانے اور مزید کام کر سکتا ہے۔
نیا چیلنج شامل کیا گیا ہے، زیادہ تر ابواب میں "GitHub Copilot Agent Challenge 🚀" تلاش کریں۔ یہ ایک نیا چیلنج ہے جو آپ GitHub Copilot اور Agent موڈ کا استعمال کرتے ہوئے مکمل کر سکتے ہیں۔ اگر آپ نے پہلے Agent موڈ استعمال نہیں کیا تو یہ نہ صرف متن تیار کر سکتا ہے بلکہ فائلیں بنا اور ایڈٹ کر سکتا ہے، کمانڈز چلا سکتا ہے اور مزید بھی۔
### 📣 اعلان - _جنریٹیو AI کے استعمال سے نیا پروجیکٹ بنائیں_
### 📣 اعلان - _نیا پروجیکٹ جنریٹو AI کے ساتھ بنانے کے لیے_
نیا AI اسسٹنٹ پروجیکٹ حال ہی میں شامل کیا گیا ہے، چیک کریں [پروجیکٹ](./9-chat-project/README.md)
نیا AI اسسٹنٹ پروجیکٹ ابھی شامل کیا گیا ہے، اسے دیکھیں [پروجیکٹ](./09-chat-project/README.md)
### 📣 اعلان - _جنریٹیو AI برائے جاوا اسکرپٹ کا نیا نصاب جاری کیا گیا_
### 📣 اعلان - _نیا نصاب_ جنریٹو AI برائے جاوا اسکرپٹ ابھی جاری کیا گیا
ہمارا نیا جنریٹیو AI نصاب مت چھوڑیں!
ہمارا نیا جنریٹو AI نصاب مت چھوڑیں!
شروع کرنے کے لیے وزٹ کریں [https://aka.ms/genai-js-course](https://aka.ms/genai-js-course)!
[https://aka.ms/genai-js-course](https://aka.ms/genai-js-course) پر جائیں اور شروع کریں!
![Background](../../translated_images/background.148a8d43afde5730.ur.png)
![Background](../../translated_images/background.148a8d43afde57303419a663f50daf586681bc2fabf833f66ef6954073983c66.ur.png)
- اسباق بنیادی باتوں سے لے کر RAG تک سب کچھ کور کرتے ہیں۔
- GenAI اور ہمارے معاون ایپ کے ذریعے تاریخی شخصیات سے بات چیت کریں۔
- دلچسپ اور مشغول نگارش، آپ وقت کے سفر پر ہوں گے!
- اسباق جو بنیادی باتوں سے لے کر RAG تک سب کچھ شامل کرتے ہیں۔
- تاریخی کرداروں کے ساتھ GenAI اور ہماری ساتھی ایپ کے ذریعے بات چیت کریں۔
- تفریحی اور مشغول کہانی، آپ وقت میں سفر کریں گے!
![character](../../translated_images/character.5c0dd8e067ffd693.ur.png)
![character](../../translated_images/character.5c0dd8e067ffd693c16e2c5b7412ab075a2215ce31f998305639fa3a05e14fbe.ur.png)
ہر سبق میں ایک اسائنمنٹ شامل ہے، ایک علم کی جانچ اور ایک چیلنج جو آپ کو سکھائے گا:
ہر سبق میں ایک اسائنمنٹ، نالج چیک اور چیلنج شامل ہے تاکہ آپ اس طرح کے موضوعات پر سیکھنے میں رہنمائی کریں:
- پرامپٹنگ اور پرامپٹ انجینئرنگ
- متن اور تصویر ایپ جنریشن
- ٹیکسٹ اور امیج ایپ جنریشن
- سرچ ایپس
[https://aka.ms/genai-js-course](https://aka.ms/genai-js-course) پر جائیں اور شروع کریں!
شروع کرنے کے لیے وزٹ کریں [https://aka.ms/genai-js-course](https://aka.ms/genai-js-course)!
## 🌱 شروعات کریں
> **اساتذہ**، ہم نے [کچھ تجاویز شامل کی ہیں](for-teachers.md) کہ اس نصاب کو کیسے استعمال کیا جائے۔ ہمیں آپ کی رائے [ہمارے مباحثہ فورم](https://github.com/microsoft/Web-Dev-For-Beginners/discussions/categories/teacher-corner) میں پسند آئے گی!
**[سیکھنے والے](https://aka.ms/student-page/?WT.mc_id=academic-77807-sagibbon)**، ہر سبق کے لیے، ایک پری لیکچر کوئز سے شروع کریں اور لیکچر کے مواد کو پڑھنے، مختلف سرگرمیاں مکمل کرنے اور پوسٹ لیکچر کوئز کے ساتھ اپنی سمجھ کو چیک کرنے کے ساتھ جاری رکھیں۔
## 🌱 شروعات کیسے کریں
اپنے سیکھنے کے تجربے کو بڑھانے کے لیے، اپنے ساتھیوں کے ساتھ مل کر پروجیکٹس پر کام کریں! مباحثے کی حوصلہ افزائی کی جاتی ہے [ہمارے مباحثہ فورم](https://github.com/microsoft/Web-Dev-For-Beginners/discussions) میں جہاں ہمارے ماڈریٹرز کی ٹیم آپ کے سوالات کے جوابات دینے کے لیے دستیاب ہوگی۔
> **اساتذہ**، ہم نے [کچھ تجاویز](for-teachers.md) شامل کی ہیں کہ اس نصاب کو کیسے استعمال کیا جائے۔ ہمیں آپ کی رائے [ہماری مباحثہ فورم میں](https://github.com/microsoft/Web-Dev-For-Beginners/discussions/categories/teacher-corner) ملنے کی خواہش ہے!
اپنی تعلیم کو مزید آگے بڑھانے کے لیے، ہم انتہائی سفارش کرتے ہیں کہ [Microsoft Learn](https://learn.microsoft.com/users/wirelesslife/collections/p1ddcy5jwy0jkm?WT.mc_id=academic-77807-sagibbon) کو اضافی مطالعہ کے مواد کے لیے دریافت کریں۔
**[طلباء](https://aka.ms/student-page/?WT.mc_id=academic-77807-sagibbon)**، ہر سبق کے لیے پہلے پری لیکچر کوئز کے ساتھ شروع کریں اور پھر لیکچر کا مواد پڑھیں، مختلف سرگرمیاں مکمل کریں اور پوسٹ لیکچر کوئز کے ساتھ اپنی سمجھ کو چیک کریں۔
### 📋 اپنے ماحول کو ترتیب دینا
اپنے تعلیم کے تجربے کو بہتر بنانے کے لیے، اپنے ساتھیوں کے ساتھ مل کر منصوبوں پر کام کریں! ہمارے [مباحثہ فورم](https://github.com/microsoft/Web-Dev-For-Beginners/discussions) میں مباحثوں کی حوصلہ افزائی کی جاتی ہے جہاں ہمارے ماڈریٹرز آپ کے سوالات کے جواب کے لیے دستیاب ہوں گے۔
یہ نصاب ایک تیار شدہ ترقیاتی ماحول کے ساتھ آتا ہے! جب آپ شروع کریں تو آپ اس نصاب کو [Codespace](https://github.com/features/codespaces/) (_ایک براؤزر پر مبنی، انسٹالیشن کی ضرورت نہیں_) یا اپنے کمپیوٹر پر مقامی طور پر کسی ٹیکسٹ ایڈیٹر جیسے [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) کا استعمال کرتے ہوئے چلا سکتے ہیں۔
اپنی تعلیم کو مزید بڑھانے کے لیے، ہم سختی سے سفارش کرتے ہیں کہ آپ اضافی مطالعہ کے مواد کے لیے [Microsoft Learn](https://learn.microsoft.com/users/wirelesslife/collections/p1ddcy5jwy0jkm?WT.mc_id=academic-77807-sagibbon) کو دریافت کریں۔
#### اپنی ریپوزٹری بنائیں
اپنے کام کو آسانی سے محفوظ کرنے کے لیے، یہ تجویز کیا جاتا ہے کہ آپ اس ریپوزٹری کی اپنی کاپی بنائیں۔ آپ یہ صفحے کے اوپر **Use this template** بٹن پر کلک کرکے کر سکتے ہیں۔ یہ آپ کے GitHub اکاؤنٹ میں نصاب کی ایک کاپی کے ساتھ ایک نئی ریپوزٹری بنائے گا۔
### 📋 اپنا ماحول کیسے سیٹ کریں
ان اقدامات پر عمل کریں:
1. **ریپوزٹری کو فورک کریں**: اس صفحے کے اوپر دائیں کونے میں "Fork" بٹن پر کلک کریں۔
2. **ریپوزٹری کو کلون کریں**: `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
اس نصاب کے لیے ایک تیار شدہ ڈویلپمنٹ ماحول موجود ہے! جیسے ہی آپ شروع کریں، آپ نصاب کو [Codespace](https://github.com/features/codespaces/) میں چلا سکتے ہیں (جو براؤزر پر مبنی اور بغیر کسی انسٹالیشن کے چلنے والا ماحول ہے)، یا اپنے کمپیوٹر پر مقامی طور پر ٹیکسٹ ایڈیٹر جیسے [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) کے ذریعے چلائیں۔
#### نصاب کو Codespace میں چلانا
#### اپنی ریپوزیٹری بنائیں
اپنا کام آسانی سے محفوظ کرنے کے لیے، سفارش کی جاتی ہے کہ آپ اس ریپوزیٹری کی اپنی کاپی بنائیں۔ آپ یہ صفحہ کے اوپر موجود **Use this template** بٹن پر کلک کرکے کر سکتے ہیں۔ یہ آپ کے GitHub اکاؤنٹ میں نصاب کی کاپی کے ساتھ ایک نئی ریپوزیٹری بنائے گا۔
اس ریپوزٹری کی اپنی کاپی میں جو آپ نے بنائی، **Code** بٹن پر کلک کریں اور **Open with Codespaces** کو منتخب کریں۔ یہ آپ کے لیے کام کرنے کے لیے ایک نیا Codespace بنائے گا۔
ان مراحل کی پیروی کریں:
1. **ریفوزیٹری کو فورک کریں**: اس صفحہ کے اوپر دائیں کونے میں موجود "Fork" بٹن پر کلک کریں۔
2. **ریفوزیٹری کو کلون کریں**: `git clone https://github.com/microsoft/Web-Dev-For-Beginners.git`
![Codespace](../../translated_images/createcodespace.0238bbf4d7a8d955fa8fa7f7b6602a3cb6499a24708fbee589f83211c5a613b7.ur.png)
#### کوڈ اسپیس میں نصاب چلانا
#### نصاب کو اپنے کمپیوٹر پر مقامی طور پر چلانا
اپنی بنائی گئی ریپوزیٹری میں، **Code** بٹن پر کلک کریں اور **Open with Codespaces** منتخب کریں۔ یہ آپ کے لیے ایک نیا Codespace بنائے گا جہاں آپ کام کر سکتے ہیں۔
اس نصاب کو اپنے کمپیوٹر پر مقامی طور پر چلانے کے لیے، آپ کو ایک ٹیکسٹ ایڈیٹر، ایک براؤزر اور ایک کمانڈ لائن ٹول کی ضرورت ہوگی۔ ہمارا پہلا سبق، [پروگرامنگ زبانوں اور ٹولز کا تعارف](../../1-getting-started-lessons/1-intro-to-programming-languages)، آپ کو ان ٹولز کے لیے مختلف اختیارات کے ذریعے لے جائے گا تاکہ آپ وہ منتخب کریں جو آپ کے لیے بہترین کام کرتا ہے۔
![Codespace](../../translated_images/createcodespace.0238bbf4d7a8d955.ur.png)
ہماری سفارش ہے کہ آپ [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) کو اپنے ایڈیٹر کے طور پر استعمال کریں، جس میں ایک بلٹ ان [Terminal](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) بھی شامل ہے۔ آپ [یہاں](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) سے Visual Studio Code ڈاؤن لوڈ کر سکتے ہیں۔
#### اپنے کمپیوٹر پر نصاب لوکل چلانا
1. اپنی ریپوزٹری کو اپنے کمپیوٹر پر کلون کریں۔ آپ یہ **Code** بٹن پر کلک کرکے اور URL کو کاپی کرکے کر سکتے ہیں:
اس نصاب کو اپنے کمپیوٹر پر چلانے کے لیے، آپ کو ایک ٹیکسٹ ایڈیٹر، ایک براؤزر اور ایک کمانڈ لائن ٹول کی ضرورت ہوگی۔ ہمارا پہلا سبق، [پروگرامنگ زبانوں اور آلات کا تعارف](../../1-getting-started-lessons/1-intro-to-programming-languages)، آپ کو ہر ایک ٹول کے مختلف اختیارات کے بارے میں گائیڈ کرے گا تاکہ آپ خود کے لیے بہترین انتخاب کرسکیں۔
[CodeSpace](./images/createcodespace.png)
ہماری سفارش ہے کہ آپ [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) استعمال کریں جو کہ ایک ایڈیٹر کے ساتھ ساتھ بلٹ ان [ٹرمینل](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) بھی فراہم کرتا ہے۔ آپ Visual Studio Code یہاں سے ڈاؤن لوڈ کرسکتے ہیں: [link](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon)۔
پھر، [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) کے اندر [Terminal](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) کھولیں اور درج ذیل کمانڈ چلائیں، `<your-repository-url>` کو اس URL سے تبدیل کریں جو آپ نے ابھی کاپی کیا ہے:
1. اپنی ریپوزیٹری اپنے کمپیوٹر پر کلون کریں۔ یہ آپ **Code** بٹن پر کلک کرکے اور URL کی کاپی کرکے کر سکتے ہیں:
[CodeSpace](./images/createcodespace.png)
پھر، [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon) میں [Terminal](https://code.visualstudio.com/docs/terminal/basics/?WT.mc_id=academic-77807-sagibbon) کھولیں اور درج ذیل کمانڈ چلائیں، `<your-repository-url>` کو اس URL سے بدلیں جو آپ نے ابھی کاپی کیا ہے:
```bash
git clone <your-repository-url>
```
2. فولڈر کو Visual Studio Code میں کھولیں۔ آپ یہ **File** > **Open Folder** پر کلک کرکے اور وہ فولڈر منتخب کرکے کر سکتے ہیں جو آپ نے ابھی کلون کیا ہے۔
> تجویز کردہ Visual Studio Code ایکسٹینشنز:
>
> * [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) - Visual Studio Code کے اندر HTML صفحات کا پیش نظارہ کرنے کے لیے
2. Visual Studio Code میں فولڈر کھولیں۔ آپ یہ کام **File** > **Open Folder** پر کلک کر کے کر سکتے ہیں اور اس فولڈر کو منتخب کریں جو آپ نے ابھی کلون کیا ہے۔
> سفارش کردہ Visual Studio Code توسیعات:
>
> * [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) - Visual Studio Code میں HTML صفحات کا پیش نظارہ کرنے کے لیے
> * [Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot&WT.mc_id=academic-77807-sagibbon) - کوڈ تیزی سے لکھنے میں مدد کے لیے
## 📂 ہر سبق میں شامل ہے:
## 📂 ہر سبق میں شامل ہیں:
- اختیاری خاکہ نوٹ
- اختیاری سکیچ نوٹ
- اختیاری اضافی ویڈیو
- سبق سے پہلے کا وارم اپ کوئز
- سبق سے پہلے وارم اپ کوئز
- تحریری سبق
- پروجیکٹ پر مبنی اسباق کے لیے، پروجیکٹ بنانے کے لیے مرحلہ وار رہنما
- پروجیکٹ کی بنیاد پر اسباق کے لیے، قدم بہ قدم ہدایات کہ پروجیکٹ کیسے بنایا جائے
- علم کی جانچ
- ایک چیلنج
- اضافی مطالعہ
- اسائنمنٹ
- [سبق کے بعد کا کوئز](https://ff-quizzes.netlify.app/web/)
- اسباق کے بعد کوئز [post-lesson quiz](https://ff-quizzes.netlify.app/web/)
> **کوئز کے بارے میں ایک نوٹ**: تمام کوئز Quiz-app فولڈر میں موجود ہیں، کل 48 کوئز، ہر ایک میں تین سوالات ہیں۔ یہ [یہاں](https://ff-quizzes.netlify.app/web/) دستیاب ہیں۔ کوئز ایپ کو مقامی طور پر چلایا جا سکتا ہے یا Azure پر تعینات کیا جا سکتا ہے؛ `quiz-app` فولڈر میں دی گئی ہدایات پر عمل کریں۔
> **کوئز کے بارے میں ایک نوٹ**: تمام کوئزز Quiz-app فولڈر میں شامل ہیں، کل 48 کوئزز جن میں سے ہر ایک میں تین سوالات ہیں۔ وہ [یہاں](https://ff-quizzes.netlify.app/web/) دستیاب ہیں، کوئز ایپ مقامی طور پر چلائی جا سکتی ہے یا Azure پر تعینات کی جا سکتی ہے؛ `quiz-app` فولڈر میں ہدایات کی پیروی کریں۔
## 🗃️ اسباق
| | پروجیکٹ کا نام | سکھائے گئے تصورات | سیکھنے کے مقاصد | منسلک سبق | مصنف |
| :-: | :------------------------------------------------------: | :--------------------------------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------: | :---------------------: |
| 01 | شروعات | پروگرامنگ کا تعارف اور پیشہ ورانہ اوزار | زیادہ تر پروگرامنگ زبانوں کے بنیادی اصولوں اور سافٹ ویئر کے بارے میں جانیں جو پیشہ ور ڈویلپرز کو ان کا کام کرنے میں مدد کرتا ہے | [پروگرامنگ زبانوں اور پیشہ ورانہ اوزار کا تعارف](./1-getting-started-lessons/1-intro-to-programming-languages/README.md) | جیسمن |
| 02 | شروعات | GitHub کی بنیادی باتیں، ٹیم کے ساتھ کام کرنا | اپنے پروجیکٹ میں GitHub کا استعمال کیسے کریں، کوڈ بیس پر دوسروں کے ساتھ تعاون کیسے کریں | [GitHub کا تعارف](./1-getting-started-lessons/2-github-basics/README.md) | فلور |
| 03 | شروعات | رسائی پذیری | ویب رسائی کی بنیادی باتیں سیکھیں | [رسائی پذیری کے بنیادی اصول](./1-getting-started-lessons/3-accessibility/README.md) | کرسٹوفر |
| 04 | جاوا اسکرپٹ کی بنیادی باتیں | جاوا اسکرپٹ ڈیٹا کی اقسام | جاوا اسکرپٹ ڈیٹا کی اقسام کی بنیادی باتیں | [ڈیٹا کی اقسام](./2-js-basics/1-data-types/README.md) | جیسمن |
| 05 | جاوا اسکرپٹ کی بنیادی باتیں | فنکشنز اور طریقے | ایپلیکیشن کے لاجک فلو کو منظم کرنے کے لیے فنکشنز اور طریقوں کے بارے میں جانیں | [فنکشنز اور طریقے](./2-js-basics/2-functions-methods/README.md) | جیسمن اور کرسٹوفر |
| 06 | جاوا اسکرپٹ کی بنیادی باتیں | جاوا اسکرپٹ کے ساتھ فیصلے کرنا | فیصلہ سازی کے طریقوں کا استعمال کرتے ہوئے اپنے کوڈ میں حالات پیدا کرنا سیکھیں | [فیصلے کرنا](./2-js-basics/3-making-decisions/README.md) | جیسمن |
| 07 | جاوا اسکرپٹ کی بنیادی باتیں | Arrays اور Loops | جاوا اسکرپٹ میں ڈیٹا کے ساتھ کام کریں Arrays اور Loops کا استعمال کرتے ہوئے | [Arrays اور Loops](./2-js-basics/4-arrays-loops/README.md) | جیسمن |
| 08 | [Terrarium](./3-terrarium/solution/README.md) | HTML کا عملی استعمال | ایک آن لائن Terrarium بنانے کے لیے HTML بنائیں، لے آؤٹ بنانے پر توجہ مرکوز کریں | [HTML کا تعارف](./3-terrarium/1-intro-to-html/README.md) | جین |
| 09 | [Terrarium](./3-terrarium/solution/README.md) | CSS کا عملی استعمال | آن لائن Terrarium کو اسٹائل کرنے کے لیے CSS بنائیں، CSS کی بنیادی باتوں پر توجہ مرکوز کریں بشمول صفحہ کو ریسپانسیو بنانا | [CSS کا تعارف](./3-terrarium/2-intro-to-css/README.md) | جین |
| 10 | [Terrarium](./3-terrarium/solution/README.md) | جاوا اسکرپٹ Closures، DOM میں تبدیلی | Terrarium کو ایک ڈریگ/ڈراپ انٹرفیس کے طور پر کام کرنے کے لیے جاوا اسکرپٹ بنائیں، Closures اور DOM میں تبدیلی پر توجہ مرکوز کریں | [جاوا اسکرپٹ Closures، DOM میں تبدیلی](./3-terrarium/3-intro-to-DOM-and-closures/README.md) | جین |
| 11 | [Typing Game](./4-typing-game/solution/README.md) | ایک Typing Game بنائیں | اپنے جاوا اسکرپٹ ایپ کی منطق کو چلانے کے لیے کی بورڈ ایونٹس کا استعمال کرنا سیکھیں | [ایونٹ پر مبنی پروگرامنگ](./4-typing-game/typing-game/README.md) | کرسٹوفر |
| 12 | [Green Browser Extension](./5-browser-extension/solution/README.md) | براؤزرز کے ساتھ کام کرنا | براؤزرز کیسے کام کرتے ہیں، ان کی تاریخ، اور براؤزر ایکسٹینشن کے پہلے عناصر کو کیسے تیار کریں | [براؤزرز کے بارے میں](./5-browser-extension/1-about-browsers/README.md) | جین |
| 13 | [Green Browser Extension](./5-browser-extension/solution/README.md) | ایک API کو کال کرنے اور متغیرات کو لوکل اسٹوریج میں محفوظ کرنے کے لیے فارم بنانا | اپنے براؤزر ایکسٹینشن کے جاوا اسکرپٹ عناصر کو ایک API کو کال کرنے کے لیے بنائیں، لوکل اسٹوریج میں محفوظ متغیرات کا استعمال کریں | [APIs، فارم، اور لوکل اسٹوریج](./5-browser-extension/2-forms-browsers-local-storage/README.md) | جین |
| 14 | [Green Browser Extension](./5-browser-extension/solution/README.md) | براؤزر میں بیک گراؤنڈ پروسیسز، ویب کی کارکردگی | براؤزر کے بیک گراؤنڈ پروسیسز کا استعمال کرتے ہوئے ایکسٹینشن کے آئیکن کو منظم کریں؛ ویب کی کارکردگی اور کچھ اصلاحات کے بارے میں جانیں | [بیک گراؤنڈ ٹاسکس اور کارکردگی](./5-browser-extension/3-background-tasks-and-performance/README.md) | جین |
| 15 | [Space Game](./6-space-game/solution/README.md) | جاوا اسکرپٹ کے ساتھ مزید جدید گیم ڈویلپمنٹ | گیم بنانے کی تیاری میں کلاسز اور کمپوزیشن دونوں کا استعمال کرتے ہوئے وراثت کے بارے میں جانیں اور Pub/Sub پیٹرن کے بارے میں جانیں | [جدید گیم ڈویلپمنٹ کا تعارف](./6-space-game/1-introduction/README.md) | کرس |
| 16 | [Space Game](./6-space-game/solution/README.md) | کینوس پر ڈرائنگ | کینوس API کے بارے میں جانیں، جو اسکرین پر عناصر کو ڈرائنگ کرنے کے لیے استعمال ہوتا ہے | [کینوس پر ڈرائنگ](./6-space-game/2-drawing-to-canvas/README.md) | کرس |
| 17 | [Space Game](./6-space-game/solution/README.md) | اسکرین پر عناصر کو حرکت دینا | دریافت کریں کہ عناصر کارٹیسین کوآرڈینیٹس اور کینوس API کا استعمال کرتے ہوئے حرکت کیسے حاصل کر سکتے ہیں | [عناصر کو حرکت دینا](./6-space-game/3-moving-elements-around/README.md) | کرس |
| 18 | [Space Game](./6-space-game/solution/README.md) | تصادم کا پتہ لگانا | عناصر کو ایک دوسرے سے ٹکرانے اور ردعمل دینے کے لیے بنائیں، کی پریسز کا استعمال کریں اور گیم کی کارکردگی کو یقینی بنانے کے لیے کول ڈاؤن فنکشن فراہم کریں | [تصادم کا پتہ لگانا](./6-space-game/4-collision-detection/README.md) | کرس |
| 19 | [Space Game](./6-space-game/solution/README.md) | اسکور رکھنا | گیم کی حیثیت اور کارکردگی کی بنیاد پر ریاضی کے حسابات انجام دیں | [اسکور رکھنا](./6-space-game/5-keeping-score/README.md) | کرس |
| 20 | [Space Game](./6-space-game/solution/README.md) | گیم کو ختم کرنا اور دوبارہ شروع کرنا | گیم کو ختم کرنے اور دوبارہ شروع کرنے کے بارے میں جانیں، بشمول اثاثوں کو صاف کرنا اور متغیر اقدار کو دوبارہ ترتیب دینا | [اختتامی حالت](./6-space-game/6-end-condition/README.md) | کرس |
| 21 | [Banking App](./7-bank-project/solution/README.md) | ایک ویب ایپ میں HTML ٹیمپلیٹس اور روٹس | ایک ملٹی پیج ویب سائٹ کی آرکیٹیکچر کا خاکہ بنانے کے لیے روٹنگ اور HTML ٹیمپلیٹس کا استعمال کرنا سیکھیں | [HTML ٹیمپلیٹس اور روٹس](./7-bank-project/1-template-route/README.md) | یوہان |
| 22 | [Banking App](./7-bank-project/solution/README.md) | لاگ ان اور رجسٹریشن فارم بنائیں | فارم بنانے اور توثیق کے معمولات کو سنبھالنے کے بارے میں جانیں | [فارمز](./7-bank-project/2-forms/README.md) | یوہان |
| 23 | [Banking App](./7-bank-project/solution/README.md) | ڈیٹا کو حاصل کرنے اور استعمال کرنے کے طریقے | آپ کی ایپ میں ڈیٹا کیسے بہتا ہے، اسے کیسے حاصل کریں، اسٹور کریں، اور ضائع کریں | [ڈیٹا](./7-bank-project/3-data/README.md) | یوہان |
| 24 | [Banking App](./7-bank-project/solution/README.md) | اسٹیٹ مینجمنٹ کے تصورات | آپ کی ایپ اسٹیٹ کو کیسے برقرار رکھتی ہے اور اسے پروگرام کے ذریعے کیسے منظم کیا جائے | [اسٹیٹ مینجمنٹ](./7-bank-project/4-state-management/README.md) | یوہان |
| 25 | [Browser/VScode Code](../../8-code-editor) | VScode کے ساتھ کام کرنا | کوڈ ایڈیٹر کا استعمال سیکھیں | [VScode کوڈ ایڈیٹر کا استعمال کریں](./8-code-editor/1-using-a-code-editor/README.md) | کرس |
| 26 | [AI Assistants](./9-chat-project/README.md) | AI کے ساتھ کام کرنا | اپنا AI اسسٹنٹ بنانے کا طریقہ سیکھیں | [AI اسسٹنٹ پروجیکٹ](./9-chat-project/README.md) | کرس |
| | پروجیکٹ کا نام | سکھائے گئے تصورات | تعلیمی مقاصد | متعلقہ سبق | مصنف |
| :-: | :--------------------------------------------------------: | :---------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------: | :-------------------: |
| 01 | شروعات کرنا | پروگرامنگ کا تعارف اور پیشہ ورانہ آلات | زیادہ تر پروگرامنگ زبانوں کے بنیادی اصول سیکھیں اور ایسے سافٹ ویئر کے بارے میں جانیں جو پیشہ ور ڈویلپرز کو ان کے کام میں مدد دیتے ہیں | [Intro to Programming Languages and Tools of the Trade](./1-getting-started-lessons/1-intro-to-programming-languages/README.md) | Jasmine |
| 02 | شروعات کرنا | GitHub کی بنیادی باتیں، ٹیم کے ساتھ کام کرنا | GitHub کو اپنے پروجیکٹ میں استعمال کرنا، اور دوسروں کے ساتھ کوڈ بیس پر مل کر کام کرنا | [Intro to GitHub](./1-getting-started-lessons/2-github-basics/README.md) | Floor |
| 03 | شروعات کرنا | قابل رسائی ہونا | ویب کی بنیادی قابل رسائی سیکھیں | [Accessibility Fundamentals](./1-getting-started-lessons/3-accessibility/README.md) | Christopher |
| 04 | JS بیسکس | جاوا اسکرپٹ ڈیٹا کی اقسام | جاوا اسکرپٹ ڈیٹا کی اقسام کی بنیادی باتیں | [Data Types](./2-js-basics/1-data-types/README.md) | Jasmine |
| 05 | JS بیسکس | فنکشنز اور طریقے | ایسی فنکشنز اور طریقوں کے بارے میں سیکھیں جو ایپلیکیشن کی منطق کے بہاؤ کو مینج کرتے ہیں | [Functions and Methods](./2-js-basics/2-functions-methods/README.md) | Jasmine and Christopher |
| 06 | JS بیسکس | JS کے ساتھ فیصلے کرنا | اپنے کوڈ میں شرائط بنانے کے لیے فیصلے کرنے کے طریقے سیکھیں | [Making Decisions](./2-js-basics/3-making-decisions/README.md) | Jasmine |
| 07 | JS بیسکس | ارے اور لوپس | جاوا اسکرپٹ میں ارے اور لوپس کا استعمال کرتے ہوئے ڈیٹا کے ساتھ کام کریں | [Arrays and Loops](./2-js-basics/4-arrays-loops/README.md) | Jasmine |
| 08 | [Terrarium](./3-terrarium/solution/README.md) | عملی HTML | آن لائن ٹیریریم بنانے کے لیے HTML تیار کریں، لے آؤٹ بنانے پر توجہ مرکوز کریں | [Introduction to HTML](./3-terrarium/1-intro-to-html/README.md) | Jen |
| 09 | [Terrarium](./3-terrarium/solution/README.md) | عملی CSS | آن لائن ٹیریریم کو اسٹائل کرنے کے لیے CSS تیار کریں، CSS کے بنیادی اصولوں پر دھیان دیں بشمول صفحے کو رد عمل پذیر بنانا | [Introduction to CSS](./3-terrarium/2-intro-to-css/README.md) | Jen |
| 10 | [Terrarium](./3-terrarium/solution/README.md) | جاوا اسکرپٹ کلوزرز، DOM میں تبدیلی | ٹیریریم کو ڈریگ/ڈراپ انٹرفیس بنانے کے لیے جاوا اسکرپٹ تیار کریں، کلوزرز اور DOM میں تبدیلی پر توجہ دیں | [JavaScript Closures, DOM manipulation](./3-terrarium/3-intro-to-DOM-and-closures/README.md) | Jen |
| 11 | [Typing Game](./4-typing-game/solution/README.md) | ٹائپنگ گیم بنائیں | اپنے جاوا اسکرپٹ ایپ کی منطق چلانے کے لیے کی بورڈ ایونٹس کا استعمال سیکھیں | [Event-Driven Programming](./4-typing-game/typing-game/README.md) | Christopher |
| 12 | [Green Browser Extension](./5-browser-extension/solution/README.md) | براؤزر کے ساتھ کام کرنا | براؤزر کیسے کام کرتے ہیں، ان کی تاریخ، اور براؤزر ایکسٹینشن کے پہلے عناصر تیار کرنے کے طریقے سیکھیں | [About Browsers](./5-browser-extension/1-about-browsers/README.md) | Jen |
| 13 | [Green Browser Extension](./5-browser-extension/solution/README.md) | فارم بنانا، API کال کرنا اور لوکل اسٹوریج میں متغیرات ذخیرہ کرنا | اپنے براؤزر ایکسٹینشن کے جاوا اسکرپٹ عناصر تیار کریں تاکہ API کال کریں جو لوکل اسٹوریج میں ذخیرہ کیے گئے متغیرات استعمال کرتا ہے | [APIs, Forms, and Local Storage](./5-browser-extension/2-forms-browsers-local-storage/README.md) | Jen |
| 14 | [Green Browser Extension](./5-browser-extension/solution/README.md) | براؤزر میں پس منظر کے عمل، ویب کی کارکردگی | براؤزر کے پس منظر کے عمل استعمال کریں تاکہ ایکسٹینشن کے آئیکون کو مینج کیا جا سکے؛ ویب کی کارکردگی کے بارے میں جانیں اور کچھ اصلاحات بھی کریں | [Background Tasks and Performance](./5-browser-extension/3-background-tasks-and-performance/README.md) | Jen |
| 15 | [Space Game](./6-space-game/solution/README.md) | جاوا اسکرپٹ کے ساتھ مزید اعلیٰ درجے کا گیم ڈیولپمنٹ | وارثت کے بارے میں سیکھیں، دونوں کلاسز اور کمپوزیشن کے ذریعے، اور پب/سب پیٹرن، کھیل بنانے کی تیاری کے لیے | [Introduction to Advanced Game Development](./6-space-game/1-introduction/README.md) | Chris |
| 16 | [Space Game](./6-space-game/solution/README.md) | کینوس پر ڈرائنگ | کینوس API کے بارے میں جانیں، جو اسکرین پر عناصر ڈرائنگ کے لیے استعمال ہوتا ہے | [Drawing to Canvas](./6-space-game/2-drawing-to-canvas/README.md) | Chris |
| 17 | [Space Game](./6-space-game/solution/README.md) | اسکرین پر عناصر کو منتقل کرنا | دریافت کریں کہ عناصر کو حرکت کیسے دی جا سکتی ہے کارٹیسین کوآرڈینیٹس اور کینوس API کا استعمال کرتے ہوئے | [Moving Elements Around](./6-space-game/3-moving-elements-around/README.md) | Chris |
| 18 | [Space Game](./6-space-game/solution/README.md) | ٹکراؤ کی شناخت | عناصر کو آپس میں ٹکرانے اور ایک دوسرے پر ردعمل ظاہر کرنے کے لیے بنائیں، کی پریس کے ذریعے، اور کھیل کی کارکردگی کو یقینی بنانے کے لیے کول ڈاؤن فنکشن فراہم کریں | [Collision Detection](./6-space-game/4-collision-detection/README.md) | Chris |
| 19 | [Space Game](./6-space-game/solution/README.md) | سکور رکھنا | کھیل کی حالت اور کارکردگی کی بنیاد پر ریاضیاتی حسابات کریں | [Keeping Score](./6-space-game/5-keeping-score/README.md) | Chris |
| 20 | [Space Game](./6-space-game/solution/README.md) | کھیل کا اختتام اور دوبارہ شروع کرنا | کھیل کے اختتام اور دوبارہ شروع کرنے کے بارے میں جانیں، بشمول اثاثے صاف کرنا اور متغیر اقدار کو ری سیٹ کرنا | [The Ending Condition](./6-space-game/6-end-condition/README.md) | Chris |
| 21 | [Banking App](./7-bank-project/solution/README.md) | ویب ایپ میں HTML ٹیمپلیٹس اور روٹس | ملٹی پیج ویب سائٹ کے ڈھانچے کے سافٹ ویئر بنانے کے لیے روٹنگ اور HTML ٹیمپلیٹس کا استعمال سیکھیں | [HTML Templates and Routes](./7-bank-project/1-template-route/README.md) | Yohan |
| 22 | [Banking App](./7-bank-project/solution/README.md) | لاگ ان اور رجسٹریشن فارم بنانا | فارم بنانے اور ویلیڈیشن روٹینز کو ہینڈل کرنے کے بارے میں جانیں | [Forms](./7-bank-project/2-forms/README.md) | Yohan |
| 23 | [Banking App](./7-bank-project/solution/README.md) | ڈیٹا حاصل کرنے اور استعمال کرنے کے طریقے | آپ کی ایپ میں ڈیٹا کی بہاؤ، اسے حاصل کرنے، ذخیرہ کرنے اور ضائع کرنے کے بارے میں جانیں | [Data](./7-bank-project/3-data/README.md) | Yohan |
| 24 | [Banking App](./7-bank-project/solution/README.md) | ریاستی انتظامیہ کے تصورات | جانیں کہ آپ کی ایپ ریاست کو کیسے برقرار رکھتی ہے اور اسے پروگرامنگ کی مدد سے کیسے مینج کرتی ہے | [State Management](./7-bank-project/4-state-management/README.md) | Yohan |
| 25 | [Browser/VScode Code](../../8-code-editor) | VScode کے ساتھ کام کرنا | کوڈ ایڈیٹر استعمال کرنے کا طریقہ سیکھیں | [Use VScode Code Editor](./8-code-editor/1-using-a-code-editor/README.md) | Chris |
| 26 | [AI Assistants](./9-chat-project/README.md) | AI کے ساتھ کام کرنا | اپنا AI اسسٹنٹ بنانا سیکھیں | [AI Assistant project](./9-chat-project/README.md) | Chris |
## 🏫 تدریسی اصول
ہمارا نصاب دو اہم تدریسی اصولوں کے ساتھ ڈیزائن کیا گیا ہے:
* پروجیکٹ پر مبنی سیکھنا
* بار بار کوئز
ہمارا نصاب دو بنیادی تدریسی اصولوں کے ساتھ ڈیزائن کیا گیا ہے:
* پروجیکٹ پر مبنی تعلیم
* بار بار کوئزز
یہ پروگرام جاوا اسکرپٹ، HTML، اور CSS کے بنیادی اصولوں کے ساتھ ساتھ آج کے ویب ڈویلپرز کے ذریعہ استعمال ہونے والے جدید ترین اوزار اور تکنیکوں کو سکھاتا ہے۔ طلباء کو ایک ٹائپنگ گیم، ورچوئل Terrarium، ماحول دوست براؤزر ایکسٹینشن، اسپیس انویڈر اسٹائل گیم، اور کاروبار کے لیے ایک بینکنگ ایپ بنانے کے ذریعے عملی تجربہ حاصل کرنے کا موقع ملے گا۔ اس سیریز کے اختتام تک، طلباء ویب ڈویلپمنٹ کی ایک مضبوط سمجھ حاصل کر لیں گے۔
یہ پروگرام جاوا اسکرپٹ، HTML، اور CSS کی بنیادی باتیں سکھاتا ہے، نیز جدید ٹولز اور طریقے جنہیں آج کے ویب ڈویلپرز استعمال کرتے ہیں۔ طلباء کو موقع ملے گا کہ وہ عملی تجربہ حاصل کریں ایک ٹائپنگ گیم، ورچوئل ٹیریریم، ماحول دوست براؤزر ایکسٹینشن، اسپیس-انوادر طرز کے گیم، اور کاروباری بینکنگ ایپ بنا کر۔ اس سلسلے کے اختتام پر طلباء کو ویب ڈیولپمنٹ کی مضبوط سمجھ حاصل ہو گی۔
> 🎓 آپ اس نصاب کے پہلے چند اسباق کو Microsoft Learn پر ایک [Learn Path](https://docs.microsoft.com/learn/paths/web-development-101/?WT.mc_id=academic-77807-sagibbon) کے طور پر لے سکتے ہیں!
> 🎓 آپ اس نصاب کے ابتدائی چند اسباق کو Microsoft Learn پر [Learn Path](https://docs.microsoft.com/learn/paths/web-development-101/?WT.mc_id=academic-77807-sagibbon) کے طور پر لے سکتے ہیں!
پروجیکٹس کے ساتھ مواد کو ہم آہنگ کر کے، عمل کو طلباء کے لیے زیادہ مشغول بنایا گیا ہے اور تصورات کی یادداشت کو بڑھایا جائے گا۔ ہم نے جاوا اسکرپٹ کی بنیادی باتوں میں کئی ابتدائی اسباق بھی لکھے ہیں تاکہ تصورات کو متعارف کرایا جا سکے، جنہیں "[Beginners Series to: JavaScript](https://channel9.msdn.com/Series/Beginners-Series-to-JavaScript/?WT.mc_id=academic-77807-sagibbon)" ویڈیو ٹیوٹوریلز کے مجموعہ کی ویڈیو کے ساتھ جوڑا گیا ہے، جن کے کچھ مصنفین نے اس نصاب میں تعاون کیا ہے۔
مواد کو پروجیکٹس کے ساتھ ہم آہنگ کر کے، عمل کو طلباء کے لیے زیادہ خوشگوار بنایا جاتا ہے اور تصورات کو یاد رکھنے میں اضافہ ہوتا ہے۔ ہم نے جاوا اسکرپٹ کی بنیادی باتیں متعارف کرانے کے لیے کئی ابتدائی اسباق لکھے ہیں، جن کے ساتھ "[Beginners Series to: JavaScript](https://channel9.msdn.com/Series/Beginners-Series-to-JavaScript/?WT.mc_id=academic-77807-sagibbon)" ویڈیو ٹیوٹوریلز کی ویڈیو شامل ہے، جن میں سے کچھ مصنفین نے اس نصاب میں حصہ لیا ہے۔
اس کے علاوہ، کلاس سے پہلے ایک کم دباؤ والا کوئز طالب علم کے ارادے کو کسی موضوع کو سیکھنے کی طرف متعین کرتا ہے، جبکہ کلاس کے بعد دوسرا کوئز مزید یادداشت کو یقینی بناتا ہے۔ یہ نصاب لچکدار اور تفریحی ہونے کے لیے ڈیزائن کیا گیا تھا اور اسے مکمل یا جزوی طور پر لیا جا سکتا ہے۔ پروجیکٹس چھوٹے شروع ہوتے ہیں اور 12 ہفتے کے سائیکل کے اختتام تک بتدریج پیچیدہ ہو جاتے ہیں۔
اس کے علاوہ، کلاس سے پہلے کم اہم کوئز طلباء کے سیکھنے کے مقصد کو متعین کرتا ہے، جبکہ کلاس کے بعد دوسرا کوئز مزید یادداشت کو یقینی بناتا ہے۔ یہ نصاب لچکدار اور تفریحی بنانے کے لیے ڈیزائن کیا گیا ہے اور اسے مکمل یا جزوی طور پر لیا جا سکتا ہے۔ پروجیکٹس شروع میں چھوٹے ہوتے ہیں اور 12 ہفتوں کے دورانیے کے اختتام تک پیچیدہ ہو جاتے ہیں۔
جبکہ ہم نے جاوا اسکرپٹ فریم ورک کو متعارف کرانے سے جان بوجھ کر گریز کیا ہے تاکہ فریم ورک اپنانے سے پہلے ایک ویب ڈویلپر کے طور پر درکار بنیادی مہارتوں پر توجہ مرکوز کی جا سکے، اس نصاب کو مکمل کرنے کے بعد ایک اچھا اگلا قدم Node.js کے بارے میں سیکھنا ہوگا، ویڈیوز کے ایک اور مجموعہ کے ذریعے: "[Beginner Series to: Node.js](https://channel9.msdn.com/Series/Beginners-Series-to-Nodejs/?WT.mc_id=academic-77807-sagibbon)"۔
جبکہ ہم نے جان بوجھ کر جاوا اسکرپٹ فریم ورکس متعارف نہیں کرائے تاکہ بنیادی مہارتوں پر توجہ دی جا سکے جو ایک ویب ڈویلپر کے لیے ضروری ہیں، اس نصاب کو مکمل کرنے کا اگلا اچھا قدم Node.js کے بارے میں سیکھنا ہو گا، جو کہ ویڈیوز کے دوسرے مجموعے "[Beginner Series to: Node.js](https://channel9.msdn.com/Series/Beginners-Series-to-Nodejs/?WT.mc_id=academic-77807-sagibbon)" کے ذریعے کیا جا سکتا ہے۔
> ہمارے [Code of Conduct](CODE_OF_CONDUCT.md) اور [Contributing](CONTRIBUTING.md) رہنما خطوط ملاحظہ کریں۔ ہم آپ کی تعمیری رائے کا خیرمقدم کرتے ہیں!
> ہمارے [Code of Conduct](CODE_OF_CONDUCT.md) اور [Contributing](CONTRIBUTING.md) رہنما اصول دیکھیں۔ ہم آپ کی تعمیری تبصرے کا خیرمقدم کرتے ہیں!
## 🧭 آف لائن رسائی
آپ اس دستاویزات کو آف لائن [Docsify](https://docsify.js.org/#/) کا استعمال کرتے ہوئے چلا سکتے ہیں۔ اس ریپو کو فورک کریں، [Docsify انسٹال کریں](https://docsify.js.org/#/quickstart) اپنی مقامی مشین پر، اور پھر اس ریپو کے روٹ فولڈر میں، `docsify serve` ٹائپ کریں۔ ویب سائٹ آپ کے لوکل ہوسٹ پر پورٹ 3000 پر پیش کی جائے گی: `localhost:3000`۔
آپ [Docsify](https://docsify.js.org/#/) استعمال کر کے اس دستاویز کو آف لائن چلا سکتے ہیں۔ اس ریپو کو فورک کریں، [Docsify انسٹال کریں](https://docsify.js.org/#/quickstart) اپنی مقامی مشین پر، اور پھر اس ریپو کے روٹ فولڈر میں `docsify serve` ٹائپ کریں۔ ویب سائٹ آپ کے لوکل ہوسٹ پر پورٹ 3000 پر دستیاب ہو گی: `localhost:3000`۔
## 📘 پی ڈی ایف
تمام اسباق کی ایک پی ڈی ایف [یہاں](https://microsoft.github.io/Web-Dev-For-Beginners/pdf/readme.pdf) دستیاب ہے۔
تمام اسباق کا پی ڈی ایف [یہاں](https://microsoft.github.io/Web-Dev-For-Beginners/pdf/readme.pdf) دستیاب ہے۔
## 🎒 دیگر کورسز
ہماری ٹیم دیگر کورسز بھی تیار کرتی ہے! دیکھیں:
### Azure / Edge / MCP / Agents
[![AZD for Beginners](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst)
[![ایج اے آئی برائے ابتدائی](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![ایم سی پی برائے ابتدائی](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst)
[![اے آئی ایجنٹس برائے ابتدائی](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst)
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
### LangChain
[![LangChain4j for Beginners](https://img.shields.io/badge/LangChain4j%20for%20Beginners-22C55E?style=for-the-badge&&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchain4j-for-beginners)
[![LangChain.js for Beginners](https://img.shields.io/badge/LangChain.js%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchainjs-for-beginners?WT.mc_id=m365-94501-dwahlin)
---
### جنریٹیو اے آئی سیریز
[![جنریٹیو اے آئی برائے ابتدائی](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![جنریٹیو اے آئی (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst)
[![جنریٹیو اے آئی (جاوا)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst)
[![جنریٹیو اے آئی (جاوا اسکرپٹ)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst)
### Azure / Edge / MCP / Agents
[![AZD for Beginners](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Edge AI for Beginners](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![MCP for Beginners](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst)
[![AI Agents for Beginners](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### بنیادی تعلیم
[![ایم ایل برائے ابتدائی](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst)
[![ڈیٹا سائنس برائے ابتدائی](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst)
[![اے آئی برائے ابتدائی](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst)
[![سائبر سیکیورٹی برائے ابتدائی](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung)
[![ویب ڈیولپمنٹ برائے ابتدائی](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst)
[![آئی او ٹی برائے ابتدائی](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst)
[![ایکس آر ڈیولپمنٹ برائے ابتدائی](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst)
### Generative AI Series
[![Generative AI for Beginners](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Generative AI (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst)
[![Generative AI (Java)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst)
[![Generative AI (JavaScript)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst)
---
### Core Learning
[![ML for Beginners](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst)
[![Data Science for Beginners](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst)
[![AI for Beginners](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst)
[![Cybersecurity for Beginners](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung)
[![Web Dev for Beginners](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst)
[![IoT for Beginners](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst)
[![XR Development for Beginners](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst)
### کوپائلٹ سیریز
[![کوپائلٹ برائے اے آئی پیئرڈ پروگرامنگ](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst)
[![کوپائلٹ برائے C#/.NET](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst)
[![کوپائلٹ ایڈونچر](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst)
---
### Copilot Series
[![Copilot for AI Paired Programming](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst)
[![Copilot for C#/.NET](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst)
[![Copilot Adventure](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst)
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
## مدد حاصل کریں
## مدد حاصل کرنا
اگر آپ کسی مسئلے میں پھنس جائیں یا اے آئی ایپلیکیشنز بنانے کے بارے میں سوالات ہوں، تو دیگر سیکھنے والوں اور تجربہ کار ڈویلپرز کے ساتھ ایم سی پی پر گفتگو میں شامل ہوں۔ یہ ایک معاون کمیونٹی ہے جہاں سوالات کا خیرمقدم کیا جاتا ہے اور علم آزادانہ طور پر شیئر کیا جاتا ہے۔
اگر آپ پھنس جائیں یا AI ایپس بنانے کے بارے میں کوئی سوال ہو۔ MCP کے بارے میں ساتھی سیکھنے والوں اور تجربہ کار ڈویلپرز کے ساتھ گفتگو میں شامل ہوں۔ یہ ایک معاون کمیونٹی ہے جہاں سوالات خوش آمدید ہیں اور علم بلا روک ٹوک شیئر کیا جاتا ہے۔
[![مائیکروسافٹ فاؤنڈری ڈسکارڈ](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
اگر آپ کو پروڈکٹ کے بارے میں رائے دینی ہو یا بلڈنگ کے دوران کوئی مسئلہ ہو تو یہاں جائیں:
اگر آپ کے پاس پروڈکٹ کی رائے یا تعمیر کے دوران غلطیاں ہیں تو ملاحظہ کریں:
[![مائیکروسافٹ فاؤنڈری ڈویلپر فورم](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
[![Microsoft Foundry Developer Forum](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
## لائسنس
## لائسنس
یہ ریپوزٹری MIT لائسنس کے تحت لائسنس یافتہ ہے۔ مزید معلومات کے لیے [LICENSE](../../LICENSE) فائل دیکھیں۔
یہ ذخیرہ MIT لائسنس کے تحت لائسنس یافتہ ہے۔ مزید معلومات کے لیے [LICENSE](../../LICENSE) فائل دیکھیں۔
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**اعلانِ لاتعلقی**:
یہ دستاویز AI ترجمہ سروس [Co-op Translator](https://github.com/Azure/co-op-translator) کا استعمال کرتے ہوئے ترجمہ کی گئی ہے۔ ہم درستگی کے لیے کوشش کرتے ہیں، لیکن براہ کرم آگاہ رہیں کہ خودکار ترجمے میں غلطیاں یا غیر درستیاں ہو سکتی ہیں۔ اصل دستاویز کو اس کی اصل زبان میں مستند ذریعہ سمجھا جانا چاہیے۔ اہم معلومات کے لیے، پیشہ ور انسانی ترجمہ کی سفارش کی جاتی ہے۔ ہم اس ترجمے کے استعمال سے پیدا ہونے والی کسی بھی غلط فہمی یا غلط تشریح کے ذمہ دار نہیں ہیں۔
**استثناء**:
اس دستاویز کا ترجمہ AI ترجمہ سروس [Co-op Translator](https://github.com/Azure/co-op-translator) کے ذریعے کیا گیا ہے۔ اگرچہ ہم درستگی کی کوشش کرتے ہیں، براہِ مہربانی آگاہ رہیں کہ خودکار ترجمے میں غلطیاں یا عدم صحت ہو سکتی ہے۔ اصل دستاویز اپنی مادری زبان میں معتبر ماخذ سمجھی جانی چاہیے۔ اہم معلومات کے لیے پیشہ ور انسانی ترجمہ کی سفارش کی جاتی ہے۔ ہم اس ترجمے کے استعمال سے پیدا ہونے والی کسی بھی غلط فہمی یا غلط تشریح کے ذمہ دار نہیں ہیں۔
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -42,10 +42,10 @@ CO_OP_TRANSLATOR_METADATA:
- Moodle Cloud میں Common Cartridge کی محدود حمایت ہے۔ اوپر دی گئی Moodle فائل کو ترجیح دیں، جسے Canvas میں بھی اپلوڈ کیا جا سکتا ہے۔
- درآمد کے بعد، ماڈیولز، مقررہ تاریخیں، اور کوئز کی ترتیبات کو اپنے ٹرم شیڈول کے مطابق دیکھیں۔
![Moodle](../../translated_images/moodle.94eb93d714a50cb2c97435b408017dee224348b61bc86203ffd43a4f4e57b95f.ur.png)
![Moodle](../../translated_images/moodle.94eb93d714a50cb2.ur.png)
> Moodle کلاس روم میں نصاب
![Canvas](../../translated_images/canvas.fbd605ff8e5b8aff567d398528ce113db304446b90b9cad55c654de3fdfcda34.ur.png)
![Canvas](../../translated_images/canvas.fbd605ff8e5b8aff.ur.png)
> Canvas میں نصاب
### ریپو کو براہ راست استعمال کریں (بغیر Classroom کے)

@ -1,64 +1,246 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "2581528206a2a01c3a0b9c88e039b7bc",
"translation_date": "2025-10-03T08:49:05+00:00",
"original_hash": "d45ddcc54eb9232a76d08328b09d792e",
"translation_date": "2026-01-06T11:58:19+00:00",
"source_file": "1-getting-started-lessons/1-intro-to-programming-languages/README.md",
"language_code": "zh"
}
-->
# 编程语言与工具入门
# 编程语言与现代开发工具简介
嗨,未来的开发者!👋 我能告诉你一件每天都会让我激动不已的事情吗?你即将发现,编程不仅仅是关于计算机——它是一种具有真正超能力的方式,能让你把最狂野的创意变成现实!
你知道用自己最喜欢的应用时那种一切完美契合的时刻吗?当你点击一个按钮,发生了某种神奇的事情,让你忍不住惊叹“哇,他们到底是怎么做到的?”那么,就像你一样的人——可能正坐在他们最喜欢的咖啡馆,凌晨两点喝着第三杯浓咖啡——写出了创造那个魔法的代码。更震撼的是:到本课结束时,你不仅会理解他们是怎么做到的,还会急切想亲自尝试一番!
听我说,我完全理解如果现在编程看起来让你感到害怕。当我刚开始时,我真的以为你得是某种数学天才,或者从五岁起就开始编程。但有件事彻底改变了我的看法:编程就像学习用一门新语言交谈。你从“你好”和“谢谢”开始,然后学会点咖啡,再到后面能谈天说地!只不过这次,你是在和计算机对话,而说实话?它们是你遇到过的最有耐心的对话伙伴——从不批评你的错误,并且永远乐意再试一次!
今天,我们将探索那些让现代网页开发不仅可行而且极其上瘾的令人难以置信的工具。我说的是 Netflix、Spotify 和你最喜欢的独立应用工作室每天使用的同样的编辑器、浏览器和工作流程。最棒的是,这些专业级、行业标准的工具大多数是完全免费的!
![Intro Programming](../../../../translated_images/webdev101-programming.d6e3f98e61ac4bff.zh.png)
> 速写笔记由 [Tomomi Imura](https://twitter.com/girlie_mac) 制作
```mermaid
journey
title 你今天的编程旅程
section 发现
什么是编程: 5: You
编程语言: 4: You
工具概览: 5: You
section 探索
代码编辑器: 4: You
浏览器与开发者工具: 5: You
命令行: 3: You
section 练习
语言侦探: 4: You
工具探索: 5: You
社区连接: 5: You
```
## 让我们看看你已经知道什么!
在我们进入有趣的内容之前,我很好奇——你已经对这个编程世界了解多少?听着,如果你看着这些问题想“我完全一点头绪都没有”,这不仅没关系,还非常完美!这意味着你正处在绝佳的起点。把这个测验想象成锻炼前的拉伸运动——我们只是让大脑先热身!
[参加课前测验](https://forms.office.com/r/dru4TE0U9n?origin=lprLink)
## 我们即将一起踏上的冒险之旅
好了,我真的非常激动要和你一同探索今天的内容!说真的,我真希望能看到你那些概念“恍然大悟”时的表情。我们将一起经历这段不可思议的旅程:
本课涵盖了编程语言的基础知识。这里讨论的主题适用于当今大多数现代编程语言。在“工具介绍”部分,您将学习一些对开发者非常有用的软件。
- **什么是编程(以及为什么它超酷!)**——我们将发现代码究竟是如何成为无形的魔法,驱动你周围所有事物,从那闹钟怎样知道今天是周一,到算法如何完美推荐你喜欢的 Netflix 内容
- **编程语言和它们令人惊讶的个性**——想象参加一个派对,每个人都有完全不同的超能力和解决问题的方式。这就是编程语言的世界,你一定会喜欢认识它们!
- **数字魔法发生的基本构建块**——把它们当作终极创意的乐高积木。一旦你理解这些零件是如何拼合的,你会发现你完全可以构建任何你想象中的东西
- **能让你感觉像拿到巫师魔杖的专业工具**——我一点都不夸张,这些工具真的会让你感觉拥有超能力,更棒的是?它们正是专业人士使用的工具!
![编程入门](../../../../translated_images/webdev101-programming.d6e3f98e61ac4bff0b27dcbf1c3f16c8ed46984866f2d29988929678b0058fde.zh.png)
> 由 [Tomomi Imura](https://twitter.com/girlie_mac) 绘制的速记图
> 💡 **温馨提示**:今天别想着把所有内容都记住!此刻,我只希望你感受到可能性的火花。细节会随着我们的实践自然沉淀——这才是真正的学习过程!
## 课前测验
[课前测验](https://forms.office.com/r/dru4TE0U9n?origin=lprLink)
> 你也可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101/introduction-programming/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
## 简介
## 那么,什么是*编程*
在本课中,我们将讨论:
好,让我们来攻克这个价值百万美元的问题:编程究竟是什么?
- 什么是编程?
- 编程语言的类型
- 程序的基本元素
- 专业开发者常用的软件和工具
我来给你讲一个让我完全改变看法的故事。上周,我试图向我妈妈解释如何使用我们的新智能电视遥控器。我发现自己说着“按那个红色按钮,不是大红按钮,是左边的小红按钮……不,你那边的左边……好了,现在按住两秒,不是一秒,也不是三秒……”是不是很熟悉?😅
> 您可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101/introduction-programming/?WT.mc_id=academic-77807-sagibbon) 上学习本课!
这就是编程!它是向一个非常强大的对象给出极其详细、逐步的指令的艺术,但必须清楚准确。只不过你不是向妈妈(她可能会问“哪个红色按钮?!”)解释,而是向计算机(它只做你说的,即使不完全是你想要的)。
## 什么是编程?
当我第一次学会这点时真是震惊到不行计算机其实很简单。它们字面上只懂两种东西——1和0也就是“是”和“否”或“开”和“关”。就是这么简单但魔幻的地方在这里——我们不必像电影《黑客帝国》一样说1和0。这时**编程语言**就派上用场了。它们就像世界上最棒的翻译官,把你完全正常的人类想法转换成计算机语言。
编程(也称为编码)是为计算机或移动设备编写指令的过程。我们使用编程语言来编写这些指令,然后由设备进行解释。这些指令集可能有不同的名称,但*程序*、*计算机程序*、*应用程序app*和*可执行文件*是一些常见的称呼。
每天早上醒来,这点仍然让我激动不已:你生活中所有的数字事物,最初都是像你一样的人,可能穿着睡衣,手拿咖啡,在笔记本上敲代码。那个让你看起来完美无瑕的 Instagram 滤镜?有人写了那段代码。带你发现新歌的推荐算法?开发者设计了它。帮助你和朋友均摊晚餐账单的应用?没错,有人想着“真烦人,我一定能改进它”,结果……他们做到了!
一个*程序*可以是任何用代码编写的东西;网站、游戏和手机应用都是程序。虽然可以在不编写代码的情况下创建程序,但底层逻辑是由设备解释的,而这些逻辑很可能是用代码编写的。一个正在*运行*或*执行*代码的程序正在执行指令。您正在阅读本课的设备正在运行一个程序,将内容显示在屏幕上。
学会编程,你不仅仅是习得一项新技能——你正在加入这样一个令人敬佩的群体,这群解决问题的人用他们的每一天思考,“如果我能造出点东西,让某个人的一天更美好一点,会怎么样?”说真的,有什么比这更酷的吗?
✅ 做一些研究:谁被认为是世界上第一位计算机程序员?
**趣味小调查**:闲暇时看看这个超酷的内容——你认为世界上第一位计算机程序员是谁?提示:她可能不是你想象中的那样!这位人士背后的故事极其精彩,说明编程从一开始就是关于创造性解决问题和跳出框架思考。
## 编程语言
### 🧠 **情绪检查:你感觉如何?**
编程语言使开发者能够为设备编写指令。设备只能理解二进制1和0而对于*大多数*开发者来说,这不是一种高效的沟通方式。编程语言是人类与计算机之间沟通的桥梁。
**花点时间想想:**
- “向计算机下指令”的想法你现在能理解了吗?
- 你能想到想用编程自动化的日常任务吗?
- 关于编程,你脑海中冒出了哪些问题?
编程语言有不同的格式并可能服务于不同的目的。例如JavaScript主要用于网络应用而Bash主要用于操作系统。
> **记住**:某些概念暂时模糊完全正常。学编程就像学新语言——需要时间让大脑建立神经回路。你做得很棒!
*低级语言*通常比*高级语言*需要更少的步骤来让设备解释指令。然而高级语言之所以受欢迎是因为它们的可读性和支持性。JavaScript被认为是一种高级语言。
## 编程语言就像不同风味的魔法
以下代码展示了使用JavaScript高级语言和ARM汇编代码低级语言的区别。
嗯,这听起来可能有点怪,但请坚持听我说——编程语言很像不同类型的音乐。想想看:有爵士乐,流畅且即兴;摇滚,强劲直接;古典,优雅而有结构;还有嘻哈,创意和富于表现力。每种风格都有自己的气质和热情的拥护者社区,同时适合不同的心情和场合。
编程语言也是一样!你不会用同一种语言去造一个有趣的手机游戏和处理庞大的气候数据,就像你不会在瑜伽课上听死亡金属(嗯,大多数瑜伽课都是这样!😄)。
但每次一想到这点我都震惊不已这些语言就像世界上最耐心、最聪明的口译员坐在你旁边。你可以用适合你人脑的方式表达想法语言帮你完成把这些转换成计算机说的1和0的复杂工作。这就像拥有一个在“人类创造力”和“计算机逻辑”两种语言之间流利切换的朋友——他们永不疲倦不用喝咖啡休息也从不因为你重复问同一个问题而评价你
### 流行编程语言及其用途
```mermaid
mindmap
root((编程语言))
Web Development
JavaScript
前端魔法
互动网站
TypeScript
JavaScript + 类型
企业应用
Data & AI
Python
数据科学
机器学习
自动化
R
统计
研究
Mobile Apps
Java
安卓
企业
Swift
iOS
苹果生态系统
Kotlin
现代安卓
跨平台
Systems & Performance
C++
游戏
性能关键
Rust
内存安全
系统编程
Go
云服务
可扩展后端
```
| 语言 | 最适合 | 为什么受欢迎 |
|------|--------|--------------|
| **JavaScript** | 网页开发,用户界面 | 在浏览器中运行,驱动互动网站 |
| **Python** | 数据科学,自动化,人工智能 | 易读易学,拥有强大库支持 |
| **Java** | 企业应用,安卓应用 | 跨平台,适合大型系统 |
| **C#** | Windows 应用,游戏开发 | 微软生态圈支持强大 |
| **Go** | 云服务,后端系统 | 快速简单,专为现代计算设计 |
### 高级语言 vs 低级语言
说实话,这是我刚开始学时觉得最烧脑的概念,所以我要分享一个让我顿悟的比喻——希望对你也有帮助!
想象你去一个不会说语言的国家,急需找厕所(我们都经历过,对吧?😅):
- **低级编程**就像学得那么好本地方言,能和街角卖水果的奶奶聊文化典故、本地俚语和只有当地人懂的笑话。超厉害且高效……如果你流利的话!但当你只是想找个厕所时,简直头大。
- **高级编程**就像有一个很棒的本地朋友完全懂你。你用英语说“我急需找厕所”,朋友帮你翻译文化差异,给你解释得非常清楚,适合不懂当地文化的你。
编程术语来说:
- **低级语言**如汇编或C让你能和计算机硬件进行极其细致的对话但你得像机器一样思考……嗯这对脑力是很大考验
- **高级语言**(如 JavaScript、Python 或 C#)让你像人类一样思考,它们在幕后处理所有机器语言。更棒的是,它们有超友好的社区,里面的人都记得刚入门的艰难,真心想帮助你!
你猜我推荐你先学哪个?😉 高级语言就像有了辅助轮,虽然你可能永远不会想摘掉,因为它让整体验更愉快!
```mermaid
flowchart TB
A["👤 人类思维:<br/>'我想计算斐波那契数列'"] --> B{选择语言级别}
B -->|高级| C["🌟 JavaScript/Python<br/>易读易写"]
B -->|低级| D["⚙️ 汇编/C<br/>直接硬件控制"]
C --> E["📝 写fibonacci(10)"]
D --> F["📝 写mov r0,#00<br/>sub r0,r0,#01"]
E --> G["🤖 计算机理解:<br/>翻译器处理复杂性"]
F --> G
G --> H["💻 相同结果:<br/>0, 1, 1, 2, 3, 5, 8, 13..."]
style C fill:#e1f5fe
style D fill:#fff3e0
style H fill:#e8f5e8
```
### 让我给你展示为什么高级语言更友好
好了,我马上给你看点东西,完美展示我为什么爱上高级语言。但先请你答应我一个条件。看到第一段代码示例时,不要慌张!它看起来吓人正是我要说明的点!
我们将看同一任务用两种完全不同风格写成的代码。它们都会产生所谓的斐波那契数列——这是一个漂亮的数学模式每个数字是前两个数字之和011235813……趣味事实你会在大自然无处不在地发现这个模式——向日葵的种子螺旋松果的形状甚至银河的形成
准备好看差别了吗?走起!
**高级语言JavaScript——人类友好**
```javascript
let number = 10
let n1 = 0, n2 = 1, nextTerm;
for (let i = 1; i <= number; i++) {
console.log(n1);
nextTerm = n1 + n2;
n1 = n2;
n2 = nextTerm;
// 第一步:基本斐波那契设置
const fibonacciCount = 10;
let current = 0;
let next = 1;
console.log('Fibonacci sequence:');
```
**这段代码做了什么:**
- **声明**一个常量,用来指定我们想生成多少个斐波那契数
- **初始化**两个变量,用于跟踪数列中的当前值和下一个值
- **设置**起始值0和1定义斐波那契序列
- **显示**一个标题消息,标示我们的输出
```javascript
// 第2步用循环生成序列
for (let i = 0; i < fibonacciCount; i++) {
console.log(`Position ${i + 1}: ${current}`);
// 计算序列中的下一个数字
const sum = current + next;
current = next;
next = sum;
}
```
```c
**代码运行过程中:**
- **用`for`循环**遍历序列中的每个位置
- **打印**每个数字及其位置,使用模板字符串格式化
- **计算**下一个斐波那契数,方法是加上当前数和下一个数
- **更新**跟踪变量,进入下一次循环
```javascript
// 第3步现代函数式方法
const generateFibonacci = (count) => {
const sequence = [0, 1];
for (let i = 2; i < count; i++) {
sequence[i] = sequence[i - 1] + sequence[i - 2];
}
return sequence;
};
// 使用示例
const fibSequence = generateFibonacci(10);
console.log(fibSequence);
```
**上述代码中:**
- **创建**了一个可复用函数,使用现代箭头函数语法
- **构建**了一个数组来存储完整序列,而不是逐个展示
- **使用**数组索引根据前面的值计算新数
- **返回**完整序列,方便在程序其他部分灵活使用
**低级语言ARM 汇编)——计算机友好:**
```assembly
area ascen,code,readonly
entry
code32
@ -83,137 +265,598 @@ back add r0,r1
end
```
相信或不相信,*它们都在做同样的事情*打印一个斐波那契数列到10
注意JavaScript 版本读起来几乎像英语指令,而汇编使用的是直接控制处理器的神秘命令。它们完成的是完全相同的任务,但高级语言更易于人类理解、编写和维护
✅ 斐波那契数列是[定义](https://en.wikipedia.org/wiki/Fibonacci_number)为一组数字其中每个数字是前两个数字的和起始值为0和1。斐波那契数列的前10个数字是0, 1, 1, 2, 3, 5, 8, 13, 21和34。
**你会注意到的主要区别:**
- **可读性**JavaScript 用像 `fibonacciCount` 这样的描述性名称,而汇编使用像 `r0`、`r1` 这样晦涩的标签
- **注释**:高级语言鼓励解释性注释,使代码具备自我说明性
- **结构**JavaScript 的逻辑流程与人类逐步思考问题的方式相匹配
- **维护**:针对不同需求更新 JavaScript 版本简单明了
## 程序的元素
**关于斐波那契数列**这个绝美的数字模式每个数字都是前两个数字之和0, 1, 1, 2, 3, 5, 8……在自然界里无处不在你会在向日葵的螺旋、松果的排列、鹦螺壳的弯曲方式甚至树枝的生长方式中发现它。数学和代码帮我们理解并重现自然界用来创造美丽的模式真是令人震撼
程序中的单条指令称为*语句*,通常会有一个字符或行间距标记指令的结束或*终止*。程序如何终止因语言而异。
## 构成魔法的基石
程序中的语句可能依赖用户或其他地方提供的数据来执行指令。数据可以改变程序的行为,因此编程语言提供了一种临时存储数据的方法,以便稍后使用。这些称为*变量*。变量是指示设备将数据保存在内存中的语句。程序中的变量类似于代数中的变量,它们有一个唯一的名称,其值可能随时间变化。
好了,现在你已经看到了编程语言的实际运作,让我们分解构成所有程序的基础部分。把它们看作你最喜欢的食谱中的基本成分——只要你了解每个成分的作用,就能在几乎任何语言中读写代码!
有些语句可能不会被设备执行。这通常是开发者设计的结果,或者是意外错误导致的。这种对应用程序的控制使其更强大且更易维护。通常,这种控制的变化发生在满足某些条件时。现代编程中常用的一种语句是`if..else`语句。
这有点像学习编程的语法。还记得你在学校学名词、动词和如何组成句子吗?编程也有自己的语法版本,说实话,比英语语法更加合乎逻辑和宽容!😄
✅ 您将在后续课程中学习更多关于这种语句的内容。
### 语句:一步步的指令
## 工具介绍
先从**语句**开始——它们就像你和电脑对话中的单句。每条语句告诉电脑做一件具体的事,就像给出方向指令:“这里左转”、“红绿灯处停下”、“在那个地方停车”。
[![工具介绍](https://img.youtube.com/vi/69WJeXGBdxg/0.jpg)](https://youtube.com/watch?v=69WJeXGBdxg "工具介绍")
我喜欢语句的地方是它们通常很易读。看看这个:
> 🎥 点击上方图片观看关于工具的视频
```javascript
// 执行单个操作的基本语句
const userName = "Alex";
console.log("Hello, world!");
const sum = 5 + 3;
```
在本节中,您将了解一些在开始专业开发旅程时可能非常有用的软件。
**这段代码做了什么:**
- **声明**一个常量变量存储用户的名字
- **向控制台输出**问候消息
- **计算**并存储一个数学运算的结果
**开发环境**是开发者在编写软件时经常使用的一组独特工具和功能。这些工具可能根据开发者的具体需求进行了定制,并可能随着开发者工作重点的变化、个人项目的变化或使用不同编程语言而改变。开发环境如同开发者本身一样独特。
```javascript
// 与网页交互的语句
document.title = "My Awesome Website";
document.body.style.backgroundColor = "lightblue";
```
### 编辑器
**一步步讲解发生了什么:**
- **修改**浏览器标签页显示的网页标题
- **更改**整个页面主体的背景颜色
软件开发中最重要的工具之一是编辑器。编辑器是您编写代码的地方,有时也是运行代码的地方。
### 变量:程序的记忆系统
开发者依赖编辑器还有以下几个原因:
好,**变量**说实话是我最喜欢讲的概念之一,因为它们就像你每天使用的东西!
- *调试*帮助逐行检查代码,发现错误和问题。一些编辑器具有调试功能;它们可以为特定编程语言进行定制和添加。
- *语法高亮*为代码添加颜色和文本格式,使其更易于阅读。大多数编辑器允许定制语法高亮。
- *扩展和集成*是为开发者设计的专业工具。这些工具并未内置于基础编辑器中。例如,许多开发者会为代码编写文档以解释其工作原理。他们可能安装拼写检查扩展来帮助发现文档中的拼写错误。大多数扩展是为特定编辑器设计的,大多数编辑器都提供搜索可用扩展的功能。
- *定制化*使开发者能够创建适合自己需求的独特开发环境。大多数编辑器都非常可定制,并可能允许开发者创建自定义扩展。
想想你手机的联系人列表。你不会记住每个人的号码——你保存的是“妈妈”、“死党”或者“凌晨2点前送餐的披萨店”然后让手机记住实际号码。变量就是这样它们是带标签的容器程序可以用名字存储信息并在需要时取出。
#### 流行的编辑器及网络开发扩展
更酷的是:变量会随着程序运行而改变(这也解释了它名字的意义)。就像你发现更好的披萨店会更新联系人一样,变量可以随着程序获取新信息或发生变化而更新!
- [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon)
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)
- [Live Share](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare)
- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
- [Atom](https://atom.io/)
- [spell-check](https://atom.io/packages/spell-check)
- [teletype](https://atom.io/packages/teletype)
- [atom-beautify](https://atom.io/packages/atom-beautify)
- [Sublimetext](https://www.sublimetext.com/)
- [emmet](https://emmet.io/)
- [SublimeLinter](http://www.sublimelinter.com/en/stable/)
让我给你演示一下多么简单漂亮:
```javascript
// 第一步:创建基本变量
const siteName = "Weather Dashboard";
let currentWeather = "sunny";
let temperature = 75;
let isRaining = false;
```
**理解这些概念:**
- **`const` 存储不变的值**(比如网站名)
- **`let` 存储程序中会变化的值**
- **赋值不同的数据类型**:字符串(文本)、数字和布尔值(真/假)
- **选择描述性名称**,说明每个变量包含什么
```javascript
// 第2步使用对象来分组相关数据
const weatherData = {
location: "San Francisco",
humidity: 65,
windSpeed: 12
};
```
### 浏览器
**上面代码中,我们:**
- **创建了一个对象**将相关的天气信息归类在一起
- **将多条数据组织在一个变量名下**
- **用键值对清楚地标注每条信息**
另一个重要工具是浏览器。网络开发者依赖浏览器来查看代码在网络上的运行情况。浏览器还用于显示编辑器中编写的网页的视觉元素例如HTML。
```javascript
// 第3步使用和更新变量
console.log(`${siteName}: Today is ${currentWeather} and ${temperature}°F`);
console.log(`Wind speed: ${weatherData.windSpeed} mph`);
许多浏览器都带有*开发者工具*DevTools其中包含一组有用的功能和信息帮助开发者收集和捕获有关其应用程序的重要信息。例如如果网页出现错误有时知道错误发生的时间会很有帮助。浏览器中的开发者工具可以配置为捕获这些信息。
// 更新可变变量
currentWeather = "cloudy";
temperature = 68;
```
#### 流行的浏览器及开发者工具
**逐一理解各部分:**
- **用模板字面量 `${}` 语法展示信息**
- **用点号访问对象属性**(如 `weatherData.windSpeed`
- **更新用 `let` 声明的变量**以响应变化的情况
- **组合多个变量创造有意义的消息**
- [Edge](https://docs.microsoft.com/microsoft-edge/devtools-guide-chromium/?WT.mc_id=academic-77807-sagibbon)
- [Chrome](https://developers.google.com/web/tools/chrome-devtools/)
- [Firefox](https://developer.mozilla.org/docs/Tools)
```javascript
// 第4步使用现代解构赋值使代码更简洁
const { location, humidity } = weatherData;
console.log(`${location} humidity: ${humidity}%`);
```
### 命令行工具
**你需要知道的是:**
- **用解构赋值提取对象中的特定属性**
- **自动创建与对象键同名的新变量**
- **避免重复点号访问简化代码**
一些开发者更喜欢使用较少图形化的界面来完成日常任务,并依赖命令行来实现这一点。编写代码需要大量的输入,一些开发者更喜欢不打断键盘上的工作流。他们会使用键盘快捷键在桌面窗口之间切换、处理不同文件以及使用工具。虽然大多数任务可以通过鼠标完成,但使用命令行的一个好处是可以在不需要鼠标和键盘切换的情况下完成许多任务。命令行的另一个好处是它们是可配置的,您可以保存自定义配置,稍后更改,并将其导入到其他开发机器中。由于开发环境对每个开发者来说都非常独特,有些人会完全避免使用命令行,有些人会完全依赖它,还有些人喜欢两者结合使用。
### 控制流:教你的程序学会思考
### 流行的命令行选项
这里编程就开始绝对让人疯狂了!**控制流**本质上是教你的程序像你每天无意识做的那样,做出聪明的决策。
命令行选项会因您使用的操作系统而有所不同。
想象一下:今天早上你大概经历的是“如果下雨,我带伞;如果冷,我穿夹克;如果迟到,我就不吃早饭顺路买杯咖啡”。你的大脑自然地遵循这种如果-那么的逻辑,每天数十次!
*💻 = 操作系统预装。*
这就是让程序显得智能、有生命力的原因,而不是死板执行无聊脚本。它们可以识别情况,评估发生了什么,并做出恰当反应。就像赋予程序一个能适应和做选择的大脑!
#### Windows
想看看这多美妙?我来给你演示:
- [Powershell](https://docs.microsoft.com/powershell/scripting/overview?view=powershell-7/?WT.mc_id=academic-77807-sagibbon) 💻
- [命令行](https://docs.microsoft.com/windows-server/administration/windows-commands/windows-commands/?WT.mc_id=academic-77807-sagibbon)也称为CMD💻
- [Windows Terminal](https://docs.microsoft.com/windows/terminal/?WT.mc_id=academic-77807-sagibbon)
- [mintty](https://mintty.github.io/)
#### MacOS
```javascript
// 第一步:基本条件逻辑
const userAge = 17;
if (userAge >= 18) {
console.log("You can vote!");
} else {
const yearsToWait = 18 - userAge;
console.log(`You'll be able to vote in ${yearsToWait} year(s).`);
}
```
**这段代码做了什么:**
- **检查**用户年龄是否满足投票要求
- **根据条件结果执行**不同代码块
- **计算**并显示未满18岁距离投票资格的时间
- **针对每种情形提供**具体且有用的反馈
```javascript
// 第2步使用逻辑运算符的多个条件
const userAge = 17;
const hasPermission = true;
if (userAge >= 18 && hasPermission) {
console.log("Access granted: You can enter the venue.");
} else if (userAge >= 16) {
console.log("You need parent permission to enter.");
} else {
console.log("Sorry, you must be at least 16 years old.");
}
```
**分解这里发生的事情:**
- **使用 `&&`(且)运算符结合多个条件**
- **`else if` 创建多重情形的条件层级**
- **用最终的 `else` 处理所有可能案例**
- **为每种不同情况提供清晰、可行的反馈**
```javascript
// 第3步使用三元运算符的简洁条件语句
const votingStatus = userAge >= 18 ? "Can vote" : "Cannot vote yet";
console.log(`Status: ${votingStatus}`);
```
**你需要记住的:**
- **用三元运算符 (`? :`) 处理简单的二选一条件**
- **写条件,跟 `?`,接真值,再 `:`,最后假值**
- **在根据条件赋值时使用这个模式**
```javascript
// 第4步处理多个特定情况
const dayOfWeek = "Tuesday";
switch (dayOfWeek) {
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
console.log("It's a weekday - time to work!");
break;
case "Saturday":
case "Sunday":
console.log("It's the weekend - time to relax!");
break;
default:
console.log("Invalid day of the week");
}
```
**这段代码实现了以下功能:**
- **将变量的值匹配多个特定情况**
- **将类似情况归入一组(工作日与周末)**
- **找到匹配时执行相应代码块**
- **`default` 处理意外值**
- **`break` 语句阻止继续执行下一个情况**
> 💡 **现实世界的比喻**:把控制流想象成世界上最有耐心的 GPS 指路。它可能告诉你“如果主街堵车,就走高速;如果高速施工,试试风景路”。程序用完全一样的条件逻辑智能响应各种情况,总是为用户提供最优体验。
### 🎯 **概念检测:构建块掌握情况**
**来看看你对基础的掌握如何:**
- 你能用自己的话解释变量和语句的区别吗?
- 想一个现实场景,用 if-then 决策(像投票的例子)
- 编程逻辑中有什么让你感到惊讶的吗?
**快速增强信心:**
```mermaid
flowchart LR
A["📝 语句<br/>(指令)"] --> B["📦 变量<br/>(存储)"] --> C["🔀 控制流<br/>(决策)"] --> D["🎉 可用程序!"]
style A fill:#ffeb3b
style B fill:#4caf50
style C fill:#2196f3
style D fill:#ff4081
```
**接下来是什么**:我们将继续深入挖掘这些概念,一起度过一段绝妙的旅程!现在,只需专注于感受未来无限可能的兴奋。具体的技能和技巧随着我们的实践会自然而然地掌握——我保证这会比你想象的更有趣!
## 工具箱
说实话,这部分我已经激动得坐不住了!🚀 我们要聊聊让你感觉像刚拿到数字飞船钥匙一样的神奇工具。
你知道厨师手中总有那些完美平衡、感觉像自己手臂延伸的刀具吗?或者音乐家那把碰即可歌唱的吉他?开发者也有属于自己的神奇工具,这些工具绝大多数竟然完全免费,真让人脑洞大开!
我激动得都快跳起来了,因为这些工具彻底改变了我们构建软件的方式。我们聊的是 AI 驱动的编码助手,可以帮你写代码(不是开玩笑!),云端环境让你只要有 Wi-Fi 就能随时随地搭建完整应用,还有调试工具如此高级,简直就是给程序装上了透视眼。
而让我仍兴奋不已的是:这些不是“初学者工具”用着用着就会淘汰的。这就是 Google、Netflix 和你喜欢的那个独立应用工作室当下使用的同款专业级工具。用它们你会感觉自己像个大牛!
```mermaid
graph TD
A["💡 你的想法"] --> B["⌨️ 代码编辑器<br/>(VS Code)"]
B --> C["🌐 浏览器开发者工具<br/>(测试与调试)"]
C --> D["⚡ 命令行<br/>(自动化与工具)"]
D --> E["📚 文档<br/>(学习与参考)"]
E --> F["🚀 惊艳的网页应用!"]
B -.-> G["🤖 AI 助手<br/>(GitHub Copilot)"]
C -.-> H["📱 设备测试<br/>(响应式设计)"]
D -.-> I["📦 包管理器<br/>(npm, yarn)"]
E -.-> J["👥 社区<br/>(Stack Overflow)"]
style A fill:#fff59d
style F fill:#c8e6c9
style G fill:#e1f5fe
style H fill:#f3e5f5
style I fill:#ffccbc
style J fill:#e8eaf6
```
### 代码编辑器和 IDE你的新数字挚友
说说代码编辑器吧——它们绝对会成为你最喜欢呆的地方!把它想象成你的专属编码圣地,大部分时间你都在这里打造、完善你的数字作品。
现代编辑器的魔力在于:它们不仅是高级文本编辑器,更像有位天才、耐心的编码导师 24/7 坐在你身边。它们会先于你发现拼写错误,建议改进让你看起来像个大师,帮你理解代码每部分功能,有些甚至能预测你要输入啥,替你把话说完!
我记得第一次发现自动补全时,简直像生活在未来。你一输入,它就说,“嘿,你是不是想调这个函数?刚好能满足你需要!”简直像个读心术编程伙伴!
**它们为什么这么不可思议?**
现代代码编辑器提供了丰富功能,大幅提升你的效率:
| 功能 | 作用 | 帮助点 |
|---------|--------------|--------------|
| **语法高亮** | 给代码不同部分着色 | 让代码更容易阅读、发现错误 |
| **自动补全** | 你输入时给出建议 | 加速编程并减少拼写错误 |
| **调试工具** | 帮你找错并修正 | 节省大量排查问题的时间 |
| **扩展** | 添加专门功能 | 让编辑器适配各种技术需求 |
| **AI 助手** | 代码建议和解释 | 加速学习和提高生产力 |
> 🎥 **视频资源**:想看看这些工具实际操作?查看这段[工具箱视频](https://youtube.com/watch?v=69WJeXGBdxg)获取全面概览。
- [终端](https://support.apple.com/guide/terminal/open-or-quit-terminal-apd5265185d-f365-44cb-8b09-71a064a42125/mac) 💻
- [iTerm](https://iterm2.com/)
- [Powershell](https://docs.microsoft.com/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-7/?WT.mc_id=academic-77807-sagibbon)
#### 推荐的网络开发编辑器
#### Linux
**[Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-77807-sagibbon)**(免费)
- Web 开发者中最流行
- 极佳的扩展生态系统
- 内置终端和 Git 集成
- **必装扩展**
- [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) - AI 代码建议
- [Live Share](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare) - 实时协作
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 自动格式化代码
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 捕捉代码拼写错误
- [Bash](https://www.gnu.org/software/bash/manual/html_node/index.html) 💻
- [KDE Konsole](https://docs.kde.org/trunk5/en/konsole/konsole/index.html)
- [Powershell](https://docs.microsoft.com/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-7/?WT.mc_id=academic-77807-sagibbon)
**[JetBrains WebStorm](https://www.jetbrains.com/webstorm/)**(收费,学生免费)
- 高级调试和测试工具
- 智能代码补全
- 内建版本控制
#### 流行的命令行工具
**云端 IDE**(不同价格)
- [GitHub Codespaces](https://github.com/features/codespaces) - 浏览器里完整的 VS Code
- [Replit](https://replit.com/) - 非常适合学习和共享代码
- [StackBlitz](https://stackblitz.com/) - 极速全栈网页开发
- [Git](https://git-scm.com/) (💻 在大多数操作系统上预装)
- [NPM](https://www.npmjs.com/)
- [Yarn](https://classic.yarnpkg.com/en/docs/cli/)
> 💡 **入门小贴士**:先用 Visual Studio Code —— 它免费、业界广泛使用,且有庞大社区制作的教程和扩展。
### 文档
### 网络浏览器:你的秘密开发实验室
当开发者想学习新知识时,他们通常会查阅文档以了解如何使用它。开发者经常依赖文档来指导他们正确使用工具和语言,并深入了解其工作原理。
准备好被彻底震撼了吗!你平常用浏览器刷社媒、看视频,对吧?实际上它们一直藏着个神奇的开发者实验室,等你去发现!
#### 网络开发相关的流行文档
每次你右键点击网页选“检查元素”,就打开了一个隐藏的开发者工具世界,这些工具比我以前花大钱买的专业软件都强大多了。就像发现自己平常用的厨房背后藏着一间专业大厨的实验室!
第一次有人给我展示浏览器开发者工具时,我光是点击四处查看,就花了大约三个小时不停地惊呼:“等等,它居然还能做这个?!”你真的可以实时编辑任何网站,准确看到加载速度,测试你的网站在不同设备上的展示效果,甚至像个专业人士一样调试 JavaScript。简直令人震惊
- [Mozilla Developer Network (MDN)](https://developer.mozilla.org/docs/Web),由发布 [Firefox](https://www.mozilla.org/firefox/) 浏览器的 Mozilla 提供
- [Frontend Masters](https://frontendmasters.com/learn/)
- [Web.dev](https://web.dev),由发布 [Chrome](https://www.google.com/chrome/) 的 Google 提供
- [Microsoft 的开发者文档](https://docs.microsoft.com/microsoft-edge/#microsoft-edge-for-developers),适用于 [Microsoft Edge](https://www.microsoft.com/edge)
- [W3 Schools](https://www.w3schools.com/where_to_start.asp)
**浏览器是你秘密武器的原因:**
✅ 做一些研究:现在您了解了网络开发者的环境,试着比较和对比它与网络设计师的环境。
当你创建一个网站或网络应用时,你需要看到它在现实中的外观和表现。浏览器不仅展示你的作品,还会提供性能、可访问性和潜在问题的详细反馈。
#### 浏览器开发者工具DevTools
现代浏览器包含全面的开发套件:
| 工具类别 | 功能 | 示例用途 |
|---------------|--------------|------------------|
| **元素检查器** | 实时查看和编辑 HTML/CSS | 调整样式以立即查看效果 |
| **控制台** | 查看错误信息和测试 JavaScript | 调试问题和尝试代码 |
| **网络监视器** | 跟踪资源加载情况 | 优化性能和加载时间 |
| **可访问性检查器** | 测试包容性设计 | 确保网站对所有用户友好 |
| **设备模拟器** | 在不同屏幕尺寸上预览 | 无需多设备即可测试响应式设计 |
#### 推荐用于开发的浏览器
- **[Chrome](https://developers.google.com/web/tools/chrome-devtools/)** 行业标准的 DevTools拥有丰富文档
- **[Firefox](https://developer.mozilla.org/docs/Tools)** 出色的 CSS Grid 和可访问性工具
- **[Edge](https://docs.microsoft.com/microsoft-edge/devtools-guide-chromium/?WT.mc_id=academic-77807-sagibbon)** 基于 Chromium集成微软开发资源
> ⚠️ **重要测试提示**务必在多个浏览器中测试你的网页Chrome 完美运行的东西,在 Safari 或 Firefox 上可能会不同。专业开发者会在所有主流浏览器中测试,以确保一致的用户体验。
### 命令行工具:开发者超级力量之门
好吧让我们对命令行有个完全坦诚的时刻我想让你听听一个真正懂它的人的心声。刚看到它那一刻——黑屏闪烁的文字——我心里真的是想“不行绝对不行这看起来像80年代黑客电影里的东西我肯定不够聪明用它”😅
但我当时希望有人告诉我的是,现在我也要告诉你:命令行一点都不可怕——它其实就像是和你的电脑直接对话。就好比点外卖的时候用带图标和菜单的漂亮 APP方便又简单和走进你最爱的本地餐厅厨师知道你喜欢啥随口说一句“给我来点惊喜”马上端上一道绝妙的菜。这是两种截然不同的体验。
命令行是开发者感觉自己像绝对巫师的地方。你输入几个看似魔法的词(其实就是命令,但感觉魔法满满),按回车,噔!你就能创建整个项目结构,安装全球厉害的工具,或者部署你的应用供数百万用户访问。尝到这种力量后,真是停不下来!
**为什么命令行会成为你最喜欢的工具:**
虽然图形界面适合很多任务,命令行却在自动化、精确和速度上占优势。许多开发工具主要通过命令行运行,学会高效使用它们能极大提升你的工作效率。
```bash
# 第一步:创建并进入项目目录
mkdir my-awesome-website
cd my-awesome-website
```
**这段代码做了什么:**
- **创建** 一个名为 “my-awesome-website” 的新目录作为项目
- **进入** 新建的目录开始工作
```bash
# 第2步使用 package.json 初始化项目
npm init -y
# 安装现代开发工具
npm install --save-dev vite prettier eslint
npm install --save-dev @eslint/js
```
**逐步讲解:**
- 用 `npm init -y` **初始化** 一个新的 Node.js 项目,使用默认配置
- **安装** Vite 作为现代构建工具,支持快速开发和生产构建
- **添加** Prettier 用于自动格式化代码ESLint 用于代码质量检查
- 使用 `--save-dev` 标记为开发时依赖
```bash
# 第3步创建项目结构和文件
mkdir src assets
echo '<!DOCTYPE html><html><head><title>My Site</title></head><body><h1>Hello World</h1></body></html>' > index.html
# 启动开发服务器
npx vite
```
**上述步骤中,我们:**
- **整理** 项目结构,创建源码和资源文件夹
- **生成** 了带有正确文档结构的基础 HTML 文件
- **启动** 了 Vite 开发服务器,实现热重载和模块替换
#### 网络开发必备命令行工具
| 工具 | 目的 | 你为什么需要它 |
|------|---------|-----------------|
| **[Git](https://git-scm.com/)** | 版本控制 | 跟踪变更,协作,备份工作 |
| **[Node.js & npm](https://nodejs.org/)** | JavaScript 运行时及包管理器 | 浏览器外运行 JS安装现代开发工具 |
| **[Vite](https://vitejs.dev/)** | 构建工具和开发服务器 | 超快速开发,支持热模块替换 |
| **[ESLint](https://eslint.org/)** | 代码质量 | 自动发现和修复 JS 问题 |
| **[Prettier](https://prettier.io/)** | 代码格式化 | 保持代码格式一致,易于阅读 |
#### 平台专属选项
**Windows**
- **[Windows Terminal](https://docs.microsoft.com/windows/terminal/?WT.mc_id=academic-77807-sagibbon)** 现代功能丰富的终端
- **[PowerShell](https://docs.microsoft.com/powershell/?WT.mc_id=academic-77807-sagibbon)** 💻 强大的脚本环境
- **[命令提示符](https://docs.microsoft.com/windows-server/administration/windows-commands/?WT.mc_id=academic-77807-sagibbon)** 💻 传统 Windows 命令行
**macOS**
- **[Terminal](https://support.apple.com/guide/terminal/)** 💻 系统自带终端应用
- **[iTerm2](https://iterm2.com/)** 功能增强的终端
**Linux**
- **[Bash](https://www.gnu.org/software/bash/)** 💻 标准 Linux shell
- **[KDE Konsole](https://docs.kde.org/trunk5/en/konsole/konsole/index.html)** 高级终端模拟器
> 💻 = 操作系统预装
> 🎯 **学习路线**:从基本命令开始,比如 `cd`(切换目录)、`ls` 或 `dir`(列出文件)、`mkdir`(创建文件夹)。练习现代工作流命令如 `npm install`、`git status`、`code .`(在 VS Code 打开当前目录)。随着熟悉,你会自然而然学到更高级的命令和自动化技巧。
### 文档:你随时可用的学习导师
好了,告诉你一个让你作为初学者更安心的小秘密:即便是最有经验的开发者,也会花大量时间看文档。这不是因为他们不会写代码,而是聪明的表现!
把文档想象成你可以24/7随时访问的、超耐心且知识渊博的老师。凌晨2点遇到难题文档就像温暖的虚拟拥抱给你正合适的答案。想学习某个大家都在讨论的新特性文档有详细逐步示例。想弄懂某个功能为什么这样设计文档乐意用让你豁然开朗的方式讲解
改变我认知的是web 开发世界变化极快没有人真的没有能把一切都记牢。我见过超过15年经验的大牛都要查基础语法你知道吗这不丢人而是聪明重点不是完美记忆而是知道在哪里快速找到可靠答案并理解如何应用。
**真正的魔法发生在这里:**
专业开发者大量时间看文档——不是因为没能力,而是技术迅速发展,持续学习必不可少。好文档不仅教你*如何*用,还解释*为什么*和*什么时候*用。
#### 重要文档资源
**[Mozilla Developer Network (MDN)](https://developer.mozilla.org/docs/Web)**
- 网页技术文档的黄金标准
- 全面指南覆盖 HTML、CSS 和 JavaScript
- 含浏览器兼容性信息
- 提供实用例子和互动演示
**[Web.dev](https://web.dev)**(谷歌出品)
- 现代网页开发最佳实践
- 性能优化指南
- 可访问性和包容性设计原则
- 来自实际项目的案例研究
**[微软开发者文档](https://docs.microsoft.com/microsoft-edge/#microsoft-edge-for-developers)**
- Edge 浏览器开发资源
- 渐进式网页应用指南
- 跨平台开发见解
**[Frontend Masters 学习路径](https://frontendmasters.com/learn/)**
- 结构化学习课程
- 行业专家视频教程
- 动手编程练习
> 📚 **学习策略**:不要试图死记文档——而是学会高效浏览。收藏常用参考,练习用搜索快速找到具体信息。
### 🔧 **工具掌握度测验:你最认同什么?**
**花点时间思考:**
- 你最想先试哪个工具?(没有错误答案!)
- 命令行还让你害怕吗?还是更好奇了?
- 能想象用浏览器 DevTools 探秘你喜欢的网站幕后吗?
```mermaid
pie title "开发者使用工具的时间分配"
"代码编辑器" : 40
"浏览器测试" : 25
"命令行" : 15
"阅读文档" : 15
"调试" : 5
```
> **有趣见解**大多数开发者大约40%的时间花在代码编辑器,其余时间用于测试、学习和解决问题。编程不仅是写代码——它是打造体验!
**思考题**:有件有趣的事想问你——你觉得构建网站的工具(开发)和设计外观的工具(设计)有什么不同?就像建筑师设计漂亮房子,和承包商实际建造房子,两者都重要,但工具箱不同!这样的思考能帮你更全面理解网站是如何诞生的。
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 探索现代代码编辑器或 IDE 的功能,展示它如何提升你作为网络开发者的工作流程。
**提示:** 选择一个代码编辑器或 IDE如 Visual Studio Code、WebStorm 或云端 IDE。列举三个功能或扩展说明它们如何帮助你更高效地编写、调试或维护代码并简要解释它们带来的好处。
---
## 🚀 挑战
比较一些编程语言。JavaScript与Java有哪些独特特性COBOL与Go又如何
**侦探,准备好第一个案子了吗?**
现在你已经有了很棒的基础,我有一个冒险任务,将帮你领略编程世界的多样与魅力。听好了,这不涉及写代码,所以别紧张!把自己当作编程语言侦探,接下你的第一个激动人心的案子!
**你的任务,如果你愿意接受:**
1. **成为语言探险家**:挑选三种来自截然不同领域的编程语言 —— 比如一种建网站,一种写移动应用,还有一种给科学家用来数据处理。找出它们都完成同样简单任务的示例。保证你会惊叹同样的事一个用法大不相同!
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/)
2. **揭示它们的起源故事**:每种语言的特别之处在哪里?有趣的是—每种编程语言诞生时,发明者都想:“得有更好方式来解决这个具体问题。”你能找到这些问题吗?某些故事特别迷人!
3. **认识社区**:看看每种语言社区的开放和热情程度。有些拥有数百万开发者分享经验和互助,另一些则小巧紧密且极具支持力。你会喜欢了解这些社区的独特个性!
4. **跟随直觉**:哪种语言现在你感觉最容易上手?别纠结做“完美”选择——听从你的直觉!这里没有对错,你以后还能继续探索其他语言。
**额外侦探任务**:试着查查哪些主流网站或应用是用这些语言构建的。保证你会对 Instagram、Netflix 或那个让你停不下来的手机游戏背后的技术大吃一惊!
> 💡 **记住**:今天你不是要成为任何语言的专家。你只是在熟悉这个“邻居”,为将来决定在哪里扎根做准备。慢慢来,玩得开心,保持好奇心!
## 一起庆祝你的发现吧!
哇哦,今天你吸收了这么多令人惊叹的信息!我真心期待看到你记住了多少这段精彩旅程。别忘了——这不是考核,不用追求完美。更像是为你即将探入的精彩世界学到的所有酷知识举行庆典!
[参加课后测验](https://ff-quizzes.netlify.app/web/)
## 复习与自学
研究一下程序员可用的不同语言。尝试用一种语言写一行代码,然后用另外两种语言重写它。您学到了什么?
**慢慢来,尽情探索和享受乐趣吧!**
你今天已经学了很多内容,这值得骄傲!现在是有趣的部分了 —— 探索那些激发你好奇心的话题。记住,这不是作业 —— 这是一场冒险!
**深入挖掘你感兴趣的内容:**
**动手实践编程语言:**
- 访问你感兴趣的2-3个编程语言的官方网站。每种语言都有其独特的个性和故事
- 试试一些在线代码游乐场,比如 [CodePen](https://codepen.io/)、[JSFiddle](https://jsfiddle.net/) 或 [Replit](https://replit.com/)。不要害怕尝试 —— 你不会弄坏任何东西!
- 了解你喜欢的语言是如何诞生的。说真的,有些起源故事很有趣,会帮助你理解这些语言为何如此设计。
## 作业
**熟悉你的新工具:**
- 如果还没下载 Visual Studio Code赶快下载 —— 它是免费的,你一定会喜欢!
- 花几分钟浏览一下扩展市场。它就像你代码编辑器的应用商店!
- 打开浏览器的开发者工具,随便点击看看。别担心全懂 —— 先熟悉一下界面和功能就好。
**加入社区:**
- 关注一些开发者社区,比如 [Dev.to](https://dev.to/)、[Stack Overflow](https://stackoverflow.com/) 或 [GitHub](https://github.com/)。编程社区对新手非常友好!
- 在 YouTube 上看一些适合初学者的编程视频。有很多很棒的创作者曾经也和你一样刚刚起步。
- 考虑参加本地聚会或者在线社区。相信我,开发者们都很乐于帮助新手!
> 🎯 **听着,我希望你记住**:你不需要一夜之间成为编程高手!现在,你只是开始认识这个你即将加入的精彩新世界。慢慢来,享受这段旅程,记住 —— 每一个你敬佩的开发者,曾经也正坐在你现在的位置,既兴奋又可能有点不知所措。这完全正常,这意味着你正在正确的道路上!
## 任务
[阅读文档](assignment.md)
> 注意:在为您的作业选择工具时,请勿选择上面已列出的编辑器、浏览器或命令行工具。
> 💡 **任务小提示**:我很想看到你去探索一些我们还没讲过的工具!跳过已经讨论过的编辑器、浏览器和命令行工具 —— 外面还有一个庞大而精彩的开发工具宇宙等待你去发现。找那些活跃维护、有生机且乐于助人的社区支持的工具(它们通常有最好的教程和最热心的人们,当你卡住需要帮助时能手把手支持你)。
---
## 🚀 你的编程之旅时间表
### ⚡ **接下来5分钟内你可以做的事**
- [ ] 收藏2-3个你感兴趣的编程语言官网
- [ ] 如果没下载,安装 Visual Studio Code
- [ ] 打开浏览器开发者工具F12随意点击浏览任意网站
- [ ] 加入一个编程社区Dev.to、Reddit 的 r/webdev或 Stack Overflow
### ⏰ **这1小时内你可以完成的任务**
- [ ] 完成课后测验并反思答案
- [ ] 配置 VS Code 并安装 GitHub Copilot 扩展
- [ ] 在线用两种不同编程语言写一个“Hello World”示例
- [ ] 观看一段“开发者的一天”视频
- [ ] 开始你的编程语言侦探工作(挑战内容)
### 📅 **你的一周冒险计划**
- [ ] 完成作业探索3个新的开发工具
- [ ] 关注5个开发者或编程账号社交媒体
- [ ] 在 CodePen 或 Replit 上尝试做一个小作品哪怕只是“Hello, [你的名字]!”)
- [ ] 阅读一篇关于某人编程历程的开发者博客
- [ ] 加入一次线上聚会或观看编程讲座
- [ ] 开始选定的语言的在线教程学习
### 🗓️ **你一个月的转变计划**
- [ ] 做出你的第一个小项目(就算简单网页也行!)
- [ ] 参与开源项目贡献(从文档修正开始)
- [ ] 指导一个刚开始编程的人
- [ ] 创建你的开发者个人作品网站
- [ ] 结识本地开发者社区或学习小组
- [ ] 开始规划下一个学习目标
### 🎯 **最终反思签到**
**继续之前,花点时间庆祝一下:**
- 今天编程中,哪些事情让你感到兴奋?
- 你想先探索哪个工具或概念?
- 对开始这段编程旅程,你的感觉如何?
- 有什么问题是你现在想问开发者的吗?
```mermaid
journey
title 你的自信心建立之旅
section 今天
好奇: 3: You
不知所措: 4: You
兴奋: 5: You
section 本周
探索: 4: You
学习: 5: You
连接: 4: You
section 下个月
建立: 5: You
自信: 5: You
帮助他人: 5: You
```
> 🌟 **记住**:每个专家都曾是初学者。每个高级开发者都曾和你一样——既兴奋又有点不知所措,当然也充满了无限好奇。你身处伟大的同行中,这段旅程将会非常精彩。欢迎来到奇妙的编程世界! 🎉
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。
本文件由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译完成。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应视为权威来源。对于重要信息,建议采用专业人工翻译。因使用本翻译内容而引起的任何误解或错误理解,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,31 +1,78 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "9e2f84e351a6fcb44bfc4066d98525f0",
"translation_date": "2025-10-03T08:49:41+00:00",
"original_hash": "17b8ec8e85d99e27dcb3f73842e583be",
"translation_date": "2026-01-06T12:01:03+00:00",
"source_file": "1-getting-started-lessons/1-intro-to-programming-languages/assignment.md",
"language_code": "zh"
}
-->
## 使用说明
# Assignment: 探索现代网络开发工具
网页开发者可能需要许多工具,这些工具列在 [MDN 客户端工具文档](https://developer.mozilla.org/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview) 中。选择 **三个工具**,这些工具**未在本课程中涉及**(排除 [列出具体工具或参考课程内容]),解释**为什么**网页开发者会使用每个工具,并找到适合每个类别的工具。对于每个工具,分享其官方文档链接(不是 MDN 上的示例)。
## Instructions
**格式:**
- 工具名称
- 为什么网页开发者会使用它2-3 句)
- 文档链接
网络开发生态系统包含数百种专门的工具,帮助开发者高效地构建、测试和维护应用程序。你的任务是研究并了解补充本课所涵盖内容的工具。
**长度:**
- 每个解释应为 2-3 句。
**你的任务:**选择**三个工具**,这些工具**未在本课中涵盖**(避免选择已列出的代码编辑器、浏览器或命令行工具)。重点关注解决现代网站开发工作流中特定问题的工具。
**针对每个工具,请提供:**
1. **工具名称和类别**例如“Figma - 设计工具”或“Jest - 测试框架”)
2. **用途和优势** - 用2-3句话解释为什么网络开发者会使用该工具以及它解决了哪些问题
3. **官方文档链接** - 提供该工具的官方文档或网站链接(而非仅教程网站)
4. **实际应用场景** - 简要说明该工具如何融入专业开发工作流程
## 建议的工具类别
可以考虑探索以下类别的工具:
| 类别 | 示例 | 功能描述 |
|----------|----------|--------------|
| **构建工具** | Vite, Webpack, Parcel, esbuild | 打包和优化生产代码,提供快速开发服务器 |
| **测试框架** | Vitest, Jest, Cypress, Playwright | 确保代码正确运行,及早捕获缺陷 |
| **设计工具** | Figma, Adobe XD, Penpot | 协作创建原型、模型和设计系统 |
| **部署平台** | Netlify, Vercel, Cloudflare Pages | 自动化CI/CD托管和分发网站 |
| **版本控制** | GitHub, GitLab, Bitbucket | 管理代码更改、协作与项目流程 |
| **CSS框架** | Tailwind CSS, Bootstrap, Bulma | 利用预构建组件库加速样式开发 |
| **包管理器** | npm, pnpm, Yarn | 安装和管理代码库依赖 |
| **无障碍工具** | axe-core, Lighthouse, Pa11y | 测试包容性设计和WCAG合规性 |
| **API开发** | Postman, Insomnia, Thunder Client | 开发过程中测试和编写API文档 |
## 格式要求
**每个工具:**
```
### [Tool Name] - [Category]
**Purpose:** [2-3 sentences explaining why developers use this tool]
**Documentation:** [Official website/documentation link]
**Workflow Integration:** [1 sentence about how it fits into development process]
```
## 质量指导原则
- **选择当前工具**选择2025年仍在积极维护且广泛使用的工具
- **聚焦价值**:解释具体优势,而非仅描述功能
- **专业背景**:考虑团队使用的工具,而非仅限个人爱好者
- **多样化选择**:从不同类别中挑选,展示生态多样性
- **现代相关性**:优先符合当前网络开发趋势和最佳实践的工具
## 评分标准
优秀 | 合格 | 需改进
--- | --- | -- |
解释了为什么网页开发者会使用工具 | 解释了如何使用,但未说明为什么开发者会使用工具 | 未提及开发者如何或为什么会使用工具 |
| 优秀 | 良好 | 需改进 |
|-----------|------|-------------------|
| **清晰解释为何开发者使用该工具及解决的问题** | **解释了工具作用但缺少价值上下文** | **仅列出工具名称,未解释用途或优势** |
| **为所有工具提供官方文档链接** | **大多为官方链接,含少量教程网站** | **主要依赖教程网站,缺少官方文档** |
| **选择当前被广泛专业使用、类别多样的工具** | **选择工具不错但类别较单一** | **选用过时工具或仅限某一类别** |
| **展示了解工具在开发流程中的应用** | **部分体现专业应用背景** | **仅聚焦工具功能,缺工作流上下文** |
> 💡 **研究建议**关注招聘网站中提及的网络开发工具查看热门开发者调查或分析GitHub上成功开源项目的依赖项
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原始语言版本的文件应视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,344 +1,776 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "ea65b75e488aa33a3cc5cb1c6c3f047a",
"translation_date": "2025-10-03T13:41:17+00:00",
"original_hash": "5c383cc2cc23bb164b06417d1c107a44",
"translation_date": "2026-01-06T12:01:16+00:00",
"source_file": "1-getting-started-lessons/2-github-basics/README.md",
"language_code": "zh"
}
-->
# GitHub简介
本课程介绍了GitHub的基础知识这是一个用于托管和管理代码变更的平台。
![GitHub简介](../../../../translated_images/webdev101-github.8846d7971abef6f947909b4f9d343e2a23778aa716ca6b9d71df7174ee5009ac.zh.png)
> [Tomomi Imura](https://twitter.com/girlie_mac) 的手绘笔记
嗨,未来的开发者!👋 准备好加入全球数百万程序员的行列了吗我真心兴奋地向你介绍GitHub——把它想象成程序员的社交媒体平台不过我们分享的不是午餐照片而是代码共同构建令人难以置信的东西
让我大开眼界的是你手机上的每个应用、你访问的每个网站以及你将学会使用的大多数工具都是由开发团队在类似GitHub的平台上协作完成的。你喜欢的那个音乐应用就有像你一样的人参与其中。那个让你爱不释手的游戏没错可能就是通过GitHub协作完成的。现在你将学会如何成为这个惊人社区的一员
我知道一开始可能觉得信息量很大——说实话我第一次看到GitHub页面时也懵了“这到底是啥意思”但事实是每一个开发者都从你现在的位置开始。课程结束时你将拥有自己的GitHub仓库把它想象成云端的个人项目展示你会知道如何保存工作与他人分享甚至为数百万用户使用的项目做贡献。
我们将一步步一起出发。没有急躁,没有压力——只有你我和一些即将成为你新朋友的酷炫工具!
![Intro to GitHub](../../../../translated_images/webdev101-github.8846d7971abef6f9.zh.png)
> 速记图由 [Tomomi Imura](https://twitter.com/girlie_mac) 制作
```mermaid
journey
title 你今天的 GitHub 冒险
section 安装设置
安装 Git: 4: You
创建账户: 5: You
第一个仓库: 5: You
section 精通 Git
本地更改: 4: You
提交与推送: 5: You
分支管理: 4: You
section 协作
派生项目: 4: You
拉取请求: 5: You
开源项目: 5: You
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app)
## 简介
## 介绍
在开始真正令人兴奋的内容之前先让你的电脑准备好迎接GitHub的魔法吧把这看作是在创作杰作前整理好艺术用品——准备好合适的工具让整个过程更流畅、更有趣。
在本课程中,我们将学习:
我会一步步带你完成每个设置步骤,保证过程没你想象的那么吓人。如果一开始没有立刻理解也没关系!我记得当初搭建第一个开发环境时,感觉自己像是在看古埃及象形文字。每个开发者都经历过你现在的阶段,怀疑自己是不是做对了。剧透一下:既然你来了这里学习,说明你已经在正确的路上了!🌟
- 如何跟踪你在本地机器上的工作
- 如何与他人协作完成项目
这节课,我们会涵盖:
- 追踪你在电脑上的工作
- 与他人协作项目
- 如何为开源软件做贡献
### 前置条件
### 先决条件
让我们先让电脑准备好迎接GitHub的魔法别担心——这只是一次性的设置完成后整个编码之旅都会顺利。
在开始之前你需要检查是否已安装Git。在终端中输入
先从基础开始我们先检查电脑上是否已经安装了Git。Git基本上就像一个超级智能的助理能记录你代码的每一次改动——比你两秒按一次Ctrl+S强多了我们都有过
在终端输入这个魔法命令看一下Git是否安装
`git --version`
如果未安装Git请[下载Git](https://git-scm.com/downloads)。然后在终端中设置你的本地Git配置文件
* `git config --global user.name "your-name"`
* `git config --global user.email "your-email"`
如果还没安装Git别着急去[下载Git](https://git-scm.com/downloads)把它装上。安装完我们需要正式介绍Git给你认识
> 💡 **首次设置**这些命令告诉Git你的身份。每次提交都会附带这些信息所以请选择你愿意公开分享的名字和邮箱。
```bash
git config --global user.name "your-name"
git config --global user.email "your-email"
```
要检查Git是否已配置可以输入
`git config --list`
你能通过输入以下命令检查Git是否已经配置
```bash
git config --list
```
你还需要一个GitHub账户一个代码编辑器如Visual Studio Code并打开你的终端或命令提示符
你还需要一个GitHub账户一个代码编辑器如Visual Studio Code并打开你的终端命令提示符也可以)。
访问 [github.com](https://github.com/) 创建账户(如果尚未创建),或登录并完善你的个人资料。
访问 [github.com](https://github.com/) ,如果还没有账户就创建一个,或者登录并完善你的个人资料。
✅ GitHub并不是唯一的代码仓库平台还有其他平台但GitHub是最知名的。
💡 **现代建议**:考虑设置[SSH密钥](https://docs.github.com/en/authentication/connecting-to-github-with-ssh)或使用[GitHub CLI](https://cli.github.com/)实现无需密码的更便捷认证。
✅ GitHub不是唯一的代码仓库但它是最知名的。
### 准备工作
你需要一个本地机器笔记本电脑或PC上的代码项目文件夹以及一个GitHub上的公共仓库这将作为如何为他人项目做贡献的示例。
你需要在本地笔记本或PC有一个包含代码项目的文件夹并且在GitHub有一个公开仓库这将作为学习如何为他人项目做贡献的范例。
---
### 保护你的代码安全
## 代码管理
聊聊安全——别担心,我们不会让你听得头疼!把这些安全措施想象成锁车或锁门,是简单易养成的习惯,能保护你的辛勤成果。
假设你在本地有一个代码项目文件夹并希望使用Git版本控制系统开始跟踪你的进度。有人将使用Git比作写给未来自己的情书。阅读几天、几周或几个月后的提交信息你可以回忆起为什么做出某个决定或者“回滚”某个更改——前提是你写了好的“提交信息”
我们将从一开始就用现代、安全的方式使用GitHub。这样你将培养出良好的习惯这些习惯在你整个编码生涯都会发挥作用
### 任务:创建仓库并提交代码
使用GitHub时遵守安全最佳实践很重要
> 查看视频
| 安全领域 | 最佳实践 | 为什么重要 |
|---------------|---------------|----------------|
| **身份认证** | 使用SSH密钥或个人访问令牌 | 密码不够安全,正被逐渐淘汰 |
| **两步验证** | 为GitHub账号启用2FA | 增加账户额外保护层 |
| **仓库安全** | 永远不要提交敏感信息 | API密钥和密码绝不能出现在公共仓库 |
| **依赖管理** | 启用Dependabot自动更新 | 保持依赖安全和最新 |
> ⚠️ **重要安全提醒**绝不可提交API密钥、密码和其他敏感信息到任何仓库。请使用环境变量和`.gitignore`文件保护敏感数据。
**现代认证配置示例:**
```bash
# 生成 SSH 密钥(现代 ed25519 算法)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 设置 Git 使用 SSH
git remote set-url origin git@github.com:username/repository.git
```
> 💡 **专业提示**SSH密钥无需重复输入密码比传统认证方法更安全。
---
## 像专家一样管理你的代码
好了,真正令人兴奋的部分来了!🎉 我们将学习如何像专业人士那样追踪和管理代码,这真是我最喜欢教的内容之一,因为它改变游戏规则。
想象一下你正在写一本精彩的故事想保留每一稿、每个精彩修改和每一个“等一下这简直是天才”的瞬间。Git就是为你的代码做了这件事它就像有一本了不起的时光笔记记录一切——每一次击键、每一次改动、每一次“糟糕坏掉了”的时刻瞬间就能撤销。
说实话一开始可能有点儿不知所措。我刚学Git时也想“我为什么不能像以前那样只保存文件”但相信我一旦你适应了Git肯定会的你会有那种灵光一闪的感觉“没有Git我怎么写代码的”就好像你一直只能走路突然发现自己能飞了一样
假设你本地有个文件夹里面有代码项目你想用git版本控制系统来追踪进度。有些人把使用git比作写给未来自己的情书。数天、数周甚至数月后再看提交信息你能回忆起当时为何做出某个决定或者“回滚”某个改动——前提是你写了好的“提交消息”。
```mermaid
flowchart TD
A[📁 你的项目文件] --> B{这是一个 Git 仓库吗?}
B -->|否| C[git init]
B -->|是| D[进行更改]
C --> D
D --> E[git add .]
E --> F["git commit -m 'message'"]
F --> G[git push]
G --> H[🌟 GitHub 上的代码!]
H --> I{想要协作吗?}
I -->|是| J[Fork & Clone]
I -->|否| D
J --> K[创建分支]
K --> L[进行更改]
L --> M[Pull Request]
M --> N[🎉 贡献中!]
style A fill:#fff59d
style H fill:#c8e6c9
style N fill:#ff4081,color:#fff
```
### 任务:创建你的第一个仓库!
> 🎯 **你的任务(我为你感到超级激动!)**我们将一起创建你的第一个GitHub仓库完成后你将拥有在网络上的一个小角落存放你的代码并且你将完成第一次“提交”开发者术语意味着用超智能的方式保存工作
>
> 这真是特别的时刻——你即将正式加入全球开发者社区!我还记得创建第一个仓库时的激动,“哇,我真的做到啦!”
让我们一步步一起踏上这段旅程。每一步不要慌,慢慢来——没有谁在着急,保证每步都合情合理。记住,每个你敬佩的编码大神,都曾与你同坐在这里,准备创建他们的第一个仓库。多酷啊!
> 观看视频
>
> [![Git和GitHub基础视频](https://img.youtube.com/vi/9R31OUPpxU4/0.jpg)](https://www.youtube.com/watch?v=9R31OUPpxU4)
1. **在GitHub上创建仓库**。在GitHub.com的仓库标签中或在右上角导航栏中找到**新建仓库**按钮。
**一起动手做:**
1. **在GitHub上创建仓库**。登陆GitHub.com找到那个醒目的绿色 **New** 按钮(或者右上角的 **+** 号)。点击,选择 **New repository**
1. 为你的仓库(文件夹)命名
1. 选择**创建仓库**。
操作步骤:
1. 给你的仓库起个名字——起一个对你有意义的名字!
1. 可以添加描述(帮助别人了解你的项目)
1. 选定公开(所有人可见)或私有(仅你可见)
1. 建议勾选添加README文件——它是项目的首页介绍
1. 点击 **Create repository**,庆祝一下——你刚刚创建了第一个仓库!🎉
1. **导航到你的工作文件夹**。在终端中,切换到你希望开始跟踪的文件夹(也称为目录)。输入:
2. **进入你的项目文件夹**。现在打开终端(别怕,其实没那么吓人!)。告诉电脑你的项目文件在哪儿,输入命令
```bash
cd [name of your folder]
```
1. **初始化Git仓库**。在你的项目中输入:
**这里做了什么:**
- 我们实质上是在告诉电脑“带我到项目文件夹”
- 就像在桌面打开特定文件夹,只不过用文本命令做这件事
- 把`[name of your folder]`替换成你项目文件夹的真实名称
3. **把你的文件夹变成Git仓库**。神奇时刻来了!输入:
```bash
git init
```
1. **检查状态**。要检查仓库的状态,输入:
**发生了什么(很酷!):**
- Git在你的项目里创建了一个隐藏的`.git`文件夹——你看不到它,但它就在那!
- 你的普通文件夹变成了一个能追踪每一次改动的“仓库”
- 就好像给文件夹赋予了超能力,能记住所有事情
4. **检查仓库当前状态**。看看Git此刻对你的项目有什么看法
```bash
git status
```
输出可能如下所示:
**理解Git告诉你的内容**
你可能会看到类似这样的信息:
```output
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(use "git restore <file>..." to discard changes in working directory)
modified: file.txt
modified: file2.txt
```
通常,`git status`命令会告诉你哪些文件已准备好被保存到仓库,或者哪些文件有更改需要持久化。
**别慌!它的意思是:**
- 红色的文件是有改动但还没准备好保存的
- 绿色的文件(如果看到)是已准备好保存的
- Git会提示你下一步该做什么很贴心
1. **添加所有文件进行跟踪**
这也称为暂存文件/将文件添加到暂存区。
> 💡 **小贴士**`git status`命令是你的好帮手不懂时就问它就像让Git告诉你“现在状况如何”。
5. **准备文件保存(也叫“暂存”)**
```bash
git add .
```
`git add`加上`.`参数表示将所有文件和更改添加到跟踪中。
**刚刚做了什么:**
- 告诉Git“把所有文件都加到下一次保存里”
- `.`表示“这个文件夹下的所有东西”
- 现在你的文件已经“暂存”好,可以进行下一步
1. **添加选定文件进行跟踪**
**想更挑剔地选择?** 你可以只添加特定文件:
```bash
git add [file or folder name]
```
当你不想一次提交所有文件时,这可以帮助我们仅添加选定文件到暂存区。
**为什么这样做?**
- 有时候你想把相关改动分批提交
- 有利于把工作整理成有逻辑的小块
- 让日后更容易理解改动内容和时间
1. **取消暂存所有文件**
**想撤销选择?** 可以这样取消暂存:
```bash
# 取消暂存所有内容
git reset
# 只取消暂存一个文件
git reset [file name]
```
此命令帮助我们一次性取消暂存所有文件。
不用担心——这不会删掉你的内容,只是把文件从“准备提交”的列表里移除
1. **取消暂存特定文件**
```bash
git reset [file or folder name]
```
此命令帮助我们仅取消暂存一个特定文件,不将其包含在下一次提交中。
1. **持久化你的工作**。此时你已将文件添加到所谓的暂存区这是Git跟踪文件的地方。要使更改永久化你需要提交文件。使用`git commit`命令创建一个提交。提交代表仓库历史中的一个保存点。输入以下命令创建提交:
6. **永久保存工作提交你的第一次commit**
```bash
git commit -m "first commit"
```
这会提交所有文件,并添加信息“首次提交”。对于未来的提交信息,你需要更具描述性,以传达你进行了哪种类型的更改。
**🎉 恭喜你你完成了第一次commit**
**发生了什么:**
- Git对所有暂存的文件做了“快照”记录当前状态
- 你的提交信息“first commit”说明了保存点的内容
- Git给这个快照一个唯一ID你随时能找到它
- 你正式开始管理项目历史了!
> 💡 **今后的提交信息**写得更有描述性别写“updated stuff”试试“给首页添加联系表单”或“修复导航菜单bug”。未来的你会感谢自己的
1. **将本地Git仓库连接到GitHub**。本地Git仓库在你的机器上很好但最终你会希望将文件备份到某个地方并邀请其他人与你一起协作。GitHub是一个很好的选择。记住我们已经在GitHub上创建了一个仓库所以我们只需要将本地Git仓库与GitHub连接起来。`git remote add`命令可以实现这一点。输入以下命令:
7. **连接本地项目到GitHub**。现在你的项目只存在电脑里连接到GitHub仓库才能分享给全世界
> 注意在输入命令之前访问你的GitHub仓库页面以找到仓库URL。你将在下面的命令中使用它。将```https://github.com/username/repository_name.git```替换为你的GitHub URL。
先打开你的GitHub仓库页面复制URL。回到这里输入
```bash
git remote add origin https://github.com/username/repository_name.git
```
把这个URL换成你的仓库实际地址
这会创建一个名为“origin”的远程连接指向你之前创建的GitHub仓库。
**刚刚做了什么:**
- 我们在你的本地项目和你的 GitHub 仓库之间建立了连接
- “origin” 只是你的 GitHub 仓库的一个昵称——就像给你的手机添加联系人一样
- 现在你的本地 Git 知道在你准备好分享代码时该把代码发送到哪里
1. **将本地文件发送到GitHub**。到目前为止你已经在本地仓库和GitHub仓库之间创建了连接。使用以下命令`git push`将这些文件发送到GitHub
💡 **更简单的方法**:如果你安装了 GitHub CLI可以用一条命令完成这一步
```bash
gh repo create my-repo --public --push --source=.
```
> 注意,你的分支名称可能默认不是```main```。
8. **将代码上传到 GitHub**(激动人心的时刻!):
```bash
git push -u origin main
```
这会将你的“main”分支中的提交发送到GitHub。在命令中包含`-u`设置`upstream`分支建立本地分支与远程分支之间的链接这样你以后可以简单地使用git push或git pull而无需指定分支名称。Git会自动使用上游分支你以后无需在命令中显式指定分支名称。
**🚀 就是这一步!你正在把代码上传到 GitHub**
**发生了什么:**
- 你的提交正从电脑传送到 GitHub
- `-u` 参数建立了永久连接,方便以后推送
- “main” 是你的主分支名称(类似主文件夹)
- 之后你只需输入 `git push` 来上传修改!
💡 **小提示**:如果分支叫其他名字(如 “master”用那个名字替代。可用 `git branch --show-current` 查看当前名字。
2. **添加更多更改**。如果你想继续进行更改并将其推送到GitHub你只需使用以下三个命令
9. **你的新日常编码节奏**(上瘾的时候到了!):
从现在开始,只要你修改项目,都遵循简单的三步流程:
```bash
git add .
git commit -m "type your commit message here"
git commit -m "describe what you changed"
git push
```
> 提示,你可能还想采用`.gitignore`文件以防止你不想跟踪的文件出现在GitHub上——比如你存储在同一文件夹中的笔记文件但它不适合放在公共仓库中。你可以在[.gitignore模板](https://github.com/github/gitignore)中找到`.gitignore`文件的模板。
**这将成为你的编码心跳:**
- 编写精彩代码 ✨
- 用 `git add` 记录修改“Git关注这些改动
- 用 `git commit` 并写清楚信息保存(未来的你会感谢现在的你!)
- 用 `git push` 分享给世界 🚀
- 循环往复——真的,这会变得自然而然!
我喜欢这个流程,就像电子游戏里多保存点。喜欢刚写的修改?提交它!想试点冒险的改动?没问题——你总能回到最后一次提交!
> 💡 **提示**:建议使用 `.gitignore` 文件避免不想追踪的文件出现在 GitHub 上——比如你存放的笔记文件,它不适合公开。你可以去 [.gitignore 模板](https://github.com/github/gitignore) 找模板,或用 [gitignore.io](https://www.toptal.com/developers/gitignore) 创建。
### 🧠 **第一次仓库提交:感觉如何?**
**花点时间庆祝和回顾:**
- 第一次在 GitHub 看到自己的代码感觉怎么样?
- 哪一步最让你困惑?哪一步出乎意料地简单?
- 你能用自己的话解释 `git add`、`git commit` 和 `git push` 的区别吗?
```mermaid
stateDiagram-v2
[*] --> LocalFiles: 创建项目
LocalFiles --> Staged: git add .
Staged --> Committed: git commit
Committed --> GitHub: git push
GitHub --> [*]: 成功!🎉
note right of Staged
文件准备保存
end note
note right of Committed
快照已创建
end note
```
> **记住**:即使是经验丰富的开发者也会忘记具体命令。让流程变成本能需要练习——你做得很棒!
#### 现代 Git 工作流程
考虑采用这些现代实践:
- **Conventional Commits规范提交**:用标准格式的提交信息如 `feat:`、`fix:`、`docs:` 等。了解更多请访问 [conventionalcommits.org](https://www.conventionalcommits.org/)
- **原子提交**:每次提交代表一个逻辑上的独立改动
- **频繁提交**:多且带描述的提交代替少且庞大的提交
#### 提交信息
一个好的Git提交主题行可以完成以下句子
如果应用此提交,它将<你的主题行>
一个好的 Git 提交主题行能完成下面句子:
如果应用该提交,它将 <你的主题>
主题用祈使句现在时态“change”不是 “changed” 或 “changes”。正文可选也用祈使句现在时。正文应说明改动的动机并与之前的行为对比。你是在解释“为什么”不是“怎么做”。
对于主题行,请使用命令式现在时:“更改”而不是“已更改”或“正在更改”。
在正文中(可选),也使用命令式现在时。正文应包括更改的动机,并与之前的行为进行对比。你是在解释“为什么”,而不是“如何”。
✅ 花几分钟逛逛 GitHub能找到一个特别棒的提交信息吗能找到特别简洁的吗你觉得提交信息中最重要有用的信息是什么
✅ 花几分钟浏览GitHub。你能找到一个非常好的提交信息吗你能找到一个非常简短的提交信息吗你认为提交信息中最重要和最有用的信息是什么
## 与他人合作(有趣部分!)
### 任务:协作
抓紧你的帽子,因为这里是 GitHub 真正神奇的时候!🪄 你已经学会管理自己的代码,现在我们进入我最喜欢的部分——与来自世界各地的优秀人才协作。
将内容放到GitHub上的主要原因是为了与其他开发者协作。
想象一下:你第二天醒来发现东京有人改进了你的代码;柏林有人修复了你一直卡住的 Bug下午时圣保罗的开发者添加了你从没想过的功能。这不是科幻——这只是 GitHub 世界里的普通一天!
## 与他人协作完成项目
让我激动的是,你将学到的协作技能正是谷歌、微软和你喜欢的创业公司每天都在用的工作流程。这不仅仅是学一个酷工具——你学会了让整个软件世界协同工作的秘密语言。
说真的,一旦你体验过别人合并你的第一次拉取请求的激动,你会明白开发者为何对开源项目如此热情。这就像参与了全世界最大最有创意的团队项目!
> 查看视频
>
> [![Git和GitHub基础视频](https://img.youtube.com/vi/bFCM-PC3cu8/0.jpg)](https://www.youtube.com/watch?v=bFCM-PC3cu8)
> [![Git and GitHub basics video](https://img.youtube.com/vi/bFCM-PC3cu8/0.jpg)](https://www.youtube.com/watch?v=bFCM-PC3cu8)
把东西放到 GitHub 的主要原因就是让与其他开发者的协作成为可能。
在你的仓库中,导航到`Insights > Community`,查看你的项目与推荐的社区标准的比较情况。
```mermaid
flowchart LR
A[🔍 寻找项目] --> B[🍴 分叉代码库]
B --> C[📥 克隆到本地]
C --> D[🌿 创建分支]
D --> E[✏️ 进行修改]
E --> F[💾 提交更改]
F --> G[📤 推送分支]
G --> H[🔄 创建合并请求]
H --> I{维护者审查}
I -->|✅ 批准| J[🎉 合并!]
I -->|❓ 请求更改| K[📝 进行更新]
K --> F
J --> L[🧹 清理分支]
style A fill:#e3f2fd
style J fill:#e8f5e8
style L fill:#fff3e0
```
在你的仓库里,导航至 `Insights > Community`,查看你的项目如何对照推荐的社区标准进行比较。
以下是一些可以改善你的GitHub仓库的事项
- **描述**。你是否为你的项目添加了描述?
- **README**。你是否添加了READMEGitHub提供了编写[README](https://docs.github.com/articles/about-readmes/?WT.mc_id=academic-77807-sagibbon)的指导。
- **贡献指南**。你的项目是否有[贡献指南](https://docs.github.com/articles/setting-guidelines-for-repository-contributors/?WT.mc_id=academic-77807-sagibbon)
- **行为准则**。是否有[行为准则](https://docs.github.com/articles/adding-a-code-of-conduct-to-your-project/)
- **许可证**。或许最重要的是,是否有[许可证](https://docs.github.com/articles/adding-a-license-to-a-repository/)
想让你的仓库看起来专业且有吸引力?去仓库点击 `Insights > Community`。这个酷功能会显示你的项目与 GitHub 社区认可的“好仓库实践”相比的情况。
所有这些资源都将有助于新团队成员的入职。这些通常是新贡献者在查看你的代码之前会关注的内容,以了解你的项目是否值得他们投入时间。
> 🎯 **让你的项目闪耀**:结构良好的仓库和完善的文档就像干净欢迎的店铺。它告诉大家你重视你的工作,也会让别人想来贡献!
✅ README文件虽然需要时间准备但经常被忙碌的维护者忽视。你能找到一个特别详细的README示例吗注意有一些[工具可以帮助创建好的README](https://www.makeareadme.com/),你可能会想尝试一下。
**一个棒仓库的要点:**
| 应该添加的内容 | 重要性 | 对你的作用 |
|-------------|-------------------|---------------------|
| **描述** | 第一印象很重要! | 让人立刻知道项目做什么 |
| **README** | 项目的主页 | 就像对新访客的友好导览 |
| **贡献指南** | 表明欢迎帮助 | 让人知道如何参与贡献 |
| **行为准则** | 营造友好氛围 | 确保每个人都感到受欢迎 |
| **许可证** | 法律明确 | 让别人知道怎么使用你的代码 |
| **安全政策** | 表明你负责任 | 展示专业规范 |
> 💡 **小窍门**GitHub 提供了所有这些文件的模板。创建新仓库时,可以勾选自动生成这些文件。
**值得探索的现代 GitHub 功能:**
🤖 **自动化 & CI/CD**
- **GitHub Actions**:自动化测试和部署
- **Dependabot**:依赖自动更新
💬 **社区 & 项目管理:**
- **GitHub Discussions**:议题以外的社区对话
- **GitHub Projects**:看板式项目管理
- **分支保护规则**:维护代码质量标准
所有这些资源都能帮助新成员快速入职。新贡献者通常先看这些东西,再决定项目是否值得投入时间。
✅ README 虽然准备需要时间,但常被繁忙的维护者忽视。你能找到一个特别详细的 README 作为例子吗?提示:有些[工具能帮你创建优秀的 README](https://www.makeareadme.com/),可以试试。
### 任务:合并代码
贡献文档帮助人们为项目做贡献。它解释了你希望获得哪种类型的贡献以及流程如何运作。贡献者需要完成一系列步骤才能为你的GitHub仓库做贡献
贡献文档帮助别人参与项目。它说明你期待的贡献类型和流程。贡献者需要经过一系列步骤,才能在 GitHub 上为你的仓库做贡献:
1. **Fork你的仓库**。你可能希望人们“fork”你的项目。Fork意味着在他们的GitHub个人资料中创建你的仓库的副本。
1. **克隆**。然后他们会将项目克隆到本地机器。
1. **创建分支**。你会希望他们为自己的工作创建一个分支。
1. **专注于一个领域的更改**。要求贡献者一次专注于一个方面的贡献——这样你合并他们工作的可能性会更高。想象他们修复了一个bug添加了一个新功能并更新了几个测试——如果你只想实现其中的2个或3个或者1个更改怎么办
1. **Fork 你的仓库**。你可能希望别人 _fork_ 你的项目。Fork 是在他们的 GitHub 账号上创建你仓库的副本。
1. **克隆**。然后他们将项目克隆到本地机器。
1. **创建分支**。你会希望他们为自己的工作创建一个 _分支_
1. **把修改聚焦在一件事**。让贡献者每次专注一件事——这样更容易 _合并_ 他们的工作。假设他们写了 bug 修复、添加新功能并更新多个测试——如果你只能合并其中两个或一个怎么办?
✅ 想象一个分支在编写和发布优质代码时特别重要的情况。你能想到哪些用例?
✅ 想想有哪些场景分支对写出和发布高质量代码特别关键
> 注意,成为你希望看到的改变,自己也为自己的工作创建分支。你进行的任何提交都会在你当前“检出”的分支上进行。使用`git status`查看当前分支。
> 注意,成为你希望看到的改变,也为你自己的工作创建分支。任何提交都发生在你当前“签出”的分支上。用 `git status` 查看当前分支。
让我们来看看贡献者的工作流程。假设贡献者已经“fork”和“克隆”了仓库因此他们在本地机器上有一个准备好工作的Git仓库
我们来看贡献者的工作流程。假设贡献者已经 _fork__clone_ 了仓库,拥有一个可本地操作的 Git 仓库:
1. **创建分支**。使用`git branch`命令创建一个分支,用于包含他们计划贡献的更改:
1. **创建分支**。用命令 `git branch` 创建将用于贡献的分支
```bash
git branch [branch-name]
```
1. **切换到工作分支**。切换到指定分支并使用`git switch`更新工作目录:
> 💡 **现代做法**:你也可以用一条命令创建并切换分支:
```bash
git switch -c [branch-name]
```
1. **切换到工作分支**。用 `git switch` 切换到指定分支并更新工作区:
```bash
git switch [branch-name]
```
1. **进行工作**。此时你可以添加更改。不要忘记使用以下命令告诉Git
> 💡 **现代提示**`git switch` 是替代 `git checkout` 修改分支的现代命令,更清晰也更安全适合新手。
1. **开始工作**。此时你添加修改。别忘了用下面命令告诉 Git
```bash
git add .
git commit -m "my changes"
```
确保为你的提交起一个好名字,对你自己以及仓库维护者都有帮助。
> ⚠️ **提交信息质量**:确保给你的提交起个好名字,为自己和仓库维护者负责。具体说明你的改动!
1. **将你的工作与`main`分支合并**。在某个时候,你完成了工作,并希望将你的工作与`main`分支的工作合并。`main`分支可能已经发生了变化,因此请确保首先使用以下命令更新到最新版本
1. **`main` 分支合并**。完成工作后,你想把改动合并回 `main`。由于 `main` 可能已变动,先用以下命令更新它
```bash
git switch main
git pull
```
此时你需要确保任何冲突Git无法轻松合并更改的情况发生在你的工作分支中。因此运行以下命令:
接下来确保任何冲突,即 Git 无法轻松合并的情况发生在你的工作分支上。运行以下命令:
```bash
git switch [branch_name]
git merge main
```
`git merge main`命令会将`main`中的所有更改带入你的分支。希望你可以直接继续。如果不能VS Code会告诉你Git“困惑”的地方你只需修改受影响的文件以确定哪个内容最准确
`git merge main` 命令将 `main` 的所有改动合入你的分支。希望你可以直接继续。如果不能VS Code 会告诉你哪里有冲突,你只需编辑相关文件,决定哪些内容是正确的
要切换到不同的分支,请使用现代的`git switch`命令
💡 **现代替代**:考虑用 `git rebase` 保持历史清晰
```bash
git switch [branch_name]
git rebase main
```
它将你的提交放到最新的 `main` 之上,创建线性历史。
1. **将你的工作发送到GitHub**。将你的工作发送到GitHub意味着两件事将你的分支推送到你的仓库然后打开一个PR拉取请求
1. **将你的工作推送到 GitHub**。推送工作到 GitHub 包含两步:推送分支到你的仓库,然后打开 PR拉取请求
```bash
git push --set-upstream origin [branch-name]
```
上述命令会在你的fork仓库中创建分支。
1. **打开一个 PR**。接下来,你需要打开一个 PR。你可以通过导航到 GitHub 上的 fork 仓库来完成此操作。你会在 GitHub 上看到一个提示,询问是否要创建一个新的 PR点击它后会进入一个界面在这里你可以修改提交信息标题并添加更合适的描述。现在你 fork 的仓库的维护者会看到这个 PR_希望_他们会欣赏并_合并_你的 PR。恭喜你现在你是一个贡献者了太棒了 :)
上面命令会在你的 fork 仓库上创建该分支。
### 🤝 **协作技能检测:准备好与他人合作了吗?**
**看看你对协作的感觉如何:**
- 你现在理解 fork 和拉取请求的概念了吗?
- 关于分支工作你还想多练习什么?
- 你对向别人的项目贡献感觉如何?
```mermaid
mindmap
root((Git 协作))
Branching
Feature branches
Bug fix branches
Experimental work
Pull Requests
Code review
Discussion
Testing
Best Practices
Clear commit messages
Small focused changes
Good documentation
```
> **信心提升**你敬佩的每个开发者当年也曾紧张他们的第一次拉取请求。GitHub 社区对新手非常友好!
1. **打开拉取请求PR**。接下来你要在 GitHub 上打开 PR。访问你的 fork 仓库GitHub 会提示你是否创建新 PR点击进入后可以修改提交信息标题写更合适的描述。原仓库维护者会看到该 PR_希望他们会喜欢并合并它_。你现在是贡献者太棒了 :)
💡 **现代小贴士**:你也可以用 GitHub CLI 创建 PR
```bash
gh pr create --title "Your PR title" --body "Description of changes"
```
1. **清理**。在成功合并 PR 后,清理工作被认为是良好的实践。你需要清理本地分支和推送到 GitHub 的分支。首先,用以下命令在本地删除分支:
🔧 **PR 最佳实践**
- 使用关键词关联相关 issues如 “Fixes #123
- 为界面改动添加截图
- 指定特定评审人
- 对进行中的工作使用草稿 PR
- 确保所有 CI 检查通过再请求评审
1. **清理**。在你成功合并一个 PR 之后进行_清理_工作被认为是一种良好习惯。你需要清理你的本地分支以及你推送到 GitHub 的分支。首先,用以下命令在本地删除它:
```bash
git branch -d [branch-name]
```
确保接下来访问 Fork 的 GitHub 页面,删除你刚刚推送的远程分支。
接着,确保前往 GitHub 上的 fork 仓库页面,删除你刚刚推送的远程分支。
`Pull request` 这个术语听起来有点奇怪,因为实际上你是想将你的更改推送到项目中。但维护者(项目所有者)或核心团队需要在合并到项目的“主”分支之前考虑你的更改,因此实际上你是在请求维护者对更改做出决定。
“拉取请求”Pull request这个术语看起来有些奇怪实际上你是想将你的变更推送到项目里。但项目维护者项目所有者或者核心团队需要先审查你的变更才会将它合并到项目的“主”分支所以你实际上是在请求维护者做出变更的决定。
Pull request 是一个比较和讨论分支中引入的差异的地方,可以进行审查、评论、集成测试等。一个好的 pull request 通常遵循与提交信息相似的规则。你可以在问题跟踪器中引用一个问题,例如当你的工作解决了某个问题时。这可以通过使用 `#` 后跟问题编号来完成。例如 `#97`
拉取请求是一个比较和讨论某个分支引入的差异的地方,带有评审、评论、集成测试等等功能。一个好的拉取请求大致遵循提交信息的相同规则。当你的工作修复了某个问题时,你可以添加该问题追踪器中问题的引用。方法是用 `#` 加上你的问题编号。例如 `#97`
🤞希望所有检查都通过,项目所有者将你的更改合并到项目中🤞
🤞 希望所有检查都通过,项目所有者能将你的改动合并进项目 🤞
用 GitHub 上对应的远程分支的所有新提交更新你当前的本地工作分支:
使以下命令更新你当前本地工作分支,使其包含 GitHub 上对应远程分支的所有新提交:
`git pull`
## 如何为开源项目做贡献
## 为开源贡献(您改变世界的机会!)
你准备好迎接将彻底震撼你心灵的事情了吗?🤯 让我们聊聊如何为开源项目做贡献——想到与您分享这些我都热血沸腾!
这是你成为真正非凡事物一部分的机会。想象一下,改进数百万开发者每天使用的工具,或者修复你朋友喜欢的应用中的一个 bug。这不仅仅是梦想——这就是开源贡献的意义
首先,让我们在 GitHub 上找到一个你感兴趣并希望贡献更改的仓库(或 **repo**)。你需要将其内容复制到你的机器上。
让我每次想到都会激动的是:你学习过的每一个工具——代码编辑器、我们将探索的框架,甚至你现在用来阅读这篇文章的浏览器——最初都是由和你一样的人首次做出贡献而开始的。那个打造你最喜欢的 VS Code 插件的优秀开发者?他们也曾是一个初学者,用颤抖的手点下“创建拉取请求”,就像你即将做的那样
✅ 找到“适合初学者”的仓库的一个好方法是[通过标签 'good-first-issue' 进行搜索](https://github.blog/2020-01-22-browse-good-first-issues-to-start-contributing-to-open-source/)。
最美妙的是开源社区就像互联网最大的集体拥抱。大多数项目都会积极欢迎新人而且有专门标记为“good first issue”好入门问题的任务就是为像你这样的人准备的维护者看到新贡献者会非常兴奋因为他们记得自己的第一步
![将仓库复制到本地](../../../../translated_images/clone_repo.5085c48d666ead57664f050d806e325d7f883be6838c821e08bc823ab7c66665.zh.png)
```mermaid
flowchart TD
A[🔍 探索 GitHub] --> B[🏷️ 找到 “good first issue”]
B --> C[📖 阅读贡献指南]
C --> D[🍴 派生仓库]
D --> E[💻 设置本地环境]
E --> F[🌿 创建功能分支]
F --> G[✨ 做出你的贡献]
G --> H[🧪 测试你的更改]
H --> I[📝 写清晰的提交信息]
I --> J[📤 推送并创建 PR]
J --> K[💬 参与反馈交流]
K --> L[🎉 合并成功!你成为贡献者了!]
L --> M[🌟 寻找下一个问题]
style A fill:#e1f5fe
style L fill:#c8e6c9
style M fill:#fff59d
```
你不仅仅是在学编程——你正在准备加入一个每天醒来都想着“我们如何让数字世界变得更好一点”的全球建设者家庭。欢迎加入!🌟
有几种复制代码的方法。一种方法是使用 HTTPS、SSH 或 GitHub CLI命令行界面“克隆”仓库的内容。
首先,让我们找到一个你感兴趣且想贡献变更的 GitHub 代码库(**repo**)。你需要把它的内容复制到你的电脑上
打开终端并像这样克隆仓库:
`git clone https://github.com/ProjectURL`
✅ 一个很好的寻找“初学者友好”仓库的方法是[通过“good-first-issue”标签搜索](https://github.blog/2020-01-22-browse-good-first-issues-to-start-contributing-to-open-source/)。
要开始处理项目,请切换到正确的文件夹:
![在本地复制仓库](../../../../translated_images/clone_repo.5085c48d666ead57.zh.png)
有几种方式可以复制代码。一种是使用 HTTPS、SSH或者 GitHub CLI命令行界面“克隆”仓库内容。
打开终端,输入以下命令克隆仓库:
```bash
# 使用 HTTPS
git clone https://github.com/ProjectURL
# 使用 SSH需要设置 SSH 密钥)
git clone git@github.com:username/repository.git
# 使用 GitHub CLI
gh repo clone username/repository
```
要开始项目工作,切换到相应文件夹:
`cd ProjectURL`
你还可以使用 [Codespaces](https://github.com/features/codespaces)GitHub 的嵌入式代码编辑器/云开发环境)或 [GitHub Desktop](https://desktop.github.com/) 打开整个项目。
你也可以用以下方式打开整个项目:
- **[GitHub Codespaces](https://github.com/features/codespaces)** —— GitHub 提供的带有浏览器中 VS Code 的云开发环境
- **[GitHub Desktop](https://desktop.github.com/)** —— Git 操作的图形界面应用
- **[GitHub.dev](https://github.dev)** —— 在任意 GitHub 仓库按 `.` 键打开浏览器中 VS Code
- 安装 GitHub Pull Requests 扩展的 VS Code
最后,你也可以下载代码的压缩文件夹。
最后,你也可以下载代码的压缩
### 关于 GitHub 的一些有趣的事情
### 关于 GitHub 的几点更多有趣内容
你可以对 GitHub 上的任何公共仓库进行加星、关注和“fork”。你可以在右上角的下拉菜单中找到你加星的仓库。这就像为代码做书签。
你可以给任何 GitHub 上的公共仓库加星、关注和/或“Fork”派生。你可以在右上角的下拉菜单中找到你加星的仓库。它就像收藏书签但针对代码
项目通常有一个问题跟踪器,大多数情况下在 GitHub 的“问题”标签中,除非另有说明,人们会在这里讨论与项目相关的问题。而 Pull Requests 标签是人们讨论和审查正在进行的更改的地方。
项目通常有一个问题追踪器,通常在 GitHub 的“Issues”标签页除非另有说明这是人们讨论与项目有关问题的地方。拉取请求页是人们讨论和复审正在进行的改动的地方。
项目可能还会在论坛、邮件列表或聊天频道(如 Slack、Discord 或 IRC中进行讨论。
项目还可能有论坛、邮件列表,或者像 Slack、Discord、IRC 这样的聊天频道
✅ 浏览一下你的新 GitHub 仓库,尝试一些操作,比如编辑设置、向仓库添加信息,以及创建一个项目(比如看板)。你可以做很多事情!
🔧 **现代 GitHub 功能**
- **GitHub Discussions** —— 内置社区讨论论坛
- **GitHub Sponsors** —— 金融支持维护者
- **安全标签** —— 漏洞报告与安全公告
- **Actions 标签** —— 查看自动化工作流和 CI/CD 管道
- **Insights 标签** —— 关于贡献者、提交和项目健康的数据分析
- **Projects 标签** —— GitHub 内置的项目管理工具
✅ 试着熟悉你的新 GitHub 仓库,尝试编辑设置、为仓库添加信息、创建项目(如看板),以及设置 GitHub Actions 实现自动化。你可以做很多事情!
---
## 🚀 挑战
与朋友配对共同处理彼此的代码。协作创建一个项目fork 代码,创建分支,并合并更改。
好了,是时候检验你闪亮的新 GitHub 超能力了!🚀 这项挑战会让一切以最令人满意的方式水到渠成:
找一个朋友(或者一直问你“你那些电脑玩意儿在干嘛”的亲戚)一起开始一场协作编程冒险!这才是真正的魔法所在——创建项目,让他们 Fork创建几个分支然后像专业人士一样合并变更。
我说实话——你们很可能会哈哈大笑(尤其是当你们俩试图同时改同一行代码时),也许会一起摸不着头脑,但你们肯定会有那些令人激动的“啊哈!”时刻,让所有学习都物有所值。而且,和别人分享第一次成功合并总是特别的——就像是对你来之不易进步的一次小小庆祝!
## 课后测验
还没有编程伙伴没关系GitHub 社区里有无数热情欢迎的成员他们都记得自己刚开始时是什么样子。寻找带有“good first issue”标签的仓库——它们基本上是在说“嘿初学者来和我们一起学习吧”多棒啊
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/en/)
## 复习与自学
## 复习与持续学习
呼!🎉 看你——你刚刚像个绝对的高手一样掌握了 GitHub 基础!如果现在感觉大脑有点满,那很正常,老实说这其实是好现象。你刚刚学会的工具,我当初花了好几周才熟悉。
阅读更多关于[如何为开源软件做贡献](https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution)的内容。
Git 和 GitHub 非常强大(真的非常强大),我认识的每个开发者——包括现在看起来像个高手的那帮人——都必须不断练习、跌跌撞撞才能完全掌握。你能完成这课说明你已经在向掌握开发者工具箱里最重要的东西迈进了
[Git 速查表](https://training.github.com/downloads/github-git-cheat-sheet/)。
这里有一些绝佳资源,帮你练习且变得更棒:
多练习多实践。GitHub 提供了很棒的学习路径:[skills.github.com](https://skills.github.com):
- [开源软件贡献指南](https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution) —— 你的改变之路地图
- [Git 速查表](https://training.github.com/downloads/github-git-cheat-sheet/) —— 随时备查!
- [GitHub 的第一周](https://skills.github.com/#first-week-on-github)
记住:练习带来进步,不是完美!你用 Git 和 GitHub 越多越觉得自然。GitHub 还推出了些很棒的交互课程,让你在安全环境中练习:
你还可以找到更高级的课程。
- [GitHub 入门](https://github.com/skills/introduction-to-github)
- [使用 Markdown 交流](https://github.com/skills/communicate-using-markdown)
- [GitHub Pages](https://github.com/skills/github-pages)
- [管理合并冲突](https://github.com/skills/resolve-merge-conflicts)
## 作业
**想挑战现代工具?查看这些:**
- [GitHub CLI 文档](https://cli.github.com/manual/) —— 想成为命令行巫师必备
- [GitHub Codespaces 文档](https://docs.github.com/en/codespaces) —— 云端编程!
- [GitHub Actions 文档](https://docs.github.com/en/actions) —— 自动化一切
- [Git 最佳实践](https://www.atlassian.com/git/tutorials/comparing-workflows) —— 升级你的工作流玩法
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成下面的挑战:
**描述:** 创建一个协作网页开发项目,展示你在本课中学到的完整 GitHub 工作流程。本挑战将帮助你在真实场景中练习仓库创建、协作功能以及现代 Git 工作流。
**提示:** 在 GitHub 创建一个新的公共仓库名为“Web Development Resources”。仓库应包含结构良好的 README.md 文件列出按类别组织的实用网页开发工具和资源HTML、CSS、JavaScript 等)。为仓库设置合适的社区规范,包括许可协议、贡献指南和行为准则。创建至少两个功能分支:一个用于添加 CSS 资源,另一个用于 JavaScript 资源。分别在两个分支做提交,并附上描述性提交信息,然后创建拉取请求合并回主分支。启用 GitHub 诸如 Issues、Discussions 功能,并设置基础的 GitHub Actions 工作流,实现自动检查。
## 任务
你的任务,如果你愿意接受:完成 GitHub Skills 上的 [GitHub 入门](https://github.com/skills/introduction-to-github) 课程。这个交互式课程会让你在安全的引导环境中练习所学。完成还有酷炫徽章奖励!🏅
**准备好接受更多挑战?**
- 为你的 GitHub 账户设置 SSH 认证(告别密码!)
- 试用 GitHub CLI 进行日常 Git 操作
- 创建包含 GitHub Actions 工作流的仓库
- 通过 GitHub Codespaces 在云端编辑这个仓库
---
完成 [GitHub 的第一周课程](https://skills.github.com/#first-week-on-github)
## 🚀 你的 GitHub 掌握时间线
### ⚡ **接下来 5 分钟能做的事**
- [ ] 给这个仓库及另外 3 个你感兴趣的项目加星
- [ ] 为你的 GitHub 账户设置双因素认证
- [ ] 为你的第一个仓库创建简单的 README
- [ ] 关注 5 位启发你的开发者
### 🎯 **本小时能完成的目标**
- [ ] 完成课后测验并反思你的 GitHub 学习之旅
- [ ] 配置 SSH 密钥实现免密码登录 GitHub
- [ ] 做出你第一个有意义且带有良好提交信息的 commit
- [ ] 探索 GitHub“Explore”标签页发现热门项目
- [ ] 练习 Fork 仓库并做一些小改动
### 📅 **一周的 GitHub 冒险**
- [ ] 完成 GitHub Skills 课程GitHub 入门Markdown
- [ ] 向开源项目提交第一个拉取请求
- [ ] 搭建 GitHub Pages 展示你的作品
- [ ] 参与你感兴趣项目的 GitHub Discussions
- [ ] 创建符合社区规范的仓库README授权等
- [ ] 试用 GitHub Codespaces 云端开发
### 🌟 **一个月的转变**
- [ ] 向 3 个不同开源项目贡献代码
- [ ] 指导 GitHub 新手(传帮带!)
- [ ] 配置自动化工作流GitHub Actions
- [ ] 构建展示你 GitHub 贡献的作品集
- [ ] 参加 Hacktoberfest 或类似社区活动
- [ ] 成为自己项目的维护者,吸引他人贡献
### 🎓 **最终 GitHub 掌握确认**
**庆祝你的进步:**
- 你最喜欢 GitHub 的哪一点?
- 哪个协作功能让你最兴奋?
- 现在你对开源贡献有多自信?
- 你第一个想贡献的项目是什么?
```mermaid
journey
title 你的 GitHub 信心旅程
section 今天
紧张: 3: 你
好奇: 4: 你
兴奋: 5: 你
section 本周
练习中: 4: 你
贡献中: 5: 你
连接中: 5: 你
section 下个月
合作中: 5: 你
领导中: 5: 你
激励他人: 5: 你
```
> 🌍 **欢迎加入全球开发者社区!** 你现在拥有了与全球数百万开发者协作的工具。你的第一次贡献可能看上去很小,但请记住——每个重大开源项目都是从有人第一次提交代码开始的。问题不在于你是否能产生影响,而是哪个令人惊叹的项目会首先受益于你独特的视角!🚀
记住:每个专家都曾是初学者。你可以的!💪
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原文以其母语版本为准。对于重要信息,建议采用专业人工翻译。因使用本翻译引起的任何误解或错误解读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,28 +1,261 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a258597a194e77d4fd469b3cd976b29e",
"translation_date": "2025-08-23T23:26:25+00:00",
"original_hash": "e6d0f456dfc22afb41bbdefeb5ec179d",
"translation_date": "2026-01-06T11:57:51+00:00",
"source_file": "1-getting-started-lessons/3-accessibility/assignment.md",
"language_code": "zh"
}
-->
# 分析一个不可访问的网站
# 综合网站无障碍审计
## 指导说明
## 说明
找出一个你认为不可访问的网站,并制定一个改进其可访问性的行动计划。
你的第一步是识别这个网站,详细说明你认为它不可访问的原因(无需使用分析工具),然后提交给 Lighthouse 进行分析。
将分析结果保存为 PDF并制定一个详细的改进计划至少包含十个改进点说明如何改进该网站。
在本作业中,你将对一个真实网站进行专业级别的无障碍审计,应用你所学的原则和技术。这一实操经验将加深你对无障碍障碍及解决方案的理解。
## 测试网站可访问性的表格
选择一个看起来存在无障碍问题的网站——这比分析已经完美的网站能带来更多学习机会。合适的候选包括较旧的网站、复杂的网络应用或含有丰富多媒体内容的网站。
| 标准 | 卓越 | 合格 | 需要改进 |
|----------|-----------|----------|----------------|
| | 缺少 <10% | 20% | 50% |
### 第一阶段:战略性手动评估
----
学生报告包括关于网站不可访问性的段落、Lighthouse 分析报告的 PDF 文件、十个改进点的列表,以及详细的改进方法
在使用自动化工具之前,先进行全面的手动评估。这种以人为中心的方法常常能发现工具未能检测到的问题,并帮助你理解真实的用户体验。
**🔍 关键评估标准:**
**导航与结构:**
- 能否仅用键盘Tab、Shift+Tab、Enter、Space、方向键导航整个网站
- 所有交互元素上是否有明显的焦点指示?
- 标题结构H1-H6是否创建了逻辑清晰的内容大纲
- 是否有跳转主内容的跳过链接?
**视觉无障碍:**
- 网站整体是否有足够的颜色对比度普通文本最低4.5:1
- 网站是否仅依靠颜色传达重要信息?
- 所有图像是否有适当的替代文本?
- 放大至200%时布局是否仍然可用?
**内容与交流:**
- 是否存在“点击这里”等模糊的链接文本?
- 无需视觉提示是否能理解内容和功能?
- 表单字段是否正确标注和分组?
- 错误信息是否清晰且有帮助?
**交互元素:**
- 所有按钮和表单控件是否支持仅用键盘操作?
- 动态内容变更是否向屏幕阅读器宣布?
- 模态对话框和复杂控件是否遵循正确的无障碍模式?
📝 **用具体示例、截图和页面 URL 记录你的发现**,注意问题和良好实践。
### 第二阶段:全面自动化测试
现在使用行业标准的无障碍测试工具验证和扩展手动发现。每种工具具有不同优势,结合多工具使用可达到全面覆盖。
**🛠️ 必用测试工具:**
1. **Lighthouse 无障碍审计**(内置于 Chrome/Edge 开发者工具)
- 在多个页面运行审计
- 关注具体指标和建议
- 记录无障碍得分和具体违规项
2. **axe DevTools**(浏览器扩展 - 行业标准)
- 比 Lighthouse 检测更详细的问题
- 提供具体代码示例解决方案
- 针对 WCAG 2.1 标准测试
3. **WAVE 无障碍评估器**(浏览器扩展)
- 可视化无障碍特征表示
- 突出错误和正面特征
- 非常适合理解页面结构
4. **颜色对比分析工具**
- WebAIM Contrast Checker 用于具体配色对检测
- 浏览器扩展用于页面全局分析
- 测试同时符合 WCAG AA 和 AAA 标准
**🎧 真实辅助技术测试:**
- **屏幕阅读器测试**:使用 NVDAWindows、VoiceOverMac或 TalkBackAndroid
- **仅键盘导航**:拔掉鼠标,使用键盘导航全站
- **放大测试**:在 200% 和 400% 缩放级别测试功能
- **语音控制测试**:如可用,尝试语音导航工具
**📊 整理结果**,创建总表包括:
- 问题描述和位置
- 严重性级别(关键/高/中/低)
- 违反的 WCAG 成功标准
- 发现问题的工具
- 截图和证据
### 第三阶段:详细发现报告
编写专业的无障碍审计报告,展示你对技术问题及其对用户影响的理解。
**📋 必含报告部分:**
1. **执行摘要**1 页)
- 网站 URL 和简要介绍
- 整体无障碍成熟度水平
- 3 个最关键问题
- 对残障用户的预估影响
2. **方法论**(½ 页)
- 测试方法和使用的工具
- 评估的页面及设备/浏览器组合
- 遵循的标准WCAG 2.1 AA
3. **详细发现**2-3 页)
- 按 WCAG 原则分类的问题(可感知、可操作、可理解、稳健)
- 包含截图和具体示例
- 记录发现的正面无障碍特征
- 与自动化工具结果交叉引用
4. **用户影响评估**1 页)
- 识别的问题如何影响不同残障用户
- 描述真实用户体验场景
- 商业影响(法律风险、搜索引擎优化、用户基数拓展)
**📸 证据收集:**
- 无障碍违规的截图
- 问题用户流程的屏幕录制
- 工具报告(保存为 PDF
- 展示问题的代码示例
### 第四阶段:专业整改计划
制定战略性、优先级排序的无障碍问题修复方案,展示你像专业开发人员一样考虑实际业务限制的能力。
**🎯 制作详细改进建议至少10项**
**针对每个问题,提供:**
- **问题描述**:清楚说明问题及其危害
- **WCAG 参考**具体违反的成功标准如“2.4.4 链接用途(上下文中)- A 级”)
- **用户影响**:如何影响不同残障用户
- **解决方案**:具体代码更改、设计调整或流程改进
- **优先级**:关键(阻断基本使用)/ 高(显著障碍)/ 中(可用性问题)/ 低(改进)
- **实施难度**:时间/复杂度估计(快速赢得 / 中等投入 / 重大重构)
- **测试验证**:如何验证修复有效
**示例改进条目:**
```
Issue: Generic "Read more" link text appears 8 times on homepage
WCAG Reference: 2.4.4 Link Purpose (In Context) - Level A
User Impact: Screen reader users cannot distinguish between links when viewed in link list
Solution: Replace with descriptive text like "Read more about sustainability initiatives"
Priority: High (major navigation barrier)
Effort: Low (30 minutes to update content)
Testing: Generate link list with screen reader - each link should be meaningful standalone
```
**📈 战略实施阶段:**
- **第1阶段0-2周**:阻碍基本功能的关键问题
- **第2阶段1-2个月**:改善用户体验的高优先级改进
- **第3阶段3-6个月**:中优先级的增强和流程改良
- **第4阶段持续进行**:持续监控和改进
## 评估标准
你的无障碍审计将根据技术准确性和专业呈现进行评估:
| 标准 | 优秀90-100% | 良好80-89% | 满意70-79% | 需改进(<70% |
|----------|-------------------|---------------|---------------------|------------------------|
| **手动测试深度** | 覆盖所有 POUR 原则,且详细观察和用户场景 | 覆盖大部分无障碍领域,发现明确,部分用户影响分析 | 覆盖关键领域,观察适当 | 测试有限,观察表面,用户影响考虑不足 |
| **工具使用与分析** | 有效使用所有工具,交叉验证,清晰证据,分析工具限制 | 使用大多数工具,有良好文档,部分交叉验证和证据 | 使用必需工具,基本文档和一定证据 | 工具使用有限,文档差,证据不足 |
| **问题识别与分类** | 识别15+具体问题,准确分级,表现出深入理解 | 识别10-14问题覆盖大多数WCAG原则分类良好 | 识别7-9问题基本覆盖分类一般 | 识别<7问题,范围有限,分类差 |
| **解决方案质量与可行性** | 10+详实、可执行方案准确WCAG引用合理实施周期验证方法 | 8-9方案引用大多准确实施细节好 | 6-7基础方案有部分细节方案现实 | <6方案、细节不足、不可行 |
| **专业沟通** | 报告结构优秀,文字清晰,含执行摘要,技术语言恰当,符合商务规范 | 组织良好,文字质量好,包含大多数必需部分,语气合适 | 组织合理,文字可接受,包含基本部分 | 组织混乱,表述不清,缺少关键部分 |
| **实际应用性** | 展示业务影响、法律考量、用户多样性和实践挑战的理解 | 展示对实际应用和部分业务背景的良好理解 | 基础了解实际应用 | 对实际应用的联系有限 |
## 进阶挑战选项
**🚀 对想挑战更高水平的学生:**
- **对比分析**:审计 2-3 个竞品网站,比较无障碍成熟度
- **移动端无障碍聚焦**:用 Android TalkBack 或 iOS VoiceOver 深入探究移动端无障碍问题
- **国际视角**研究应用不同国家无障碍标准EN 301 549、Section 508、ADA
- **无障碍声明审查**:根据你的发现评估网站现有无障碍声明(如有)
## 交付物
提交一份综合无障碍审计报告,展示专业分析与可行整改方案:
**📄 最终报告要求:**
1. **执行摘要**1页
- 网站概况与无障碍成熟度评估
- 关键发现及商业影响汇总
- 优先推荐措施
2. **方法论与范围**1页
- 测试方法、工具和评估标准
- 评估页面/章节及限制
- 遵循标准体系WCAG 2.1 AA
3. **详细发现报告**3-4页
- 手动测试观察和用户场景
- 自动化工具结果与交叉验证
- 按 WCAG 原则组织的问题及证据
- 识别的正面无障碍特征
4. **战略整改计划**3-4页
- 优先级改进建议至少10项
- 实施时间表及工作量估算
- 成功指标和验证方法
- 长期无障碍维护策略
5. **支持证据**(附录)
- 无障碍违规和测试工具截图
- 展示问题及解决方案的代码示例
- 工具报告和审计摘要
- 屏幕阅读器测试笔记或录制
**📊 格式要求:**
- **文档格式**PDF专业呈现
- **字数**2500-3500 字(不含附录和截图)
- **视觉元素**:贯穿包含截图、图表和示例
- **引用**:适当引用 WCAG 指南和无障碍资源
**💡 卓越建议:**
- 使用专业报告格式,标题和样式统一
- 包含目录便于导航
- 技术准确与清晰商务语言兼顾
- 展示技术实现和用户影响的理解
## 学习收益
完成本综合无障碍审计后,你将掌握核心专业技能:
**🎯 技术能力:**
- **无障碍测试精通**:熟练应用行业标准手动和自动测试方法
- **WCAG 应用**:实践下应用 Web 内容无障碍指南经验
- **辅助技术理解**:亲手体验屏幕阅读器和键盘导航
- **问题-方案映射**:能识别无障碍障碍并制定具体可行的整改策略
**💼 职业技能:**
- **技术沟通**:为多元利益相关者撰写专业无障碍报告经验
- **战略规划**:基于用户影响和实施可行性优先排序改进
- **质量保证**:理解无障碍测试在开发生命周期中的角色
- **风险评估**:认识无障碍合规的法律、商业和伦理意义
**🌍 包容性设计心态:**
- **用户共情**:深入理解多样用户需求及辅助技术交互
- **通用设计原则**:认知无障碍设计惠及所有用户,不仅限残障
- **持续改进**:建立无障碍持续评估和优化框架
- **倡导能力**:自信推动未来项目和团队无障碍最佳实践
**🚀 职业准备:**
本作业模拟真实无障碍咨询项目,为你提供作品集级经验,展现:
- 系统性问题解决方法
- 技术细节与商业影响兼顾
- 复杂技术概念的清晰沟通
- 网页开发法律与伦理责任理解
完成后,你将能有效参与任何网页开发岗位的无障碍工作,并在职业生涯中倡导包容性设计实践。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对于因使用此翻译而引起的任何误解或误读不承担责任。
本文件由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译。尽管我们努力保证准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用此翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because it is too large Load Diff

@ -1,215 +1,618 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "b95fdd8310ef467305015ece1b0f9411",
"translation_date": "2025-08-29T14:48:32+00:00",
"original_hash": "672b0bb6e8b431075f3bdb7130590d2d",
"translation_date": "2026-01-06T11:12:57+00:00",
"source_file": "2-js-basics/1-data-types/README.md",
"language_code": "zh"
}
-->
# JavaScript 基础:数据类型
![JavaScript 基础 - 数据类型](../../../../translated_images/webdev101-js-datatypes.4cc470179730702c756480d3ffa46507f746e5975ebf80f99fdaaf1cff09a7f4.zh.png)
> 由 [Tomomi Imura](https://twitter.com/girlie_mac) 绘制的手绘笔记
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/)
本课将介绍 JavaScript 的基础知识,这是一种为网页提供交互功能的语言。
![JavaScript Basics - Data types](../../../../translated_images/webdev101-js-datatypes.4cc470179730702c.zh.png)
> 手绘笔记,作者 [Tomomi Imura](https://twitter.com/girlie_mac)
```mermaid
journey
title 你的 JavaScript 数据类型冒险
section 基础
变量与常量: 5: You
声明语法: 4: You
赋值概念: 5: You
section 核心类型
数字与数学: 4: You
字符串与文本: 5: You
布尔值与逻辑: 4: You
section 应用知识
类型转换: 4: You
现实世界示例: 5: You
最佳实践: 5: You
```
数据类型是 JavaScript 中你在每个程序中都会遇到的基本概念之一。把数据类型想象成古代亚历山大图书管理员使用的归档系统 —— 他们为包含诗歌、数学和历史记录的卷轴设定了特定的存放位置。JavaScript 以类似的方式组织信息,不同类别用于不同类型的数据。
> 你可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-variables/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
在本课中,我们将探索让 JavaScript 工作的核心数据类型。你将学会如何处理数字、文本、真/假值,并理解为什么为程序选择正确的数据类型至关重要。这些概念起初可能看起来抽象,但通过练习,它们将变成你第二天性。
[![变量](https://img.youtube.com/vi/JNIXfGiDWM8/0.jpg)](https://youtube.com/watch?v=JNIXfGiDWM8 "JavaScript 中的变量")
理解数据类型会让 JavaScript 中的其他内容变得更加清晰。就像建筑师需要了解不同的建筑材料才能建造大教堂一样,这些基础知识将支撑你未来构建的一切。
[![JavaScript 中的数据类型](https://img.youtube.com/vi/AWfA95eLdq8/0.jpg)](https://youtube.com/watch?v=AWfA95eLdq8 "JavaScript 中的数据类型")
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/)
> 🎥 点击上方图片观看关于变量和数据类型的视频
本课涵盖了 JavaScript 的基础知识,这种语言为网页提供交互性。
让我们从变量和填充它们的数据类型开始吧!
> 你可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-variables/?WT.mc_id=academic-77807-sagibbon) 上学习本课程
[![Variables](https://img.youtube.com/vi/JNIXfGiDWM8/0.jpg)](https://youtube.com/watch?v=JNIXfGiDWM8 "Variables in JavaScript")
[![Data Types in JavaScript](https://img.youtube.com/vi/AWfA95eLdq8/0.jpg)](https://youtube.com/watch?v=AWfA95eLdq8 "Data Types in JavaScript")
> 🎥 点击上方图片观看关于变量与数据类型的视频
让我们从变量以及填充变量的数据类型开始吧!
```mermaid
mindmap
root((JavaScript 数据))
Variables
let myVar
const PI = 3.14
var oldStyle
Primitive Types
number
42
3.14
-5
string
"你好"
'世界'
`模板`
boolean
true
false
undefined
null
Operations
Arithmetic
+ - * / %
String Methods
连接
模板字面量
Type Conversion
隐式
显式
```
## 变量
变量用于存储值,这些值可以在代码中使用并随时更改。
变量是编程中的基础构件。就像中世纪炼金术士用于存放不同物质的标记罐子,变量让你存储信息并给它一个描述性的名称,以便以后引用。需要记住某人的年龄?将其存储在名为 `age` 的变量里。想追踪用户的名字?把它保存在 `userName` 变量中
创建和**声明**变量的语法是 **[关键字] [名称]**,它由以下两部分组成:
我们将专注于 JavaScript 中创建变量的现代方法。这里学习的技巧代表了语言多年来的发展和编程社区的最佳实践。
- **关键字**。关键字可以是 `let``var`
创建和 **声明** 变量的语法是 **[关键字] [名称]**。它由两部分组成:
`let` 关键字是在 ES6 中引入的,它为变量提供了所谓的 _块级作用域_。推荐使用 `let` 而不是 `var`。我们将在后续部分更深入地讨论块级作用域。
- **变量名**,这是你自己选择的名称。
- **关键字**。对可变的变量使用 `let`,对保持不变的值使用 `const`
- **变量名**,是你自己选择的描述性名称。
✅ 关键字 `let` 是在 ES6 中引入的,赋予变量所谓的 _块作用域_。推荐使用 `let``const` 替代旧的 `var` 关键字。我们将在后续部分更深入地讲解块作用域。
### 任务 - 使用变量
1. **声明一个变量**。让我们使用 `let` 关键字声明一个变量:
1. **声明变量**。让我们先创建第一个变量:
```javascript
let myVariable;
```
现在,`myVariable` 已经使用 `let` 关键字声明了,但目前还没有赋值。
**这样做的效果:**
- 告诉 JavaScript 创建一个叫做 `myVariable` 的存储位置
- JavaScript 在内存中为该变量分配空间
- 变量当前没有值undefined
1. **赋值**。使用 `=` 运算符为变量存储一个值,后面跟随期望的值。
2. **赋值**。现在给变量赋一个值:
```javascript
myVariable = 123;
```
> 注意:在本课中,`=` 表示我们使用了“赋值运算符”,用于为变量设置值。它并不表示相等。
**赋值的工作原理:**
- `=` 操作符将值 123 赋给了变量
- 变量现在包含该值,不再是 undefined
- 你可以在代码中使用 `myVariable` 引用这个值
现在,`myVariable` 已经被赋值为 123。
> 注意:本课中 `=` 表示“赋值操作符”,用于给变量设置值,不表示等号
1. **重构**。将代码替换为以下语句:
3. **聪明做法**。实际上,我们可以把这两个步骤合并
```javascript
let myVariable = 123;
```
上述操作称为 _显式初始化_,即在声明变量的同时为其赋值。
**这种做法更高效:**
- 在一条语句中声明变量并赋值
- 这是开发者的标准实践
- 代码更简洁且保持清晰
1. **更改变量值**。通过以下方式更改变量值:
4. **改变想法**。如果想存储不同的数字呢?
```javascript
myVariable = 321;
```
一旦声明了变量,你可以随时使用 `=` 运算符和新值更改其值。
**重新赋值的理解:**
- 变量现在包含 321 而不是 123
- 之前的值被替换 —— 变量一次只存储一个值
- 这种可变性是用 `let` 声明变量的关键特征
✅ 试试看!你可以直接在浏览器中写 JavaScript。打开浏览器窗口进入开发者工具。在控制台提示符下输入 `let myVariable = 123`,回车,然后输入 `myVariable`。会发生什么呢?你将在后续课程中了解更多这些概念。
✅ 试试看!你可以直接在浏览器中编写 JavaScript。打开浏览器窗口并导航到开发者工具。在控制台中你会看到一个提示符输入 `let myVariable = 123`,按回车键,然后输入 `myVariable`。会发生什么?注意,你将在后续课程中学习更多相关概念。
### 🧠 **变量掌握检测:提升熟练度**
**来看看你对变量的理解:**
- 你能解释声明变量和赋值变量的区别吗?
- 如果你在声明变量之前使用它,会发生什么?
- 在什么情况下你会选择用 `let` 而不是 `const`
```mermaid
stateDiagram-v2
[*] --> Declared: 声明 myVar
Declared --> Assigned: myVar = 123
Assigned --> Reassigned: myVar = 456
Assigned --> [*]: 变量已准备好!
Reassigned --> [*]: 更新的值
note right of Declared
变量存在但
没有值(未定义)
end note
note right of Assigned
变量包含
值123
end note
```
> **小提示**:把变量想象成带标签的储物箱。你创建箱子(`let`),把东西放进去(`=`),后续可以替换里面的内容!
## 常量
常量的声明和初始化与变量的概念相同,但使用的是 `const` 关键字。常量通常使用全大写字母声明。
有时你需要存储在程序执行过程中永远不变的信息。常量就像古希腊欧几里得建立的数学原理 —— 一旦被证明和记录,永远保持不变。
常量的工作方式和变量类似,但有一个重要限制:赋值后不能更改。这种不可变性有助于防止对程序中的关键值发生意外修改。
声明并初始化常量的概念和变量相同,唯一不同的是使用 `const` 关键字。常量通常用全大写字母声明。
```javascript
const MY_VARIABLE = 123;
```
常量与变量类似,但有两个例外:
**这段代码做了什么:**
- **创建** 一个名为 `MY_VARIABLE` 的常量,值为 123
- **使用** 常量的全大写命名惯例
- **防止** 未来对该值的任何更改
常量的两条主要规则:
- **必须有值**。常量必须在声明时初始化,否则运行代码时会报错。
- **引用不可更改**。一旦初始化,常量的引用不能更改,否则运行代码时会报错。以下是两个示例:
- **简单值**。以下操作不被允许:
- **必须立即赋值** —— 不允许定义空常量!
- **值永远不能更改** —— 任何尝试更改都会导致错误。来看例子:
**简单值** - 以下做法是不被允许的:
```javascript
const PI = 3;
PI = 4; // not allowed
PI = 4; // 不允许
```
**你需要记住的:**
- **尝试重新赋值常量会导致错误**
- **保护** 重要的数值不被意外更改
- **确保** 程序中值的一致性
- **对象引用受保护**。以下操作不被允许:
**对象引用是被保护的** - 以下做法不被允许:
```javascript
const obj = { a: 3 };
obj = { b: 5 } // not allowed
obj = { b: 5 } // 不允许
```
- **对象值未受保护**。以下操作被允许:
**这些概念的理解:**
- **防止** 用新对象替换整个原对象
- **保护** 原始对象的引用
- **保持** 对象在内存中的身份
**对象值是不被保护的** - 以下做法是允许的:
```javascript
const obj = { a: 3 };
obj.a = 5; // allowed
obj.a = 5; // 允许
```
上述代码更改了对象的值,但没有更改其引用,因此是允许的。
**这里发生了什么:**
- **修改** 对象内部的属性值
- **保持** 相同的对象引用
- **表明** 对象内容可以改变,但引用保持不变
> 注意,`const` 表示引用受到保护,不能重新赋值。但值本身并非 _不可变_,尤其是当它是一个复杂结构(如对象)时,值仍然可以更改。
> 注意,`const` 保护的是引用不被重新赋值。值本身不是不可变的,尤其是当它是复杂类型如对象时,值可以改变
## 数据类型
变量可以存储多种不同类型的值,例如数字和文本。这些不同类型的值被称为**数据类型**。数据类型是软件开发中的重要组成部分,因为它帮助开发者决定代码的编写方式以及软件的运行方式。此外,一些数据类型具有独特的特性,可以帮助转换或提取值中的附加信息。
JavaScript 将信息组织成不同的类别,称为数据类型。这个概念类似于古代学者如何分类知识 —— 亚里士多德区分了不同的推理类型,知道逻辑原则不能统一运用于诗歌、数学和自然哲学。
数据类型很重要因为不同的操作处理不同种类的信息。就像你不能对一个人的名字进行算术运算或对数学方程排序一样JavaScript 需要对每个操作使用合适的数据类型。理解这一点可以避免错误,让代码更可靠。
变量可以存储许多不同类型的值,比如数字和文本。这些不同类型的值统称为**数据类型**。数据类型是软件开发的重要一环,因为它帮助开发者决定如何编写代码以及软件如何运行。此外,某些数据类型具有独特的特性,能够帮助转换或提取值中的附加信息。
✅ 数据类型也被称为 JavaScript 数据原始类型因为它们是语言提供的最低级别的数据类型。JavaScript 中有 7 种原始数据类型string、number、bigint、boolean、undefined、null 和 symbol。花点时间想象一下这些原始类型分别代表什么。`zebra` 是什么?`0` 又是什么?`true` 呢?
✅ 数据类型也称为 JavaScript 的原始数据类型,因为它们是语言提供的最低级别数据类型。共有 7 种原始数据类型string字符串、number数字、bigint大整数、boolean布尔值、undefined未定义、null空值和 symbol符号。花点时间想象这些原始类型分别代表什么。什么是 `zebra``0` 是什么?`true` 呢?
### 数字
在上一节中,`myVariable` 的值是一个数字数据类型。
数字是 JavaScript 中最直接的数据类型。无论你操作像 42 这样整数,还是 3.14 这样的小数,或 -5 这样的负数JavaScript 都统一处理。
还记得我们之前的变量吗?我们存储的 123 实际上是数字类型:
```javascript
let myVariable = 123;
```
`let myVariable = 123;`
**主要特征:**
- JavaScript 自动识别数字值
- 你可以对这些变量执行数学运算
- 不需要显式声明类型
变量可以存储所有类型的数字,包括小数或负数。数字还可以与算术运算符一起使用,这将在[下一节](../../../../2-js-basics/1-data-types)中介绍。
变量可以存储所有类型的数字,包括小数和负数。数字也可以与算术运算符一起使用,详见[下一节](../../../../2-js-basics/1-data-types)
```mermaid
flowchart LR
A["🔢 数字"] --> B[" 加法"]
A --> C[" 减法"]
A --> D["✖️ 乘法"]
A --> E["➗ 除法"]
A --> F["📊 余数 %"]
B --> B1["1 + 2 = 3"]
C --> C1["5 - 3 = 2"]
D --> D1["4 * 3 = 12"]
E --> E1["10 / 2 = 5"]
F --> F1["7 % 3 = 1"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
### 算术运算符
在执行算术操作时,可以使用多种运算符,以下列出了一些:
算术运算符让你在 JavaScript 中执行数学计算。这些运算符遵循数学家们使用了几个世纪的原则 —— 就像代数学符号的发明者花拉子米一样。
| 符号 | 描述 | 示例 |
| ---- | ---------------------------------------------------------------------- | --------------------------------- |
| `+` | **加法**:计算两个数字的和 | `1 + 2 // 预期答案是 3` |
| `-` | **减法**:计算两个数字的差 | `1 - 2 // 预期答案是 -1` |
| `*` | **乘法**:计算两个数字的积 | `1 * 2 // 预期答案是 2` |
| `/` | **除法**:计算两个数字的商 | `1 / 2 // 预期答案是 0.5` |
| `%` | **取余**:计算两个数字相除后的余数 | `1 % 2 // 预期答案是 1` |
运算符的工作方式和传统数学相符:加号表示加法,减号表示减法,等等。
✅ 试试看!在浏览器的控制台中尝试一个算术操作。结果是否让你感到惊讶?
执行算术运算时,可以使用以下几种运算符:
| 符号 | 描述 | 示例 |
| ------ | ------------------------------------------------------------------- | -------------------------------- |
| `+` | **加法**:计算两个数字的和 | `1 + 2 // 预期结果是 3` |
| `-` | **减法**:计算两个数字的差 | `1 - 2 // 预期结果是 -1` |
| `*` | **乘法**:计算两个数字的乘积 | `1 * 2 // 预期结果是 2` |
| `/` | **除法**:计算两个数字的商 | `1 / 2 // 预期结果是 0.5` |
| `%` | **取余**:计算两个数字相除后的余数 | `1 % 2 // 预期结果是 1` |
✅ 试试看!在浏览器的控制台尝试一个算术运算,结果有没有让你感到惊讶?
### 🧮 **数学技能检测:自信计算**
**测试你的算术理解:**
- `/`(除法)和 `%`(取余)有什么区别?
- 你能预测 `10 % 3` 的结果吗?(提示:不是 3.33……)
- 为什么在编程中取余运算符很有用?
```mermaid
pie title "JavaScript 数字操作使用情况"
"加法 (+)" : 35
"减法 (-)" : 20
"乘法 (*)" : 20
"除法 (/)" : 15
"取余 (%)" : 10
```
> **现实世界的启示**:取余运算符 % 非常有用,可以用来检查数字的偶奇性,创建模式,或在数组中循环!
### 字符串
字符串是一组位于单引号或双引号之间的字符。
在 JavaScript 中,文本数据由字符串表示。“字符串”一词来自字符按顺序串联的概念,就像中世纪修道院的抄写员将字母连接成词句记录在手稿里
- `'这是一个字符串'`
- `"这也是一个字符串"`
- `let myString = '这是存储在变量中的字符串值';`
字符串是网页开发的基础。网站上显示的每段文本 —— 用户名、按钮标签、错误信息、内容 —— 都是字符串数据。理解字符串对创建功能性用户界面至关重要。
记得在编写字符串时使用引号,否则 JavaScript 会认为它是一个变量名。
字符串是一组字符,放在单引号或双引号之间。
### 格式化字符串
```javascript
'This is a string'
"This is also a string"
let myString = 'This is a string value stored in a variable';
```
字符串是文本,有时需要进行格式化。
**理解这些概念:**
- **使用** 单引号 `'` 或 双引号 `"` 来定义字符串
- **存储** 可以包含字母、数字和符号的文本数据
- **将** 字符串值赋给变量以供后续使用
- **需要** 使用引号以区分文本和变量名
要**连接**两个或多个字符串(即将它们拼接在一起),可以使用 `+` 运算符。
记住写字符串时一定要用引号,否则 JavaScript 会把它当作变量名。
```mermaid
flowchart TD
A["📝 字符串"] --> B["单引号"]
A --> C["双引号"]
A --> D["模板字面量"]
B --> B1["'Hello World'"]
C --> C1["\"Hello World\""]
D --> D1["`Hello \${name}`"]
E["字符串操作"] --> F["拼接"]
E --> G["模板插入"]
E --> H["长度 & 方法"]
F --> F1["'Hello' + ' ' + 'World'"]
G --> G1["`Hello \${firstName} \${lastName}`"]
H --> H1["myString.length"]
style A fill:#e3f2fd
style E fill:#fff3e0
style D fill:#e8f5e8
style G fill:#e8f5e8
```
### 字符串格式化
字符串操作让你可以组合文本元素、插入变量,并创建响应程序状态的动态内容。这种技术让你能够以编程方式构造文本。
常常需要把多个字符串合并 —— 这个过程叫做连接。
要**连接**两个或多个字符串,或将它们连接在一起,使用 `+` 运算符。
```javascript
let myString1 = "Hello";
let myString2 = "World";
myString1 + myString2 + "!"; //HelloWorld!
myString1 + " " + myString2 + "!"; //Hello World!
myString1 + ", " + myString2 + "!"; //Hello, World!
myString1 + myString2 + "!"; //你好,世界!
myString1 + " " + myString2 + "!"; //你好,世界!
myString1 + ", " + myString2 + "!"; //你好,世界!
```
✅ 为什么在 JavaScript 中 `1 + 1 = 2`,而 `'1' + '1' = 11`?想一想。那 `'1' + 1` 又会怎样?
**一步步来看,发生了什么:**
- 使用 `+` 运算符合并多个字符串
- 第一个例子中**直接连接**字符串,中间没有空格
- 在字符串之间**添加**空格字符 `" "` 以增加可读性
- **插入**逗号等标点符号以创建正确的格式
✅ 为什么在 JavaScript 中 `1 + 1 = 2`,但 `'1' + '1' = 11`?想一想。那 `'1' + 1` 会怎样?
**模板字符串**是另一种格式化字符串的方法,不同之处在于它使用反引号代替引号。任何非纯文本的内容都必须放在占位符 `${ }` 中。这包括可能是字符串的变量。
**模板字符串**是另一种格式化字符串的方式,不同于引号,使用反引号 `` ` ``。所有非纯文本内容都必须放在占位符 `${ }` 内。这包括任何可能是字符串的变量。
```javascript
let myString1 = "Hello";
let myString2 = "World";
`${myString1} ${myString2}!` //Hello World!
`${myString1}, ${myString2}!` //Hello, World!
`${myString1} ${myString2}!` //你好,世界!
`${myString1}, ${myString2}!` //你好,世界!
```
你可以使用任意一种方法实现格式化目标,但模板字符串会保留所有空格和换行。
✅ 你会在什么情况下使用模板字符串而不是普通字符串?
**我们来理解每个部分:**
- 使用反引号 `` ` `` 替代普通引号来创建模板字符串
- 直接使用 `${}` 占位符语法嵌入变量
- 精确保留空格和格式
- 提供一种更简洁的方法来构建包含变量的复杂字符串
你可以用上述任一方法实现你的格式需求,但模板字符串会尊重所有空格和换行。
✅ 什么时候你会选择使用模板字符串而非普通字符串?
### 🔤 **字符串掌握检测:文本操作自信度**
**评估你的字符串技能:**
- 你能解释为什么 `'1' + '1'` 等于 `'11'` 而不是 `2` 吗?
- 你觉得哪种字符串方法更易读:连接符还是模板字符串?
- 如果忘记给字符串加引号,会发生什么?
```mermaid
stateDiagram-v2
[*] --> PlainText: "你好"
[*] --> Variable: name = "Alice"
PlainText --> Concatenated: + " " + name
Variable --> Concatenated
PlainText --> Template: `你好 ${name}`
Variable --> Template
Concatenated --> Result: "你好 Alice"
Template --> Result
note right of Concatenated
传统方法
更冗长
end note
note right of Template
现代 ES6 语法
更简洁且易读
end note
```
> **专家提示**:模板字符串通常更适合复杂字符串构建,因为它们更易读且能优雅处理多行字符串!
### 布尔值
布尔值只有两个可能的值:`true` 或 `false`。布尔值可以帮助决定在满足某些条件时运行哪些代码行。在许多情况下,[运算符](../../../../2-js-basics/1-data-types) 会协助设置布尔值,你会经常看到变量在初始化时或其值更新时使用运算符。
布尔值代表最简单的数据形式:它们只能有两个值之一——`true` 或 `false`。这种二元逻辑系统可追溯到19世纪数学家乔治·布尔George Boole开发的布尔代数。
尽管简单,布尔值对程序逻辑至关重要。它们让代码能基于条件做出决策——比如用户是否已登录,是否点击了按钮,或是否满足某些条件。
布尔值只能是两个值之一:`true` 或 `false`。布尔值有助于根据特定条件决定哪些代码行应该运行。在许多情况下,[运算符](../../../../2-js-basics/1-data-types)帮助设置布尔值的值,而你也常会看到并写出变量初始化或使用运算符更新其值。
```javascript
let myTrueBool = true;
let myFalseBool = false;
```
- `let myTrueBool = true`
- `let myFalseBool = false`
**在上例中,我们:**
- **创建**了一个存储布尔值 `true` 的变量
- **演示**了如何存储布尔值 `false`
- **使用**了准确的关键字 `true``false`(无需引号)
- **准备**了这些变量供条件语句使用
✅ 如果一个变量的值被认为是布尔值 `true`,则它可以被视为“真值”。有趣的是,在 JavaScript 中,[所有值都是真值,除非被定义为假值](https://developer.mozilla.org/docs/Glossary/Truthy)。
✅ 如果变量计算结果为布尔 `true`,它可以被认为是“真值”。有趣的是,在 JavaScript 中,[除非定义为假值,否则所有值都是“真值”](https://developer.mozilla.org/docs/Glossary/Truthy)。
```mermaid
flowchart LR
A["🔘 布尔值"] --> B["true"]
A --> C["false"]
D["真值"] --> D1["'hello'"]
D --> D2["42"]
D --> D3["[]"]
D --> D4["{}"]
E["假值"] --> E1["false"]
E --> E2["0"]
E --> E3["''"]
E --> E4["null"]
E --> E5["undefined"]
E --> E6["NaN"]
style B fill:#e8f5e8
style C fill:#ffebee
style D fill:#e3f2fd
style E fill:#fff3e0
```
### 🎯 **布尔逻辑检测:决策能力**
**测试你的布尔理解:**
- 为什么你认为 JavaScript 中有“真值”和“假值”,而不仅仅是 `true``false`
- 你能预测以下哪些是假值吗:`0`、`"0"`、`[]`、`"false"`
- 布尔值如何在控制程序流程中发挥作用?
```mermaid
pie title "常见布尔用例"
"条件逻辑" : 40
"用户状态" : 25
"功能切换" : 20
"验证" : 15
```
> **记住**:在 JavaScript 中,只有 6 个是假值:`false`、`0`、`""`、`null`、`undefined` 和 `NaN`。其他全部是真值!
---
## 📊 **你的数据类型工具包总结**
```mermaid
graph TD
A["🎯 JavaScript 数据类型"] --> B["📦 变量"]
A --> C["🔢 数字"]
A --> D["📝 字符串"]
A --> E["🔘 布尔值"]
B --> B1["let 可变"]
B --> B2["const 不可变"]
C --> C1["423.14-5"]
C --> C2["+ - * / %"]
D --> D1["'单引号' 或 \\\"双引号\\\""]
D --> D2["`模板字符串`"]
E --> E1["true 或 false"]
E --> E2["真值与假值"]
F["⚡ 关键概念"] --> F1["类型对操作很重要"]
F --> F2["JavaScript 是动态类型"]
F --> F3["变量可以改变类型"]
F --> F4["命名区分大小写"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 创建一个个人信息管理程序,演示本课中学到的所有 JavaScript 数据类型,同时处理实际数据场景。
**提示:** 构建一个 JavaScript 程序,创建一个用户资料对象,包含:个人姓名(字符串)、年龄(数字)、是否为学生状态(布尔)、喜爱的颜色数组,以及含有街道、城市和邮编属性的地址对象。包括显示资料信息和更新各字段的函数。确保演示字符串连接、模板字符串、年龄的算术操作,以及学生状态的布尔逻辑。
了解更多关于[Agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
JavaScript 因其在处理数据类型时的一些令人惊讶的方式而臭名昭著。研究一下这些“陷阱”。例如:大小写敏感可能会让你吃亏!在控制台中试试这个:`let age = 1; let Age = 2; age == Age`(结果是 `false` —— 为什么?)。你还能找到哪些陷阱?
JavaScript 有一些行为可能让开发者措手不及。这里有一个经典范例:试着在浏览器控制台输入:`let age = 1; let Age = 2; age == Age`,然后观察结果。它返回 `false` —— 你能找出原因吗?
这代表了许多值得理解的 JavaScript 行为熟悉这些怪癖将帮助你写出更可靠的代码,更高效地调试问题。
## 课后测验
## 课后测验
[课后测验](https://ff-quizzes.netlify.app)
## 复习与自学
查看[这份 JavaScript 练习列表](https://css-tricks.com/snippets/javascript/)并尝试完成其中一个。你学到了什么?
看看[这份 JavaScript 练习列表](https://css-tricks.com/snippets/javascript/),尝试其中一个。你学到了什么?
## 作业
[数据类型练习](assignment.md)
## 🚀 你的 JavaScript 数据类型掌握时间表
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开浏览器控制台,创建 3 个不同数据类型的变量
- [ ] 尝试挑战题:`let age = 1; let Age = 2; age == Age`,并找出为什么结果是 false
- [ ] 练习用名字和喜欢的数字进行字符串连接
- [ ] 测试将数字加到字符串上会发生什么
### 🎯 **这小时你可以完成什么**
- [ ] 完成课后测验并复习任何有疑惑的概念
- [ ] 创建一个简单计算器,实现加减乘除两数运算
- [ ] 使用模板字符串构建简单的姓名格式化器
- [ ] 探索 `==``===` 比较运算符的区别
- [ ] 练习不同数据类型之间的转换
### 📅 **你的一周 JavaScript 基础**
- [ ] 自信且富有创造力地完成作业
- [ ] 创建一个包含所有学过数据类型的个人资料对象
- [ ] 练习使用[来自 CSS-Tricks 的 JavaScript 练习](https://css-tricks.com/snippets/javascript/)
- [ ] 构建一个使用布尔逻辑的简单表单验证器
- [ ] 试验数组和对象数据类型(预览后续课程)
- [ ] 加入 JavaScript 社区,提出关于数据类型的问题
### 🌟 **你一个月的转变**
- [ ] 将数据类型知识融入更大型的编程项目
- [ ] 理解何时以及为何在实际应用中使用每种数据类型
- [ ] 帮助其他初学者理解 JavaScript 基础
- [ ] 构建一个管理不同类型用户数据的小应用
- [ ] 探索高级数据类型概念,如类型强制转换和严格相等
- [ ] 参与开源 JavaScript 项目的文档改进
### 🧠 **最终数据类型掌握检测**
**庆祝你的 JavaScript 基础:**
- 哪种数据类型的行为让你最感惊讶?
- 你讲解变量与常量的区别给朋友时感觉如何?
- 关于 JavaScript 的类型系统你发现的最有趣的事情是什么?
- 你能想象用这些基础构建什么实际应用?
```mermaid
journey
title 你的 JavaScript 信心之旅
section 今天
困惑: 3: You
好奇: 4: You
兴奋: 5: You
section 本周
练习中: 4: You
理解中: 5: You
构建中: 5: You
section 下个月
解决问题: 5: You
教授他人: 5: You
实际项目: 5: You
```
> 💡 **你已经打好了基础!** 了解数据类型就像学字母表为写故事做准备。你写的每个 JavaScript 程序都会用到这些基本概念。你现在拥有构建交互式网站、动态应用以及用代码解决实际问题的基石。欢迎来到奇妙的 JavaScript 世界! 🎉
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用人工智能翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。应以原始语言的原版文件为权威来源。对于关键信息,建议寻求专业人工翻译。因使用本翻译而产生的任何误解或误译,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,25 +1,103 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "de0ec12c337394806425c7fd2f003b62",
"translation_date": "2025-10-03T08:48:13+00:00",
"original_hash": "6fd645e97c48cd5eb5a3d290815ec8b5",
"translation_date": "2026-01-06T11:14:42+00:00",
"source_file": "2-js-basics/1-data-types/assignment.md",
"language_code": "zh"
}
-->
# 数据类型练习
# 数据类型练习:电子商务购物车
## 说明
假设你正在构建一个购物车。编写关于完成购物体验所需数据类型的文档。对于每种数据类型,解释如何以及为什么使用它,并提供一个示例。六种 JavaScript 数据类型分别是String、Number、Boolean、Null、Undefined 和 Object
想象你正在构建一个现代的电子商务购物车系统。此作业将帮助你理解不同的 JavaScript 数据类型如何协同工作以创建真实世界的应用程序
## 评分标准
### 你的任务
标准 | 卓越 | 合格 | 需要改进
--- | --- | --- | --- |
数据类型 | 六种数据类型均被列出,详细探讨并附有示例 | 探讨了四种数据类型并有一定解释 | 仅探讨了两种数据类型且解释较少 |
创建一个关于如何在购物车应用中使用 JavaScript 数据类型的全面分析。针对七种原始数据类型和对象,你需要:
1. **识别** 数据类型及其用途
2. **解释** 为什么这种数据类型是特定购物车功能的最佳选择
3. **提供** 展示该数据类型使用的真实代码示例
4. **描述** 这种数据类型如何与购物车的其他部分交互
### 需要涵盖的数据类型
**原始数据类型:**
- **String**:产品名称、描述、用户信息
- **Number**:价格、数量、税费计算
- **Boolean**:商品可用性、用户偏好、购物车状态
- **Null**:有意为空的值(如缺失的折扣代码)
- **Undefined**:未初始化的值或缺失的数据
- **Symbol**:唯一标识符(高级用法)
- **BigInt**:大额财务计算(高级用法)
**引用类型:**
- **Object**:产品详情、用户资料、购物车内容
- **Array**:产品列表、订单历史、分类
### 每种数据类型的示例格式
对于每个数据类型,按如下结构组织你的回应:
```markdown
## [Data Type Name]
**Purpose in Shopping Cart:** [Explain what this data type does]
**Why This Type:** [Explain why this is the best choice]
**Code Example:**
```javascript
// Your realistic code example here
```
**实际应用:** [描述该数据类型在实践中的工作方式]
**交互关系:** [解释该数据类型如何与其他数据类型协作]
```
### Bonus Challenges
1. **Type Coercion**: Show an example where JavaScript automatically converts between data types in your shopping cart (e.g., string "5" + number 10)
2. **Data Validation**: Demonstrate how you would check if user input is the correct data type before processing
3. **Performance Considerations**: Explain when you might choose one data type over another for performance reasons
### Submission Guidelines
- Create a markdown document with clear headings for each data type
- Include working JavaScript code examples
- Use realistic e-commerce scenarios in your examples
- Explain your reasoning clearly for beginners to understand
- Test your code examples to ensure they work correctly
## Rubric
| Criteria | Exemplary (90-100%) | Proficient (80-89%) | Developing (70-79%) | Needs Improvement (Below 70%) |
|----------|---------------------|---------------------|---------------------|------------------------------|
| **Data Type Coverage** | All 7 primitive types and objects/arrays covered with detailed explanations | 6-7 data types covered with good explanations | 4-5 data types covered with basic explanations | Fewer than 4 data types or minimal explanations |
| **Code Examples** | All examples are realistic, working, and well-commented | Most examples work and are relevant to e-commerce | Some examples work but may be generic | Code examples are incomplete or non-functional |
| **Real-world Application** | Clearly connects each data type to practical shopping cart features | Good connection to e-commerce scenarios | Some connection to shopping cart context | Limited real-world application demonstrated |
| **Technical Accuracy** | All technical information is correct and demonstrates deep understanding | Most technical information is accurate | Generally accurate with minor errors | Contains significant technical errors |
| **Communication** | Explanations are clear, beginner-friendly, and well-organized | Good explanations that are mostly clear | Explanations are understandable but may lack clarity | Explanations are unclear or poorly organized |
| **Bonus Elements** | Includes multiple bonus challenges with excellent execution | Includes one or more bonus challenges well done | Attempts bonus challenges with mixed success | No bonus challenges attempted |
### Learning Objectives
By completing this assignment, you will:
- ✅ **Understand** the seven JavaScript primitive data types and their uses
- ✅ **Apply** data types to real-world programming scenarios
- ✅ **Analyze** when to choose specific data types for different purposes
- ✅ **Create** working code examples that demonstrate data type usage
- ✅ **Explain** technical concepts in beginner-friendly language
- ✅ **Connect** fundamental programming concepts to practical applications
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译完成。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威来源。对于关键内容,建议使用专业人工翻译。因使用本翻译所引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,45 +1,105 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "92e136090efc4341b1d51c37924c1802",
"translation_date": "2025-08-29T14:47:51+00:00",
"original_hash": "71f7d7dafa1c7194d79ddac87f669ff9",
"translation_date": "2026-01-06T11:10:57+00:00",
"source_file": "2-js-basics/2-functions-methods/README.md",
"language_code": "zh"
}
-->
# JavaScript基础方法和函数
![JavaScript基础 - 函数](../../../../translated_images/webdev101-js-functions.be049c4726e94f8b7605c36330ac42eeb5cd8ed02bcdd60fdac778174d6cb865.zh.png)
> [Tomomi Imura](https://twitter.com/girlie_mac) 的手绘笔记
# JavaScript 基础:方法与函数
![JavaScript Basics - Functions](../../../../translated_images/webdev101-js-functions.be049c4726e94f8b.zh.png)
> 速记图由 [Tomomi Imura](https://twitter.com/girlie_mac) 制作
```mermaid
journey
title 你的JavaScript函数冒险
section 基础
Function Syntax: 5: You
Calling Functions: 4: You
Parameters & Arguments: 5: You
section 高级概念
Return Values: 4: You
Default Parameters: 5: You
Function Composition: 4: You
section 现代JavaScript
Arrow Functions: 5: You
Anonymous Functions: 4: You
Higher-Order Functions: 5: You
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app)
在编写代码时,我们总是希望代码易于阅读。虽然这听起来有些反直觉,但代码被阅读的次数远远多于被编写的次数。开发者工具箱中的一个核心工具,用于确保代码可维护性,就是**函数**。
[![方法和函数](https://img.youtube.com/vi/XgKsD6Zwvlc/0.jpg)](https://youtube.com/watch?v=XgKsD6Zwvlc "方法和函数")
> 🎥 点击上方图片观看关于方法和函数的视频。
> 你可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-functions/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
重复写同样的代码是编程中最常见的挫败感之一。函数解决了这个问题,它让你把代码打包成可重复使用的块。把函数想象成使亨利·福特的装配线革命化的标准化零件——一旦你创建了一个可靠的组件,就可以在任何需要的地方使用它,而不必重新构建。
函数允许你把一段代码打包,这样你就能在整个程序中重复使用它们。你不用到处复制粘贴相同的逻辑,而是创建一个函数,然后在需要时调用它。这种方法让你的代码更有条理,也更容易维护。
在本课中,你将学习如何创建自己的函数、如何传递信息给它们以及如何从中获取有用的结果。你会发现函数和方法的区别,学习现代的语法写法,并看到函数是如何与其他函数协作的。我们将一步步构建这些概念。
[![方法与函数](https://img.youtube.com/vi/XgKsD6Zwvlc/0.jpg)](https://youtube.com/watch?v=XgKsD6Zwvlc "方法与函数")
> 🎥 点击上方图片查看关于方法与函数的视频。
> 你也可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-functions/?WT.mc_id=academic-77807-sagibbon) 上学习本课内容!
```mermaid
mindmap
root((JavaScript 函数))
Basic Concepts
Declaration
传统语法
箭头函数语法
Calling
使用括号
需要括号
Parameters
Input Values
多个参数
默认值
Arguments
传入的值
可以是任何类型
Return Values
Output Data
return 语句
退出函数
Use Results
存储在变量中
链式调用函数
Advanced Patterns
Higher-Order
函数作为参数
回调函数
Anonymous
无需名称
内联定义
```
## 函数
从本质上讲,函数是一段可以按需执行的代码块。这非常适合需要多次执行相同任务的场景;与其在多个地方重复逻辑(这会在需要更新时变得困难),我们可以将其集中在一个位置,并在需要执行操作时调用它——甚至可以从其他函数中调用函数!
函数是一个自包含的代码块,用来执行特定任务。它封装了你可以在需要时执行的逻辑。
你不用在程序中多次写相同代码,而是把它打包成函数,按需调用。这样你的代码更整洁,也更易更新。想想看,如果你必须修改散落在代码库中二十个不同位置的逻辑,那维护工作会多么复杂。
同样重要的是为函数命名的能力。虽然这看起来微不足道,但名称为代码段提供了一种快速的文档化方式。你可以将其视为按钮上的标签。如果我点击一个写着“取消计时器”的按钮,我就知道它会停止计时。
给函数起一个描述性名字非常重要。一个名字明确的函数可以清晰表达它的目的——当你看到 `cancelTimer()` 时,你立即知道它是做什么的,就像一个标签清晰的按钮告诉你点击后会发生什么一样
## 创建和调用函数
函数的语法如下所示:
让我们看看如何创建函数。语法遵循固定模式
```javascript
function nameOfFunction() { // function definition
// function definition/body
function nameOfFunction() { // 函数定义
// 函数定义/函数体
}
```
如果我想创建一个函数来显示问候语,它可能看起来像这样:
我们来拆解一下:
- `function` 关键字告诉 JavaScript “嘿,我正在创建一个函数!”
- `nameOfFunction` 是你给函数起的描述性名字
- 括号 `()` 是你可以添加参数的位置(我们稍后会讲)
- 花括号 `{}` 包含当你调用函数时执行的实际代码
让我们创建一个简单的问候函数,看看效果:
```javascript
function displayGreeting() {
@ -47,28 +107,57 @@ function displayGreeting() {
}
```
每当我们想要调用(或执行)函数时,我们使用函数名称后跟 `()`。值得注意的是我们的函数可以在调用之前或之后定义JavaScript编译器会帮你找到它。
这个函数会在控制台打印 "Hello, world!"。定义之后,你可以根据需要多次使用它。
要执行或“调用”函数写函数名后接括号。JavaScript 允许你先调用函数后定义JavaScript 引擎会处理执行顺序。
```javascript
// calling our function
// 调用我们的函数
displayGreeting();
```
> **NOTE:** 有一种特殊类型的函数称为**方法**,你已经在使用了!事实上,我们在上面的演示中使用 `console.log` 时就看到了这一点。方法与函数的不同之处在于,方法附属于一个对象(在我们的例子中是 `console`),而函数是独立的。你会发现许多开发者会将这些术语互换使用。
运行这行代码时,它会执行 `displayGreeting` 函数里的所有代码,在浏览器控制台显示 "Hello, world!"。你可以反复调用这个函数。
### 🧠 **函数基础检测:构建你的第一个函数**
**来测试你对基本函数的理解:**
- 为什么函数定义中要用花括号 `{}`
- 如果只写 `displayGreeting` 而不加括号,会发生什么?
- 为什么你可能想多次调用同一个函数?
```mermaid
flowchart TD
A["✏️ 定义函数"] --> B["📦 打包代码"]
B --> C["🏷️ 给它命名"]
C --> D["📞 需要时调用"]
D --> E["🔄 任意重用"]
F["💡 好处"] --> F1["无代码重复"]
F --> F2["易于维护"]
F --> F3["组织清晰"]
F --> F4["测试更简单"]
style A fill:#e3f2fd
style E fill:#e8f5e8
style F fill:#fff3e0
```
> **注意:** 在本课程中,你一直在使用**方法**。`console.log()` 是一个方法——本质上是属于 `console` 对象的函数。关键区别是方法附属于对象,而函数是独立存在的。很多开发者在日常对话中会混用这两个词。
### 函数的最佳实践
### 函数最佳实践
创建函数时需要牢记一些最佳实践:
这里有几个帮助你写出优秀函数的小贴士
- 一如既往地使用描述性名称,这样你就知道函数会做什么
- 使用**驼峰命名法**来组合单词
- 让你的函数专注于一个特定任务
- 给函数起清晰、描述明确的名字——未来的你会感谢自己!
- 多单词名称使用**驼峰式命名**(比如用 `calculateTotal`,而不是 `calculate_total`
- 每个函数专注做好一件事
## 向函数传递信息
## 函数传递信息
为了让函数更具可重用性,你通常会希望向其传递信息。如果我们考虑上面的 `displayGreeting` 示例,它只会显示 **Hello, world!**。这并不是一个最有用的函数。如果我们想让它更灵活,比如允许指定要问候的人的名字,我们可以添加一个**参数**。参数(有时也称为**实参**)是传递给函数的额外信息。
我们的 `displayGreeting` 函数很有限——它只能显示 “Hello, world!”。参数让函数更灵活更有用
参数在定义部分列出,括号内用逗号分隔,如下所示:
**参数** 就像占位符,每次调用函数时可以传入不同的值。这样同一个函数每次调用可以使用不同的信息。
定义函数时,你在括号里列出参数,多个参数用逗号分隔:
```javascript
function name(param, param2, param3) {
@ -76,7 +165,9 @@ function name(param, param2, param3) {
}
```
我们可以更新 `displayGreeting` 来接受一个名字并显示它。
每个参数像个占位符——调用函数时,调用者会提供实际值,填入这些位置。
让我们把问候函数改造一下,能接收一个人的名字:
```javascript
function displayGreeting(name) {
@ -85,16 +176,44 @@ function displayGreeting(name) {
}
```
当我们想要调用函数并传递参数时,我们在括号中指定它。
你会注意到我们使用了反引号 (`` ` ``) 和 `${}` 来直接把名字插入消息中——这叫模板字符串,是构建带变量字符串的很方便方式。
现在调用时,我们可以传入任意名字:
```javascript
displayGreeting('Christopher');
// displays "Hello, Christopher!" when run
// 运行时显示 “你好Christopher
```
JavaScript 将字符串 `'Christopher'` 赋值给参数 `name`,生成个性化消息 "Hello, Christopher!"
```mermaid
flowchart LR
A["🎯 函数调用"] --> B["📥 参数"]
B --> C["⚙️ 函数体"]
C --> D["📤 结果"]
A1["displayGreeting('Alice')"] --> A
B1["name = 'Alice'"] --> B
C1["模板字面量\n\`Hello, \${name}!\`"] --> C
D1["'Hello, Alice!'"] --> D
E["🔄 参数类型"] --> E1["字符串"]
E --> E2["数字"]
E --> E3["布尔值"]
E --> E4["对象"]
E --> E5["函数"]
style A fill:#e3f2fd
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#f3e5f5
```
## 默认值
我们可以通过添加更多参数使函数更加灵活。但如果我们不希望每个值都必须指定呢?继续使用问候语的例子,我们可以将名字设为必需(我们需要知道要问候谁),但希望允许问候语根据需要进行自定义。如果有人不想自定义,我们可以提供一个默认值。要为参数提供默认值,我们设置它的方式与为变量设置值类似——`parameterName = 'defaultValue'`。完整示例如下:
如果我们想让某些参数可选怎么办?这时默认值很有用!
假设我们希望用户能自定义问候语,但如果没指定,就默认用 "Hello"。你可以用等号设置默认值,就像变量赋值一样:
```javascript
function displayGreeting(name, salutation='Hello') {
@ -102,29 +221,63 @@ function displayGreeting(name, salutation='Hello') {
}
```
当我们调用函数时,可以决定是否为 `salutation` 设置值。
这里,`name` 仍是必需的,`salutation` 则有默认的 `'Hello'`,如果调用者不传就用默认值。
这样我们可以用两种方式调用函数:
```javascript
displayGreeting('Christopher');
// displays "Hello, Christopher"
// 显示 "Hello, Christopher"
displayGreeting('Christopher', 'Hi');
// displays "Hi, Christopher"
// 显示 "Hi, Christopher"
```
第一次调用没传问候语JavaScript 用默认的 "Hello"。第二次调用传了 "Hi",它就用这个自定义值。这种灵活性让函数能适应不同场景。
### 🎛️ **参数掌握检测:让函数更灵活**
**考考你对参数的理解:**
- 参数和实参有什么区别?
- 为什么默认值在实际编程中有用?
- 如果传入的实参比参数多,会发生什么?
```mermaid
stateDiagram-v2
[*] --> NoParams: function greet() {}
[*] --> WithParams: function greet(name) {}
[*] --> WithDefaults: function greet(name, greeting='Hi') {}
NoParams --> Static: 始终相同的输出
WithParams --> Dynamic: 随输入变化
WithDefaults --> Flexible: 可选的自定义
Static --> [*]
Dynamic --> [*]
Flexible --> [*]
note right of WithDefaults
最灵活的方法
向后兼容
end note
```
> **专业提示**:默认参数让函数对用户更友好,用户可以快速开始,用合适的默认值,但也能按需自定义!
## 返回值
到目前为止,我们构建的函数总是输出到 [console](https://developer.mozilla.org/docs/Web/API/console)。有时这正是我们想要的,尤其是当我们创建会调用其他服务的函数时。但如果我想创建一个辅助函数来执行计算并返回值,以便在其他地方使用呢?
到目前为止我们的函数只是打印消息,但万一你想让函数计算并返回结果呢?
我们可以通过使用**返回值**来实现这一点。返回值由函数返回,可以像存储字符串或数字这样的字面值一样存储在变量中。
这就用到**返回值**。函数不仅可以显示内容,还能返回值,你可以把返回值存到变量里,或者用于代码的其他部分
如果函数确实返回某些内容,则使用关键字 `return`。`return` 关键字需要一个值或引用来返回,如下所示:
使用 `return` 关键字,后面跟你想返回的值
```javascript
return myVariable;
```
```
我们可以创建一个函数来生成问候语并将值返回给调用者。
这里需要注意的是:函数遇到 `return` 语句,会立即停止执行,并把那个值返回给调用它的人。
来修改一下问候函数,不打印只返回消息:
```javascript
function createGreetingMessage(name) {
@ -133,35 +286,81 @@ function createGreetingMessage(name) {
}
```
调用此函数时,我们会将值存储在变量中。这与我们将变量设置为静态值(例如 `const name = 'Christopher'`)的方式非常相似。
这个函数不打印消息,而是构造消息并返回给调用方。
要用返回值,我们可以像处理其他值一样,把它存到变量里:
```javascript
const greetingMessage = createGreetingMessage('Christopher');
```
## 函数作为函数的参数
现在 `greetingMessage` 变量里保存了 "Hello, Christopher",我们可以在代码里任何地方使用——网页中显示,发送邮件,或者传给其他函数。
```mermaid
flowchart TD
A["🔧 函数处理"] --> B{"return 语句?"}
B -->|是| C["📤 返回值"]
B -->|否| D["📭 返回 undefined"]
C --> E["💾 存储在变量中"]
C --> F["🔗 在表达式中使用"]
C --> G["📞 传递给函数"]
D --> H["⚠️ 通常没有用处"]
I["📋 返回值的用途"] --> I1["计算结果"]
I --> I2["验证输入"]
I --> I3["转换数据"]
I --> I4["创建对象"]
style C fill:#e8f5e8
style D fill:#ffebee
style I fill:#e3f2fd
```
### 🔄 **返回值检测:拿回结果**
**评估你对返回值的理解:**
- 函数里 `return` 后的代码会怎样?
- 为什么返回值通常比只打印更好?
- 函数能返回不同类型的值(字符串、数字、布尔)吗?
```mermaid
pie title "常见返回值类型"
"字符串" : 30
"数字" : 25
"对象" : 20
"布尔值" : 15
"数组" : 10
```
> **关键洞察**:返回值的函数更灵活,调用方决定如何处理结果。这让代码更模块化,更易复用!
## 作为参数的函数
随着编程技能的提升,你会遇到接受函数作为参数的函数。这种巧妙的技巧通常用于我们不知道某件事情何时发生或完成,但我们知道需要在响应中执行某个操作的场景。
函数可以作为参数传递给其他函数。刚开始这可能有点复杂,但这是个强大特性,能实现灵活的编程模式
例如,考虑 [setTimeout](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout),它启动一个计时器并在完成时执行代码。我们需要告诉它我们想要执行什么代码。这听起来是一个完美的函数任务!
这种模式很常见,比如你想说“当某事发生时,执行另一段代码”。比如,“计时结束时执行这段代码”,“用户点击按钮时调用这个函数”。
如果运行下面的代码3秒后你会看到消息 **3秒已过去**
来看 `setTimeout`,这是一个内置函数,会等待一段时间再运行代码。你得告诉它跑什么代码——传函数给它就是完美用法!
试试这段代码3秒后你会看到消息
```javascript
function displayDone() {
console.log('3 seconds has elapsed');
}
// timer value is in milliseconds
// 定时器值以毫秒为单位
setTimeout(displayDone, 3000);
```
注意我们把 `displayDone`(没有括号)传给 `setTimeout`。我们不是自己调用它,而是把函数交给 `setTimeout`让它3秒后调用。
### 匿名函数
让我们再看看我们构建的内容。我们创建了一个带有名称的函数,该函数将被使用一次。随着应用程序变得更加复杂,我们可能会创建许多只会被调用一次的函数。这并不理想。事实证明,我们并不总是需要提供名称!
有时候你只用一次函数,不想给它起名字。想想看——只用一次,为何要额外起一个名字占用代码空间?
当我们将函数作为参数传递时,可以跳过提前创建它,而是在参数中直接构建它。我们使用相同的 `function` 关键字,但将其作为参数构建。
JavaScript 支持**匿名函数**——没有名字的函数,你可以直接在需要的地方定义它们
让我们重写上面的代码以使用匿名函数:
改写上面计时例子,使用匿名函数:
```javascript
setTimeout(function() {
@ -169,13 +368,15 @@ setTimeout(function() {
}, 3000);
```
如果运行我们的新代码,你会注意到结果是一样的。我们创建了一个函数,但不需要给它命名!
效果一样,但函数定义直接写在 `setTimeout` 调用里,不需分开声明函数。
### 箭头函数
许多编程语言包括JavaScript中常见的一个快捷方式是使用所谓的**箭头**或**胖箭头**函数。它使用一个特殊的符号 `=>`,看起来像一个箭头——因此得名!通过使用 `=>`,我们可以跳过 `function` 关键字。
现代 JavaScript 有更简短的函数写法,叫**箭头函数**。它用 `=>`(看起来像箭头——你懂的)表示,开发者极其喜欢用。
箭头函数省略了 `function` 关键字,写起代码更简洁。
让我们再一次重写代码以使用箭头函数:
这就是用箭头函数写的计时例子
```javascript
setTimeout(() => {
@ -183,28 +384,200 @@ setTimeout(() => {
}, 3000);
```
### 何时使用每种策略
你现在已经看到我们有三种将函数作为参数传递的方法,可能会想知道何时使用哪一种。如果你知道函数会被多次使用,就正常创建它。如果只会在一个地方使用,通常最好使用匿名函数。至于使用箭头函数还是传统的 `function` 语法,这取决于你,但你会发现大多数现代开发者更喜欢 `=>`
`()` 里放参数(这里空着),接箭头 `=>`,最后是花括号里的函数体。功能一样,语法更紧凑。
```mermaid
flowchart LR
A["📝 函数风格"] --> B["传统"]
A --> C["箭头"]
A --> D["匿名"]
B --> B1["function name() {}"]
B --> B2["提升的"]
B --> B3["有名的"]
C --> C1["const name = () => {}"]
C --> C2["简洁语法"]
C --> C3["现代风格"]
D --> D1["function() {}"]
D --> D2["无名称"]
D --> D3["一次性使用"]
E["⏰ 何时使用"] --> E1["传统:可重用函数"]
E --> E2["箭头:简短回调"]
E --> E3["匿名:事件处理器"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
```
### 何时使用哪种写法
什么时候用哪种?一个实用指南是:如果你要多次调用一个函数,给它起名并单独定义;若只用一次,可以考虑匿名函数。箭头函数和传统语法都有效,但箭头函数是现代代码的主流。
### 🎨 **函数风格掌握检测:选择合适的语法**
**考考你对语法的理解:**
- 什么时候你更喜欢用箭头函数?
- 匿名函数的最大优势是什么?
- 你能想到啥场景中有名函数优于匿名函数?
```mermaid
quadrantChart
title 函数选择决策矩阵
x-axis 简单 --> 复杂
y-axis 一次性使用 --> 可复用
quadrant-1 箭头函数
quadrant-2 命名函数
quadrant-3 匿名函数
quadrant-4 传统函数
Event Handlers: [0.3, 0.2]
Utility Functions: [0.7, 0.8]
Callbacks: [0.2, 0.3]
Class Methods: [0.8, 0.7]
Mathematical Operations: [0.4, 0.6]
```
> **现代趋势**:箭头函数因为简洁,成为许多开发者的默认选择,但传统函数依然有用武之地!
---
## 🚀 挑战
你能用一句话说明函数和方法的区别吗?试试看!
你能用一句话说清函数和方法的区别吗?试试看!
## GitHub Copilot Agent 挑战 🚀
用 Agent 模式完成以下挑战:
**描述:** 创建一个数学函数工具库,演示本课中涉及的函数概念,包括参数、默认值、返回值和箭头函数。
**提示:** 创建一个叫 `mathUtils.js` 的 JavaScript 文件,包含以下函数:
1. 一个 `add` 函数,接受两个参数,返回它们的和
2. 一个带默认参数值的 `multiply` 函数第二个参数默认是1
3. 一个箭头函数 `square`,接受一个数字返回它的平方
4. 一个 `calculate` 函数,接受另一个函数和两个数字作为参数,然后对这两个数字应用该函数
5. 展示对每个函数的调用示例和测试用例
了解更多关于 [agent模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app)
## 复习与自学
值得[多了解一下箭头函数](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions),因为它们在代码库中越来越常用。练习编写一个函数,然后用这种语法重写它。
值得[多读一些箭头函数](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions)的内容,因为它们在代码库中用得越来越多。练习写函数,然后用这种语法改写
## 作业
[函数趣味练习](assignment.md)
[Fun with Functions](assignment.md)
---
## 🧰 **你的 JavaScript 函数工具包总结**
```mermaid
graph TD
A["🎯 JavaScript 函数"] --> B["📋 函数声明"]
A --> C["📥 参数"]
A --> D["📤 返回值"]
A --> E["🎨 现代语法"]
B --> B1["function name() {}"]
B --> B2["描述性命名"]
B --> B3["可重用代码块"]
C --> C1["输入数据"]
C --> C2["默认值"]
C --> C3["多个参数"]
D --> D1["return 语句"]
D --> D2["退出函数"]
D --> D3["传回数据"]
E --> E1["箭头函数: () =>"]
E --> E2["匿名函数"]
E --> E3["高阶函数"]
F["⚡ 关键优势"] --> F1["代码重用性"]
F --> F2["更好组织"]
F --> F3["更易测试"]
F --> F4["模块化设计"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
---
## 🚀 你的 JavaScript 函数掌握时间线
### ⚡ **接下来 5 分钟你可以做的事**
- [ ] 写一个简单函数,返回你最喜欢的数字
- [ ] 创建一个有两个参数的函数,把它们相加
- [ ] 尝试将传统函数转换为箭头函数语法
- [ ] 练习挑战:解释函数和方法之间的区别
### 🎯 **你这小时可以完成的目标**
- [ ] 完成课后测验并复习任何令人困惑的概念
- [ ] 构建 GitHub Copilot 挑战中的数学工具库
- [ ] 创建一个使用另一个函数作为参数的函数
- [ ] 练习编写带有默认参数的函数
- [ ] 试验在函数返回值中使用模板字符串
### 📅 **你的一周函数精通计划**
- [ ] 富有创造性地完成“函数的乐趣”作业
- [ ] 将你编写的一些重复代码重构为可重用函数
- [ ] 仅使用函数构建一个小型计算器(无全局变量)
- [ ] 练习使用数组方法如 `map()``filter()` 的箭头函数
- [ ] 创建一组用于常见任务的实用函数集合
- [ ] 学习高阶函数和函数式编程概念
### 🌟 **你的一月转变计划**
- [ ] 掌握高级函数概念,如闭包和作用域
- [ ] 构建一个大量使用函数组合的项目
- [ ] 通过改进函数文档为开源项目做贡献
- [ ] 教别人函数及不同语法风格的知识
- [ ] 探索 JavaScript 中的函数式编程范式
- [ ] 创建一个个人可重用函数库以备将来项目使用
### 🏆 **终极函数大师签到**
**庆祝你的函数掌握成就:**
- 到目前为止,你写过的最有用的函数是什么?
- 学习函数如何改变了你对代码组织的思考?
- 你喜欢哪种函数语法,为什么?
- 你会通过写函数解决什么现实世界的问题?
```mermaid
journey
title 你的函数信心演变
section 今天
语法困惑: 3: 你
理解基础: 4: 你
编写简单函数: 5: 你
section 本周
使用参数: 4: 你
返回值: 5: 你
现代语法: 5: 你
section 下个月
函数组合: 5: 你
高级模式: 5: 你
教授他人: 5: 你
```
> 🎉 **你已掌握编程中最强大的概念之一!** 函数是更大程序的构建模块。你将创建的每个应用程序都会使用函数来组织、重用和结构化代码。你现在理解了如何将逻辑打包成可重用的组件,这使你成为一个更高效、更有效的程序员。欢迎来到模块化编程的世界!🚀
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译完成。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。应以原始语言的文档为权威来源。对于重要信息,建议采用专业人工翻译。我们对因使用本翻译而产生的任何误解或误释不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,25 +1,82 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "8973f96157680a13e9446e4bb540ee57",
"translation_date": "2025-08-23T22:42:45+00:00",
"original_hash": "8328f58f4593b4671656ff8f4b2edbd9",
"translation_date": "2026-01-06T11:12:43+00:00",
"source_file": "2-js-basics/2-functions-methods/assignment.md",
"language_code": "zh"
}
-->
# 玩转函数
# 有趣的函数
## 说明
创建不同的函数,包括返回值的函数和不返回值的函数
在本次作业中,你将练习创建不同类型的函数,以巩固你所学的 JavaScript 函数、参数、默认值和返回语句的概念
试着创建一个包含普通参数和带默认值参数的混合函数。
创建一个名为 `functions-practice.js` 的 JavaScript 文件,并实现以下函数:
### 第一部分:基础函数
1. **创建一个名为 `sayHello` 的函数**,该函数不接受任何参数,仅在控制台输出 "Hello!"。
2. **创建一个名为 `introduceYourself` 的函数**,该函数接受一个 `name` 参数,并在控制台输出类似 "Hi, my name is [name]" 的消息。
### 第二部分:带默认参数的函数
3. **创建一个名为 `greetPerson` 的函数**,它接受两个参数:`name`(必需)和 `greeting`(可选,默认为 "Hello")。该函数应在控制台输出类似 "[greeting], [name]!" 的消息。
### 第三部分:返回值的函数
4. **创建一个名为 `addNumbers` 的函数**,它接受两个参数(`num1` 和 `num2`)并返回它们的和。
5. **创建一个名为 `createFullName` 的函数**,它接受 `firstName``lastName` 参数并返回一个完整的全名字符串。
### 第四部分:综合练习
6. **创建一个名为 `calculateTip` 的函数**,它接受两个参数:`billAmount`(必需)和 `tipPercentage`(可选,默认为 15。该函数应计算并返回小费金额。
### 第五部分:测试你的函数
添加函数调用,测试每个函数并使用 `console.log()` 显示结果。
**示例测试调用:**
```javascript
// 在这里测试你的函数
sayHello();
introduceYourself("Sarah");
greetPerson("Alex");
greetPerson("Maria", "Hi");
const sum = addNumbers(5, 3);
console.log(`The sum is: ${sum}`);
const fullName = createFullName("John", "Doe");
console.log(`Full name: ${fullName}`);
const tip = calculateTip(50);
console.log(`Tip for $50 bill: $${tip}`);
```
## 评分标准
| 标准 | 优秀 | 合格 | 需改进 |
| -------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------- |
| | 提供了两个或更多性能良好的函数,且参数多样化 | 提供了一个可运行的函数,参数较少 | 解决方案存在问题 |
| 标准 | 优秀 | 及格 | 需改进 |
| -------- | --------- | -------- | ----------------- |
| **函数创建** | 所有 6 个函数均正确实现,语法和命名规范正确 | 4-5 个函数正确实现,语法有轻微问题 | 实现 3 个或更少函数,或存在严重语法错误 |
| **参数和默认值** | 正确使用必需参数、可选参数和默认值 | 参数使用正确但默认值存在问题 | 参数实现不正确或缺失 |
| **返回值** | 应返回值的函数正确返回,不应返回值的函数仅执行操作 | 大多数返回值正确,有轻微问题 | 返回语句有重大问题 |
| **代码质量** | 代码干净、结构良好,变量名有意义,缩进正确 | 代码能工作但可更清晰或更好组织 | 代码难以阅读或结构差 |
| **测试** | 所有函数均使用合适的调用进行测试,结果清晰展示 | 大多数函数测试充分 | 测试有限或测试错误 |
## 额外挑战(可选)
如果你想进一步挑战自己:
1. **创建一个箭头函数版本** 的某个函数
2. **创建一个接受另一个函数作为参数的函数**(如课程中的 `setTimeout` 示例)
3. **添加输入验证**,确保你的函数能够优雅地处理无效输入
---
> 💡 **提示**记得打开浏览器的开发者控制台F12查看 `console.log()` 语句的输出!
---
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始语言版本的文件应被视为权威来源。对于重要信息,建议使用专业人工翻译。因使用此翻译而引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,183 +1,477 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "f7009631b73556168ca435120a231c98",
"translation_date": "2025-08-29T14:48:11+00:00",
"original_hash": "c688385d15dd3645e924ea0ffee8967f",
"translation_date": "2026-01-06T11:14:50+00:00",
"source_file": "2-js-basics/3-making-decisions/README.md",
"language_code": "zh"
}
-->
# JavaScript 基础:做出决策
# JavaScript基础做出决策
![JavaScript Basics - Making decisions](../../../../translated_images/webdev101-js-decisions.69e1b20f272dd1f0.zh.png)
> 速写笔记由 [Tomomi Imura](https://twitter.com/girlie_mac) 提供
```mermaid
journey
title 你的 JavaScript 决策冒险
section 基础
布尔值: 5: 你
比较运算符: 4: 你
逻辑思维: 5: 你
section 基本决策
If 语句: 4: 你
If-Else 逻辑: 5: 你
Switch 语句: 4: 你
section 高级逻辑
逻辑运算符: 5: 你
复杂条件: 4: 你
三元表达式: 5: 你
```
你有没有想过应用程序是如何做出智能决策的?比如导航系统如何选择最快路线,或者恒温器如何决定何时开启供暖?这就是编程中决策制定的基本概念。
![JavaScript 基础 - 做出决策](../../../../translated_images/webdev101-js-decisions.69e1b20f272dd1f0b1cb2f8adaff3ed2a77c4f91db96d8a0594132a353fa189a.zh.png)
正如查尔斯·巴贝奇的分析机设计为根据条件执行不同的操作序列一样现代的JavaScript程序也需要根据不同的情况做出选择。分支和决策的能力使得静态代码变成响应型的智能应用程序。
> 由 [Tomomi Imura](https://twitter.com/girlie_mac) 绘制的速记笔记
在本课中,你将学习如何在程序中实现条件逻辑。我们将探讨条件语句、比较运算符和逻辑表达式,让你的代码能够评估情况并做出恰当响应。
## 课前测验
## 课前
[课前测验](https://ff-quizzes.netlify.app/web/quiz/11)
[课前测](https://ff-quizzes.netlify.app/web/quiz/11)
做出决策并控制代码运行的顺序可以让代码更具复用性和稳健性。本节将介绍在 JavaScript 中控制数据流的语法,以及它与布尔数据类型结合使用时的重要性。
做出决策和控制程序流程的能力是编程的基础部分。本节涵盖如何使用布尔值和条件逻辑来控制JavaScript程序的执行路径
[![做出决策](https://img.youtube.com/vi/SxTp8j-fMMY/0.jpg)](https://youtube.com/watch?v=SxTp8j-fMMY "做出决策")
[![Making Decisions](https://img.youtube.com/vi/SxTp8j-fMMY/0.jpg)](https://youtube.com/watch?v=SxTp8j-fMMY "Making Decisions")
> 🎥 点击上方图片观看关于做出决策的视频。
> 你可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-if-else/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
> 你还可以在[Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-if-else/?WT.mc_id=academic-77807-sagibbon)上学习本课程!
```mermaid
mindmap
root((决策制定))
Boolean Logic
true/false
比较结果
逻辑表达式
Conditional Statements
if statements
单一条件
代码执行
if-else
两个路径
替代操作
switch
多个选项
清晰结构
Operators
Comparison
=== !== < > <= >=
值关系
Logical
&& || !
组合条件
Advanced Patterns
Ternary
? : 语法
内联决策
Complex Logic
嵌套条件
多重标准
```
## 布尔值简要回顾
布尔值只有两个可能的值:`true` 或 `false`。布尔值帮助我们决定在满足某些条件时应该运行哪些代码行。
在探讨决策制定前,让我们回顾上一节课提到的布尔值。布尔值以数学家乔治·布尔命名,代表两个二进制状态——`true` 或 `false`。没有模糊,没有中间状态
可以像这样设置布尔值为 true 或 false
这些二进制值构成了所有计算逻辑的基础。你程序中每个决策最终都归结为一次布尔值判断。
`let myTrueBool = true`
`let myFalseBool = false`
创建布尔变量非常简单:
✅ 布尔值以英国数学家、哲学家和逻辑学家 George Boole18151864的名字命名。
```javascript
let myTrueBool = true;
let myFalseBool = false;
```
## 比较运算符与布尔值
这创建了两个明确具有布尔值的变量。
运算符用于通过比较生成布尔值来评估条件。以下是一些常用运算符的列表。
✅ 布尔值以英国数学家、哲学家和逻辑学家乔治·布尔18151864命名
| 符号 | 描述 | 示例 |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- |
| `<` | **小于**:比较两个值,如果左侧值小于右侧值,则返回 `true` 布尔值 | `5 < 6 // true` |
| `<=` | **小于或等于**:比较两个值,如果左侧值小于或等于右侧值,则返回 `true` 布尔值 | `5 <= 6 // true` |
| `>` | **大于**:比较两个值,如果左侧值大于右侧值,则返回 `true` 布尔值 | `5 > 6 // false` |
| `>=` | **大于或等于**:比较两个值,如果左侧值大于或等于右侧值,则返回 `true` 布尔值 | `5 >= 6 // false` |
| `===` | **严格相等**:比较两个值,如果左右两侧的值相等且数据类型相同,则返回 `true` 布尔值 | `5 === 6 // false` |
| `!==` | **不等**:比较两个值,返回与严格相等运算符相反的布尔值 | `5 !== 6 // true` |
## 比较运算符与布尔值
✅ 在浏览器的控制台中写一些比较语句来检查你的知识。返回的数据是否有让你感到意外的地方?
在实际中,你很少手动设置布尔值。相反,你会通过条件判断生成它们:比如“这个数字大于那个吗?”或者“这些值相等吗?”
比较运算符支持这些判断。它们比较两个值并根据操作数之间的关系返回布尔结果。
| 符号 | 描述 | 例子 |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| `<` | **小于**:比较两个值,如果左边的值小于右边,则返回布尔值 `true` | `5 < 6 // true` |
| `<=` | **小于或等于**:比较两个值,如果左边的值小于或等于右边,则返回布尔值 `true` | `5 <= 6 // true` |
| `>` | **大于**:比较两个值,如果左边的值大于右边,则返回布尔值 `true` | `5 > 6 // false` |
| `>=` | **大于或等于**:比较两个值,如果左边的值大于或等于右边,则返回布尔值 `true` | `5 >= 6 // false` |
| `===` | **严格相等**:比较两个值,如果两边的值相等且数据类型相同,返回布尔值 `true` | `5 === 6 // false` |
| `!==` | **不等于**:比较两个值,返回严格相等运算符相反的布尔值 | `5 !== 6 // true` |
✅ 通过在浏览器控制台里写一些比较语句来检验你的理解。有返回结果让你感到惊讶吗?
```mermaid
flowchart LR
A["🔢 值"] --> B["⚖️ 比较"]
B --> C["✅ 布尔结果"]
D["5"] --> E["< 6"]
E --> F["true"]
G["10"] --> H["=== '10'"]
H --> I["false"]
J["'hello'"] --> K["!== 'world'"]
K --> L["true"]
M["📋 操作符类型"] --> M1["相等:=== !=="]
M --> M2["关系:< > <= >="]
M --> M3["严格与宽松"]
style A fill:#e3f2fd
style C fill:#e8f5e8
style M fill:#fff3e0
```
### 🧠 **比较运算理解测试:布尔逻辑掌握**
**测试你的比较理解能力:**
- 为什么一般推荐用 `===` (严格相等) 而不是 `==` (宽松相等)
- 你能预测 `5 === '5'` 返回什么吗?`5 == '5'` 呢?
- `!==``!=` 有什么区别?
```mermaid
stateDiagram-v2
[*] --> Comparison: 两个值
Comparison --> StrictEqual: === 或 !==
Comparison --> Relational: < > <= >=
StrictEqual --> TypeCheck: 检查类型和数值
Relational --> NumberCompare: 转换为数字
TypeCheck --> BooleanResult: true 或 false
NumberCompare --> BooleanResult
note right of StrictEqual
推荐方法
不进行类型转换
end note
note right of Relational
适用于区间
数值比较
end note
```
> **实用建议**:除非需要类型转换,否则总是使用 `===``!==` 进行相等性检查。这能防止意外行为发生!
## If 语句
如果条件为 trueif 语句将运行其块中的代码。
`if` 语句就像在你的代码中提出一个问题。“如果这个条件为真,那么就执行这件事。” 这可能是你在JavaScript中做决策时用得最重要的工具。
运作方式如下:
```javascript
if (condition) {
//Condition is true. Code in this block will run.
// 条件为真。此代码块中的代码将会执行。
}
```
逻辑运算符通常用于构成条件。
条件放在括号内,如果结果为 `true`JavaScript会执行大括号中的代码。如果是 `false`JavaScript会跳过这整个代码块。
你经常会用比较运算符来组成这些条件。来看一个实际的例子:
```javascript
let currentMoney;
let laptopPrice;
let currentMoney = 1000;
let laptopPrice = 800;
if (currentMoney >= laptopPrice) {
//Condition is true. Code in this block will run.
// 条件为真。此块中的代码将会运行。
console.log("Getting a new laptop!");
}
```
因为 `1000 >= 800` 计算结果为 `true`代码块内的内容得以执行控制台打印出“Getting a new laptop!”。
```mermaid
flowchart TD
A["🚀 程序开始"] --> B{"💰 currentMoney >= laptopPrice?"}
B -->|true| C["🎉 '买新笔记本电脑!'"]
B -->|false| D["⏭️ 跳过代码块"]
C --> E["📋 继续程序"]
D --> E
F["📊 If语句结构"] --> F1["if (condition) {"]
F1 --> F2[" // 如果条件为真时运行的代码"]
F2 --> F3["}"]
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#ffebee
style F fill:#e3f2fd
```
## If..Else 语句
当条件为 false 时,`else` 语句将运行其块中的代码。它是 `if` 语句的可选部分。
但是如果你想在条件为假时执行不同的操作呢?这时就用到 `else` —— 就像有备选方案一样。
`else` 语句让你说“如果这个条件不为真,那就执行另一件事情。”
```javascript
let currentMoney;
let laptopPrice;
let currentMoney = 500;
let laptopPrice = 800;
if (currentMoney >= laptopPrice) {
//Condition is true. Code in this block will run.
// 条件为真。此代码块中的代码将运行。
console.log("Getting a new laptop!");
} else {
//Condition is false. Code in this block will run.
// 条件为假。此代码块中的代码将运行。
console.log("Can't afford a new laptop, yet!");
}
```
✅ 在浏览器控制台中运行这段代码以及后续代码来测试你的理解。更改 `currentMoney``laptopPrice` 变量的值以改变 `console.log()` 的返回结果。
现在由于 `500 >= 800``false`JavaScript跳过第一个代码块转而执行 `else` 代码块。你会看到控制台打印“Can't afford a new laptop, yet!”。
✅ 通过运行这段代码和下面代码来测试你的理解。改变 `currentMoney``laptopPrice` 变量的值,观察控制台输出变化。
### 🎯 **If-Else 逻辑检测:分支路径**
**评估你对条件逻辑的理解:**
- 如果 `currentMoney` 正好等于 `laptopPrice` 会发生什么?
- 你能想到一个现实场景哪里使用if-else逻辑会很有用
- 你如何扩展这个逻辑来处理多个价格区间?
```mermaid
flowchart TD
A["🔍 评估条件"] --> B{"条件为真?"}
B -->|是| C["📤 执行 IF 块"]
B -->|否| D["📥 执行 ELSE 块"]
C --> E["✅ 一条路径被执行"]
D --> E
F["🌐 现实示例"] --> F1["用户登录状态"]
F --> F2["年龄验证"]
F --> F3["表单验证"]
F --> F4["游戏状态变化"]
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#e3f2fd
style F fill:#f3e5f5
```
> **关键见解**If-else 确保只有一条路径被执行。这保证你的程序对任何条件都有响应!
## Switch 语句
`switch` 语句用于根据不同条件执行不同的操作。使用 `switch` 语句可以选择要执行的多个代码块之一。
有时你需要把一个值和多个选项进行比较。虽然可以串联多个 `if..else` 语句,但代码会变得难以管理。`switch` 语句为多个离散值提供了更清晰的结构。
这个概念类似于早期电话交换机中的机械切换系统 — 一个输入值决定执行哪个具体路径。
```javascript
switch (expression) {
case x:
// code block
// 代码块
break;
case y:
// code block
// 代码块
break;
default:
// code block
// 代码块
}
```
它的结构如下:
- JavaScript只计算表达式一次
- 遍历每个 `case` 寻找匹配项
- 找到匹配时执行该代码块
- `break` 使JavaScript停止并退出switch
- 如果没有匹配项执行 `default` 块(如果存在)
```javascript
// program using switch statement
let a = 2;
// 使用 switch 语句的周日程序
let dayNumber = 2;
let dayName;
switch (a) {
switch (dayNumber) {
case 1:
a = "one";
dayName = "Monday";
break;
case 2:
a = "two";
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
default:
a = "not found";
dayName = "Unknown day";
break;
}
console.log(`The value is ${a}`);
console.log(`Today is ${dayName}`);
```
✅ 在浏览器控制台中运行这段代码以及后续代码来测试你的理解。更改变量 `a` 的值以改变 `console.log()` 的返回结果。
在该例中JavaScript看到 `dayNumber``2`,匹配到 `case 2`,将 `dayName` 设置为"Tuesday"然后跳出switch。结果就是控制台打印“Today is Tuesday”。
```mermaid
flowchart TD
A["📥 switch(表达式)"] --> B["🔍 只计算一次"]
B --> C{"匹配案例 1?"}
C -->|是| D["📋 执行案例 1"]
C -->|否| E{"匹配案例 2?"}
E -->|是| F["📋 执行案例 2"]
E -->|否| G{"匹配案例 3?"}
G -->|是| H["📋 执行案例 3"]
G -->|否| I["📋 执行默认"]
D --> J["🛑 break"]
F --> K["🛑 break"]
H --> L["🛑 break"]
J --> M["✅ 退出 switch"]
K --> M
L --> M
I --> M
style A fill:#e3f2fd
style B fill:#fff3e0
style M fill:#e8f5e8
```
✅ 通过运行这段代码和接下来的代码来测试你的理解。改变变量 `a` 的值,观察控制台输出变化。
## 逻辑运算符与布尔值
### 🔄 **Switch 语句掌握:多选项处理**
决策可能需要多个比较,可以通过逻辑运算符将它们串联起来以生成布尔值。
**测试你的switch理解**
- 如果忘了写 `break` 会发生什么?
- 你什么时候会选择用 `switch` 而不是多个 `if-else` 语句?
- 即使你认为涵盖了所有可能,为什么 `default` 情况仍然有用?
| 符号 | 描述 | 示例 |
| ----- | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `&&` | **逻辑与**:比较两个布尔表达式。仅当两侧都为 true 时返回 true | `(5 > 6) && (5 < 6 ) //一侧为 false另一侧为 true。返回 false` |
| `\|\|` | **逻辑或**:比较两个布尔表达式。只要至少一侧为 true 就返回 true | `(5 > 6) \|\| (5 < 6) //一侧为 false另一侧为 true。返回 true` |
| `!` | **逻辑非**:返回布尔表达式的相反值 | `!(5 > 6) // 5 不大于 6但 "!" 会返回 true` |
```mermaid
pie title "何时使用每种决策结构"
"简单的 if-else" : 40
"复杂的 if-else 链" : 25
"Switch 语句" : 20
"三元运算符" : 15
```
> **最佳实践**:当需要对一个变量与多个具体值进行比较时,用 `switch`。处理数值范围或复杂条件时,用 `if-else`
## 逻辑运算符与布尔值
## 使用逻辑运算符的条件与决策
复杂决策通常需要同时评估多个条件。正如布尔代数允许数学家结合逻辑表达式,编程语言也提供了逻辑运算符来连接多个布尔条件。
这些运算符通过组合简单的真/假判断,支持复杂的条件逻辑。
| 符号 | 描述 | 示例 |
| ------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `&&` | **逻辑与AND**:比较两个布尔表达式,只有两边都为真时返回 `true` | `(5 > 3) && (5 < 10) // 两边都为真返回true` |
| `\|\|` | **逻辑或OR**:比较两个布尔表达式,只要有一边为真就返回 `true` | `(5 > 10) \|\| (5 < 10) // 一边是假另一边是真返回true` |
| `!` | **逻辑非NOT**:返回布尔表达式的相反值 | `!(5 > 10) // 5不大于10"!"使其变成true` |
这些运算符让你以有用的方式组合条件:
- AND (`&&`) 表示两个条件都必须为真
- OR (`||`) 表示至少一个条件为真
- NOT (`!`) 将真变假,假变真
```mermaid
flowchart LR
A["🔗 逻辑运算符"] --> B["&& 与"]
A --> C["|| 或"]
A --> D["! 非"]
B --> B1["两者都必须为真"]
B --> B2["真 && 真 = 真"]
B --> B3["真 && 假 = 假"]
C --> C1["至少一个为真"]
C --> C2["真 || 假 = 真"]
C --> C3["假 || 假 = 假"]
D --> D1["取反值"]
D --> D2["!真 = 假"]
D --> D3["!假 = 真"]
E["🌍 真实例子"] --> E1["年龄 >= 18 && 有驾照"]
E --> E2["是周末 || 是假日"]
E --> E3["!已登录"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
```
## 逻辑运算符的条件与决策
逻辑运算符可以用于在 if..else 语句中构成条件。
来看一个更现实的例子,演示这些逻辑运算符的用法:
```javascript
let currentMoney;
let laptopPrice;
let laptopDiscountPrice = laptopPrice - laptopPrice * 0.2; //Laptop price at 20 percent off
let currentMoney = 600;
let laptopPrice = 800;
let laptopDiscountPrice = laptopPrice - (laptopPrice * 0.2); // 笔记本电脑价格打八折
if (currentMoney >= laptopPrice || currentMoney >= laptopDiscountPrice) {
//Condition is true. Code in this block will run.
// 条件为真。此代码块中的代码将被执行。
console.log("Getting a new laptop!");
} else {
//Condition is true. Code in this block will run.
// 条件为假。此代码块中的代码将被执行。
console.log("Can't afford a new laptop, yet!");
}
```
### 非运算符
在此示例中我们计算出20%的折扣价640然后判断资金是否足够支付全价或折扣价。由于600未达到折扣价640条件整个表达式计算结果为false。
### 🧮 **逻辑运算符检测:条件组合**
**测试你的逻辑运算符理解:**
- 在表达式 `A && B` 中,如果 A 为假B 会被计算吗?
- 你能想到什么情况下需要同时使用 `&&`, `||`, `!` 三个运算符吗?
- `!user.isActive``user.isActive !== true` 有什么区别?
```mermaid
stateDiagram-v2
[*] --> EvaluateA: A && B
EvaluateA --> CheckB: A为真
EvaluateA --> ReturnFalse: A为假
CheckB --> ReturnTrue: B为真
CheckB --> ReturnFalse: B为假
[*] --> EvaluateC: A || B
EvaluateC --> ReturnTrue: A为真
EvaluateC --> CheckD: A为假
CheckD --> ReturnTrue: B为真
CheckD --> ReturnFalse: B为假
note right of EvaluateA
短路求值:
如果A为假永远不会检查B
end note
```
> **性能提示**JavaScript使用“短路求值”——在 `A && B` 中,如果 A 为假B不会被计算。利用这一点可以优化代码
### 取反运算符
到目前为止,你已经看到如何使用 `if...else` 语句来创建条件逻辑。任何进入 `if` 的内容都需要评估为 true 或 false。通过使用 `!` 运算符,你可以**取反**表达式。它看起来像这样:
有时更容易思考某事“不成立”的情况。比如不问“用户是否登录?”,而是问“用户是否未登录?”。感叹号(`!`)运算符就帮你翻转逻辑。
```javascript
if (!condition) {
// runs if condition is false
// 如果条件为假则执行
} else {
// runs if condition is true
// 如果条件为真则执行
}
```
`!` 运算符就像说“相反的……”,如果条件是 `true``!` 使它变成 `false`,反之亦然。
### 三元表达式
`if...else` 不是表达决策逻辑的唯一方式。你还可以使用一种称为三元运算符的方式。它的语法如下:
对于简单的条件赋值JavaScript提供了**三元运算符**。这种简洁写法允许你在一行中写出条件表达式,在需要根据条件赋值两种情形时特别有用。
```javascript
let variable = condition ? <return this if true> : <return this if false>
let variable = condition ? returnThisIfTrue : returnThisIfFalse;
```
下面是一个更具体的示例:
它读起来像个问题:“这个条件成立吗?如果是,用这个值。不成立,用那个值。”
下面是更具体的例子:
```javascript
let firstNumber = 20;
@ -185,15 +479,11 @@ let secondNumber = 10;
let biggestNumber = firstNumber > secondNumber ? firstNumber : secondNumber;
```
✅ 花点时间多读几遍这段代码。你理解这些运算符是如何工作的了吗?
上述代码表示:
✅ 花点时间多读几遍这段代码。你理解这些运算如何工作吗?
- 如果 `firstNumber` 大于 `secondNumber`
- 那么将 `firstNumber` 赋值给 `biggestNumber`
- 否则将 `secondNumber` 赋值给 `biggestNumber`
这句代码相当于:“`firstNumber` 是否大于 `secondNumber`?如果是,把 `firstNumber` 赋给 `biggestNumber`,否则赋 `secondNumber`。”
三元表达式只是以下代码的简洁写法
三元运算符是传统 `if..else` 语句的简写方式:
```javascript
let biggestNumber;
@ -204,29 +494,179 @@ if (firstNumber > secondNumber) {
}
```
两种写法结果相同。三元运算符较简洁而传统的if-else结构在复杂条件下更易读。
```mermaid
flowchart LR
A["🤔 三元运算符"] --> B["条件 ?"]
B --> C["值为真时 :"]
C --> D["值为假时"]
E["📝 传统的 If-Else"] --> F["if (条件) {"]
F --> G[" 返回 值为真"]
G --> H["} else {"]
H --> I[" 返回 值为假"]
I --> J["}"]
K["⚡ 何时使用"] --> K1["简单赋值"]
K --> K2["简短条件"]
K --> K3["内联决策"]
K --> K4["返回语句"]
style A fill:#e3f2fd
style E fill:#fff3e0
style K fill:#e8f5e8
```
---
## 🚀 挑战
创建一个程序,首先使用逻辑运算符编写,然后使用三元表达式重写它。你更喜欢哪种语法?
写一个程序,先用逻辑运算符实现,再用三元表达式重写。你更喜欢哪种写法?
---
## 课后测验
## GitHub Copilot Agent 挑战 🚀
用Agent模式完成以下挑战
**描述:** 创建一个综合评分计算器,演示本课多种决策概念,包括 if-else 语句、switch 语句、逻辑运算符和三元表达式。
[课后测验](https://ff-quizzes.netlify.app/web/quiz/12)
**提示:** 编写一个 JavaScript 程序输入学生的数字成绩0-100根据以下标准确定字母等级
- A90-100
- B80-89
- C70-79
- D60-69
- F低于60
## 复习与自学
要求:
1. 使用 if-else 语句确定字母等级
2. 使用逻辑运算符检查学生是否及格grade >= 60且获得荣誉grade >= 90
3. 使用 switch 语句为每个成绩等级提供具体反馈
4. 使用三元运算符判断学生是否有资格参加下一门课程grade >= 70
5. 包含输入验证以确保分数在 0 到 100 之间
阅读更多关于用户可用的运算符的信息:[MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators)。
使用多种分数测试你的程序,包括临界值如 59、60、89、90 以及无效输入。
浏览 Josh Comeau 的精彩 [运算符速查表](https://joshwcomeau.com/operator-lookup/)
在此处了解更多关于 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 的信息。
## 作业
[运算符](assignment.md)
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/12)
## 复习与自学
阅读更多关于用户可用的多种运算符,[请见 MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators)。
浏览 Josh Comeau 精彩的[运算符查找](https://joshwcomeau.com/operator-lookup/)
## 作业
[运算符](assignment.md)
---
## 🧠 **你的决策工具包总结**
```mermaid
graph TD
A["🎯 JavaScript 决策"] --> B["🔍 布尔逻辑"]
A --> C["📊 条件语句"]
A --> D["🔗 逻辑运算符"]
A --> E["⚡ 高级模式"]
B --> B1["true/false 值"]
B --> B2["比较运算符"]
B --> B3["真值概念"]
C --> C1["if 语句"]
C --> C2["if-else 链"]
C --> C3["switch 语句"]
D --> D1["&& (与)"]
D --> D2["|| (或)"]
D --> D3["! (非)"]
E --> E1["三元运算符"]
E --> E2["短路求值"]
E --> E3["复杂条件"]
F["💡 关键原则"] --> F1["清晰易读的条件"]
F --> F2["一致的比较风格"]
F --> F3["正确的运算符优先级"]
F --> F4["高效的求值顺序"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
---
## 🚀 你的 JavaScript 决策能力掌握时间线
### ⚡ **接下来 5 分钟内你能做什么**
- [ ] 在浏览器控制台练习比较运算符
- [ ] 编写一个简单的 if-else 语句来检查你的年龄
- [ ] 尝试挑战:用三元运算符重写 if-else
- [ ] 测试不同“真值”和“假值”时的表现
### 🎯 **接下来一小时内你能完成的任务**
- [ ] 完成课后测验并复习任何困惑的概念
- [ ] 构建 GitHub Copilot 挑战中的综合成绩计算器
- [ ] 创建一个现实场景的简单决策树(例如选择穿什么)
- [ ] 练习用逻辑运算符组合多个条件
- [ ] 试验 switch 语句在不同用例中的应用
### 📅 **你的周度逻辑掌握**
- [ ] 完成包含创造性示例的运算符作业
- [ ] 使用各种条件结构构建迷你测验应用
- [ ] 创建一个检查多个输入条件的表单验证器
- [ ] 练习 Josh Comeau 的[运算符查找](https://joshwcomeau.com/operator-lookup/)练习
- [ ] 重构现有代码以使用更合适的条件结构
- [ ] 研究短路求值和性能影响
### 🌟 **你的月度提升计划**
- [ ] 精通复杂嵌套条件且保持代码可读性
- [ ] 构建带有复杂决策逻辑的应用
- [ ] 通过改进现有项目中的条件逻辑参与开源贡献
- [ ] 教授他人不同条件结构及其适用场景
- [ ] 探索函数式编程在条件逻辑中的应用
- [ ] 创建一份条件最佳实践的个人参考指南
### 🏆 **最终决策大师自查**
**庆祝你的逻辑思维掌握:**
- 你成功实现过的最复杂的决策逻辑是什么?
- 你觉得哪种条件结构最自然,为什么?
- 学习逻辑运算符如何改变了你的问题解决方法?
- 哪些现实应用会从复杂决策逻辑中获益?
```mermaid
journey
title 你的逻辑思维进化
section 今天
布尔困惑: 3: You
If-Else 理解: 4: You
操作符识别: 5: You
section 本周
复杂条件: 4: You
Switch 精通: 5: You
逻辑组合: 5: You
section 下个月
高级模式: 5: You
性能意识: 5: You
教授他人: 5: You
```
> 🧠 **你已经掌握了数字决策的艺术!** 每个交互式应用都依赖条件逻辑来智能地响应用户操作和变化的环境。你现在理解了如何让程序进行思考、评估并选择适当的响应。这一逻辑基础将为你构建的每一个动态应用提供强大动力! 🎉
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而导致的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原始语言版本的文件应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或错误理解,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,52 +1,120 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "bf62b82567e6f9bdf4abda9ae0ccb64a",
"translation_date": "2025-08-23T22:39:24+00:00",
"original_hash": "ffe366b2d1f037b99fbadbe1dc81083d",
"translation_date": "2026-01-06T11:17:04+00:00",
"source_file": "2-js-basics/3-making-decisions/assignment.md",
"language_code": "zh"
}
-->
# 运算符
# 做决策:学生成绩处理器
## 说明
## 学习目标
尝试使用运算符。以下是一个可以实现的程序建议:
在此作业中,您将通过构建一个处理来自不同评分系统的学生成绩的程序来练习本课的决策概念。您将使用 `if...else` 语句、比较运算符和逻辑运算符来确定哪些学生通过了课程。
你有一组来自两个不同评分系统的学生。
## 挑战
### 第一个评分系统
您供职的学校最近与另一所学校合并。现在,您需要处理来自两种完全不同评分系统的学生成绩,并确定哪些学生及格。这是练习条件逻辑的绝佳机会!
第一个评分系统的分数范围是1到5其中3分及以上表示通过课程。
### 理解评分系统
### 第二个评分系统
#### 第一评分系统(数字)
- 成绩以 1-5 数字表示
- **及格分数**3 及以上3、4 或 5
- **不及格分数**:低于 31 或 2
另一个评分系统的分数为 `A, A-, B, B-, C, C-`,其中 `A` 是最高分,`C` 是最低的及格分。
#### 第二评分系统(字母等级)
- 成绩使用字母:`A`、`A-`、`B`、`B-`、`C`、`C-`
- **及格等级**`A`、`A-`、`B`、`B-`、`C`、`C-`(列出的所有等级均为及格)
- **注意**:该系统不包含像 `D``F` 这样的不及格等级
### 任务
### 您的任务
给定以下数组 `allStudents`,表示所有学生及其成绩,构造一个新数组 `studentsWhoPass`,包含所有通过的学生。
> TIP使用 for 循环、if...else 和比较运算符:
给定以下数组 `allStudents`,表示所有学生及其成绩,构建一个新数组 `studentsWhoPass`,包含根据各自评分系统及格的所有学生。
```javascript
let allStudents = [
'A',
'B-',
1,
4,
5,
2
]
'A', // 等级 - 及格
'B-', // 等级 - 及格
1, // 数值等级 - 不及格
4, // 数值等级 - 及格
5, // 数值等级 - 及格
2 // 数值等级 - 不及格
];
let studentsWhoPass = [];
```
### 逐步方法
1. **设置循环** 遍历 `allStudents` 数组中的每个成绩
2. **检查成绩类型**(是数字还是字符串?)
3. **应用相应的评分系统规则**
- 数字:检查成绩是否 >= 3
- 字符串:检查是否为有效及格字母等级之一
4. **将及格成绩** 添加到 `studentsWhoPass` 数组中
### 有用的代码技巧
使用本课的这些 JavaScript 概念:
- **typeof 运算符**`typeof grade === 'number'` 用于检查是否为数字成绩
- **比较运算符**`>=` 用于比较数字成绩
- **逻辑运算符**`||` 用于检查多个字母等级条件
- **if...else 语句**:处理不同的评分系统
- **数组方法**`.push()` 将及格成绩添加到新数组
### 预期输出
运行程序时,`studentsWhoPass` 应包含:`['A', 'B-', 4, 5]`
**这些成绩及格原因:**
- `'A'``'B-'` 是有效的字母等级(此系统的所有字母等级均及格)
- `4``5` 是 >= 3 的数字成绩
- `1``2` 不及格,因为它们是 < 3 的数字成绩
## 测试您的解决方案
用不同场景测试您的代码:
```javascript
// 使用不同的成绩组合进行测试
let testGrades1 = ['A-', 3, 'C', 1, 'B'];
let testGrades2 = [5, 'A', 2, 'C-', 4];
// 你的解决方案应适用于任何有效成绩的组合
```
## 额外挑战
完成基本作业后,尝试以下扩展:
1. **添加验证**:检查无效成绩(如负数或无效字母)
2. **统计计数**:计算通过和未通过的学生数量
3. **成绩转换**将所有成绩转换为单一数字系统A=5B=4C=3 等)
## 评分标准
| 标准 | 优秀 | 合格 | 需要改进 |
| -------- | ------------------------------ | ----------------------------- | ------------------------------- |
| | 提供了完整的解决方案 | 提供了部分解决方案 | 提供的解决方案存在错误 |
| 标准 | 优秀 (4) | 良好 (3) | 进行中 (2) | 初学 (1) |
|----------|---------------|----------------|----------------|---------------|
| **功能性** | 程序正确识别来自两个系统的所有及格成绩 | 程序有轻微问题或边缘情况 | 程序部分正常,但存在逻辑错误 | 程序严重错误或无法运行 |
| **代码结构** | 代码整洁、组织有序且使用适当的 if...else 逻辑 | 结构良好,条件语句恰当 | 结构可接受,组织上有些问题 | 结构差,逻辑难以理解 |
| **概念应用** | 有效使用比较运算符、逻辑运算符和条件语句 | 很好地使用课程概念,有少许缺漏 | 有部分使用课程概念但缺少关键元素 | 课程概念应用有限 |
| **问题解决** | 清晰理解问题,方案优雅 | 解决方案良好,逻辑扎实 | 能解决,但有些混淆 | 方案不清晰,未展现理解 |
## 提交指南
1. **充分测试代码**,使用提供的示例
2. **添加注释**,解释您的逻辑,尤其是条件语句
3. **验证输出** 是否符合预期:`['A', 'B-', 4, 5]`
4. **考虑边缘情况**,如空数组或意外的数据类型
> 💡 **专业提示**:从简单开始!先实现基本功能,然后添加更复杂的特性。记住,目标是用本课学到的工具练习决策逻辑。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对于因使用本翻译而引起的任何误解或误读不承担责任。
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力保证准确性,但请注意自动翻译可能存在错误或不准确之处。原始文档的母语版本应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用本翻译而产生的任何误解或误释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,141 +1,640 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "9029f96b0e034839c1799f4595e4bb66",
"translation_date": "2025-08-29T14:49:03+00:00",
"original_hash": "1710a50a519a6e4a1b40a5638783018d",
"translation_date": "2026-01-06T11:17:26+00:00",
"source_file": "2-js-basics/4-arrays-loops/README.md",
"language_code": "zh"
}
-->
# JavaScript 基础:数组和循环
![JavaScript 基础 - 数组](../../../../translated_images/webdev101-js-arrays.439d7528b8a294558d0e4302e448d193f8ad7495cc407539cc81f1afe904b470.zh.png)
> 由 [Tomomi Imura](https://twitter.com/girlie_mac) 绘制的手绘笔记
# JavaScript 基础知识:数组和循环
![JavaScript Basics - Arrays](../../../../translated_images/webdev101-js-arrays.439d7528b8a29455.zh.png)
> 速写笔记,作者:[Tomomi Imura](https://twitter.com/girlie_mac)
```mermaid
journey
title 你的数组与循环冒险
section 数组基础
创建数组: 5: You
访问元素: 4: You
数组方法: 5: You
section 循环精通
For 循环: 4: You
While 循环: 5: You
现代语法: 4: You
section 数据处理
数组 + 循环: 5: You
现实应用: 4: You
性能优化: 5: You
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/13)
本课程介绍了 JavaScript 的基础知识,这是一种为网页提供交互功能的语言。在本课程中,你将学习数组和循环,它们用于操作数据。
有没有想过网站是如何跟踪购物车商品或者显示你的好友列表的?这就涉及到了数组和循环。数组就像是存放多条信息的数字容器,而循环则让你能高效地处理所有数据,而不需要重复写代码。
这两个概念共同构成了处理程序中信息的基础。你将学会如何从手动编写每一步,转变为创建智能、高效的代码,可以快速处理数百甚至数千个条目。
到本课结束时,你将懂得如何用几行代码完成复杂的数据任务。让我们一起探索这些基本的编程概念。
[![Arrays](https://img.youtube.com/vi/1U4qTyq02Xw/0.jpg)](https://youtube.com/watch?v=1U4qTyq02Xw "Arrays")
[![Loops](https://img.youtube.com/vi/Eeh7pxtTZ3k/0.jpg)](https://www.youtube.com/watch?v=Eeh7pxtTZ3k "Loops")
> 🎥 点击上方图片,观看关于数组和循环的视频。
> 你也可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-arrays/?WT.mc_id=academic-77807-sagibbon) 上学习这节课!
```mermaid
mindmap
root((数据处理))
Arrays
Structure
方括号语法
零基索引
动态大小
Operations
push/pop
shift/unshift
indexOf/includes
Types
数字数组
字符串数组
混合类型
Loops
For Loops
计数迭代
数组处理
可预测流程
While Loops
基于条件
未知迭代次数
用户输入
Modern Syntax
for...of
forEach
函数式方法
Applications
Data Analysis
统计
过滤
转换
User Interfaces
列表
菜单
图册
```
## 数组
[![数组](https://img.youtube.com/vi/1U4qTyq02Xw/0.jpg)](https://youtube.com/watch?v=1U4qTyq02Xw "Arrays")
把数组想象为数字化的文件柜——不是每个抽屉只存放一份文档,而是可以把多个相关项目组织到一个结构化的容器中。用编程术语来说,数组让你可以把多条信息存储在一个有序的包裹里。
[![循环](https://img.youtube.com/vi/Eeh7pxtTZ3k/0.jpg)](https://www.youtube.com/watch?v=Eeh7pxtTZ3k "Loops")
无论你是在构建图片库、管理待办事项,还是统计游戏中的最高分,数组都为数据组织提供了基础。让我们来看它们是如何工作的。
> 🎥 点击上方图片观看关于数组和循环的视频。
✅ 数组无处不在!你能想到一个现实生活中的数组例子吗,比如太阳能电池板阵列?
> 你可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101-arrays/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
### 创建数组
## 数组
创建数组非常简单——只需用方括号!
处理数据是任何编程语言中的常见任务,当数据以结构化的格式(如数组)组织时,这项任务会变得更加简单。通过数组,数据以类似列表的结构存储。数组的一个主要优点是你可以在一个数组中存储不同类型的数据。
```javascript
// 空数组——就像一个等待添加商品的空购物车
const myArray = [];
```
✅ 数组无处不在!你能想到一个现实生活中的数组例子吗,比如太阳能电池板阵列?
**这里发生了什么?**
你用这对方括号 `[]` 创建了一个空容器。把它想象成一个空的书架,它已经准备好放你想存放的任何书籍了。
数组的语法是一对方括号。
你还可以一开始就给数组填入初始值:
```javascript
let myArray = [];
```
// 你的冰淇淋店口味菜单
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
这是一个空数组,但数组也可以在声明时就包含数据。数组中的多个值用逗号分隔。
// 用户的个人资料信息(混合不同类型的数据)
const userData = ["John", 25, true, "developer"];
```javascript
let iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 你最喜欢的课程的考试成绩
const scores = [95, 87, 92, 78, 85];
```
**有趣的点:**
- 数组里可以同时存储文本、数字甚至布尔值true/false
- 每个元素用逗号分隔——非常简单!
- 数组非常适合将相关信息存放在一起
```mermaid
flowchart LR
A["📦 数组"] --> B["创建 [ ]"]
A --> C["存储多个项目"]
A --> D["通过索引访问"]
B --> B1["const arr = []"]
B --> B2["const arr = [1,2,3]"]
C --> C1["数字"]
C --> C2["字符串"]
C --> C3["布尔值"]
C --> C4["混合类型"]
D --> D1["arr[0] = 第一个"]
D --> D2["arr[1] = 第二个"]
D --> D3["arr[2] = 第三个"]
E["📊 数组索引"] --> E1["索引 0: 第一个"]
E --> E2["索引 1: 第二个"]
E --> E3["索引 2: 第三个"]
E --> E4["索引 n-1: 最后一个"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
```
### 数组索引
这里有个可能最初让你觉得不寻常的地方:数组的编号是从 0 开始的,而不是从 1 开始。这个以零为基础的索引源于计算机内存的工作方式——这是自 C 语言等早期编程语言以来的惯例。数组中的每个位置都有一个被称为**索引**的地址号。
| 索引 | 值 | 说明 |
|-------|-------|-------------|
| 0 | "Chocolate" | 第一个元素 |
| 1 | "Strawberry" | 第二个元素 |
| 2 | "Vanilla" | 第三个元素 |
| 3 | "Pistachio" | 第四个元素 |
| 4 | "Rocky Road" | 第五个元素 |
数组中的值被分配了一个称为 **索引** 的唯一值,这是一个从数组开头开始计算的整数。在上面的例子中,字符串值 "Chocolate" 的索引是 0而 "Rocky Road" 的索引是 4。使用方括号和索引可以检索、更改或插入数组中的值。
✅ 你是否对数组从零开始编号感到惊讶?在某些编程语言中,索引是从 1 开始的。这里有一段有趣的历史,你可以在 [Wikipedia 上阅读](https://en.wikipedia.org/wiki/Zero-based_numbering)
✅ 你是否感到惊讶,数组的索引是从 0 开始的?在某些编程语言中,索引是从 1 开始的。关于这一点有一个有趣的历史背景,你可以在 [维基百科](https://en.wikipedia.org/wiki/Zero-based_numbering) 上阅读相关内容。
**访问数组元素:**
```javascript
let iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
iceCreamFlavors[2]; //"Vanilla"
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 使用括号表示法访问单个元素
console.log(iceCreamFlavors[0]); // "Chocolate" - 第一个元素
console.log(iceCreamFlavors[2]); // "Vanilla" - 第三个元素
console.log(iceCreamFlavors[4]); // "Rocky Road" - 最后一个元素
```
你可以利用索引来更改一个值,例如:
**解析这段代码:**
- **使用** 方括号加索引数字来访问元素
- **返回** 数组中对应位置存储的值
- **索引** 从 0 开始计数,首个元素索引为 0
**修改数组元素:**
```javascript
iceCreamFlavors[4] = "Butter Pecan"; //Changed "Rocky Road" to "Butter Pecan"
// 更改现有值
iceCreamFlavors[4] = "Butter Pecan";
console.log(iceCreamFlavors[4]); // “黄油山核桃”
// 在末尾添加一个新元素
iceCreamFlavors[5] = "Cookie Dough";
console.log(iceCreamFlavors[5]); // “曲奇面团”
```
你也可以在指定索引处插入一个新值,例如:
**以上操作包括:**
- **将** 索引 4 处的元素从 "Rocky Road" 修改为 "Butter Pecan"
- **在** 索引 5 添加新元素 "Cookie Dough"
- **自动** 在添加超出当前边界时扩展数组长度
### 数组长度和常用方法
数组自带了属性和方法,让处理数据变得更加轻松。
**获取数组长度:**
```javascript
iceCreamFlavors[5] = "Cookie Dough"; //Added "Cookie Dough"
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
console.log(iceCreamFlavors.length); // 5
// 随着数组变化长度自动更新
iceCreamFlavors.push("Mint Chip");
console.log(iceCreamFlavors.length); // 6
```
✅ 更常见的向数组添加值的方法是使用数组操作符,比如 array.push()。
**要点:**
- **返回** 数组中元素的总数
- **自动更新**,元素增加或删除时动态改变
- **提供** 动态计数,适用于循环和验证
要知道数组中有多少项,可以使用 `length` 属性。
**常用数组方法:**
```javascript
let iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
iceCreamFlavors.length; //5
const fruits = ["apple", "banana", "orange"];
// 添加元素
fruits.push("grape"); // 添加到末尾: ["apple", "banana", "orange", "grape"]
fruits.unshift("strawberry"); // 添加到开头: ["strawberry", "apple", "banana", "orange", "grape"]
// 删除元素
const lastFruit = fruits.pop(); // 删除并返回 "grape"
const firstFruit = fruits.shift(); // 删除并返回 "strawberry"
// 查找元素
const index = fruits.indexOf("banana"); // 返回 1 ("banana"的位置)
const hasApple = fruits.includes("apple"); // 返回 true
```
✅ 试一试!使用浏览器的控制台创建并操作一个你自己设计的数组。
**关于这些方法:**
- 通过 `push()`(尾部)和 `unshift()`(开头)添加元素
- 通过 `pop()`(尾部)和 `shift()`(开头)删除元素
- 通过 `indexOf()` 查找元素位置,`includes()` 检查是否包含
- 返回有用的值,比如删除的元素或元素索引
✅ 试试吧!在浏览器控制台创建并操作一个你自己的数组。
### 🧠 **数组基础检测:组织你的数据**
**测试你的数组理解:**
- 你为什么认为数组是从 0 开始计数而不是从 1
- 如果你尝试访问不存在的索引(比如一个有 5 个元素的数组里访问 `arr[100]`)会怎样?
- 你能想到三个现实场景里数组非常有用的地方吗?
```mermaid
stateDiagram-v2
[*] --> EmptyArray: const arr = []
EmptyArray --> WithItems: 添加元素
WithItems --> Accessing: 使用索引
Accessing --> Modifying: 修改值
Modifying --> Processing: 使用方法
WithItems --> WithItems: push(), unshift()
Processing --> Processing: pop(), shift()
note right of Accessing
从零开始的索引
arr[0] = 第一个元素
end note
note right of Processing
内置方法
动态操作
end note
```
> **现实世界见解**:在编程中数组无处不在!社交媒体信息流、购物车、图片库、播放列表歌曲——背后都是数组!
## 循环
循环允许我们执行重复或 **迭代** 的任务可以节省大量时间和代码。每次迭代的变量、值和条件都可能不同。JavaScript 中有不同类型的循环,它们之间有一些细微的差别,但本质上都做同样的事情:遍历数据。
想象一下狄更斯小说里的惩罚,一个学生要反复在黑板上写同一句话。假如你能简单告诉别人“写这句话 100 遍”,并让它自动完成,那就是循环在代码中的作用。
循环就像一位不知疲倦的助手,可以重复任务而不出错。不论是检查购物车中的每件物品,还是显示相册里的所有照片,循环都能高效地处理重复操作。
JavaScript 提供了多种循环类型。让我们来看看各自的用法及适用场景。
```mermaid
flowchart TD
A["🔄 循环类型"] --> B["For 循环"]
A --> C["While 循环"]
A --> D["For...of 循环"]
A --> E["forEach 方法"]
B --> B1["已知的迭代次数"]
B --> B2["基于计数器"]
B --> B3["for(init; condition; increment)"]
C --> C1["未知的迭代次数"]
C --> C2["基于条件"]
C --> C3["while(condition)"]
D --> D1["现代 ES6+"]
D --> D2["数组迭代"]
D --> D3["for(item of array)"]
E --> E1["函数式风格"]
E --> E2["数组方法"]
E --> E3["array.forEach(callback)"]
F["⏰ 何时使用"] --> F1["For计数索引"]
F --> F2["While用户输入搜索"]
F --> F3["For...of简单迭代"]
F --> F4["forEach函数式编程"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
### For 循环
`for` 循环需要三个部分来进行迭代:
- `counter` 一个变量,通常初始化为一个数字,用于计数迭代次数
- `condition` 一个使用比较运算符的表达式,当为 `false` 时循环停止
- `iteration-expression` 在每次迭代结束时运行,通常用于更改计数器的值
`for` 循环就像设置了一个计时器——你知道任务要执行多少次。它非常有序且可预测,非常适合处理数组或需要计数的场合。
**For 循环结构:**
| 组成部分 | 作用 | 示例 |
|-----------|---------|----------|
| **初始化** | 设定起点 | `let i = 0` |
| **条件** | 继续执行的条件 | `i < 10` |
| **增量** | 如何更新 | `i++` |
```javascript
// Counting up to 10
// 从0数到9
for (let i = 0; i < 10; i++) {
console.log(i);
console.log(`Count: ${i}`);
}
// 更实际的例子:处理分数
const testScores = [85, 92, 78, 96, 88];
for (let i = 0; i < testScores.length; i++) {
console.log(`Student ${i + 1}: ${testScores[i]}%`);
}
```
✅ 在浏览器控制台中运行这段代码。当你对计数器、条件或迭代表达式做出小的修改时会发生什么?你能让它倒着运行,创建一个倒计时吗?
**逐步理解这个过程:**
- **初始化** 计数器变量 `i` 为 0
- **判断** 条件 `i < 10`,为真时进入循环体
- **执行** 代码块
- **执行** 循环体后,`i++` 使 `i` 增加 1
- **循环结束** 当条件为假(即 `i` 达到 10
✅ 在浏览器控制台运行此代码。改变计数器、条件或递增表达式,会发生什么?你能让它倒计时吗?
### 🗓️ **For 循环掌握检测:控制重复**
**评估你的 for 循环理解:**
- for 循环的三个部分是什么,它们分别做什么?
- 怎么让 for 循环倒着遍历数组?
- 如果忘记写增量部分(`i++`)会怎样?
```mermaid
flowchart TD
A["🚀 开始 For 循环"] --> B["初始化: let i = 0"]
B --> C{"条件: i < array.length?"}
C -->|true| D["执行代码块"]
D --> E["递增: i++"]
E --> C
C -->|false| F["✅ 退出循环"]
G["📋 常见模式"] --> G1["for(let i=0; i<n; i++)"]
G --> G2["for(let i=n-1; i>=0; i--)"]
G --> G3["for(let i=0; i<arr.length; i+=2)"]
style A fill:#e3f2fd
style F fill:#e8f5e8
style G fill:#fff3e0
```
> **循环智慧**for 循环适合你已经知道要重复多少次的情况。它们是处理数组的最常用选择!
### While 循环
`for` 循环的语法不同,`while` 循环只需要一个条件,当条件变为 `false` 时循环停止。循环中的条件通常依赖于其他值(如计数器),并且必须在循环中进行管理。计数器的初始值必须在循环外创建,任何满足条件的表达式(包括更改计数器)都必须在循环内维护。
`while` 循环相当于“持续做这件事直到……”,你不一定知道会执行多少次,但知道什么时候停止。它非常适合用户输入验证,或者在找到想要的数据前不断搜索。
**While 循环特征:**
- **在条件为真时** 持续执行
- **需要** 手动管理计数变量
- **在每次执行前** 判断条件
- **风险** 条件永远为真则发生死循环
```javascript
//Counting up to 10
// 基本计数示例
let i = 0;
while (i < 10) {
console.log(i);
i++;
console.log(`While count: ${i}`);
i++; // 别忘了递增!
}
// 更实用的示例:处理用户输入
let userInput = "";
let attempts = 0;
const maxAttempts = 3;
while (userInput !== "quit" && attempts < maxAttempts) {
userInput = prompt(`Enter 'quit' to exit (attempt ${attempts + 1}):`);
attempts++;
}
if (attempts >= maxAttempts) {
console.log("Maximum attempts reached!");
}
```
**解析这些例子:**
- **在循环内** 手动管理计数器变量 `i`
- **防止死循环** 适当增加计数器
- **展示** 用户输入和尝试次数限制实际用例
- **包含** 安全机制防止无限循环
### ♾️ **While 循环智慧检测:基于条件的重复**
**测试你对 while 循环的理解:**
- 使用 while 循环时最大的风险是什么?
- 什么情况下你会选择用 while 循环而非 for 循环?
- 如何预防死循环?
```mermaid
flowchart LR
A["🔄 While 与 For 对比"] --> B["While 循环"]
A --> C["For 循环"]
B --> B1["未知的迭代次数"]
B --> B2["条件驱动"]
B --> B3["用户输入,搜索"]
B --> B4["⚠️ 风险:无限循环"]
C --> C1["已知的迭代次数"]
C --> C2["计数器驱动"]
C --> C3["数组处理"]
C --> C4["✅ 安全:可预测结束"]
D["🛡️ 安全提示"] --> D1["始终修改条件变量"]
D --> D2["包含跳出条件"]
D --> D3["设置最大迭代次数"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#ffebee
```
> **安全第一**while 循环功能强大但需要谨慎管理条件。确保条件最终会变成假!
### 现代循环替代方案
JavaScript 提供了更现代的循环语法,使代码更易读且减少出错。
**For...of 循环ES6+**
```javascript
const colors = ["red", "green", "blue", "yellow"];
// 现代方法 - 更简洁更安全
for (const color of colors) {
console.log(`Color: ${color}`);
}
// 与传统for循环比较
for (let i = 0; i < colors.length; i++) {
console.log(`Color: ${colors[i]}`);
}
```
✅ 为什么你会选择使用 for 循环而不是 while 循环17K 名用户在 StackOverflow 上有同样的问题,其中一些观点可能会 [引起你的兴趣](https://stackoverflow.com/questions/39969145/while-loops-vs-for-loops-in-javascript)。
**for...of 的优势:**
- **无需** 管理索引,避免 off-by-one 错误
- **直接** 访问数组元素
- **提升** 代码可读性并减少语法复杂度
## 循环与数组
**forEach 方法:**
数组经常与循环一起使用,因为大多数条件需要数组的长度来停止循环,而索引也可以作为计数器的值。
```javascript
const prices = [9.99, 15.50, 22.75, 8.25];
// 使用 forEach 进行函数式编程风格
prices.forEach((price, index) => {
console.log(`Item ${index + 1}: $${price.toFixed(2)}`);
});
// 使用箭头函数的 forEach 进行简单操作
prices.forEach(price => console.log(`Price: $${price}`));
```
**关于 forEach 你需要知道:**
- **为数组的每个元素** 执行函数
- **提供** 元素值和索引参数
- **无法** 早停(不同于传统循环)
- **返回** undefined不生成新的数组
✅ 你会选择 for 循环还是 while 循环17K 人在 StackOverflow 上讨论过这个问题,[一些观点可能会引起你的兴趣](https://stackoverflow.com/questions/39969145/while-loops-vs-for-loops-in-javascript)。
### 🎨 **现代循环语法检测:拥抱 ES6+**
**评估你对现代 JavaScript 的理解:**
- `for...of` 相比传统 for 循环有哪些优势?
- 你什么时候还会偏好传统 for 循环?
- `forEach``map` 有什么区别?
```mermaid
quadrantChart
title 循环选择指南
x-axis 传统 --> 现代
y-axis 简单 --> 复杂
quadrant-1 现代 复杂
quadrant-2 传统 复杂
quadrant-3 传统 简单
quadrant-4 现代 简单
Traditional For: [0.2, 0.7]
While Loop: [0.3, 0.6]
For...of: [0.8, 0.3]
forEach: [0.9, 0.4]
Array Methods: [0.8, 0.8]
```
> **现代趋势**ES6+ 语法如 `for...of``forEach` 正逐渐成为遍历数组的首选方式,因为更简洁且不易出错!
## 循环和数组
数组与循环结合能创造强大的数据处理能力。这一搭配几乎是许多编程任务的基础,从显示列表到计算统计数据。
**传统数组处理:**
```javascript
let iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 经典的for循环方法
for (let i = 0; i < iceCreamFlavors.length; i++) {
console.log(iceCreamFlavors[i]);
} //Ends when all flavors are printed
console.log(`Flavor ${i + 1}: ${iceCreamFlavors[i]}`);
}
// 现代的for...of方法
for (const flavor of iceCreamFlavors) {
console.log(`Available flavor: ${flavor}`);
}
```
✅ 在浏览器的控制台中尝试用循环遍历一个你自己设计的数组。
**理解每种方式:**
- **通过** 数组长度属性确定循环边界
- **传统 for 循环** 按索引访问元素
- **for...of 循环** 直接访问元素值
- **保证** 每个数组元素被处理一次
**实用数据处理示例:**
```javascript
const studentGrades = [85, 92, 78, 96, 88, 73, 89];
let total = 0;
let highestGrade = studentGrades[0];
let lowestGrade = studentGrades[0];
// 用一个循环处理所有成绩
for (let i = 0; i < studentGrades.length; i++) {
const grade = studentGrades[i];
total += grade;
if (grade > highestGrade) {
highestGrade = grade;
}
if (grade < lowestGrade) {
lowestGrade = grade;
}
}
const average = total / studentGrades.length;
console.log(`Average: ${average.toFixed(1)}`);
console.log(`Highest: ${highestGrade}`);
console.log(`Lowest: ${lowestGrade}`);
```
**代码工作原理:**
- **初始化** 总和及极值追踪变量
- **单次循环** 高效处理每个成绩
- **累计** 总分用于计算平均数
- **追踪** 遍历过程中最高和最低分
- **统计** 循环结束后计算最终结果
✅ 在浏览器控制台试着自己创建数组并用循环操作它。
```mermaid
flowchart TD
A["📦 数组数据"] --> B["🔄 循环处理"]
B --> C["📈 结果"]
A1["[85, 92, 78, 96, 88]"] --> A
B --> B1["计算总和"]
B --> B2["查找最小/最大值"]
B --> B3["统计条件"]
B --> B4["转换数据"]
C --> C1["平均值: 87.8"]
C --> C2["最高分: 96"]
C --> C3["及格数: 5/5"]
C --> C4["字母等级"]
D["⚡ 处理模式"] --> D1["累积(求和)"]
D --> D2["比较(最小/最大)"]
D --> D3["过滤(条件)"]
D --> D4["映射(转换)"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e8
style D fill:#f3e5f5
```
---
## GitHub Copilot 代理挑战 🚀
使用代理模式完成以下挑战:
**描述:** 构建一个综合数据处理函数,结合数组和循环对数据集进行分析并生成有意义的洞察。
**要求:** 创建一个名为 `analyzeGrades` 的函数,接受包含学生姓名和分数的成绩对象数组,返回包含最高分、最低分、平均分、及格(分数 >= 70的学生数量以及分数高于平均分的学生姓名数组的统计对象。解决方案中需使用至少两种不同类型的循环。
想了解更多请访问 [代理模式介绍](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
JavaScript 提供了几种现代数组方法,可以替代特定任务中的传统循环。探索 [forEach](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)、[for-of](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for...of)、[map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map)、[filter](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) 和 [reduce](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)。
除了 for 和 while 循环,还有其他方法可以遍历数组,比如 [forEach](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)、[for-of](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for...of) 和 [map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map)。用这些技术之一重写你的数组循环。
**你的挑战:** 使用至少三种不同的数组方法重构学生成绩示例。注意使用现代 JavaScript 语法后,代码变得多么简洁和易读
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/14)
## 复习与自学
JavaScript 中的数组有许多附加方法,这些方法在数据操作中非常有用。[阅读这些方法](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) 并尝试在你自己创建的数组上使用一些方法(比如 push、pop、slice 和 splice
JavaScript 中的数组有很多附带方法,非常适合数据操作。[阅读这些方法](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array),并在你创建的数组上尝试它们(比如 push、pop、slice 和 splice
## 作业
@ -143,5 +642,109 @@ JavaScript 中的数组有许多附加方法,这些方法在数据操作中非
---
## 📊 **你的数组与循环工具包总结**
```mermaid
graph TD
A["🎯 数组与循环精通"] --> B["📦 数组基础"]
A --> C["🔄 循环类型"]
A --> D["🔗 数据处理"]
A --> E["🎨 现代技巧"]
B --> B1["创建: [ ]"]
B --> B2["索引: arr[0]"]
B --> B3["方法: push, pop"]
B --> B4["属性: length"]
C --> C1["For: 已知次数"]
C --> C2["While: 条件控制"]
C --> C3["For...of: 直接访问"]
C --> C4["forEach: 函数式"]
D --> D1["统计计算"]
D --> D2["数据转换"]
D --> D3["过滤与搜索"]
D --> D4["实时处理"]
E --> E1["箭头函数"]
E --> E2["方法链"]
E --> E3["解构赋值"]
E --> E4["模板字符串"]
F["💡 关键优势"] --> F1["高效数据处理"]
F --> F2["减少代码重复"]
F --> F3["可扩展解决方案"]
F --> F4["更简洁语法"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
```
---
## 🚀 你的数组与循环精通时间线
### ⚡ **接下来5分钟你能做什么**
- [ ] 创建一个你最喜欢电影的数组,并访问特定元素
- [ ] 编写一个从 1 数到 10 的 for 循环
- [ ] 尝试本节课的现代数组方法挑战
- [ ] 在浏览器控制台练习数组索引
### 🎯 **接下来一小时你能完成的**
- [ ] 完成课后测验并复习任何有挑战的概念
- [ ] 构建 GitHub Copilot 挑战中的综合成绩分析器
- [ ] 创建一个可以添加和移除商品的简单购物车
- [ ] 练习不同循环类型之间的转换
- [ ] 试验数组方法如 `push`、`pop`、`slice` 和 `splice`
### 📅 **你的一周数据处理旅程**
- [ ] 完成“遍历数组”作业并进行创意增强
- [ ] 使用数组和循环构建一个待办事项应用
- [ ] 创建一个用于数值数据的简单统计计算器
- [ ] 练习 [MDN 数组方法](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)
- [ ] 构建照片图库或音乐播放列表界面
- [ ] 探索函数式编程中的 `map`、`filter` 和 `reduce`
### 🌟 **你的一月转变**
- [ ] 掌握高级数组操作与性能优化
- [ ] 构建完整的数据可视化仪表盘
- [ ] 为涉及数据处理的开源项目做贡献
- [ ] 用实际示例向他人教授数组和循环
- [ ] 创建个人可重用数据处理函数库
- [ ] 探索基于数组的算法和数据结构
### 🏆 **最终数据处理冠军签到**
**庆祝你的数组和循环掌握成果:**
- 你学到的最实用的数组操作是什么,适用于真实世界应用?
- 哪种循环类型对你来说最自然,为什么?
- 理解数组和循环如何改变了你组织数据的方法?
- 你接下来想挑战什么复杂的数据处理任务?
```mermaid
journey
title 你的数据处理演进
section 今天
数组困惑: 3: 你
循环基础: 4: 你
索引理解: 5: 你
section 本周
方法精通: 4: 你
高效处理: 5: 你
现代语法: 5: 你
section 下个月
复杂算法: 5: 你
性能优化: 5: 你
教授他人: 5: 你
```
> 📦 **你已解锁数据组织与处理的力量!** 数组和循环是你将构建的几乎每个应用程序的基础。从简单的列表到复杂的数据分析,你现在拥有高效优雅处理信息的工具。每个动态网站、移动应用和数据驱动应用都依赖这些基本概念。欢迎来到可扩展数据处理的世界!🎉
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引发的任何误解或误读,我们概不负责。
本文件由AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译而成。虽然我们致力于准确性,但请注意自动翻译可能包含错误或不准确之处。应以原始语言版本的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用本翻译而产生的任何误解或错误解读承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,25 +1,124 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "8b2381170bd0fd2870f5889bb8620f02",
"translation_date": "2025-08-23T22:45:25+00:00",
"original_hash": "8abcada0534e0fb3a7556ea3c5a2a8a4",
"translation_date": "2026-01-06T11:19:25+00:00",
"source_file": "2-js-basics/4-arrays-loops/assignment.md",
"language_code": "zh"
}
-->
# 遍历数组
# 数组与循环作业
## 说明
创建一个程序列出1到20之间的每第3个数字并将其打印到控制台
完成以下练习以练习数组和循环的使用。每个练习都建立在课程的概念基础上,并鼓励你应用不同的循环类型和数组方法
> 提示使用for循环并修改迭代表达式
### 练习 1数字模式生成器
创建一个程序列出1到20之间每隔3个的数字并将其打印到控制台。
**要求:**
- 使用带自定义增量的 `for` 循环
- 以用户友好的格式显示数字
- 添加描述性注释解释你的逻辑
**预期输出:**
```
3, 6, 9, 12, 15, 18
```
> **提示:** 修改你的 for 循环中的迭代表达式以跳过数字。
### 练习 2数组分析
创建一个包含至少8个不同数字的数组并编写函数分析这些数据。
**要求:**
- 创建一个名为 `numbers` 的数组包含至少8个值
- 编写一个函数 `findMaximum()` 返回最高数字
- 编写一个函数 `findMinimum()` 返回最低数字
- 编写一个函数 `calculateSum()` 返回所有数字的总和
- 测试每个函数并显示结果
**额外挑战:** 创建一个函数,找出数组中第二高的数字。
### 练习 3字符串数组处理
创建一个包含你喜欢的电影/书籍/歌曲的数组,练习不同的循环类型。
**要求:**
- 创建一个包含至少5个字符串值的数组
- 使用传统的 `for` 循环显示带编号的项目1. 项目名称)
- 使用 `for...of` 循环显示项目的大写形式
- 使用 `forEach()` 方法计算并显示字符总数
**示例输出:**
```
Traditional for loop:
1. The Matrix
2. Inception
3. Interstellar
For...of loop (uppercase):
THE MATRIX
INCEPTION
INTERSTELLAR
Character count:
Total characters across all titles: 42
```
### 练习 4数据过滤高级
创建一个处理学生对象数组的程序。
**要求:**
- 创建一个包含至少5个学生对象的数组属性包括`name`、`age`、`grade`
- 使用循环找出年龄在18岁及以上的学生
- 计算所有学生的平均成绩
- 创建一个仅包含成绩超过85分学生的新数组
**示例结构:**
```javascript
const students = [
{ name: "Alice", age: 17, grade: 92 },
{ name: "Bob", age: 18, grade: 84 },
// 添加更多学生...
];
```
## 测试你的代码
通过以下方式测试你的程序:
1. 在浏览器控制台运行每个练习
2. 验证输出是否符合预期结果
3. 使用不同的数据集进行测试
4. 检查代码能否处理边界情况(空数组、单个元素)
## 提交指南
提交时请包括:
- 每个练习的带注释 JavaScript 代码
- 程序运行的截图或文本输出
- 简短说明你为每个任务选择的循环类型及原因
## 评分标准
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | --------------------------------------- | ------------------------ | ------------------------------ |
| | 程序运行正确且有注释 | 程序没有注释 | 程序不完整或存在错误 |
| 标准 | 杰出3分 | 合格2分 | 需改进1分 |
| -------- | -------------------- | ------------------- | --------------------------- |
| **功能性** | 所有练习均正确完成及附加挑战 | 所有必做练习均正确工作 | 部分练习未完成或含错误 |
| **代码质量** | 代码整洁、结构良好,变量名描述清晰 | 代码能工作但可优化 | 代码混乱或难以理解 |
| **注释** | 详尽注释解释逻辑和决策 | 有基础注释 | 注释很少或没有 |
| **循环使用** | 适当使用不同循环类型,体现理解 | 正确使用循环,但种类较少 | 循环使用不当或效率低 |
| **测试** | 有充分多样的测试证据 | 展示了基础测试 | 测试证据少 |
## 反思问题
完成练习后请思考:
1. 哪种循环类型用起来最自然,为什么?
2. 使用数组时遇到了哪些挑战?
3. 这些技能如何应用到真实的网页开发项目中?
4. 如果需要优化代码性能,你会如何做?
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。如涉及重要信息,建议采用专业人工翻译。因使用本翻译而引起的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,84 +1,168 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "89f7f9f800ce7c9f149e98baaae8491a",
"translation_date": "2025-08-29T14:49:22+00:00",
"original_hash": "3fcfa99c4897e051b558b5eaf1e8cc74",
"translation_date": "2026-01-06T11:48:52+00:00",
"source_file": "3-terrarium/1-intro-to-html/README.md",
"language_code": "zh"
}
-->
# Terrarium 项目第一部分HTML 入门
![HTML 入门](../../../../translated_images/webdev101-html.4389c2067af68e98280c1bde52b6c6269f399eaae3659b7c846018d8a7b0bbd9.zh.png)
> [Tomomi Imura](https://twitter.com/girlie_mac) 的手绘笔记
```mermaid
journey
title 你的HTML学习之旅
section 基础
创建HTML文件: 3: Student
添加DOCTYPE: 4: Student
结构文档: 5: Student
section 内容
添加元数据: 4: Student
插入图片: 5: Student
组织布局: 5: Student
section 语义
使用正确标签: 4: Student
提升无障碍性: 5: Student
建造生态瓶: 5: Student
```
![HTML 入门](../../../../translated_images/webdev101-html.4389c2067af68e98.zh.png)
> 速记图由 [Tomomi Imura](https://twitter.com/girlie_mac) 提供
HTML即超文本标记语言是你访问过的每个网站的基础。把 HTML 想象成网页的骨架 —— 它定义了内容的位置、组织方式以及每个部分的含义。虽然 CSS 会在之后用颜色和布局“装饰”你的 HTMLJavaScript 会通过交互让它“活起来”,但 HTML 则提供了实现一切的基本结构。
在本课中,你将为一个虚拟的玻璃植物箱界面创建 HTML 结构。这个动手项目将教会你基本的 HTML 概念,同时构建一个视觉上有吸引力的东西。你将学习如何使用语义元素来组织内容、处理图片,并为一个交互式网页应用创建基础。
课程结束时你将拥有一个可以显示植物图片并组织成列的工作HTML页面为下一课的样式设计做好准备。如果一开始看起来很基础不用担心 —— 这正是 HTML 在 CSS 添加视觉装饰之前应有的样子。
```mermaid
mindmap
root((HTML 基础))
Structure
DOCTYPE 声明
HTML 元素
头部部分
主体内容
Elements
标签与属性
自闭合标签
嵌套元素
块元素 vs 行内元素
Content
文本元素
图像
容器 (div)
列表
Semantics
有意义的标签
无障碍
屏幕阅读器
SEO 优势
Best Practices
正确嵌套
有效标记
描述性替代文本
结构清晰
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/15)
> 查看视频
>
> [![Git 和 GitHub 基础视频](https://img.youtube.com/vi/1TvxJKBzhyQ/0.jpg)](https://www.youtube.com/watch?v=1TvxJKBzhyQ)
### 简介
HTML超文本标记语言是网页的“骨架”。如果说 CSS 是为 HTML“穿衣打扮”JavaScript 是赋予其“生命”,那么 HTML 就是网页应用的“身体”。HTML 的语法甚至反映了这一点因为它包含了“head”头部、“body”主体和“footer”页脚标签。
> 📺 **观看学习**:查看这段有帮助的视频综述
>
> [![HTML 基础视频](https://img.youtube.com/vi/1TvxJKBzhyQ/0.jpg)](https://www.youtube.com/watch?v=1TvxJKBzhyQ)
在本课中,我们将使用 HTML 来布局虚拟生态瓶界面的“骨架”。界面将包括一个标题和三个列:左右两侧的列放置可拖动的植物,中间区域将是玻璃状的生态瓶。到本课结束时,你将能够看到列中的植物,但界面可能看起来有点奇怪;别担心,在下一节中,你将添加 CSS 样式来让界面更美观。
## 设置你的项目
### 任务
在开始编写 HTML 代码之前,让我们为你的玻璃植物箱项目搭建一个合适的工作空间。从一开始创建一个有序的文件结构是一个非常重要的习惯,它将在你整个网页开发旅程中为你带来帮助。
在你的电脑上创建一个名为“terrarium”的文件夹并在其中创建一个名为“index.html”的文件。你可以在 Visual Studio Code 中完成此操作:创建 terrarium 文件夹后,打开一个新的 VS Code 窗口,点击“打开文件夹”,导航到你的新文件夹。然后点击资源管理器面板中的小“文件”按钮,创建新文件:
![VS Code 中的资源管理器](../../../../translated_images/vs-code-index.e2986cf919471eb984a0afef231380c8b132b000635105f2397bd2754d1b689c.zh.png)
或者
使用以下 git bash 命令:
* `mkdir terrarium`
* `cd terrarium`
* `touch index.html`
* `code index.html``nano index.html`
> index.html 文件告诉浏览器它是文件夹中的默认文件;例如,`https://anysite.com/test` 可能是基于一个文件夹结构构建的,其中包含一个名为 `test` 的文件夹和一个 `index.html` 文件URL 中不一定会显示 `index.html`
---
### 任务:创建你的项目结构
## DocType 和 html 标签
你将为玻璃植物箱项目创建专用文件夹,并添加你的第一个 HTML 文件。这里有两个方法可供选择:
HTML 文件的第一行是它的 DocType。这行代码需要放在文件的最顶部虽然看起来有点奇怪但它告诉旧版浏览器需要以标准模式渲染页面并遵循当前的 HTML 规范。
**选项 1使用 Visual Studio Code**
1. 打开 Visual Studio Code
2. 点击“文件”→“打开文件夹”或使用快捷键 `Ctrl+K, Ctrl+O`Windows/Linux`Cmd+K, Cmd+O`Mac
3. 创建一个名为 `terrarium` 的新文件夹并选中它
4. 在资源管理器面板点击“新建文件”图标
5. 将你的文件命名为 `index.html`
> 提示:在 VS Code 中,你可以将鼠标悬停在标签上,查看 MDN 参考指南中关于其用途的信息。
![VS Code 资源管理器显示新建文件](../../../../translated_images/vs-code-index.e2986cf919471eb9.zh.png)
第二行应该是 `<html>` 标签的开始标签,紧接着是它的结束标签 `</html>`。这些标签是界面的根元素。
### 任务
在你的 `index.html` 文件顶部添加以下代码:
**选项 2使用终端命令**
```bash
mkdir terrarium
cd terrarium
touch index.html
code index.html
```
**这些命令实现的操作有:**
- **创建** 一个名为 `terrarium` 的新目录
- **进入** 该 `terrarium` 目录
- **创建** 一个空的 `index.html` 文件
- **在 Visual Studio Code 中打开** 该文件进行编辑
> 💡 **专业提示**`index.html` 文件名在网页开发中很特殊。当访问网站时,浏览器会自动寻找 `index.html` 作为默认显示页面。这意味着像 `https://mysite.com/projects/` 这样的 URL 会自动加载 `projects` 文件夹中的 `index.html`,无需在 URL 中指定文件名。
## 理解 HTML 文档结构
每个 HTML 文档都有特定的结构,浏览器需要通过它来理解并正确显示页面内容。把这种结构想象成一封正式的信 —— 它由按特定顺序排列的必需元素组成,帮助接收者(这里是浏览器)正确处理内容。
```mermaid
flowchart TD
A["<!DOCTYPE html>"] --> B["<html>"]
B --> C["<head>"]
C --> D["<title>标题"]
C --> E["<meta charset>"]
C --> F["<meta viewport>"]
B --> G["<body>"]
G --> H["<h1> 标题"]
G --> I["<div> 容器"]
G --> J["<img> 图片"]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#fff3e0
style G fill:#e8f5e8
```
让我们先添加每个 HTML 文档都需要的基础内容。
### DOCTYPE 声明和根元素
任何 HTML 文件的前两行作为对浏览器的“文档介绍”:
```HTML
```html
<!DOCTYPE html>
<html></html>
```
**理解这段代码做了什么:**
- **声明** 文档类型为 HTML5使用 `<!DOCTYPE html>`
- **创建** 含有所有页面内容的根 `<html>` 元素
- **确立** 现代网页标准,确保浏览器正确渲染
- **保证** 各种浏览器和设备上的一致显示效果
✅ 通过设置 DocType 的查询字符串可以确定不同的模式:[Quirks 模式和标准模式](https://developer.mozilla.org/docs/Web/HTML/Quirks_Mode_and_Standards_Mode)。这些模式曾用于支持非常旧的浏览器(如 Netscape Navigator 4 和 Internet Explorer 5但现在通常不再使用。你可以坚持使用标准的 DocType 声明。
> 💡 **VS Code 提示**:在 VS Code 中将鼠标悬停于任意 HTML 标签上,可以看到来自 MDN Web Docs 的帮助信息,包括用法示例和浏览器兼容性详情
---
> 📚 **了解更多**DOCTYPE 声明确保浏览器不会进入“怪异模式”,怪异模式用于支持非常古老的网站。现代网页开发使用简单的 `<!DOCTYPE html>` 声明以保证[标准兼容渲染](https://developer.mozilla.org/docs/Web/HTML/Quirks_Mode_and_Standards_Mode)。
### 🔄 **教学检查点**
**暂停并反思**:在继续之前,确保你理解了:
- ✅ 为什么每个 HTML 文档都需要 DOCTYPE 声明
- ✅ `<html>` 根元素包含了什么
- ✅ 这种结构如何帮助浏览器正确渲染页面
## 文档的 'head'
**快速自测**:你能用自己的话解释“标准兼容渲染”是什么意思吗?
HTML 文档的 'head' 区域包含关于网页的重要信息,也称为 [元数据](https://developer.mozilla.org/docs/Web/HTML/Element/meta)。在我们的例子中,我们告诉将渲染此页面的网络服务器以下四件事:
## 添加必要的文档元数据
- 网页的标题
- 页面元数据,包括:
- 字符集,指示页面使用的字符编码
- 浏览器信息,包括 `x-ua-compatible`,指示支持 IE=edge 浏览器
- 关于视口在加载时如何表现的信息。将视口设置为初始缩放比例为 1 可以控制页面首次加载时的缩放级别。
HTML 文档的 `<head>` 部分包含了浏览器和搜索引擎需要的关键信息,但访客不会直接看到它。这部分可以看作是“幕后”信息,帮助你的网页正常工作且在不同设备和平台上正确显示。
### 任务
这段元数据告诉浏览器如何显示页面,使用什么字符编码,以及如何处理不同屏幕尺寸 —— 这些都是构建专业且可访问网页的重要因素。
`<html>` 标签对之间添加一个 'head' 块。
### 任务:添加文档头部
将以下 `<head>` 部分插入到 `<html>` 标签的开头和结尾之间:
```html
<head>
@ -88,18 +172,29 @@ HTML 文档的 'head' 区域包含关于网页的重要信息,也称为 [元
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
```
**拆解每个元素的作用:**
- **设置** 在浏览器标签和搜索结果中显示的页面标题
- **指定** UTF-8 字符编码,确保文本能正确显示全球字符
- **保证** 兼容现代版本的 Internet Explorer
- **通过设置视口匹配设备宽度** 来实现响应式设计
- **控制** 页面初始缩放,保证内容按自然大小显示
✅ 如果你像这样设置视口元标签:`<meta name="viewport" content="width=600">`,会发生什么?阅读更多关于 [视口](https://developer.mozilla.org/docs/Web/HTML/Viewport_meta_tag) 的信息。
> 🤔 **思考这个问题**:如果你设置了 `<meta name="viewport" content="width=600">` 会发生什么?页面会被强制固定为 600 像素宽,打破响应式设计!了解更多关于[正确视口配置](https://developer.mozilla.org/docs/Web/HTML/Viewport_meta_tag)。
---
## 构建文档主体
`<body>` 元素包含网页所有的可见内容 —— 用户将看到并与之交互的一切。虽然 `<head>` 向浏览器提供指令,`<body>` 才是真正持有内容:文字、图片、按钮及其他创建用户界面的元素。
## 文档的 `body`
让我们添加主体结构,理解 HTML 标签如何协作创建有意义内容。
### HTML 标签
### 理解 HTML 标签结构
在 HTML 中,你可以在 .html 文件中添加标签来创建网页元素。每个标签通常都有一个开始标签和结束标签,例如:`<p>hello</p>` 表示一个段落。通过在 `<html>` 标签对内添加一组 `<body>` 标签来创建界面的主体;你的标记现在看起来像这样:
HTML 使用成对标签定义元素。大多数标签有开标签如 `<p>` 和闭标签如 `</p>`,中间包含内容:`<p>Hello, world!</p>`表示一个包含文本“Hello, world!”的段落元素。
### 任务
### 任务:添加 `<body>` 元素
更新你的 HTML 文件,加入 `<body>` 元素:
```html
<!DOCTYPE html>
@ -113,101 +208,180 @@ HTML 文档的 'head' 区域包含关于网页的重要信息,也称为 [元
<body></body>
</html>
```
**该完整结构提供了:**
- **建立** 基本的 HTML5 文档框架
- **包含** 正确渲染所必须的元数据
- **创建** 一个空白主体,为你的可见内容准备位置
- **符合** 现代网页开发的最佳实践
现在你可以开始添加玻璃植物箱的可见元素了。我们将用 `<div>` 元素作为容器来组织不同内容区域,并用 `<img>` 标签显示植物图片。
现在,你可以开始构建你的页面了。通常,你会使用 `<div>` 标签来创建页面中的各个元素。我们将创建一系列 `<div>` 元素,这些元素将包含图片。
### 使用图片和布局容器
### 图片
图片在 HTML 中比较特殊,因为它们使用“自闭合”标签。与像 `<p></p>` 这类包裹内容的元素不同,`<img>` 标签在标签内部通过属性(如 `src` 指向图片文件路径,`alt` 用于无障碍访问)包含了所需全部信息。
一个不需要结束标签的 HTML 标签是 `<img>` 标签,因为它有一个 `src` 元素,包含页面渲染该项目所需的所有信息。
添加图片前,你需要通过创建图片文件夹并添加植物图形来合理组织项目文件
在你的应用中创建一个名为 `images` 的文件夹,并将 [源代码文件夹](../../../../3-terrarium/solution/images) 中的所有图片添加到其中;(有 14 张植物图片)。
**首先,设置你的图片:**
1. 在玻璃植物箱项目文件夹中创建一个名为 `images` 的文件夹
2. 从 [solution folder](../../../../3-terrarium/solution/images) 下载植物图片共14张
3. 将所有植物图片复制到你的新 `images` 文件夹中
### 任务
### 任务:创建植物展示布局
`<body></body>` 标签之间的两列中添加这些植物图片:
现在,在你的 `<body></body>` 标签之间,添加组织成两列的植物图片:
```html
<div id="page">
<div id="left-container" class="container">
<div class="plant-holder">
<img class="plant" alt="plant" id="plant1" src="./images/plant1.png" />
<img class="plant" alt="plant" id="plant1" src="../../../../translated_images/plant1.d87946a2ca70cc43.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant2" src="./images/plant2.png" />
<img class="plant" alt="plant" id="plant2" src="../../../../translated_images/plant2.8daa1606c9c1ad89.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant3" src="./images/plant3.png" />
<img class="plant" alt="plant" id="plant3" src="../../../../translated_images/plant3.8b0d484381a2a2a7.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant4" src="./images/plant4.png" />
<img class="plant" alt="plant" id="plant4" src="../../../../translated_images/plant4.656e16ae1df37be2.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant5" src="./images/plant5.png" />
<img class="plant" alt="plant" id="plant5" src="../../../../translated_images/plant5.2b41b9355f11ebcc.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant6" src="./images/plant6.png" />
<img class="plant" alt="plant" id="plant6" src="../../../../translated_images/plant6.3d1827d03b656994.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant7" src="./images/plant7.png" />
<img class="plant" alt="plant" id="plant7" src="../../../../translated_images/plant7.8152c302ac97f621.zh.png" />
</div>
</div>
<div id="right-container" class="container">
<div class="plant-holder">
<img class="plant" alt="plant" id="plant8" src="./images/plant8.png" />
<img class="plant" alt="plant" id="plant8" src="../../../../translated_images/plant8.38d6428174ffa850.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant9" src="./images/plant9.png" />
<img class="plant" alt="plant" id="plant9" src="../../../../translated_images/plant9.f0e38d3327c37fc2.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant10" src="./images/plant10.png" />
<img class="plant" alt="plant" id="plant10" src="../../../../translated_images/plant10.b159d6d6e985595f.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant11" src="./images/plant11.png" />
<img class="plant" alt="plant" id="plant11" src="../../../../translated_images/plant11.2a03a1c2ec8ea84e.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant12" src="./images/plant12.png" />
<img class="plant" alt="plant" id="plant12" src="../../../../translated_images/plant12.60e9b53e538fbaf3.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant13" src="./images/plant13.png" />
<img class="plant" alt="plant" id="plant13" src="../../../../translated_images/plant13.07a51543c820bcf5.zh.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant14" src="./images/plant14.png" />
<img class="plant" alt="plant" id="plant14" src="../../../../translated_images/plant14.6e486371ba7d36ba.zh.png" />
</div>
</div>
</div>
```
> 注意Span 和 Div 的区别。Div 被认为是“块”元素,而 Span 是“内联”元素。如果你将这些 div 转换为 span会发生什么
通过这些标记,植物现在会显示在屏幕上。看起来可能很糟,因为它们还没有使用 CSS 进行样式化,我们将在下一课中完成样式化。
每张图片都有 alt 文本即使你无法看到或渲染图片alt 文本也会显示。这是一个重要的属性有助于提高可访问性。在后续课程中你将了解更多关于可访问性的信息目前请记住alt 属性为图片提供了替代信息以防用户因某些原因无法查看图片例如网络连接慢、src 属性错误或用户使用屏幕阅读器)。
✅ 你是否注意到每张图片都有相同的 alt 标签?这是一个好习惯吗?为什么?你能改进这段代码吗?
---
## 语义化标记
通常,在编写 HTML 时,使用有意义的“语义化”标记是更好的选择。这是什么意思?这意味着你使用 HTML 标签来表示它们设计用于的数据或交互类型。例如,页面上的主要标题文本应该使用 `<h1>` 标签。
在打开的 `<body>` 标签下方添加以下代码:
**这段代码的步骤说明如下:**
- **创建** 一个主页面容器,`id="page"`,用于包含所有内容
- **建立** 两个列容器:`left-container` 和 `right-container`
- **将** 7 株植物放入左列7 株放入右列
- **用** `plant-holder` div 包裹每株植物图片,方便单独定位
- **应用** 一致的类名,方便下一课中 CSS 样式设定
- **为** 每个植物图片分配唯一 ID便于后续 JavaScript 操作
- **包含** 指向 images 文件夹的正确文件路径
> 🤔 **考虑这个问题**:注意所有图片的 alt 属性都写成了“plant”这不利于无障碍访问。屏幕阅读器会连续读取14次“plant”用户无法区分每张图片具体是哪株植物。你能想到更合适、描述更准确的 alt 文本吗?
> 📝 **HTML 元素类型**`<div>` 是“块级元素”,占满整行宽度;`<span>` 是“内联元素”,只占内容所需宽度。如果把这些 `<div>` 标签全部换成 `<span>` 会怎样?
### 🔄 **教学检查点**
**结构理解**:花点时间回顾你的 HTML 结构:
- ✅ 你能识别布局中的主要容器吗?
- ✅ 你理解为什么每张图片都需要唯一 ID
- ✅ 你会怎么描述 `plant-holder` div 的作用?
**视觉检查**:在浏览器中打开你的 HTML 文件。你应该能看到:
- 一个基础的植物图片列表
- 图片分成两列排列
- 简单且未加样式的布局
**记住**:这种朴素的外观正是 CSS 添加样式前 HTML 应有的样子!
有了这些标记,植物将出现在屏幕上,虽然还没有美观的样式 —— 那正是下一课 CSS 的作用!现在你有了坚实的 HTML 基础,内容被正确组织且符合无障碍最佳实践。
## 使用语义 HTML 提升无障碍性
语义 HTML 指的是根据内容的意义和用途选择 HTML 元素,而不是仅仅根据外观使用。当你使用语义标记时,就在向浏览器、搜索引擎和辅助技术(如屏幕阅读器)传达内容的结构和意义。
```mermaid
flowchart TD
A[需要添加内容?] --> B{类型?}
B -->|主标题| C["<h1>"]
B -->|副标题| D["<h2>, <h3> 等"]
B -->|段落| E["<p>"]
B -->|列表| F["<ul>, <ol>"]
B -->|导航| G["<nav>"]
B -->|文章| H["<article>"]
B -->|章节| I["<section>"]
B -->|通用容器| J["<div>"]
C --> K[屏幕阅读器宣布为主标题]
D --> L[创建正确的标题层级]
E --> M[提供适当的文本间距]
F --> N[启用列表导航快捷方式]
G --> O[识别导航地标]
H --> P[标记独立内容]
I --> Q[分组相关内容]
J --> R[仅在没有语义标签适用时使用]
style C fill:#4caf50
style D fill:#4caf50
style E fill:#4caf50
style F fill:#4caf50
style G fill:#2196f3
style H fill:#2196f3
style I fill:#2196f3
style J fill:#ff9800
```
这种方法让你的网站对残障用户更友好,也帮助搜索引擎更好地理解内容。这是现代网页开发的基本原则,能为所有用户创造更好的体验。
### 添加语义页面标题
让我们给玻璃植物箱页面添加一个合适的标题。将这行代码插入到你的 `<body>` 标签之后:
```html
<h1>My Terrarium</h1>
```
**语义标记重要性的原因:**
- **帮助** 屏幕阅读器导航并理解页面结构
- **改善** 搜索引擎优化SEO明确内容层级
- **增强** 视觉障碍或认知障碍用户的无障碍性
- **创造** 跨所有设备和平台更佳的用户体验
- **符合** 网页标准和专业开发的最佳实践
使用语义化标记,例如将标题设置为 `<h1>`,将无序列表渲染为 `<ul>`,可以帮助屏幕阅读器更好地导航页面。通常,按钮应该写为 `<button>`,列表项应该写为 `<li>`。虽然可以使用带有点击处理程序的特殊样式 `<span>` 元素来模拟按钮,但对于残障用户来说,使用技术来确定页面上的按钮位置并与之交互会更方便。如果元素显示为按钮,屏幕阅读器会更容易识别。因此,尽量使用语义化标记。
**语义与非语义选择示例:**
✅ 查看屏幕阅读器 [如何与网页交互](https://www.youtube.com/watch?v=OUDV1gqs9GA)。你能理解为什么非语义化标记可能会让用户感到沮丧吗?
| 目的 | ✅ 语义选择 | ❌ 非语义选择 |
|---------|-------------------|------------------------|
| 主要标题 | `<h1>Title</h1>` | `<div class="big-text">Title</div>` |
| 导航 | `<nav><ul><li></li></ul></nav>` | `<div class="menu"><div></div></div>` |
| 按钮 | `<button>Click me</button>` | `<span onclick="...">Click me</span>` |
| 文章内容 | `<article><p></p></article>` | `<div class="content"><div></div></div>` |
## 生态瓶
> 🎥 **示范视频**:观看[屏幕阅读器如何与网页交互](https://www.youtube.com/watch?v=OUDV1gqs9GA),理解语义标记为何对无障碍性至关重要。注意规范的 HTML 结构如何让用户高效导航。
界面的最后一部分涉及创建标记,这些标记将被样式化以创建生态瓶。
## 创建玻璃植物箱容器
### 任务:
现在,让我们添加玻璃植物箱自身的 HTML 结构 —— 这是存放植物的玻璃容器。该部分展示了一个重要概念HTML 提供结构,但没有 CSS 样式,这些元素暂时不可见。
在最后一个 `</div>` 标签上方添加以下标记:
玻璃植物箱标记使用了描述性很强的类名,方便下一课 CSS 直观且易维护的设计。
### 任务:添加玻璃植物箱结构
将以下标记插入到最后一个 `</div>` 标签之前(即页面容器关闭标签之前):
```html
<div id="terrarium">
@ -220,14 +394,73 @@ HTML 文档的 'head' 区域包含关于网页的重要信息,也称为 [元
<div class="jar-bottom"></div>
</div>
```
**理解这个玻璃植物箱结构:**
- **创建** 一个主要的玻璃植物箱容器,并赋予唯一 ID 以便样式设计
- **定义** 每个视觉组件(顶部、墙壁、泥土、底部)的独立元素
- **包含** 用于玻璃反射效果的嵌套元素(光泽元素)
- **使用** 描述性类名,明确指示每个元素的用途
- **准备** CSS 样式结构,以创建玻璃生态瓶的外观
> 🤔 **注意到了吗?**:即使你添加了这些标记,你在页面上也看不到任何新内容!这完美说明了 HTML 提供结构,而 CSS 提供外观。这些 `<div>` 元素存在,但尚未有视觉样式——这将在下一课中完成!
```mermaid
flowchart TD
A[HTML 文档] --> B[文档头部]
A --> C[文档主体]
B --> D[标题元素]
B --> E[元字符集]
B --> F[元视口]
C --> G[主标题]
C --> H[页面容器]
H --> I[左侧容器内含7株植物]
H --> J[右侧容器内含7株植物]
H --> K[生态瓶结构]
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#e8f5e8
style H fill:#f3e5f5
```
### 🔄 **教学自查**
**HTML 结构掌握**:在继续之前,请确保你能够:
- ✅ 解释 HTML 结构和视觉外观的区别
- ✅ 识别语义和非语义的 HTML 元素
- ✅ 描述正确的标记如何有利于无障碍访问
- ✅ 认识完整的文档树结构
✅ 即使你将这些标记添加到屏幕上,你却看不到任何渲染。为什么?
**测试你的理解**:尝试在禁用 JavaScript 和移除 CSS 的浏览器中打开你的 HTML 文件。这样你就能看到你创建的纯粹语义结构!
---
## 🚀挑战
## GitHub Copilot Agent 挑战
HTML 中有一些有趣的“旧”标签,虽然不建议使用已弃用的标签,例如 [这些标签](https://developer.mozilla.org/docs/Web/HTML/Element#Obsolete_and_deprecated_elements),但它们仍然值得一试。你能使用旧的 `<marquee>` 标签让 h1 标题水平滚动吗?(如果你这样做,记得之后将其删除)
使用 Agent 模式完成以下挑战:
**描述:** 创建一个语义化的 HTML 结构,用于添加到生态瓶项目中的植物护理指南部分。
**提示:** 创建一个语义化的 HTML 段落包含主标题“Plant Care Guide”植物护理指南三个子部分标题分别为“Watering”浇水、“Light Requirements”光照需求和“Soil Care”土壤护理每部分包含一段植物护理信息。使用合适的语义 HTML 标签,如 `<section>`、`<h2>`、`<h3>` 和 `<p>`,来适当组织内容。
了解更多关于 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 。
## 探索 HTML 历史挑战
**了解网页演变**
自 1990 年 Tim Berners-Lee 在 CERN 创建第一个网页浏览器以来HTML 已经发生了巨大变革。一些老旧标签如 `<marquee>` 现在被废弃,因为它们与现代无障碍标准和响应式设计原则不兼容。
**尝试这个实验:**
1. 临时用 `<marquee>` 标签包裹你的 `<h1>` 标题:`<marquee><h1>My Terrarium</h1></marquee>`
2. 在浏览器中打开页面,观察滚动效果
3. 思考为什么该标签被废弃(提示:考虑用户体验和无障碍)
4. 移除 `<marquee>` 标签,恢复语义化标记
**反思问题:**
- 滚动标题如何影响视力障碍或动作敏感的用户?
- 哪些现代 CSS 技术可以更无障碍地实现类似视觉效果?
- 为什么使用当前的网页标准比使用废弃元素更重要?
探索更多关于 [过时和废弃的 HTML 元素](https://developer.mozilla.org/docs/Web/HTML/Element#Obsolete_and_deprecated_elements) ,了解网页标准如何发展以提升用户体验。
## 课后测验
@ -235,15 +468,127 @@ HTML 中有一些有趣的“旧”标签,虽然不建议使用已弃用的标
## 复习与自学
HTML 是一种“久经考验”的构建块系统,帮助网页发展到今天的样子。通过研究一些旧标签和新标签,了解它的历史。你能弄清楚为什么某些标签被弃用,而某些标签被添加吗?未来可能会引入哪些标签?
**加深你的 HTML 知识**
HTML 作为网页的基础已有 30 多年历史,从简单的文档标记语言演变为构建互动应用的复杂平台。理解这一演变有助于你更好地理解现代网页标准,并做出更好的开发决策。
**推荐学习路径:**
1. **HTML 历史与演变**
- 研究从 HTML 1.0 到 HTML5 的时间线
- 探讨某些标签被废弃的原因(无障碍、移动友好性、可维护性)
- 调查新兴的 HTML 特性和提案
2. **语义 HTML 深入学习**
- 学习完整的 [HTML5 语义元素列表](https://developer.mozilla.org/docs/Web/HTML/Element)
- 练习识别 `<article>`、`<section>`、`<aside>` 和 `<main>` 的使用时机
- 了解增强无障碍的 ARIA 属性
3. **现代网页开发**
- 探索 Microsoft Learn 上的 [构建响应式网站](https://docs.microsoft.com/learn/modules/build-simple-website/?WT.mc_id=academic-77807-sagibbon)
- 理解 HTML 如何与 CSS 和 JavaScript 集成
- 学习网页性能和 SEO 最佳实践
**反思问题:**
- 你发现了哪些被废弃的 HTML 标签?它们为何被移除?
- 未来版本有哪些新的 HTML 特性正在提案中?
- 语义 HTML 如何助力网页无障碍和 SEO
### ⚡ **未来 5 分钟内可做事项**
- [ ] 打开 DevToolsF12并检查你喜欢网站的 HTML 结构
- [ ] 创建一个包含基本标签 `<h1>`、`<p>`、`<img>` 的简单 HTML 文件
- [ ] 使用 W3C HTML Validator 进行 HTML 验证
- [ ] 尝试用 `<!-- comment -->` 添加 HTML 注释
### 🎯 **未来一小时可完成事项**
- [ ] 完成课后测验并复习语义 HTML 概念
- [ ] 使用恰当的 HTML 结构建立一个简单的个人网页
- [ ] 试验不同的标题级别和文本格式化标签
- [ ] 添加图片和链接练习多媒体集成
- [ ] 研究你未尝试过的 HTML5 特性
### 📅 **未来一周的 HTML 学习计划**
- [ ] 使用语义标记完成生态瓶项目作业
- [ ] 创建一个使用 ARIA 标签和角色的无障碍网页
- [ ] 练习创建带有多种输入类型的表单
- [ ] 探索 HTML5 API比如 localStorage 或地理位置
- [ ] 学习响应式 HTML 模式和移动优先设计
- [ ] 审查其他开发者的 HTML 代码,学习最佳实践
### 🌟 **未来一个月的网页基础计划**
- [ ] 构建展示你 HTML 精通程度的个人作品网站
- [ ] 学习使用 Handlebars 等框架进行 HTML 模板编写
- [ ] 通过改进 HTML 文档贡献开源项目
- [ ] 掌握高级 HTML 概念,如自定义元素
- [ ] 将 HTML 与 CSS 框架和 JavaScript 库整合
- [ ] 指导其他 HTML 初学者
## 🎯 你的 HTML 掌握时间表
```mermaid
timeline
title HTML 学习进度
section 基础 (5分钟)
文档结构: DOCTYPE 声明
: HTML 根元素
: 头部与主体理解
section 元数据 (10分钟)
必要的元标签: 字符编码
: 视口配置
: 浏览器兼容性
section 内容创建 (15分钟)
图片集成: 正确的文件路径
: 替代文本的重要性
: 自闭合标签
section 布局组织 (20分钟)
容器策略: 使用 Div 元素结构
: 类名和 ID 命名
: 嵌套元素层级
section 语义掌握 (30分钟)
有意义的标记: 标题层级
: 屏幕阅读器导航
: 可访问性最佳实践
section 高级概念 (1小时)
HTML5 特性: 现代语义元素
: ARIA 属性
: 性能考虑
section 专业技能 (1周)
代码组织: 文件结构模式
: 可维护的标记
: 团队协作
section 专家级别 (1个月)
现代网页标准: 渐进式增强
: 跨浏览器兼容性
: HTML 规范更新
```
### 🛠️ 你的 HTML 工具包总结
完成本课后,你已具备:
- **文档结构**:完整的 HTML5 基础,包含正确的 DOCTYPE
- **语义标记**:富有意义、有助于无障碍和 SEO 的标签
- **图像集成**:合理的文件组织和 alt 文本规范
- **布局容器**:用描述性类名战略性地使用 div
- **无障碍意识**:理解屏幕阅读器的导航方式
- **现代标准**:掌握当前 HTML5 实践及废弃标签知识
- **项目基础**:为 CSS 样式和 JavaScript 交互搭建坚实基础
了解更多关于为网页和移动设备构建网站的信息,请访问 [Microsoft Learn](https://docs.microsoft.com/learn/modules/build-simple-website/?WT.mc_id=academic-77807-sagibbon)。
**下一步**:你的 HTML 结构已准备好进行 CSS 样式设计!你所构建的语义基础将使下一课更加易懂
## 作业
[练习 HTML构建博客模型](assignment.md)
[练习你的 HTML构建博客模拟页面](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始文件的母语版本应被视为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而产生的任何误解或误读,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,53 +1,154 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "5a764667bbe82aa72ac0a67f4c97ff4a",
"translation_date": "2025-10-03T08:50:02+00:00",
"original_hash": "650e63282e1dfa032890fcf5c1c4119d",
"translation_date": "2026-01-06T11:50:29+00:00",
"source_file": "3-terrarium/1-intro-to-html/assignment.md",
"language_code": "zh"
}
-->
# HTML实践作业:构建博客模
# HTML 练习作业:构建博客原
## 目标
## 学习目标
设计并手写个人博客主页的HTML结构。通过这个练习你将练习语义化HTML、布局规划以及代码组织
通过设计和编码一个完整的博客主页结构,应用您的 HTML 知识。这个实践作业将强化语义 HTML 概念、无障碍最佳实践以及专业代码组织技能,这些技能将在您的整个网页开发旅程中使用
## 说明
**完成此作业后,您将能够:**
- 练习在编码前规划网站布局
- 适当地应用语义 HTML 元素
- 创建可访问的、结构良好的标记
- 培养带有注释和组织的专业编码习惯
1. **设计你的博客模型**
- 绘制博客主页的视觉模型草图。包括关键部分,如页眉、导航栏、主要内容、侧边栏和页脚。
- 你可以使用纸张绘制并扫描你的草图或者使用数字工具例如Figma、Adobe XD、Canva甚至PowerPoint
## 项目要求
2. **识别HTML元素**
- 列出你计划在每个部分中使用的HTML元素例如`<header>`、`<nav>`、`<main>`、`<article>`、`<aside>`、`<footer>`、`<section>`、`<h1>``<h6>`、`<p>`、`<img>`、`<ul>`、`<li>`、`<a>`等)。
### 第 1 部分:设计规划(视觉原型)
3. **编写HTML标记**
- 手写你的模型的HTML代码。专注于语义结构和最佳实践。
- 至少包含10个不同的HTML元素。
- 添加注释以解释你的选择和结构。
**创建您的博客主页的视觉原型,包括:**
- 带有网站标题和导航的页眉
- 具有至少 2-3 篇博客文章预览的主内容区
- 包含附加信息的侧边栏(关于部分、最近帖子、分类)
- 带有联系信息或链接的页脚
4. **提交你的作品**
- 上传你的草图/模型和HTML文件。
- 可选提供一段简短的反思23句话说明你的设计决策。
**原型创建选项:**
- **手绘草图**:使用纸和铅笔,然后拍照或扫描您的设计
- **数字工具**Figma、Adobe XD、Canva、PowerPoint 或任何绘图应用
- **线框工具**Balsamiq、MockFlow 或类似的线框软件
## 评分标准
**在您的原型部分标注您计划使用的 HTML 元素**(例如,“页眉 - `<header>`”、“博客文章 - `<article>`”)。
| 评估标准 | 卓越表现 | 合格表现 | 需改进表现 |
|----------------|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| 视觉模型 | 清晰、详细的模型,标注了各部分并具有深思熟虑的布局 | 基本模型,标注了一些部分 | 模型简单或不清晰;缺乏部分标注 |
| HTML元素 | 使用10个以上语义化HTML元素展示了对结构和最佳实践的理解 | 使用59个HTML元素部分语义化结构 | 使用少于5个元素缺乏语义化结构 |
| 代码质量 | 代码组织良好、可读性强带有注释遵循HTML标准 | 代码大体组织良好;注释较少 | 代码组织混乱;缺乏注释 |
| 反思 | 深刻反思设计选择和挑战 | 基本反思 | 无反思或缺乏相关性 |
### 第 2 部分HTML 元素规划
## 提示
**创建一个列表,将您的原型的每个部分映射到特定的 HTML 元素:**
- 使用语义化HTML标签以提高可访问性和SEO。
- 使用缩进和注释来组织代码。
- 参考 [MDN HTML元素参考](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) 获取指导。
- 考虑你的布局如何在未来的作业中扩展或进行样式化。
```
Example:
- Site Header → <header>
- Main Navigation → <nav> with <ul> and <li>
- Blog Post → <article> with <h2>, <p>, <time>
- Sidebar → <aside> with <section> elements
- Page Footer → <footer>
```
**必须包含的元素:**
您的 HTML 必须至少包含以下列表中 10 种不同的语义元素:
- `<header>`, `<nav>`, `<main>`, `<article>`, `<section>`, `<aside>`, `<footer>`
- `<h1>`, `<h2>`, `<h3>`, `<p>`, `<ul>`, `<li>`, `<a>`
- `<img>`, `<time>`, `<blockquote>`, `<strong>`, `<em>`
### 第 3 部分HTML 实现
**编码您的博客主页,遵循以下标准:**
1. **文档结构**:包含正确的 DOCTYPE、html、head 和 body 元素
2. **语义标记**:根据用途使用 HTML 元素
3. **无障碍**:为图片加入恰当的 alt 文本和有意义的链接文本
4. **代码质量**:使用一致的缩进和有意义的注释
5. **内容**:包含真实的博客内容(您可以使用占位文本)
**示例 HTML 结构:**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Personal Blog</title>
</head>
<body>
<!-- Main site header -->
<header>
<h1>My Blog Title</h1>
<nav>
<!-- Navigation menu -->
</nav>
</header>
<!-- Main content area -->
<main>
<!-- Blog posts go here -->
</main>
<!-- Sidebar content -->
<aside>
<!-- Additional information -->
</aside>
<!-- Site footer -->
<footer>
<!-- Footer content -->
</footer>
</body>
</html>
```
### 第 4 部分:反思
**写一个简短的反思3-5 句),内容包括:**
- 哪些 HTML 元素是您最有信心使用的?
- 规划或编码过程中遇到了哪些挑战?
- 语义 HTML 如何帮助您组织内容?
- 下一次 HTML 项目中您会有什么不同的做法?
## 提交清单
**提交前,请确保您已完成:**
- [ ] 带有标注 HTML 元素的视觉原型
- [ ] 完整的 HTML 文件,具有正确的文档结构
- [ ] 至少使用了 10 种不同且恰当的语义 HTML 元素
- [ ] 有意义的注释,解释您的代码结构
- [ ] 有效的 HTML 语法(在浏览器中测试)
- [ ] 针对提示问题的书面反思
## 评估标准
| 评估标准 | 优秀 (4) | 良好 (3) | 发展中 (2) | 初学者 (1) |
|----------|----------|----------|------------|------------|
| **规划与设计** | 详尽且标注清晰的原型,展示了对布局和 HTML 语义结构的深刻理解 | 清晰的原型,大部分部分都有恰当标注 | 基本原型,有一些标注,表现出一般理解 | 原型内容少或不清晰,缺乏正确的部分识别 |
| **语义 HTML 使用** | 适当使用 10 种以上语义元素,表现出对 HTML 结构和无障碍的深刻理解 | 正确使用 8-9 种语义元素,显示良好的语义标记理解 | 使用 6-7 种语义元素,对适当使用有一些混淆 | 使用少于 6 种元素或误用语义元素 |
| **代码质量与组织** | 代码组织异常良好,缩进正确,有全面的注释,且 HTML 语法完美 | 代码组织良好,有良好缩进和有用注释,语法有效 | 代码大致有序,有少量注释,存在轻微语法问题 | 组织差,极少注释,存在多处语法错误 |
| **无障碍与最佳实践** | 极佳的无障碍考虑,有意义的 alt 文本,恰当的标题层级,遵循所有现代 HTML 最佳实践 | 良好的无障碍特性,恰当使用标题和 alt 文本,遵循大多数最佳实践 | 有一些无障碍考虑,基本的 alt 文本和标题结构 | 无障碍特性有限,标题结构差,不遵循最佳实践 |
| **反思与学习** | 有深刻见解的反思,展现了对 HTML 概念和学习过程的深刻理解和分析 | 良好的反思,显示了对关键概念的理解和一定的自我认知 | 基本反思,对 HTML 概念或学习过程的见解有限 | 反思很少或缺失,几乎没有对学习内容的理解 |
## 学习资源
**必备参考资料:**
- [MDN HTML 元素参考](https://developer.mozilla.org/docs/Web/HTML/Element) - 全面 HTML 元素指南
- [HTML5 语义元素](https://developer.mozilla.org/docs/Web/HTML/Element#content_sectioning) - 理解语义标记
- [网页无障碍指导原则](https://www.w3.org/WAI/WCAG21/quickref/) - 创建无障碍网页内容
- [HTML 校验器](https://validator.w3.org/) - 检查您的 HTML 语法
**成功技巧:**
- 在编写任何代码之前先开始制作原型
- 使用浏览器的开发者工具检查您的 HTML 结构
- 测试您的页面在不同屏幕尺寸下的显示(即使没有 CSS
- 大声朗读您的 HTML 以检查结构是否逻辑通顺
- 考虑屏幕阅读器如何解释您的页面结构
> 💡 **记住**:本作业关注 HTML 结构和语义。不要担心视觉样式 —— 那是 CSS 的工作!您的页面可能看起来很普通,但应结构良好且有意义。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们力求准确,但请注意,自动翻译可能存在错误或不准确之处。原始文本应被视为权威来源。对于重要信息,建议采用专业人工翻译。我们不对因使用本翻译内容而引起的任何误解或错误解释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,278 +1,727 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "acb5ae00cde004304296bb97da8ff4c3",
"translation_date": "2025-08-29T14:49:50+00:00",
"original_hash": "e39f3a4e3bcccf94639e3af1248f8a4d",
"translation_date": "2026-01-06T11:53:01+00:00",
"source_file": "3-terrarium/2-intro-to-css/README.md",
"language_code": "zh"
}
-->
# Terrarium 项目第二部分CSS 入门
![CSS 入门](../../../../translated_images/webdev101-css.3f7af5991bf53a200d79e7257e5e450408d8ea97f5b531d31b2e3976317338ee.zh.png)
> [Tomomi Imura](https://twitter.com/girlie_mac) 的手绘笔记
# Terrarium Project 第二部分CSS 介绍
```mermaid
journey
title 你的 CSS 样式旅程
section 基础
连接 CSS 文件: 3: Student
理解层叠: 4: Student
学习继承: 4: Student
section 选择器
元素定位: 4: Student
类模式: 5: Student
ID 特异性: 5: Student
section 布局
定位元素: 4: Student
创建容器: 5: Student
搭建生态箱: 5: Student
section 打磨
添加视觉效果: 5: Student
响应式设计: 5: Student
玻璃反光: 5: Student
```
![Introduction to CSS](../../../../translated_images/webdev101-css.3f7af5991bf53a20.zh.png)
> 速写笔记作者 [Tomomi Imura](https://twitter.com/girlie_mac)
还记得你的 HTML 生态瓶看起来很基础吗CSS 就是把那个普通的结构变成视觉上更吸引人的东西。
如果说 HTML 就像搭建房子的框架,那么 CSS 就是让它感觉像家的所有东西——油漆颜色、家具布置、灯光,以及房间之间的流动。想想凡尔赛宫最初只是一个简单的狩猎小屋,但经过精心的装饰和布局,就变成了世界上最宏伟的建筑之一。
今天,我们将把你的生态瓶从功能性变成精致。你将学习如何精准定位元素,使布局响应不同屏幕尺寸,并创造让网站引人注目的视觉效果。
本课结束时,你将看到战略性的 CSS 样式如何极大提升你的项目。让我们为你的生态瓶增添一些风格吧。
```mermaid
mindmap
root((CSS 基础))
Cascade
Specificity Rules
Inheritance
Priority Order
Conflict Resolution
Selectors
Element Tags
Classes (.class)
IDs (#id)
Combinators
Box Model
Margin
Border
Padding
Content
Layout
Positioning
Display Types
Flexbox
Grid
Visual Effects
Colors
Shadows
Transitions
Animations
Responsive Design
Media Queries
Flexible Units
Viewport Meta
Mobile First
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/17)
### 简介
## CSS 入门
CSS全称为层叠样式表解决了网页开发中的一个重要问题如何让你的网站看起来更美观。为你的应用程序添加样式可以使其更易用且更具吸引力你还可以使用 CSS 创建响应式网页设计RWD使你的应用在任何屏幕尺寸下都能保持良好的显示效果。CSS 不仅仅是为了让应用看起来漂亮它的规范还包括动画和变换功能可以为你的应用实现复杂的交互效果。CSS 工作组负责维护当前的 CSS 规范,你可以在 [万维网联盟的网站](https://www.w3.org/Style/CSS/members)上关注他们的工作。
CSS 常被认为只是“美化”但它的作用远不止如此。CSS 就像电影导演——你不仅控制一切的外观,还控制其运动、响应交互以及适应不同情况
> 注意CSS 是一种不断发展的语言,就像网络上的所有事物一样,并不是所有浏览器都支持最新的规范部分。请随时通过 [CanIUse.com](https://caniuse.com) 检查你的实现。
现代 CSS 非常强大。你可以编写代码,自动调整手机、平板和桌面电脑的布局。你可以创建平滑动画,引导用户注意力。所有功能协同工作时效果非常惊人
在本课中,我们将为在线的微型生态瓶添加样式,并学习多个 CSS 概念:层叠、继承、选择器的使用、定位以及使用 CSS 构建布局。在此过程中,我们将布局微型生态瓶并创建实际的生态瓶。
> 💡 **小贴士**CSS 持续演进,增加新特性和功能。使用新 CSS 特性前,请务必访问 [CanIUse.com](https://caniuse.com) 检查浏览器支持情况
### 前置条件
**本课目标:**
- **创建** 用现代 CSS 技术完整设计你的生态瓶视觉效果
- **探索** 级联、继承和 CSS 选择器等基础概念
- **实现** 响应式定位和布局策略
- **构建** 生态瓶容器,使用 CSS 形状和样式
你应该已经构建好微型生态瓶的 HTML并准备好进行样式设计。
### 先修条件
> 查看视频
你应该完成了上一课的生态瓶 HTML 结构,准备好进行样式设计。
>
> [![Git 和 GitHub 基础视频](https://img.youtube.com/vi/6yIdOIV9p1I/0.jpg)](https://www.youtube.com/watch?v=6yIdOIV9p1I)
> 📺 **视频资源**:观看此视频讲解
>
> [![CSS 基础教程](https://img.youtube.com/vi/6yIdOIV9p1I/0.jpg)](https://www.youtube.com/watch?v=6yIdOIV9p1I)
### 任务
### 设置你的 CSS 文件
在你的微型生态瓶文件夹中,创建一个名为 `style.css` 的新文件。在 `<head>` 部分导入该文件:
开始样式设计前,我们需要将 CSS 连接到 HTML。这让浏览器知道哪里能找到生态瓶的样式指令。
在你的生态瓶文件夹中,创建一个名为 `style.css` 的新文件,然后在 HTML 文档的 `<head>` 部分链接它:
```html
<link rel="stylesheet" href="./style.css" />
```
---
**此代码作用:**
- **建立** HTML 和 CSS 文件之间的连接
- **告诉**浏览器加载并应用 `style.css` 中的样式
- **使用** `rel="stylesheet"` 属性声明这是 CSS 文件
- **以** `href="./style.css"` 路径引用文件
## 层叠
## 理解 CSS 级联
层叠样式表包含了样式“层叠”的概念,即样式的应用是由其优先级决定的。网站作者设置的样式优先于浏览器设置的样式。内联样式优先于外部样式表中的样式。
你有没有想过为什么 CSS 叫“层叠样式表”?样式像瀑布一样层叠,有时相互冲突
### 任务
想象军队指挥结构——将军命令“所有士兵穿绿衣”但某个单位的具体命令是“典礼穿礼服蓝”这时具体命令优先。CSS 也遵循类似逻辑,理解此层级关系才能更好地调试。
为你的 `<h1>` 标签添加内联样式 "color: red"
### 级联优先级实验
```HTML
让我们通过样式冲突来观察级联。先给你的 `<h1>` 标签添加行内样式:
```html
<h1 style="color: red">My Terrarium</h1>
```
然后,将以下代码添加到你的 `style.css` 文件中:
**代码做了什么:**
- **直接** 用行内样式将 `<h1>` 设置为红色
- **使用** `style` 属性直接在 HTML 中嵌入 CSS
- **创建** 该元素的最高优先级样式规则
```CSS
接着,在你的 `style.css` 文件中添加以下规则:
```css
h1 {
color: blue;
color: blue;
}
```
✅ 你的网页应用中显示了哪种颜色?为什么?你能找到一种方法来覆盖样式吗?在什么情况下你会想要这样做,或者为什么不这样做?
**上述说明:**
- **定义** 了所有 `<h1>` 元素的 CSS 规则
- **用** 外部样式表将文本颜色设置为蓝色
- **优先级** 低于行内样式
**知识检测**:网页中显示的是哪个颜色?为什么这个颜色胜出?你能想到什么时候需要覆盖样式吗?
```mermaid
flowchart TD
A["浏览器遇到 h1 元素"] --> B{"检查内联样式"}
B -->|找到| C["style='color: red'"]
B -->|无| D{"检查 ID 规则"}
C --> E["应用红色 (1000 分)"]
D -->|找到| F["#heading { color: green }"]
D -->|无| G{"检查类规则"}
F --> H["应用绿色 (100 分)"]
G -->|找到| I[".title { color: blue }"]
G -->|无| J{"检查元素规则"}
I --> K["应用蓝色 (10 分)"]
J -->|找到| L["h1 { color: purple }"]
J -->|无| M["使用浏览器默认"]
L --> N["应用紫色 (1 分)"]
style C fill:#ff6b6b
style F fill:#51cf66
style I fill:#339af0
style L fill:#9775fa
```
> 💡 **CSS 优先级顺序(从高到低):**
> 1. **行内样式**style 属性)
> 2. **ID 选择器**#myId
> 3. **类选择器**.myClass和属性选择器
> 4. **元素选择器**h1divp
> 5. **浏览器默认**
---
## CSS 继承原理
## 继承
CSS 继承很像遗传学——元素继承父元素的某些属性。如果你给 body 元素设置字体,全页文本都会自动使用同样字体。这就像哈布斯堡王朝的家族下巴,在没有具体指定的情况下代代相传。
样式可以从祖先元素继承到后代元素,即嵌套的元素会继承其父元素的样式。
但不是所有属性都会继承。文本样式如字体和颜色会继承,布局属性如外边距和边框则不会。就像孩子可能继承父母的外貌特征,但不一定继承穿衣风格
### 任务
### 观察字体继承
将 body 的字体设置为指定字体,并检查嵌套元素的字体:
试试给 `<body>` 元素设置字体:
```CSS
```css
body {
font-family: helvetica, arial, sans-serif;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
```
打开浏览器的控制台,进入“元素”标签,观察 H1 的字体。它继承了 body 的字体,浏览器中会显示这一点:
**解释这里发生的事情:**
- **设置** 全页面字体,针对 `<body>` 元素
- **使用** 字体栈托底,提升浏览器兼容性
- **应用** 现代系统字体,跨操作系统表现良好
- **确保** 所有子元素继承字体,除非被特别覆盖
![继承的字体](../../../../translated_images/1.cc07a5cbe114ad1d4728c35134584ac1b87db688eff83cf75985cf31fe0ed95c.zh.png)
打开浏览器开发者工具F12切换到 Elements 面板,检查 `<h1>` 元素,你会看到它继承自 body 的字体:
✅ 你能让嵌套样式继承不同的属性吗?
![inherited font](../../../../translated_images/1.cc07a5cbe114ad1d.zh.png)
---
**试验时间**:尝试给 `<body>` 设置其他可继承属性如 `color``line-height` 或 `text-align`。你的标题和其他元素会发生什么变化?
> 📝 **可继承属性包括**`color``font-family``font-size``line-height``text-align``visibility`
>
> **不可继承属性包括**`margin``padding``border``width``height``position`
### 🔄 **教学进度检查**
**CSS 基础理解情况**:在学习选择器前,请确保你能:
- ✅ 解释级联与继承的区别
- ✅ 预测样式冲突中哪个样式会生效
- ✅ 识别哪些属性会从父元素继承
- ✅ 正确连接 CSS 和 HTML 文件
**快速测试**:如果样式如下,`<div class="special">` 内的 `<h1>` 显示什么颜色?
```css
div { color: blue; }
.special { color: green; }
h1 { color: red; }
```
*答案:红色(元素选择器直接针对 h1*
## CSS 选择器
## 精通 CSS 选择器
### 标签
CSS 选择器是你指定样式目标元素的方式。它们就像给出精确指示——不是说“那栋房子”,而是说“枫树街上蓝色门的房子”。
到目前为止,你的 `style.css` 文件只为少数标签设置了样式,应用看起来很奇怪:
CSS 提供了多种定位方式,选择正确选择器就像选对工具。你有时要给整个街区的每扇门统一造型,有时只对某一扇特殊的门操作。
```CSS
### 元素选择器(标签)
元素选择器通过标签名称定位 HTML 元素。很适合设置页面全局基础样式:
```css
body {
font-family: helvetica, arial, sans-serif;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
}
h1 {
color: #3a241d;
text-align: center;
color: #3a241d;
text-align: center;
font-size: 2.5rem;
margin-bottom: 1rem;
}
```
这种为标签设置样式的方法可以让你控制独特的元素,但你需要控制微型生态瓶中许多植物的样式。为此,你需要利用 CSS 选择器。
**这些样式做了什么:**
- **用** `body` 选择器设置统一字体排版
- **清除** 浏览器默认的外边距和内边距,方便精准控制
- **给所有标题元素** 设定颜色、对齐和间距
- **使用** `rem` 单位,提升字体大小的可伸缩性与无障碍性
虽然元素选择器适合通用样式,但针对生态瓶里的具体植物组件,你需要更具体的选择器。
### ID 选择器用于唯一元素
### Ids
ID 选择器用 `#` 符号,定位具有唯一 `id` 属性的元素。ID 在页面中唯一,非常适合样式化单个特定元素,比如生态瓶左、右侧的植物容器。
为左侧和右侧容器添加一些样式。由于标记中只有一个左侧容器和一个右侧容器,它们被赋予了 id。要为它们设置样式请使用 `#`
你的生态瓶侧边容器创建样式
```CSS
```css
#left-container {
background-color: #eee;
width: 15%;
left: 0px;
top: 0px;
position: absolute;
height: 100%;
padding: 10px;
background-color: #f5f5f5;
width: 15%;
left: 0;
top: 0;
position: absolute;
height: 100vh;
padding: 1rem;
box-sizing: border-box;
}
#right-container {
background-color: #eee;
width: 15%;
right: 0px;
top: 0px;
position: absolute;
height: 100%;
padding: 10px;
background-color: #f5f5f5;
width: 15%;
right: 0;
top: 0;
position: absolute;
height: 100vh;
padding: 1rem;
box-sizing: border-box;
}
```
在这里,你使用绝对定位将这些容器放置在屏幕的最左侧和最右侧,并使用百分比设置它们的宽度,以便它们可以适应小型移动屏幕。
**本代码实现:**
- **用** `absolute` 定位将容器固定在屏幕左右边缘
- **用** `vh`(视口高度)单位实现响应式高度,适应屏幕尺寸
- **设置** `box-sizing: border-box`,确保内边距包括在宽度内
- **移除** 零值的 `px` 单位,使代码简洁
- **设置** 柔和背景色,比生硬灰色更舒适
✅ 这段代码重复性较高因此不符合“DRY”不要重复自己的原则你能找到一种更好的方法来为这些 id 设置样式吗?也许可以结合 id 和 class你需要更改标记并重构 CSS
**代码质量挑战**:此 CSS 违反了 DRY不重复自己原则。你能用 ID 和类重构它吗?
**改进方案:**
```html
<div id="left-container" class="container"></div>
<div id="right-container" class="container"></div>
```
```css
.container {
background-color: #f5f5f5;
width: 15%;
top: 0;
position: absolute;
height: 100vh;
padding: 1rem;
box-sizing: border-box;
}
#left-container {
left: 0;
}
#right-container {
right: 0;
}
```
### Classes
### 类选择器用于可复用样式
在上面的示例中,你为屏幕上的两个独特元素设置了样式。如果你希望样式应用于屏幕上的多个元素,可以使用 CSS 类。这样做可以布局左侧和右侧容器中的植物。
类选择器用 `.` 符号,适合给多个元素应用相同样式。不同于 ID类可以在 HTML 中多次使用,适合统一样式模式
注意HTML 标记中的每个植物都有 id 和类的组合。id 在这里是供你稍后添加的 JavaScript 使用,用于操作微型生态瓶中的植物位置。而类则为所有植物提供了统一的样式。
在生态瓶中,每株植物样式相似但定位不同。我们会用类做共享样式,用 ID 做单独定位
**各植物的 HTML 结构如下:**
```html
<div class="plant-holder">
<img class="plant" alt="plant" id="plant1" src="./images/plant1.png" />
<img class="plant" alt="Decorative plant for terrarium" id="plant1" src="../../../../translated_images/plant1.d18b18ffe73da18f.zh.png" />
</div>
```
将以下内容添加到你的 `style.css` 文件中:
**关键元素说明:**
- **`class="plant-holder"`** 用于各植物容器,统一样式
- **`class="plant"`** 用于植物图片,共享样式和行为
- **`id="plant1"`** 唯一 ID用于定位和 JS 交互
- **提供** alt 文本,提升屏幕阅读器可访问性
现在将这些样式添加到 `style.css`
```CSS
```css
.plant-holder {
position: relative;
height: 13%;
left: -10px;
position: relative;
height: 13%;
left: -0.6rem;
}
.plant {
position: absolute;
max-width: 150%;
max-height: 150%;
z-index: 2;
position: absolute;
max-width: 150%;
max-height: 150%;
z-index: 2;
transition: transform 0.3s ease;
}
.plant:hover {
transform: scale(1.05);
}
```
在这个代码片段中,值得注意的是相对定位和绝对定位的混合,我们将在下一节中详细讨论。观察高度是如何通过百分比处理的:
**样式详解:**
- **为植物容器** 设定相对定位,创建定位依据
- **设置** 每个容器高度为 13%,确保植物整体垂直可见无滚动
- **稍微向左偏移**,更好地将植物居中在容器内
- **让植物图片** 能响应式缩放,设置最大宽高限制
- **用** `z-index` 让植物层级高于其他元素
- **添加** 细微的悬停动画,提升用户交互体验
**深入思考**:为什么需要同时使用 `.plant-holder``.plant` 选择器?如果只用一个,会怎样?
> 💡 **设计模式**:容器 `.plant-holder` 负责布局和定位,内容 `.plant` 负责外观和缩放。分离职责让代码更易维护更灵活。
## 理解 CSS 定位
CSS 定位像舞台导演——你决定演员站哪里,怎么动。某些演员按标准站位,其它演员为了戏剧效果需要特殊定位。
理解定位后,很多布局问题迎刃而解。想要滚动页面时导航栏固定顶部?定位来帮忙。需要特定位置显示提示框?也是定位。
### 五种定位值
```mermaid
quadrantChart
title CSS 定位策略
x-axis 文档流 --> 脱离文档流
y-axis 静态定位 --> 精确控制
quadrant-1 绝对定位
quadrant-2 固定定位
quadrant-3 静态定位
quadrant-4 粘性定位
Static: [0.2, 0.2]
Relative: [0.3, 0.6]
Absolute: [0.8, 0.8]
Fixed: [0.9, 0.7]
Sticky: [0.5, 0.9]
```
| 定位值 | 行为 | 用途 |
|--------|------|------|
| `static` | 默认文档流,忽略 top/left/right/bottom | 正常布局 |
| `relative` | 相对于正常位置定位 | 微调位置,创建定位上下文 |
| `absolute` | 相对于最近的定位祖先 | 精确定位,覆盖层 |
| `fixed` | 相对于视口 | 固定导航栏,悬浮元素 |
| `sticky` | 滚动时在 `relative``fixed` 之间切换 | 滚动固定头部 |
### 生态瓶中的定位应用
我们用组合定位策略,创建所需布局:
```css
/* Container positioning */
.container {
position: absolute; /* Removes from normal flow */
/* ... other styles ... */
}
你将植物容器的高度设置为 13%,这是一个不错的数字,可以确保所有植物都显示在每个垂直容器中而无需滚动。
/* Plant holder positioning */
.plant-holder {
position: relative; /* Creates positioning context */
/* ... other styles ... */
}
你将植物容器向左移动,以使植物在其容器中更居中。图片有大量透明背景,为了使它们更易于拖动,需要向左移动以更好地适应屏幕。
/* Plant positioning */
.plant {
position: absolute; /* Allows precise placement within holder */
/* ... other styles ... */
}
```
然后,植物本身的最大宽度设置为 150%。这使得它可以随着浏览器的缩小而缩小。尝试调整浏览器大小,植物会保持在其容器中,但会缩小以适应。
**定位策略说明:**
- **绝对容器** 从正常文档流移除,被钉在屏幕边缘
- **相对植物容器** 保持文档流,同时创建定位上下文
- **绝对植物** 可在相对容器内精准定位
- **组合使用** 允许植物垂直堆叠,且能单独定位
> 🎯 **为什么重要**`plant` 元素需要绝对定位,方便下一课实现拖拽。绝对定位将其从文档流中剥离,使拖放交互成为可能。
**实验时间**:尝试更改定位值,观察效果:
- 将 `.container``absolute` 改为 `relative` 会怎样?
- 如果 `.plant-holder` 使用 `absolute` 而不是 `relative`,布局会如何变化?
- 当你将 `.plant` 切换为 `relative` 定位时会发生什么?
### 🔄 **教学检查点**
**CSS 定位掌握情况**:暂停,确认你的理解:
- ✅ 你能解释为什么植物需要绝对定位来实现拖放吗?
- ✅ 你理解相对容器如何创建定位上下文吗?
- ✅ 为什么侧边容器使用绝对定位?
- ✅ 如果完全移除定位声明,会发生什么?
**现实世界联系**:思考 CSS 定位如何反映现实布局:
- **静态**:书架上的书(自然顺序)
- **相对**:稍微移动一本书,但保持它的位置
- **绝对**:在特定页码放置书签
- **固定**:翻页时仍然可见的贴纸
## 使用 CSS 构建玻璃瓶
现在我们将仅用 CSS 构建一个玻璃罐——不需要图像或图形软件。
使用定位和透明度创建逼真的玻璃、阴影和深度效果,展示了 CSS 的视觉能力。这种技术类似包豪斯运动中的建筑师如何用简单的几何形状创造复杂且美丽的结构。一旦你理解了这些原理,就能认识出许多网页设计背后的 CSS 技巧。
```mermaid
flowchart LR
A[罐子顶部] --> E[完整生态瓶]
B[罐子墙壁] --> E
C[泥土层] --> E
D[罐子底部] --> E
F[玻璃效果] --> E
A1["宽度50%<br/>高度5%<br/>顶部位置"] --> A
B1["宽度60%<br/>高度80%<br/>圆角<br/>不透明度0.5"] --> B
C1["宽度60%<br/>高度5%<br/>深棕色<br/>底层"] --> C
D1["宽度50%<br/>高度1%<br/>底部位置"] --> D
F1["细微阴影<br/>透明度<br/>层叠顺序"] --> F
style E fill:#d1e1df,stroke:#3a241d
style A fill:#e8f5e8
style B fill:#e8f5e8
style C fill:#8B4513
style D fill:#e8f5e8
```
### 创建玻璃罐组件
另一个值得注意的是 z-index 的使用,它控制元素的相对高度(使植物位于容器之上,看起来像是放置在微型生态瓶中)。
让我们逐个构建生态瓶的罐体部分。每个部分都使用绝对定位和百分比尺寸以实现响应式设计:
✅ 为什么需要同时使用植物容器和植物的 CSS 选择器?
```css
.jar-walls {
height: 80%;
width: 60%;
background: #d1e1df;
border-radius: 1rem;
position: absolute;
bottom: 0.5%;
left: 20%;
opacity: 0.5;
z-index: 1;
box-shadow: inset 0 0 2rem rgba(0, 0, 0, 0.1);
}
## CSS 定位
.jar-top {
width: 50%;
height: 5%;
background: #d1e1df;
position: absolute;
bottom: 80.5%;
left: 25%;
opacity: 0.7;
z-index: 1;
border-radius: 0.5rem 0.5rem 0 0;
}
混合使用定位属性(包括静态、相对、固定、绝对和粘性定位)可能会有些棘手,但如果使用得当,可以很好地控制页面上的元素。
.jar-bottom {
width: 50%;
height: 1%;
background: #d1e1df;
position: absolute;
bottom: 0;
left: 25%;
opacity: 0.7;
border-radius: 0 0 0.5rem 0.5rem;
}
绝对定位的元素是相对于其最近的定位祖先进行定位的,如果没有定位祖先,则相对于文档主体进行定位。
.dirt {
width: 60%;
height: 5%;
background: #3a241d;
position: absolute;
border-radius: 0 0 1rem 1rem;
bottom: 1%;
left: 20%;
opacity: 0.7;
z-index: -1;
}
```
相对定位的元素是根据 CSS 的指令调整其位置,使其偏离初始位置。
**理解生态瓶构建:**
- **使用** 基于百分比的尺寸,实现所有屏幕尺寸的响应式缩放
- **绝对定位** 元素,以精确地堆叠和对齐
- **应用** 不同的不透明度值,创造玻璃透明效果
- **实现** `z-index` 分层,使植物显示在瓶子内部
- **添加** 细微的盒阴影和圆角边框,增强真实感
在我们的示例中,`plant-holder` 是一个相对定位的元素,它位于一个绝对定位的容器内。结果是侧边栏容器固定在左侧和右侧,而 `plant-holder` 是嵌套的,在侧边栏内调整自身位置,为植物的垂直排列留出空间。
### 百分比响应式设计
> `plant` 本身也具有绝对定位,这是使其可拖动的必要条件,你将在下一课中了解这一点。
注意所有尺寸都是用百分比,而非固定像素值:
✅ 尝试切换侧边容器和植物容器的定位类型。会发生什么?
**为什么重要:**
- **确保** 生态瓶在任何屏幕尺寸下成比例缩放
- **维护** 瓶子各部件间的视觉关系
- **提供** 从手机到大型桌面显示器的一致体验
- **允许** 设计自适应且不破坏视觉布局
## CSS 布局
### CSS 单位示范
现在你将使用所学内容完全通过 CSS 构建微型生态瓶!
我们使用 `rem` 单位来设置圆角,它相对于根字体大小缩放。这样创建的设计更易访问,尊重用户的字体偏好。详见官方规范中的 [CSS 相对单位](https://www.w3.org/TR/css-values-3/#font-relative-lengths)。
首先,使用 CSS 将 `.terrarium` div 的子元素样式化为一个圆角矩形:
**视觉实验**:尝试修改这些数值,观察效果:
- 将罐子的透明度从 0.5 改为 0.8——这如何影响玻璃外观?
- 将土壤颜色从 `#3a241d` 改为 `#8B4513`——视觉效果怎样改变?
- 修改土壤的 `z-index` 为 2——分层效果发生了什么
```CSS
.jar-walls {
height: 80%;
width: 60%;
background: #d1e1df;
border-radius: 1rem;
position: absolute;
bottom: 0.5%;
left: 20%;
opacity: 0.5;
z-index: 1;
}
### 🔄 **教学检查点**
**CSS 视觉设计理解**:确认你对视觉 CSS 的掌握:
- ✅ 百分比尺寸如何实现响应式设计?
- ✅ 为什么透明度能创建玻璃透明效果?
- ✅ `z-index` 在分层中起什么作用?
- ✅ 圆角值如何塑造罐子形状?
.jar-top {
width: 50%;
height: 5%;
background: #d1e1df;
position: absolute;
bottom: 80.5%;
left: 25%;
opacity: 0.7;
z-index: 1;
}
**设计原则**:注意我们如何用简单形状构建复杂视觉:
1. **矩形** → **圆角矩形** → **罐子组件**
2. **纯色** → **透明度** → **玻璃效果**
3. **单个元素** → **分层组合** → **三维效果**
.jar-bottom {
width: 50%;
height: 1%;
background: #d1e1df;
position: absolute;
bottom: 0%;
left: 25%;
opacity: 0.7;
}
---
.dirt {
width: 60%;
height: 5%;
background: #3a241d;
position: absolute;
border-radius: 0 0 1rem 1rem;
bottom: 1%;
left: 20%;
opacity: 0.7;
z-index: -1;
}
```
## GitHub Copilot Agent 挑战 🚀
注意这里使用了百分比。如果你缩小浏览器,可以看到瓶子也会缩小。还要注意瓶子元素的宽度和高度百分比,以及每个元素如何绝对定位在中心并固定在视口底部。
使用 Agent 模式完成以下挑战:
我们还使用了 `rem` 来设置边框半径,这是一种与字体相关的长度。可以在 [CSS 规范](https://www.w3.org/TR/css-values-3/#font-relative-lengths)中了解更多关于这种相对测量的方法
**描述:** 创建一个 CSS 动画,使生态瓶中的植物轻柔地摇摆,模拟自然微风效果。帮助你练习 CSS 动画、变换和关键帧,同时增强生态瓶的视觉吸引力。
✅ 尝试更改瓶子的颜色和透明度与泥土的颜色和透明度。会发生什么?为什么?
**提示:** 添加 CSS 关键帧动画,使生态瓶内的植物缓慢地左右摇摆。创建一个摇摆动画,让每棵植物左右旋转约 2-3 度,持续时间为 3-4 秒,应用于 `.plant` 类。确保动画无限循环,且采用缓动函数以获得自然流畅的动作。
---
了解更多关于 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 。
## 🚀挑战
## 🚀 挑战:添加玻璃反光效果
在瓶子的左下区域添加一个“气泡”光泽,使其看起来更像玻璃。你将为 `.jar-glossy-long``.jar-glossy-short` 设置样式,使其看起来像反射的光泽。效果如下:
准备好用真实的玻璃反光效果增强你的生态瓶吗?这项技术将为设计添加深度和真实感。
![完成的微型生态瓶](../../../../translated_images/terrarium-final.2f07047ffc597d0a06b06cab28a77801a10dd12fdb6c7fc630e9c40665491c53.zh.png)
你将创建细腻的高光模拟光在玻璃表面的反射。这与文艺复兴画家扬·凡·艾克Jan van Eyck使用光线和反射使绘画玻璃呈现三维感的手法类似。你的目标如下
要完成课后测验,请浏览以下学习模块:[使用 CSS 为 HTML 应用程序添加样式](https://docs.microsoft.com/learn/modules/build-simple-website/4-css-basics/?WT.mc_id=academic-77807-sagibbon)
![finished terrarium](../../../../translated_images/terrarium-final.2f07047ffc597d0a.zh.png)
**你的挑战:**
- **创建** 微妙的白色或浅色椭圆形反光
- **将其定位** 在罐子的左侧恰当位置
- **应用** 适当的不透明度和模糊效果,实现真实光反射
- **用** `border-radius` 制造有机、气泡状形状
- **尝试** 渐变或盒阴影增强真实感
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/18)
## 复习与自学
## 拓展你的 CSS 知识
CSS 起初可能显得复杂,但掌握这些核心概念将为深入学习打下坚实基础。
**你的下一步 CSS 学习领域:**
- **Flexbox** - 简化元素对齐和分布
- **CSS 网格布局** - 强大工具,创建复杂布局
- **CSS 变量** - 降低重复,提高可维护性
- **响应式设计** - 确保网站在不同屏幕尺寸上表现良好
### 互动学习资源
通过这些有趣的实战游戏来练习概念:
- 🐸 [Flexbox Froggy](https://flexboxfroggy.com/) - 通过有趣挑战掌握 Flexbox
- 🌱 [Grid Garden](https://codepip.com/games/grid-garden/) - 通过种植虚拟胡萝卜学习 CSS 网格
- 🎯 [CSS Battle](https://cssbattle.dev/) - 用编码挑战测试你的 CSS 技能
### 额外学习资源
想系统学习 CSS 基础,完成微软学习模块:[用 CSS 样式化你的 HTML 应用](https://docs.microsoft.com/learn/modules/build-simple-website/4-css-basics/?WT.mc_id=academic-77807-sagibbon)
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开开发者工具,使用元素面板检查任何网站的 CSS 样式
- [ ] 创建一个简单的 CSS 文件,并链接到 HTML 页面
- [ ] 尝试用不同方式改变颜色十六进制、RGB 和命名颜色
- [ ] 通过添加内边距和外边距练习盒模型
### 🎯 **接下来一小时你能完成什么**
- [ ] 完成课后测验,复习 CSS 基础
- [ ] 给你的 HTML 页面添加字体、颜色和间距样式
- [ ] 使用 flexbox 或 grid 创建简单布局
- [ ] 试验 CSS 过渡实现平滑效果
- [ ] 用媒体查询练习响应式设计
### 📅 **你的 CSS 一周学习计划**
- [ ] 富有创意地完成生态瓶样式作业
- [ ] 通过建立照片图库布局掌握 CSS 网格
- [ ] 学习 CSS 动画,让设计更生动
- [ ] 探索 Sass 或 Less 等 CSS 预处理器
- [ ] 学习设计原则并应用到 CSS 中
- [ ] 分析并复刻你在网上发现的有趣设计
### 🌟 **你的 CSS 一个月设计精通计划**
- [ ] 构建完整响应式网站设计系统
- [ ] 学习 CSS-in-JS 或类似 Tailwind 的实用优先框架
- [ ] 为开源项目贡献 CSS 优化
- [ ] 掌握高级 CSS 概念,如自定义属性和封装内容
- [ ] 创建可重用组件库,编写模块化 CSS
- [ ] 指导他人学习 CSS分享设计知识
## 🎯 你的 CSS 掌握时间线
```mermaid
timeline
title CSS 学习进度
section 基础10分钟
文件连接:将 CSS 连接到 HTML
:理解层叠规则
:学习继承基础
section 选择器15分钟
定位元素:元素选择器
:类模式
ID 特异性
:组合器
section 盒模型20分钟
布局基础:外边距和内边距
:边框属性
:内容尺寸
:盒模型行为
section 定位25分钟
元素放置:静态与相对定位
:绝对定位
层叠顺序z-index
:响应式单位
section 视觉设计30分钟
样式掌握:颜色与不透明度
:阴影与效果
:过渡
:变换属性
section 响应式设计45分钟
多设备支持:媒体查询
:灵活布局
:移动优先方法
:视口优化
section 高级技巧1周
现代 CSS弹性盒布局
CSS 网格系统
:自定义属性
:动画关键帧
section 专业技能1个月
CSS 架构:组件模式
:可维护代码
:性能优化
:跨浏览器兼容性
```
### 🛠️ 你的 CSS 工具总结
完成本课后,你已经拥有:
- **层叠理解**:样式如何继承和覆盖
- **选择器掌握**:精准定位元素、类和 ID
- **定位技能**:战略性元素放置和分层
- **视觉设计**:创建玻璃效果、阴影和透明度
- **响应式技术**:基于百分比的布局适应任何屏幕
- **代码组织**:清晰且可维护的 CSS 结构
- **现代实践**:使用相对单位和无障碍设计模式
CSS 看似简单但在尝试为所有浏览器和所有屏幕尺寸完美地设计应用时会遇到许多挑战。CSS-Grid 和 Flexbox 是为使工作更结构化、更可靠而开发的工具。通过玩 [Flexbox Froggy](https://flexboxfroggy.com/) 和 [Grid Garden](https://codepip.com/games/grid-garden/) 来学习这些工具。
**下一步**你的生态瓶现在有了结构HTML和样式CSS。最后一课将添加交互功能JavaScript
## 作业
@ -280,5 +729,7 @@ CSS 看似简单,但在尝试为所有浏览器和所有屏幕尺寸完美地
---
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件通过 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的原始文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,8 +1,8 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a212cc22a18eddf9046b7a16dfbafd8b",
"translation_date": "2025-10-03T08:49:47+00:00",
"original_hash": "bee6762d4092a13fc7c338814963f980",
"translation_date": "2026-01-06T11:54:36+00:00",
"source_file": "3-terrarium/2-intro-to-css/assignment.md",
"language_code": "zh"
}
@ -11,31 +11,126 @@ CO_OP_TRANSLATOR_METADATA:
## 目标
重构植物箱项目,使用 **Flexbox****CSS Grid** 进行布局。根据需要更新 HTML 和 CSS以实现现代化、响应式设计。无需实现可拖动元素——只需专注于布局和样式
将您的微型生态瓶项目转换为使用现代 CSS 布局技术!重构当前的绝对定位方法,改用 **Flexbox****CSS Grid** 实现更易维护、响应式的设计。此作业挑战您在保持生态瓶视觉美感的同时,应用现代 CSS 标准
## 说明
理解何时及如何使用不同的布局方法,是现代网页开发的关键技能。本练习架起传统定位技术与现代 CSS 布局系统之间的桥梁。
1. **创建一个新版本**的植物箱应用。更新标记和 CSS使用 Flexbox 或 CSS Grid 进行布局。
2. **确保艺术和元素保持原样**,与原始版本一致。
3. **在至少两个不同的浏览器中测试设计**例如Chrome、Firefox、Edge
4. **截取植物箱在每个浏览器中的截图**,以展示跨浏览器兼容性。
5. **提交**更新后的代码和截图。
## 作业说明
## 评分标准
### 阶段 1分析与规划
1. **审查当前生态瓶代码** - 识别哪些元素当前使用绝对定位
2. **选择布局方法** - 决定 Flexbox 还是 CSS Grid 更适合您的设计目标
3. **绘制新布局结构图** - 规划容器及植物元素如何组织
| 标准 | 卓越表现 | 合格表现 | 需改进表现 |
|------------|--------------------------------------------------------------------------|---------------------------------------|----------------------------------------|
| 布局 | 完全使用 Flexbox 或 CSS Grid 重构;视觉效果吸引人且响应式设计 | 部分元素重构;部分使用 Flexbox 或 Grid | 很少或未使用 Flexbox 或 Grid布局未改变 |
| 跨浏览器 | 提供多个浏览器的截图;外观一致 | 提供一个浏览器的截图;有轻微不一致 | 无截图或存在重大不一致 |
| 代码质量 | HTML/CSS 干净且组织良好;注释清晰 | 有一定组织;注释较少 | 代码杂乱无章;缺乏注释 |
### 阶段 2实现
1. **创建生态瓶项目的新版本**,放在单独文件夹中
2. **根据需要更新 HTML 结构**,以支持所选布局方法
3. **重构 CSS**,使用 Flexbox 或 CSS Grid 替代绝对定位
4. **保持视觉一致性** - 确保植物与生态瓶罐保持相同位置
5. **实现响应式行为** - 使布局能优雅适应不同屏幕尺寸
## 提示
### 阶段 3测试与文档
1. **跨浏览器测试** - 验证设计在 Chrome、Firefox、Edge 和 Safari 中表现正常
2. **响应式测试** - 检查布局在移动设备、平板和桌面屏幕尺寸上的表现
3. **文档编写** - 在 CSS 中添加注释,说明布局设计选择
4. **截图** - 捕捉生态瓶在不同浏览器及屏幕尺寸下的效果
- 查看 [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) 和 [CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) 指南。
- 使用浏览器开发者工具测试响应性。
- 为代码添加注释以提高可读性。
## 技术要求
### 布局实现
- **选择一项**:仅实现 Flexbox 或 CSS Grid同一元素不可同时使用两者
- **响应式设计**:使用相对单位(`rem`、`em`、`%`、`vw`、`vh`)替代固定像素
- **无障碍**:保持适当的语义 HTML 结构和替代文本
- **代码质量**:使用一致的命名规范,逻辑清晰地组织 CSS
### 需包含现代 CSS 特性
```css
/* Example Flexbox approach */
.terrarium-container {
display: flex;
flex-direction: column;
min-height: 100vh;
align-items: center;
justify-content: center;
}
.plant-containers {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 1200px;
}
/* Example Grid approach */
.terrarium-layout {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: auto 1fr;
min-height: 100vh;
gap: 1rem;
}
```
### 浏览器支持要求
- **Chrome/Edge**:最新 2 个版本
- **Firefox**:最新 2 个版本
- **Safari**:最新 2 个版本
- **移动浏览器**iOS Safari、Chrome Mobile
## 交付物
1. **更新的 HTML 文件**,改进语义结构
2. **重构后的 CSS 文件**,采用现代布局技术
3. **截图集**,展示跨浏览器兼容性:
- 桌面视图1920x1080
- 平板视图768x1024
- 手机视图375x667
- 至少包含 2 种不同浏览器
4. **README.md 文件**,内容包括:
- 您的布局选择Flexbox 或 Grid及理由
- 重构过程中遇到的挑战
- 浏览器兼容性说明
- 运行代码说明
## 评估标准
| 评估项 | 优秀 (4) | 良好 (3) | 进行中 (2) | 初学 (1) |
|--------|-----------|-----------|-------------|-----------|
| **布局实现** | 熟练使用 Flexbox/Grid 及高级功能;完全响应式 | 正确实现,响应式表现良好 | 具备基本实现,响应式有轻微问题 | 实现不完整或错误 |
| **代码质量** | CSS 清晰有序,注释丰富,命名规范 | 组织良好,包含部分注释 | 组织尚可,注释有限 | 组织混乱,不易理解 |
| **跨浏览器兼容性** | 各要求浏览器表现一致,附截图证明 | 与部分浏览器兼容良好,差异注释明确 | 存在兼容性问题但不影响功能 | 主要兼容问题或缺少测试 |
| **响应式设计** | 优秀的移动优先策略,断点流畅 | 响应式表现良好,断点合理 | 基本响应式,有局部布局问题 | 响应式表现有限或有缺陷 |
| **文档** | README 详尽,解释深入,见解丰富 | 文档良好,涵盖所有必要内容 | 基础文档,解释有限 | 文档不完整或缺失 |
## 有用资源
### 布局方法指南
- 📖 [Flexbox 完整指南](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
- 📖 [CSS Grid 完整指南](https://css-tricks.com/snippets/css/complete-guide-grid/)
- 📖 [Flexbox 与 Grid 的选择](https://blog.webdevsimplified.com/2022-11/flexbox-vs-grid/)
### 浏览器测试工具
- 🛠️ [浏览器开发者工具响应式模式](https://developer.chrome.com/docs/devtools/device-mode/)
- 🛠️ [Can I Use - 特性支持查询](https://caniuse.com/)
- 🛠️ [BrowserStack - 跨浏览器测试](https://www.browserstack.com/)
### 代码质量工具
- ✅ [CSS 验证器](https://jigsaw.w3.org/css-validator/)
- ✅ [HTML 验证器](https://validator.w3.org/)
- ✅ [WebAIM 对比度检测器](https://webaim.org/resources/contrastchecker/)
## 额外挑战
🌟 **高级布局**:在设计不同部分同时使用 Flexbox 和 Grid
🌟 **动画集成**:添加与新布局配合的 CSS 过渡或动画
🌟 **暗模式**:实现基于 CSS 自定义属性的主题切换器
🌟 **容器查询**:使用现代容器查询技术实现组件级响应式
> 💡 **记住**:目标不仅是让它运行,而是理解为何您选择的布局方法是本设计挑战的最佳解决方案!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件通过 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译完成。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始语言版本应被视为权威来源。如涉及重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,62 +1,205 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "61c14b27044861e5e69db35dd52c4403",
"translation_date": "2025-08-29T14:50:45+00:00",
"original_hash": "973e48ad87d67bf5bb819746c9f8e302",
"translation_date": "2026-01-06T11:50:49+00:00",
"source_file": "3-terrarium/3-intro-to-DOM-and-closures/README.md",
"language_code": "zh"
}
-->
# Terrarium 项目第三部分DOM 操作与闭包
![DOM 和闭包](../../../../translated_images/webdev101-js.10280393044d7eaaec7e847574946add7ddae6be2b2194567d848b61d849334a.zh.png)
> [Tomomi Imura](https://twitter.com/girlie_mac) 的手绘笔记
# Terrarium 项目第三部分DOM 操作与 JavaScript 闭包
```mermaid
journey
title 你的 JavaScript DOM 之旅
section 基础
理解 DOM: 3: Student
学习闭包: 4: Student
连接元素: 4: Student
section 交互
设置拖拽事件: 4: Student
跟踪坐标: 5: Student
处理移动: 5: Student
section 打磨
添加清理: 4: Student
测试功能: 5: Student
完成生态箱: 5: Student
```
![DOM 和闭包](../../../../translated_images/webdev101-js.10280393044d7eaa.zh.png)
> 草图笔记作者:[Tomomi Imura](https://twitter.com/girlie_mac)
欢迎来到网页开发中最具趣味性的部分之一——让页面变得互动文档对象模型DOM就像是你的 HTML 和 JavaScript 之间的一座桥梁,今天我们将用它让你的生态瓶变得栩栩如生。当 Tim Berners-Lee 创建第一款网页浏览器时他设想了一个可以动态交互的网页世界——而DOM让这个设想成为可能。
我们还将探讨 JavaScript 闭包,起初听起来可能令人生畏。把闭包想象成创建“记忆口袋”,你的函数可以记住重要信息。就像生态瓶中的每株植物都有自己的数据记录来跟踪位置。到本节课结束时,你会明白闭包其实是多么自然且有用。
我们要构建的是一个生态瓶,用户可以将植物拖放到任意位置。你将学习 DOM 操作技术,这些技术支持从拖放文件上传到互动游戏的所有功能。让我们一起赋予你的生态瓶生命吧。
```mermaid
mindmap
root((DOM & JavaScript))
DOM Tree
元素选择
属性访问
事件处理
动态更新
Events
指针事件
鼠标事件
触摸事件
事件监听器
Closures
私有变量
函数作用域
内存持久性
状态管理
Drag & Drop
位置跟踪
坐标计算
事件生命周期
用户交互
Modern Patterns
事件委托
性能
跨设备
可访问性
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/19)
### 简介
## 认识 DOM通往交互式网页的大门
文档对象模型DOM是 JavaScript 与你的 HTML 元素沟通的方式。当浏览器加载 HTML 页面时,会在内存中创建该页面的结构化表示——这就是 DOM。把它想象成一棵家谱树每个 HTML 元素都是一个成员JavaScript 可以访问、修改或重新排列它们。
DOM 操作将静态页面转换成交互式网站。每当你看到按钮悬停时变色、内容无需刷新自动更新或元素可拖动时,背后都是 DOM 操作的功劳。
```mermaid
flowchart TD
A["文档"] --> B["HTML"]
B --> C["头部"]
B --> D["主体"]
C --> E["标题"]
C --> F["元标签"]
D --> G["H1: 我的生态瓶"]
D --> H["Div: 页面容器"]
H --> I["Div: 左侧容器"]
H --> J["Div: 右侧容器"]
H --> K["Div: 生态瓶"]
I --> L["植物元素 1-7"]
J --> M["植物元素 8-14"]
L --> N["img#plant1"]
L --> O["img#plant2"]
M --> P["img#plant8"]
M --> Q["img#plant9"]
style A fill:#e1f5fe
style B fill:#f3e5f5
style D fill:#e8f5e8
style H fill:#fff3e0
style N fill:#ffebee
style O fill:#ffebee
style P fill:#ffebee
style Q fill:#ffebee
```
![DOM 树结构表示](../../../../translated_images/dom-tree.7daf0e763cbbba92.zh.png)
> DOM 及其关联 HTML 标记的表示。来自 [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
**DOM 的强大之处在于:**
- **提供** 结构化的方法访问页面中的任意元素
- **支持** 无需刷新页面即可动态更新内容
- **允许** 实时响应用户点击和拖动等操作
- **奠定** 现代交互式网页应用的基础
## JavaScript 闭包:创建有组织且强大的代码
[JavaScript 闭包](https://developer.mozilla.org/docs/Web/JavaScript/Closures)就像给函数分配了自己的专属工作空间,拥有持久的记忆。想象加拉帕戈斯群岛上的达尔文雀根据不同环境发展出专门嘴型——闭包也是如此,创建了“记住”特定上下文的专用函数,即便它们的父函数已经执行完毕。
在我们的生态瓶中,闭包帮助每株植物独立记住自己的位置。这个模式在专业 JavaScript 开发中随处可见,是一个值得理解的重要概念。
```mermaid
flowchart LR
A["dragElement(plant1)"] --> B["创建闭包"]
A2["dragElement(plant2)"] --> B2["创建闭包"]
B --> C["私有变量"]
B2 --> C2["私有变量"]
C --> D["pos1, pos2, pos3, pos4"]
C --> E["pointerDrag 函数"]
C --> F["elementDrag 函数"]
C --> G["stopElementDrag 函数"]
C2 --> D2["pos1, pos2, pos3, pos4"]
C2 --> E2["pointerDrag 函数"]
C2 --> F2["elementDrag 函数"]
C2 --> G2["stopElementDrag 函数"]
H["植物1记住它的位置"] --> B
H2["植物2记住它的位置"] --> B2
style B fill:#e8f5e8
style B2 fill:#e8f5e8
style C fill:#fff3e0
style C2 fill:#fff3e0
```
> 💡 **理解闭包**:闭包是 JavaScript 中的重要话题,许多开发者多年使用后才完全掌握所有理论细节。今天我们专注于实用应用——你将看到闭包在实现交互功能时自然而然出现。理解将随着你观察它们解决实际问题而逐步加深。
操作 DOM文档对象模型是 Web 开发的关键部分。根据 [MDN](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction) 的定义,“文档对象模型 (DOM) 是 Web 上构成文档结构和内容的对象的数据表示形式。” Web 上的 DOM 操作挑战通常是开发者选择使用 JavaScript 框架而不是原生 JavaScript 来管理 DOM 的原因,但我们将尝试自己完成!
![DOM 树结构表示](../../../../translated_images/dom-tree.7daf0e763cbbba92.zh.png)
此外,本课程将介绍 [JavaScript 闭包](https://developer.mozilla.org/docs/Web/JavaScript/Closures) 的概念。闭包可以理解为一个函数被另一个函数包裹,使得内部函数可以访问外部函数的作用域。
> DOM 及其关联 HTML 标记的表示。来自 [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
> JavaScript 闭包是一个广泛且复杂的主题。本课程仅涉及最基本的概念。在这个项目的代码中,你会发现一个闭包:一个内部函数和一个外部函数的构造方式使得内部函数可以访问外部函数的作用域。有关闭包如何工作的更多信息,请访问 [详细文档](https://developer.mozilla.org/docs/Web/JavaScript/Closures)。
本节课,我们将完善交互生态瓶项目,创建 JavaScript 代码让用户能够操作页面上的植物
我们将使用闭包来操作 DOM。
## 开始之前:成功准备
可以将 DOM 想象成一棵树,表示网页文档可以被操作的所有方式。各种 API应用程序接口已经被开发出来程序员可以使用自己选择的编程语言访问 DOM并对其进行编辑、修改、重新排列或其他管理。
你需要之前生态瓶课程中的 HTML 和 CSS 文件——我们将让那个静态设计变得可交互。如果你是首次加入,建议先完成那些课程以获得重要背景
![DOM 树表示](../../../../translated_images/dom-tree.7daf0e763cbbba9273f9a66fe04c98276d7d23932309b195cb273a9cf1819b42.zh.png)
我们将实现的功能:
- **流畅的拖放操作**,适用于所有生态瓶中的植物
- **坐标跟踪**,让植物记住它们的位置
- **完整的交互界面**,使用纯 JavaScript 实现
- **清晰有序的代码结构**,运用闭包设计模式
> DOM 和 HTML 标记的表示形式。来自 [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
## 设置你的 JavaScript 文件
在本课程中,我们将完成互动式生态瓶项目,通过创建 JavaScript 代码让用户能够操作页面上的植物。
让我们创建使生态瓶具备交互性的 JavaScript 文件
### 前置条件
**步骤 1创建脚本文件**
你应该已经完成了生态瓶的 HTML 和 CSS 部分。在本课程结束时,你将能够通过拖动将植物移入或移出生态瓶。
在你的生态瓶文件夹中,新建一个名为 `script.js` 的文件
### 任务
**步骤 2将 JavaScript 关联到 HTML**
在你的生态瓶文件夹中创建一个名为 `script.js` 的新文件,并在 `<head>` 部分导入该文件:
在你的 `index.html` 文件的 `<head>` 部分添加以下脚本标签
```html
<script src="./script.js" defer></script>
<script src="./script.js" defer></script>
```
> 注意:在将外部 JavaScript 文件导入 HTML 文件时使用 `defer`,以确保 JavaScript 代码在 HTML 文件完全加载后才执行。你也可以使用 `async` 属性,它允许脚本在 HTML 文件解析时执行但在我们的案例中重要的是在拖动脚本执行之前HTML 元素必须完全加载。
**为什么 `defer` 属性很重要:**
- **确保** JavaScript 脚本等到 HTML 完全加载后再执行
- **防止** JavaScript 访问尚未准备好的元素时出错
- **保证** 所有植物元素可交互
- **相比将脚本放在页面底部,提供更好的性能**
> ⚠️ **重要提示**`defer` 属性避免了常见的时序问题。没有它JavaScript 可能在 HTML 元素加载前就开始访问,引发错误。
---
## DOM 元素
## 关联 JavaScript 与 HTML 元素
首先,你需要在 DOM 中创建对要操作的元素的引用。在我们的案例中,它们是当前位于侧边栏中的 14 个植物。
在让元素可拖动之前JavaScript 需要定位它们在 DOM 中的位置。想象这像图书馆的目录系统——拿到适合的目录号,才能准确找到你需要的那本书并浏览其内容
### 任务
我们将使用 `document.getElementById()` 方法建立这些连接。它就像精准的文件系统——你提供 ID它就能准确找到 HTML 中对应元素。
```html
### 为所有植物启用拖动功能
将以下代码添加到你的 `script.js` 文件中:
```javascript
// 为所有14种植物启用拖动功能
dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
@ -73,163 +216,556 @@ dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));
```
这里发生了什么?你正在引用文档并在其 DOM 中查找具有特定 Id 的元素。还记得在 HTML 的第一课中,你为每个植物图片分配了单独的 Id (`id="plant1"`) 吗?现在你将利用这一努力。在识别每个元素后,你将该元素传递给一个名为 `dragElement` 的函数稍后会构建。因此HTML 中的元素现在可以拖动,或者很快就可以。
**这段代码完成了以下任务:**
- **定位** DOM 中每个植物元素,基于它们独特的 ID
- **获取** 每个 HTML 元素的 JavaScript 引用
- **将** 每个元素传入 `dragElement` 函数(我们接着会创建)
- **为** 所有植物准备拖放交互功能
- **将** HTML 结构与 JavaScript 功能连接起来
> 🎯 **为什么用 ID 而不用类?** ID 为特定元素提供唯一标识,而 CSS 类用于样式分组。当 JavaScript 需要操作单个元素时ID 提供精准且高效的定位。
> 💡 **实用小贴士**:注意我们为每株植物单独调用了 `dragElement()`。这种方式确保每个植物拥有独立的拖动行为,是流畅交互的关键。
### 🔄 **教学小结**
**DOM 连接理解检查**:在继续拖动功能前,确认你能:
- ✅ 解释 `document.getElementById()` 如何定位 HTML 元素
- ✅ 理解为何每个植物需要唯一 ID
- ✅ 描述 `defer` 属性在 script 标签中的作用
- ✅ 识别 JavaScript 与 HTML 如何通过 DOM 关联
✅ 为什么我们通过 Id 引用元素?为什么不通过它们的 CSS 类?你可以参考上一课的 CSS 来回答这个问题。
**快速自测**:如果两个元素拥有相同 ID会发生什么为何 `getElementById()` 只返回一个元素?
*回答ID 应该唯一;如果重复,只返回第一个匹配元素*
---
## 闭包
## 构建拖拽元素的闭包
现在你准备创建 `dragElement` 闭包,这是一个外部函数,包裹了一个或多个内部函数(在我们的案例中是三个)。
现在我们创建拖动功能的核心:一个闭包,负责管理每株植物的拖动行为。这个闭包内部包含多个函数,协同工作以追踪鼠标移动并更新元素位置
当一个或多个函数需要访问外部函数的作用域时,闭包非常有用。以下是一个示例:
闭包非常适合该任务,因为它们允许创建“私有”变量,在函数调用之间保持状态,使每个植物拥独立的坐标跟踪系统。
### 用简单例子理解闭包
用一个简单示例演示闭包:
```javascript
function displayCandy(){
let candy = ['jellybeans'];
function addCandy(candyType) {
candy.push(candyType)
}
addCandy('gumdrops');
function createCounter() {
let count = 0; // 这就像是一个私有变量
function increment() {
count++; // 内部函数记住了外部变量
return count;
}
return increment; // 我们返回内部函数
}
displayCandy();
console.log(candy)
```
在这个示例中,`displayCandy` 函数包裹了一个函数,该函数将新的糖果类型推入已经存在于函数中的数组。如果你运行这段代码,`candy` 数组将是未定义的,因为它是一个局部变量(局限于闭包)。
✅ 如何让 `candy` 数组可访问?尝试将它移到闭包之外。这样,数组就变成了全局变量,而不是仅限于闭包的局部作用域。
const myCounter = createCounter();
console.log(myCounter()); // 1
console.log(myCounter()); // 2
```
### 任务
**该闭包模式的工作机制:**
- **创建** 私有的 `count` 变量,仅存于该闭包内
- **内部函数** 可访问并修改外部变量(闭包机制)
- **返回** 内部函数时,它依然保持对私有数据的连接
- **即便** `createCounter()` 调用结束,`count` 依然存在并记忆当前值
### 为什么闭包适合拖动功能
对于我们的生态瓶,每株植物需要记住它当前位置坐标。闭包是完美方案:
**本项目的关键优势:**
- **保持** 每株植物独立的私有位置变量
- **在拖动事件间** 保持坐标数据
- **避免** 不同可拖动元素间变量冲突
- **创建** 干净有序的代码结构
> 🎯 **学习目标**:你不必现在完全掌握闭包的所有细节。专注于理解它们如何帮助组织代码、维护拖动功能状态。
```mermaid
stateDiagram-v2
[*] --> Ready: 页面加载
Ready --> DragStart: 用户按下pointerdown
DragStart --> Dragging: 鼠标/手指移动pointermove
Dragging --> Dragging: 继续移动
Dragging --> DragEnd: 用户释放pointerup
DragEnd --> Ready: 重置以进行下一次拖拽
state DragStart {
[*] --> CapturePosition
CapturePosition --> SetupListeners
SetupListeners --> [*]
}
state Dragging {
[*] --> CalculateMovement
CalculateMovement --> UpdatePosition
UpdatePosition --> [*]
}
state DragEnd {
[*] --> RemoveListeners
RemoveListeners --> CleanupState
CleanupState --> [*]
}
```
### 创建 dragElement 函数
`script.js` 文件的元素声明下创建一个函数:
接下来编写处理拖动逻辑的主函数。将此函数添加到植物元素声明代码之后
```javascript
function dragElement(terrariumElement) {
//set 4 positions for positioning on the screen
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
terrariumElement.onpointerdown = pointerDrag;
// 初始化位置跟踪变量
let pos1 = 0, // 之前的鼠标X位置
pos2 = 0, // 之前的鼠标Y位置
pos3 = 0, // 当前的鼠标X位置
pos4 = 0; // 当前的鼠标Y位置
// 设置初始拖动事件监听器
terrariumElement.onpointerdown = pointerDrag;
}
```
`dragElement` 从脚本顶部的声明中获取其 `terrariumElement` 对象。然后,你为传递给函数的对象设置一些初始位置为 `0` 的局部变量。这些局部变量将在闭包中为每个元素添加拖放功能时进行操作。生态瓶将由这些拖动的元素填充,因此应用程序需要跟踪它们的放置位置。
此外,传递给该函数的 `terrariumElement` 被分配了一个 `pointerdown` 事件,这是 [Web API](https://developer.mozilla.org/docs/Web/API) 的一部分,旨在帮助管理 DOM。`onpointerdown` 在按钮被按下时触发,或者在我们的案例中,当一个可拖动的元素被触摸时触发。这个事件处理程序适用于 [Web 和移动浏览器](https://caniuse.com/?search=onpointerdown),但有一些例外。
✅ [事件处理程序 `onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick) 在跨浏览器支持方面更广泛;为什么不在这里使用它?思考一下你想要创建的屏幕交互的具体类型。
**理解位置追踪系统:**
- **`pos1``pos2`**:存储旧鼠标位置和新鼠标位置的差值
- **`pos3``pos4`**:追踪当前鼠标坐标
- **`terrariumElement`**:特定的植物元素,我们要让它可拖动
- **`onpointerdown`**:触发用户开始拖动的事件
**闭包模式运作方式:**
- **为每株植物** 创建私有位置变量
- **在拖动生命周期中** 保持这些变量
- **确保** 每株植物独立追踪自身坐标
- **通过 `dragElement` 函数** 提供清晰接口
### 为什么使用指针事件?
你可能好奇为何用 `onpointerdown`而不是更熟悉的 `onclick`。原因如下:
| 事件类型 | 适用场景 | 缺点 |
|------------|----------|-------------|
| `onclick` | 简单按钮点击 | 只能处理点击和释放,无法拖动 |
| `onpointerdown` | 鼠标和触摸均适用 | 新技术,但现已广泛支持 |
| `onmousedown` | 仅限桌面鼠标 | 移动端用户体验不足 |
**指针事件为何对我们构建的功能完美契合:**
- **适用于** 鼠标、手指甚至触控笔
- **在** 笔记本、平板和手机上体验一致
- **负责** 拖动实际过程(不仅是点击)
- **打造** 用户期望的流畅现代体验
> 💡 **面向未来**:指针事件是处理用户交互的现代方法。无需为鼠标和触控分别写代码,二者兼得。很棒,对吧?
### 🔄 **教学小结**
**事件处理理解测试**:停顿确认你已理解事件:
- ✅ 为什么用指针事件而非鼠标事件?
- ✅ 闭包变量如何在函数调用间持续?
- ✅ `preventDefault()` 在流畅拖动中起什么作用?
- ✅ 为什么监听器绑定到 document而非直接绑定元素
**现实连接**:思考你每天用到的拖放界面:
- **文件上传**:将文件拖入浏览器窗口
- **看板工具**:任务列间拖动卡片
- **图片库**:调整图片排序
- **移动端界面**:触屏滑动和拖动操作
---
## Pointerdrag 函数
## pointerDrag 函数:捕获拖动开始
`terrariumElement` 已准备好被拖动;当触发 `onpointerdown` 事件时,函数 `pointerDrag` 被调用。在这行代码下添加该函数:`terrariumElement.onpointerdown = pointerDrag;`
当用户按下植物(无论鼠标点击还是手指触摸),`pointerDrag` 函数启动。它捕获初始坐标并搭建拖动系统。
### 任务
将该函数添加到 `dragElement` 闭包内,紧接 `terrariumElement.onpointerdown = pointerDrag;` 行之后:
```javascript
function pointerDrag(e) {
e.preventDefault();
console.log(e);
pos3 = e.clientX;
pos4 = e.clientY;
// 防止默认的浏览器行为(如文本选择)
e.preventDefault();
// 捕捉初始的鼠标/触摸位置
pos3 = e.clientX; // 拖动开始时的 X 坐标
pos4 = e.clientY; // 拖动开始时的 Y 坐标
// 设置拖动过程的事件监听器
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
}
```
发生了几件事。首先,你通过使用 `e.preventDefault();` 阻止了 `pointerdown` 上通常发生的默认事件。这样你可以更好地控制界面的行为。
**步骤说明:**
- **阻止** 浏览器默认行为,避免干扰拖动
- **记录** 用户开始拖动的准确坐标
- **建立** 后续拖动移动事件监听器
- **准备** 跟踪鼠标/手指在整个文档上的移动
> 当你完全构建了脚本文件后,回到这一行并尝试去掉 `e.preventDefault()` ——会发生什么?
### 理解事件阻止
其次,在浏览器窗口中打开 `index.html` 并检查界面。当你点击一个植物时,你可以看到如何捕获 'e' 事件。深入研究事件,看看一个 `pointerdown` 事件可以收集多少信息!
`e.preventDefault()` 是保证拖动流畅的关键所在:
接下来,注意如何将局部变量 `pos3``pos4` 设置为 `e.clientX`。你可以在检查面板中找到 `e` 的值。这些值捕获了你点击或触摸植物时的 x 和 y 坐标。你需要对植物的行为进行精细控制,因此需要跟踪它们的坐标。
**不阻止的话,浏览器可能会:**
- **选中文本**,导致拖动时页面出现不适视觉
- **触发** 右键上下文菜单
- **干扰** 我们自定义的拖动行为
- **造成** 拖动过程中的视觉异常
✅ 为什么整个应用程序是用一个大的闭包构建的变得更清晰了吗?如果不是闭包,你如何为 14 个可拖动的植物维护作用域?
> 🔍 **实验**:完成本节后,试试去掉 `e.preventDefault()`,观察拖动体验如何变化。你将直观感受到该代码的重要性!
完成初始函数,通过在 `pos4 = e.clientY` 下添加两个指针事件操作:
### 坐标追踪系统
```html
`e.clientX``e.clientY` 属性提供精准鼠标/触摸坐标:
| 属性 | 测量内容 | 用途 |
|----------|------------------|----------|
| `clientX` | 相对于视口的水平位置 | 跟踪左右移动 |
| `clientY` | 相对于视口的垂直位置 | 跟踪上下移动 |
**理解这些坐标:**
- **提供**像素级精准定位信息
- **随着用户移动指针**实时更新
- **在不同屏幕尺寸和缩放级别**下保持一致
- **实现**流畅且响应迅速的拖拽交互
### 设置文档级事件监听器
注意我们把移动和停止事件绑定到整个 `document`,而不仅仅是植物元素:
```javascript
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
```
现在你正在指示希望植物随着指针移动而被拖动,并在取消选择植物时停止拖动。`onpointermove` 和 `onpointerup` 都是与 `onpointerdown` 相同 API 的一部分。界面现在会抛出错误,因为你尚未定义 `elementDrag``stopElementDrag` 函数,因此接下来构建它们。
**为什么绑定到 document**
- **即使鼠标离开植物元素也能继续跟踪**
- **防止用户快速移动时拖拽中断**
- **提供整个屏幕范围内的流畅拖拽**
- **处理光标移出浏览器窗口的边缘情况**
---
> ⚡ **性能提示**:拖拽停止时,我们会清理这些文档级监听器以避免内存泄漏和性能问题。
## elementDrag 和 stopElementDrag 函数
## 完成拖拽系统:移动与清理
你将通过添加两个内部函数来完成闭包,这些函数将处理拖动植物和停止拖动时发生的事情。你希望的行为是可以随时拖动任何植物并将其放置在屏幕上的任何位置。这个界面非常灵活(例如没有放置区域),允许你通过添加、移除和重新定位植物来设计你的生态瓶。
现在我们将添加剩余两个函数,分别处理实际拖动移动和拖拽停止时的清理。这些函数协同工作,实现花园中植物的平滑、响应式移动
### 任务
### elementDrag 函数:跟踪移动
`pointerDrag` 的结束大括号后添加 `elementDrag` 函数:
`pointerDrag` 函数的闭括号之后添加 `elementDrag` 函数:
```javascript
function elementDrag(e) {
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
console.log(pos1, pos2, pos3, pos4);
terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
// 计算自上次事件以来移动的距离
pos1 = pos3 - e.clientX; // 水平移动距离
pos2 = pos4 - e.clientY; // 垂直移动距离
// 更新当前位置跟踪
pos3 = e.clientX; // 新的当前 X 位置
pos4 = e.clientY; // 新的当前 Y 位置
// 将移动应用到元素的位置
terrariumElement.style.top = (terrariumElement.offsetTop - pos2) + 'px';
terrariumElement.style.left = (terrariumElement.offsetLeft - pos1) + 'px';
}
```
在这个函数中,你对外部函数中设置的初始位置 1-4 进行了大量编辑。这里发生了什么?
当你拖动时,通过将 `pos3`(之前设置为 `e.clientX`)减去当前的 `e.clientX` 值来重新分配 `pos1`。对 `pos2` 也进行了类似的操作。然后,你将 `pos3``pos4` 重置为元素的新 X 和 Y 坐标。你可以在拖动时在控制台中观察这些变化。然后,你操作植物的 CSS 样式,根据这些新位置计算植物的顶部和左侧 X 和 Y 坐标,设置其新位置。
> `offsetTop``offsetLeft` 是 CSS 属性,基于其父元素设置元素的位置;其父元素可以是任何非 `static` 定位的元素。
所有这些位置重新计算允许你微调生态瓶和植物的行为。
### 任务
**理解坐标数学:**
- **`pos1``pos2`**:计算鼠标自上次更新以来移动的距离
- **`pos3``pos4`**:存储当前鼠标位置用于下次计算
- **`offsetTop``offsetLeft`**:获取元素当前在页面上的位置
- **减法逻辑**:根据鼠标移动距离同步移动元素
```mermaid
sequenceDiagram
participant User
participant Mouse
participant JavaScript
participant Plant
User->>Mouse: 在 (100, 50) 开始拖拽
Mouse->>JavaScript: pointerdown 事件
JavaScript->>JavaScript: 存储初始位置 (pos3=100, pos4=50)
JavaScript->>JavaScript: 设置移动/释放监听器
User->>Mouse: 移动到 (110, 60)
Mouse->>JavaScript: pointermove 事件
JavaScript->>JavaScript: 计算: pos1=10, pos2=10
JavaScript->>Plant: 更新: left += 10px, top += 10px
Plant->>Plant: 在新位置渲染
User->>Mouse: 在 (120, 65) 释放
Mouse->>JavaScript: pointerup 事件
JavaScript->>JavaScript: 移除监听器
JavaScript->>JavaScript: 重置以便下一次拖拽
```
**移动计算细节说明:**
1. **测量**鼠标旧位置和新位置的差值
2. **计算**根据鼠标移动量应移动元素的距离
3. **实时更新**元素的 CSS 位置属性
4. **存储**新位置为下一次移动计算的基线
### 数学的视觉表示
```mermaid
sequenceDiagram
participant Mouse
participant JavaScript
participant Plant
Mouse->>JavaScript: 从 (100,50) 移动到 (110,60)
JavaScript->>JavaScript: 计算:向右移动 10px向下移动 10px
JavaScript->>Plant: 位置更新 +10px 向右,+10px 向下
Plant->>Plant: 在新位置渲染
```
### stopElementDrag 函数:清理工作
完成界面的最后一步是在 `elementDrag` 的结束大括号后添加 `stopElementDrag` 函数:
`elementDrag` 函数闭括号后添加清理函数:
```javascript
function stopElementDrag() {
document.onpointerup = null;
document.onpointermove = null;
// 移除文档级别的事件监听器
document.onpointerup = null;
document.onpointermove = null;
}
```
这个小函数重置了 `onpointerup``onpointermove` 事件,以便你可以通过再次开始拖动植物来重新开始植物的移动,或者开始拖动新的植物。
**为什么清理至关重要:**
- **防止遗留事件监听器导致内存泄漏**
- **用户松开植物时停止拖拽行为**
- **允许其他元素独立拖拽**
- **为下一次拖拽操作重置系统**
**不清理会带来什么问题:**
- 拖拽停止后事件监听器依旧运行
- 未使用监听器堆积导致性能下降
- 交互其他元素时出现异常行为
- 浏览器资源被无用事件处理占用
### 理解 CSS 定位属性
我们的拖拽系统操作两个关键 CSS 属性:
| 属性 | 控制内容 | 用途 |
|----------|------------------|---------------|
| `top` | 距顶部边缘距离 | 拖拽过程中的垂直定位 |
| `left` | 距左侧边缘距离 | 拖拽过程中的水平定位 |
**关于 offset 属性的关键点:**
- **`offsetTop`**:当前相对于定位父元素顶部的距离
- **`offsetLeft`**:当前相对于定位父元素左侧的距离
- **定位上下文**:这些数值相对于最近的定位祖先元素
- **实时更新**:当我们修改 CSS 属性时立即生效
> 🎯 **设计理念**:该拖拽系统故意保持灵活——没有“放置区”或限制。用户可以将植物放置于任意位置,完全自由设计他们的花园。
## 整合:完整的拖拽系统
✅ 如果不将这些事件设置为 null会发生什么
恭喜!你刚刚用原生 JavaScript 构建了一个复杂的拖放系统。你完整的 `dragElement` 函数包含强大的闭包控件,实现:
现在你已经完成了你的项目!
**闭包的功能点:**
- **为每个植物独立维护私有位置变量**
- **管理从开始到结束的完整拖拽生命周期**
- **提供整个屏幕范围内顺畅且响应迅速的移动**
- **正确清理资源避免内存泄漏**
- **创建直观且富有创意的花园设计界面**
🥇恭喜!你完成了美丽的生态瓶! ![完成的生态瓶](../../../../translated_images/terrarium-final.0920f16e87c13a84cd2b553a5af9a3ad1cffbd41fbf8ce715d9e9c43809a5e2c.zh.png)
### 测试你的交互式花园
现在测试你的交互式花园吧!在浏览器打开 `index.html`,试试这些操作:
1. **点击并按住**任意植物开始拖动
2. **移动鼠标或手指**,观察植物平滑跟随
3. **松开**以放置植物到新位置
4. **尝试不同布局**,探索界面可能性
🥇 **成就**你创建了一个完整的交互式网页应用运用了专业开发者每日使用的核心概念。这个拖放功能与文件上传、看板kanban和其他交互界面背后的原理相同。
### 🔄 **教学检查点**
**完整系统理解**:验证你对整个拖拽系统的掌握:
- ✅ 闭包如何为每棵植物维护独立状态?
- ✅ 为什么坐标计算对于流畅移动是必需的?
- ✅ 忘记清理事件监听器会有什么后果?
- ✅ 这种模式如何扩展到更复杂的交互?
**代码质量反思**:检查你的完整方案:
- **模块化设计**:每棵植物拥有自己的闭包实例
- **事件效率**:正确设置和清理监听器
- **跨设备支持**:兼容桌面和移动端
- **性能意识**:无内存泄漏或冗余计算
![完成的花园](../../../../translated_images/terrarium-final.0920f16e87c13a84.zh.png)
---
## 🚀挑战
## GitHub Copilot 代理挑战 🚀
使用代理模式完成以下挑战:
为你的闭包添加新的事件处理程序,让植物实现更多功能;例如,双击植物将其置于最前面。发挥创意!
**描述:** 通过添加重置功能,增强花园项目,使所有植物能够平滑动画回到它们的初始位置。
**提示:** 创建一个重置按钮,点击时使用 CSS 过渡动画将所有植物平滑移回侧边栏的原始位置。函数应在页面加载时存储初始位置,点击重置按钮时以 1 秒动画过渡回这些位置。
在此了解更多关于 [代理模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 额外挑战:提升技能
准备好将你的花园带到新水平了吗?尝试实现这些增强功能:
**创意扩展:**
- **双击**植物使其置于最前端z-index 操作)
- **添加视觉反馈**,例如悬停时轻微发光
- **实现边界限制**,防止植物被拖出花园范围
- **创建保存功能**,使用 localStorage 记住植物位置
- **添加音效**,为拾取和放置植物播放声音
> 💡 **学习机会**:每个挑战都将教你 DOM 操作、事件处理和用户体验设计的新内容。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/20)
## 复习与自学
## 复习与自学:深化理解
你已掌握 DOM 操作和闭包基础,但总有提升空间!以下是拓展知识与技能的路径。
### 其他拖放方案
我们使用了指针事件来获得最大灵活性,但网页开发提供多种方案:
| 方案 | 适用场景 | 学习价值 |
|----------|----------|----------------|
| [HTML 拖放 API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) | 文件上传,正式拖放区 | 理解浏览器原生功能 |
| [触摸事件](https://developer.mozilla.org/docs/Web/API/Touch_events) | 移动端交互 | 移动优先开发模式 |
| CSS `transform` 属性 | 流畅动画 | 性能优化技术 |
### 进阶 DOM 操作主题
**学习下一步:**
- **事件委托**:高效处理多个元素事件
- **Intersection Observer**:检测元素进入/离开视口
- **Mutation Observer**:监控 DOM 结构变化
- **Web Components**:创建可复用、封装的 UI 组件
- **虚拟 DOM 概念**:理解框架如何优化 DOM 更新
### 持续学习必备资源
**技术文档:**
- [MDN 指针事件指南](https://developer.mozilla.org/docs/Web/API/Pointer_events) - 全面指针事件参考
- [W3C 指针事件规范](https://www.w3.org/TR/pointerevents1/) - 官方标准文档
- [JavaScript 闭包详解](https://developer.mozilla.org/docs/Web/JavaScript/Closures) - 高级闭包模式
**浏览器兼容性:**
- [CanIUse.com](https://caniuse.com/) - 跨浏览器特性支持查询
- [MDN 浏览器兼容数据](https://github.com/mdn/browser-compat-data) - 详细兼容信息
**实践机会:**
- **构建**一款使用类似拖拽机制的拼图游戏
- **创建**带拖放任务管理的看板
- **设计**一个可拖拽照片排列的图片库
- **尝试**移动端触摸手势交互
> 🎯 **学习策略**:实践是巩固概念的最佳途径。尝试构建各种可拖拽界面,每个项目都会教你新的用户交互和 DOM 操作技巧。
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开浏览器开发者工具,在控制台输入 `document.querySelector('body')`
- [ ] 试着用 `innerHTML``textContent` 修改网页文本
- [ ] 给网页上的任意按钮或链接添加点击事件监听器
- [ ] 使用 Elements 面板查看 DOM 树结构
### 🎯 **本小时你能完成的任务**
- [ ] 完成课后测验并复习 DOM 操作概念
- [ ] 创建响应用户点击的交互网页
- [ ] 练习不同事件类型的事件处理(点击、悬停、按键)
- [ ] 使用 DOM 操作构建简单待办清单或计数器
- [ ] 探索 HTML 元素与 JavaScript 对象的关系
### 📅 **你的为期一周的 JavaScript 学习计划**
- [ ] 完成交互式花园项目,包含拖放功能
- [ ] 掌握事件委托以提升事件处理效率
- [ ] 了解事件循环与异步 JavaScript
- [ ] 通过构建具私有状态的模块练习闭包
- [ ] 学习现代 DOM API如 Intersection Observer
- [ ] 尝试无框架构建交互组件
### 🌟 **你的为期一个月的 JavaScript 精通计划**
- [ ] 使用原生 JavaScript 创建复杂单页应用
- [ ] 学习现代框架React、Vue 或 Angular并对比原生日 DOM
- [ ] 参与开源 JavaScript 项目贡献代码
- [ ] 掌握高级概念,如 Web Components 和自定义元素
- [ ] 构建高性能网页应用,优化 DOM 模式
- [ ] 教授他人 DOM 操作与 JavaScript 基础知识
## 🎯 你的 JavaScript DOM 精通时间线
```mermaid
timeline
title DOM 与 JavaScript 学习进度
section 基础15分钟
DOM 理解:元素选择方法
:树结构导航
:属性访问模式
section 事件处理20分钟
用户交互:指针事件基础
:事件监听设置
:跨设备兼容性
:事件阻止技术
section 闭包25分钟
作用域管理:私有变量创建
:函数持久化
:状态管理模式
:内存效率
section 拖拽系统30分钟
交互特性:坐标跟踪
:位置计算
:运动数学
:清理程序
section 高级模式45分钟
专业技能:事件委托
:性能优化
:错误处理
:无障碍考虑
section 框架理解(一周)
现代开发:虚拟 DOM 概念
:状态管理库
:组件架构
:构建工具集成
section 专家级别(一月)
高级 DOM APIIntersection Observer
Mutation Observer
:自定义元素
Web 组件
```
### 🛠️ 你的 JavaScript 工具箱总结
虽然在屏幕上拖动元素看起来很简单,但实现这一功能有很多方法和陷阱,具体取决于你想要的效果。事实上,有一个完整的 [拖放 API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) 供你尝试。我们没有在本模块中使用它,因为我们想要的效果有所不同,但可以在自己的项目中尝试这个 API看看能实现什么。
完成本课后,你已经掌握:
- **DOM 精通**:元素选取、属性操作及树结构导航
- **事件专业**:跨设备指针事件交互处理
- **闭包理解**:私有状态管理与函数持久性
- **交互系统**:从零实现完整拖拽功能
- **性能意识**:正确事件清理与内存管理
- **现代模式**:专业开发中应用的代码组织技术
- **用户体验**:创建直观、响应迅速的界面
在 [W3C 文档](https://www.w3.org/TR/pointerevents1/) 和 [MDN Web 文档](https://developer.mozilla.org/docs/Web/API/Pointer_events) 上找到更多关于指针事件的信息。
**获得的专业技能**:你构建的功能使用了与以下相同技术:
- **Trello/看板**:卡片拖拽跨列操作
- **文件上传系统**:拖放文件处理
- **图片库**:照片排列界面
- **移动应用**:基于触摸的交互模式
始终使用 [CanIUse.com](https://caniuse.com/) 检查浏览器的兼容性。
**下一步**:你已准备好学习如 React、Vue 或 Angular 等基于这些 DOM 基础概念构建的现代框架!
## 作业
## 任务
[进一步操作 DOM](assignment.md)
[继续练习 DOM](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的原文应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,139 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "22fb6c3cb570c47f1ac65048393941fa",
"translation_date": "2025-08-23T22:31:40+00:00",
"original_hash": "947ca5ce7c94aee9c7de7034e762bc17",
"translation_date": "2026-01-06T11:52:45+00:00",
"source_file": "3-terrarium/3-intro-to-DOM-and-closures/assignment.md",
"language_code": "zh"
}
-->
# 更深入了解 DOM
# DOM 元素调查作业
## 概述
既然你已经亲身体验了 DOM 操作的强大功能,现在是时候探索更广泛的 DOM 接口世界了。本作业将加深你对不同网络技术如何与 DOM 交互的理解,而不仅仅是拖拽元素。
## 学习目标
完成此作业后,你将能够:
- **研究**并深入理解特定的 DOM 接口
- **分析**现实世界中 DOM 操作的实现
- **将**理论概念与实际应用相连接
- **培养**技术文档编写和分析的能力
## 说明
通过“认领”一个 DOM 元素来进一步研究 DOM。访问 MDN 的[DOM 接口列表](https://developer.mozilla.org/docs/Web/API/Document_Object_Model),选择一个接口。在网络上的某个网站中找到它的使用实例,并写一篇解释它如何被使用的说明。
### 第一步:选择你的 DOM 接口
访问 MDN 的全面 [DOM 接口列表](https://developer.mozilla.org/docs/Web/API/Document_Object_Model),选择一个你感兴趣的接口。你可以考虑以下类别以丰富选择:
**初学者友好选项:**
- `Element.classList` - 动态管理 CSS 类
- `Document.querySelector()` - 高级元素选择
- `Element.addEventListener()` - 指针事件之外的事件处理
- `Window.localStorage` - 客户端数据存储
**中级挑战:**
- `Intersection Observer API` - 检测元素可见性
- `MutationObserver` - 监视 DOM 变化
- `Drag and Drop API` - 我们指针方法的替代方案
- `Geolocation API` - 获取用户位置
**高级探索:**
- `Web Components` - 自定义元素与影子 DOM
- `Canvas API` - 编程图形绘制
- `Web Workers` - 后台处理
- `Service Workers` - 离线功能
### 第二步:研究与文档
撰写一份全面分析300-500字内容包括
#### 技术概述
- **定义**你的接口用简单易懂的语言说明其功能
- **解释**关键方法、属性或事件
- **描述**该接口设计解决的主要问题
#### 现实世界应用
- **找到**一个使用了你选择接口的网站(通过查看代码或研究案例)
- **记录**具体的实现方式,如可能,包含代码片段
- **分析**开发者选择这种方式的原因
- **解释**它如何改善用户体验
#### 实际应用
- **比较**你的接口和我们在生态瓶项目中使用的技术
- **建议**你的接口如何增强或扩展生态瓶的功能
- **识别**其他适合使用该接口的项目
### 第三步:代码示例
包含一个简单且可运行的代码示例,用以演示你的接口。示例应:
- **功能可用** - 代码应能实际运行
- **加注释** - 解释每个部分的作用
- **相关** - 与实际应用场景相关联
- **友好初学者** - 易于学习前端开发者理解
## 提交格式
请用清晰的标题结构组织你的提交:
```markdown
# [Interface Name] DOM Investigation
## What It Does
[Technical overview]
## Real-World Example
[Website analysis and implementation details]
## Code Demonstration
[Your working example with comments]
## Reflection
[How this connects to our terrarium project and future applications]
```
## 评估标准
| 评价标准 | 优秀A | 良好B | 发展中C | 需改进D |
|----------|----------|------------|-------------|------------|
| **技术理解** | 展示深刻理解,准确解释且术语正确 | 体现扎实理解,解释大部分准确 | 基本理解但有部分误解 | 理解有限,错误较多 |
| **现实分析** | 识别且详细分析实际实现,提供具体例子 | 找到真实案例并进行充分分析 | 定位案例但分析不够深入 | 对现实联系的描述模糊或不准确 |
| **代码示例** | 代码可运行且注释清晰,展示接口 | 功能代码及适当注释 | 代码可用但注释欠缺 | 代码有错误或解释差 |
| **写作质量** | 文字清晰,结构合理,技术表达好 | 结构良好,技术表达得当 | 组织尚可,表达一般 | 结构松散,表达不清 |
| **批判性思维** | 深刻连接概念,提出创新应用 | 分析良好,相关连接明显 | 有一些分析,但深度不够 | 批判思维不足 |
## 成功提示
**研究策略:**
- **从** MDN 文档开始,获取权威信息
- **查找** GitHub 或 CodePen 上的代码示例
- **使用**浏览器开发者工具检查流行网站
- **观看**视频教程获取直观讲解
**写作指南:**
- **使用**自己的语言,而非照抄文档
- **包含**具体例子和代码片段
- **像教朋友一样**解释技术概念
- **连接**你的接口与更广泛的网页开发概念
**代码示例思路:**
- **设计**展示接口主要功能的简单演示
- **借鉴**生态瓶项目的相关概念
- **注重**功能实现而非视觉设计
- **测试**确保代码正确运行
## 截止提交日期
[插入截止日期]
## 有疑问?
## 评分标准
如果你对作业的任何方面有疑问,请随时提问!此调查将深化你对 DOM 如何支持我们日常使用的交互式网页体验的理解。
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | ------------------------------------------ | -------------------------------------------- | ---------------------- |
| | 提供了段落说明,并附有示例 | 提供了段落说明,但没有附示例 | 未提供任何说明 |
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力确保准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文档的母语版本应视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用此翻译而产生的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,43 +1,30 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "7965cd2bc5dc92ad888dc4c6ab2ab70a",
"translation_date": "2025-08-23T22:23:07+00:00",
"original_hash": "bc5c5550f79d10add90ce419ee34abb3",
"translation_date": "2026-01-06T11:06:19+00:00",
"source_file": "3-terrarium/README.md",
"language_code": "zh"
}
-->
# 我的微型生态瓶一个学习HTML、CSS和使用JavaScript操作DOM的项目 🌵🌱
## 部署您的 Terrarium
一个小型的拖放代码冥想项目。通过一些HTML、JS和CSS你将能够构建一个网页界面对其进行样式设计甚至添加你选择的多种交互功能
您可以使用 **Azure Static Web Apps** 将您的 Terrarium 部署或发布到网络上
![我的微型生态瓶](../../../3-terrarium/images/screenshot_gray.png)
1. Fork 此仓库
# 课程
2. 按下此按钮 👇
1. [HTML入门](./1-intro-to-html/README.md)
2. [CSS入门](./2-intro-to-css/README.md)
3. [DOM和JS闭包入门](./3-intro-to-DOM-and-closures/README.md)
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.StaticApp)
## 致谢
3. 按照设置向导创建您的应用。
- 将 **应用根目录** 设置为 `/solution` 或您的代码库根目录。
- 此应用没有 API您可以跳过 API 配置。
- 系统会自动创建一个 `.github` 文件夹,帮助 Azure Static Web Apps 构建和发布您的应用。
由[Jen Looper](https://www.twitter.com/jenlooper)用 ♥️ 编写。
通过CSS创建的微型生态瓶灵感来源于Jakub Mandra的玻璃罐 [codepen](https://codepen.io/Rotarepmi/pen/rjpNZY)。
艺术作品由[Jen Looper](http://jenlooper.com)手绘完成并借助Procreate完成。
## 部署你的微型生态瓶
你可以使用Azure Static Web Apps将你的微型生态瓶部署或发布到网上。
1. Fork此代码库
2. 点击这个按钮
[![Deploy to Azure button](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/?feature.customportal=false&WT.mc_id=academic-77807-sagibbon#create/Microsoft.StaticApp)
3. 按照向导创建你的应用。确保将应用根目录设置为`/solution`或你的代码库的根目录。此应用中没有API因此无需担心添加API。一个GitHub文件夹将会在你Fork的代码库中创建这将帮助Azure Static Web Apps的构建服务构建并将你的应用发布到一个新的URL。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意,自动翻译可能包含错误或不准确之处。原始语言的原始文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,42 +1,290 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "957547b822c40042e07d591c4fbfde4f",
"translation_date": "2025-08-24T00:16:54+00:00",
"original_hash": "efa2ab875b8bb5a7883816506da6b6d2",
"translation_date": "2026-01-06T11:05:33+00:00",
"source_file": "4-typing-game/README.md",
"language_code": "zh"
}
-->
# 事件驱动编程 - 构建一个打字游戏
```mermaid
journey
title 你的打字游戏开发旅程
section 基础
规划游戏结构: 3: Student
设计用户界面: 4: Student
设置HTML元素: 4: Student
section 功能
处理用户输入: 4: Student
跟踪时间: 5: Student
计算准确率: 5: Student
section 特性
添加视觉反馈: 5: Student
实现游戏逻辑: 5: Student
优化体验: 5: Student
```
## 介绍
打字是开发者最被低估的技能之一。能够快速将脑海中的想法转移到编辑器中,可以让创造力自由流动。而学习的最佳方式之一就是玩游戏!
这里有件每个开发者都知道但很少谈论的事:打字快是一种超级能力!🚀 想想看——你把想法从大脑传到代码编辑器的速度越快,你的创造力就能流动得越顺畅。这就像在你的思维和屏幕之间建立了一条直接通道。
> 那么,让我们来构建一个打字游戏吧!
```mermaid
pie title 游戏特征
"实时反馈" : 25
"性能跟踪" : 20
"交互式界面" : 20
"计时系统" : 15
"引用管理" : 10
"结果显示" : 10
```
想知道提升这项技能的最佳方法之一吗?没错——我们要做一个游戏!
你将使用迄今为止学到的 JavaScript、HTML 和 CSS 技能来创建一个打字游戏。游戏会向玩家展示一段随机的引用(我们使用的是 [福尔摩斯](https://en.wikipedia.org/wiki/Sherlock_Holmes) 的名言),并计时玩家准确输入这段文字所需的时间。你将使用迄今为止学到的 JavaScript、HTML 和 CSS 技能来创建一个打字游戏。
```mermaid
flowchart LR
A[玩家开始游戏] --> B[显示随机引用]
B --> C[玩家输入字符]
C --> D{字符正确吗?}
D -->|是| E[绿色高亮]
D -->|否| F[红色高亮]
E --> G[更新准确率]
F --> G
G --> H{引用完成?}
H -->|否| C
H -->|是| I[计算每分钟词数]
I --> J[显示结果]
J --> K[再玩一次?]
K -->|是| B
K -->|否| L[游戏结束]
style A fill:#e1f5fe
style D fill:#fff3e0
style E fill:#e8f5e8
style F fill:#ffebee
style I fill:#f3e5f5
```
> 让我们一起创建一个很棒的打字游戏吧!
准备好把你一直在学习的 JavaScript、HTML 和 CSS 技能用起来了吗?我们将构建一个打字游戏,它会用传奇侦探 [夏洛克·福尔摩斯](https://en.wikipedia.org/wiki/Sherlock_Holmes) 的随机名言来考验你的速度和准确度——相信我,这比你想象的还要上瘾!
```mermaid
mindmap
root((打字游戏开发))
User Interface
Input Elements
Visual Feedback
Responsive Design
Accessibility
Game Logic
Quote Selection
Timer Management
Accuracy Tracking
Score Calculation
Event Handling
Keyboard Input
Button Clicks
Real-time Updates
Game State Changes
Performance Metrics
Words Per Minute
Character Accuracy
Error Tracking
Progress Display
User Experience
Immediate Feedback
Clear Instructions
Engaging Content
Achievement System
```
![demo](../../../4-typing-game/images/demo.gif)
## 前置知识
## 你需要了解的内容
本课程假设你已经熟悉以下概念:
```mermaid
flowchart TD
A[用户操作] --> B{事件类型?}
B -->|按键| C[键盘事件]
B -->|按钮点击| D[鼠标事件]
B -->|定时器| E[时间事件]
C --> F[检查字符]
D --> G[开始/重置游戏]
E --> H[更新时间]
F --> I{正确吗?}
I -->|是| J[高亮绿色]
I -->|否| K[高亮红色]
J --> L[更新分数]
K --> L
L --> M[检查游戏状态]
G --> N[生成新语录]
H --> O[显示时间]
M --> P{游戏完成?}
P -->|是| Q[显示结果]
P -->|否| R[继续游戏]
style A fill:#e1f5fe
style F fill:#e8f5e8
style I fill:#fff3e0
style Q fill:#f3e5f5
```
在我们开始之前,确保你熟悉以下概念(如果需要快速复习也没关系——我们都有过的!):
- 创建文本输入框和按钮控件
- CSS 和使用类设置样式
- 创建文本输入和按钮控件
- 使用类设置 CSS 样式
- JavaScript 基础
- 创建数组
- 生成随机数
- 获取当前时间
## 课程
如果这些有点生疏,那完全没问题!有时候巩固知识的最好方法就是跳进项目中,边干边学。
### 🔄 **教学检查**
**基础评估**:开始开发之前,请确保你理解:
- ✅ HTML 表单和输入元素的工作原理
- ✅ CSS 类和动态样式
- ✅ JavaScript 事件监听器和处理程序
- ✅ 数组操作和随机选择
- ✅ 时间测量和计算
**快速自测**:你能解释这些概念如何在交互式游戏中协同工作吗?
- **事件**在用户与元素交互时触发
- **处理程序**处理这些事件并更新游戏状态
- **CSS**为用户操作提供视觉反馈
- **计时**支持性能测量和游戏进程
```mermaid
quadrantChart
title 输入游戏技能发展
x-axis 初学者 --> 专家
y-axis 静态 --> 交互式
quadrant-1 高级游戏
quadrant-2 实时应用
quadrant-3 基础页面
quadrant-4 互动网站
HTML Forms: [0.3, 0.2]
CSS Styling: [0.4, 0.3]
Event Handling: [0.7, 0.8]
Game Logic: [0.8, 0.9]
Performance Tracking: [0.9, 0.7]
```
## 让我们动手吧!
[使用事件驱动编程创建打字游戏](./typing-game/README.md)
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开浏览器控制台,尝试使用 `addEventListener` 监听键盘事件
- [ ] 创建一个带输入框的简单 HTML 页面,测试输入检测
- [ ] 练习字符串操作,将输入文本与目标文本进行比较
- [ ] 使用 `setTimeout` 了解定时函数
### 🎯 **你一小时内能完成的目标**
- [ ] 完成课程后测验,理解事件驱动编程
- [ ] 构建一个带单词验证的基本打字游戏版本
- [ ] 为正确和错误输入添加视觉反馈
- [ ] 实现一个基于速度和准确度的简单计分系统
- [ ] 使用 CSS 美化游戏界面
[通过事件驱动编程创建一个打字游戏](./typing-game/README.md)
### 📅 **你一周内的游戏开发计划**
- [ ] 完善完整的打字游戏及其所有功能和细节
- [ ] 添加难度等级,提供不同复杂度的词汇
- [ ] 实现用户统计跟踪(字数速度、准确率随时间变化)
- [ ] 制作音效和动画提升用户体验
- [ ] 使游戏支持移动设备响应和触摸操作
- [ ] 在线分享你的游戏并收集用户反馈
### 🌟 **你一个月的互动开发计划**
- [ ] 构建多个游戏,探索不同的交互模式
- [ ] 学习游戏循环、状态管理和性能优化
- [ ] 参与开源游戏开发项目
- [ ] 精通高级计时概念和平滑动画
- [ ] 创建展示各类交互应用的作品集
- [ ] 指导对游戏开发和用户交互感兴趣的其他人
## 🎯 你的打字游戏精通时间线
```mermaid
timeline
title 游戏开发学习进度
section 设置 (10分钟)
项目结构: HTML基础
: CSS样式设置
: JavaScript文件创建
section 用户界面 (20分钟)
交互元素: 输入字段
: 按钮控制
: 显示区域
: 响应式布局
section 事件处理 (25分钟)
用户交互: 键盘事件
: 鼠标事件
: 实时反馈
: 状态管理
section 游戏逻辑 (30分钟)
核心功能: 引用生成
: 字符比较
: 准确率计算
: 计时器实现
section 性能跟踪 (35分钟)
指标与分析: WPM计算
: 错误跟踪
: 进度可视化
: 结果显示
section 打磨与增强 (45分钟)
用户体验: 视觉反馈
: 音效
: 动画
: 无障碍功能
section 高级功能 (1周)
扩展功能: 难度等级
: 排行榜
: 自定义引用
: 多人选项
section 专业技能 (1个月)
游戏开发: 性能优化
: 代码架构
: 测试策略
: 部署模式
```
### 🛠️ 你的游戏开发工具总结
完成此项目后,你将掌握:
- **事件驱动编程**:响应用户输入的互动界面
- **实时反馈**:即时的视觉和性能更新
- **性能测量**:精准的计时和计分系统
- **游戏状态管理**:控制应用流程和用户体验
- **交互设计**:打造引人入胜、令人上瘾的用户体验
- **现代网页 API**:利用浏览器能力实现丰富互动
- **无障碍模式**:为所有用户设计包容性体验
**现实应用**:这些技能广泛应用于:
- **网络应用**:任何互动界面或仪表盘
- **教育软件**:学习平台和技能评估工具
- **生产力工具**:文本编辑器、集成开发环境和协作软件
- **游戏行业**:浏览器游戏和互动娱乐
- **移动开发**:基于触控的界面和手势处理
**下一步**:你已准备好探索高级游戏框架、实时多人系统或复杂交互应用!
## 致谢
由 [Christopher Harrison](http://www.twitter.com/geektrainer) 用 ♥️ 编写
由 [Christopher Harrison](http://www.twitter.com/geektrainer) 用 ♥️ 撰写
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们尽力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力保证译文的准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文档的原文版本应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或曲解,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,88 +1,154 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "1b0aeccb600f83c603cd70cb42df594d",
"translation_date": "2025-08-29T14:52:04+00:00",
"original_hash": "da8bc72041a2bb3826a54654ee1a8844",
"translation_date": "2026-01-06T11:47:12+00:00",
"source_file": "4-typing-game/typing-game/README.md",
"language_code": "zh"
}
-->
# 使用事件创建游戏
你有没有想过网站是如何知道你点击了按钮或在文本框中输入的?这就是事件驱动编程的魔力!还有什么比通过构建一个能够响应你每一次按键的打字速度游戏来学习这项关键技能更好的方法呢。
你将亲眼见证网页浏览器如何“与”你的JavaScript代码“对话”。每当你点击、输入或移动鼠标时浏览器都会向你的代码发送小信息我们称之为事件而你来决定如何响应
完成本教程后,你将创建一个能够跟踪你的打字速度和准确率的真实打字游戏。更重要的是,你将理解支撑每个互动网站的基本概念。让我们开始吧!
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/21)
## 事件驱动编程
在创建基于浏览器的应用程序时我们为用户提供了一个图形用户界面GUI以便用户与我们构建的内容进行交互。与浏览器交互最常见的方式是点击和在各种元素中输入内容。作为开发者我们面临的挑战是无法预知用户何时会执行这些操作
想想你最喜欢的应用或网站——是什么让它感觉生动且响应灵敏?这全在于它如何对你的操作做出反应!每次点击、敲击、滑动或按键都会产生我们所说的“事件”,真正的网页开发魔力就在这里。
让网页编程如此有趣的是:我们永远不知道别人什么时候会点击按钮或开始在文本框中输入。他们可能马上点击,等待五分钟,甚至可能从不点击!这种不可预测性意味着我们需要用不同的思路写代码。
[事件驱动编程](https://en.wikipedia.org/wiki/Event-driven_programming) 是我们需要用来创建 GUI 的编程方式。如果我们稍微拆解一下这个短语,可以看到核心词是 **事件**。根据 Merriam-Webster 的定义,[事件](https://www.merriam-webster.com/dictionary/event) 是“某种发生的事情”。这完美地描述了我们的情况。我们知道会发生某些事情,需要执行一些代码来响应,但我们不知道它会在何时发生。
我们不再写那种像食谱一样自上而下执行的代码而是写一段坐在那里耐心等待事情发生的代码。这有点像19世纪的电报操作员坐在设备旁准备在信息通过电线传来时立刻响应
我们通过创建一个函数来标记我们想要执行的代码部分。在 [过程式编程](https://en.wikipedia.org/wiki/Procedural_programming) 中,函数按照特定的顺序被调用。在事件驱动编程中也是如此,不同之处在于函数的调用方式
那么什么是“事件”呢?简单来说,它就是发生的事情!你点击按钮——那是一个事件。你输入一个字母——那是一个事件。你移动鼠标——又是一个事件
为了处理事件(如按钮点击、输入等),我们需要注册 **事件监听器**。事件监听器是一个监听事件发生并作出响应的函数。事件监听器可以更新用户界面、向服务器发出请求,或者根据用户的操作执行其他需要完成的任务。我们通过使用 [addEventListener](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) 并提供一个要执行的函数来添加事件监听器
事件驱动编程让我们可以设置代码去“监听”和响应这些事件。我们创建称为**事件监听器**的特殊函数,它们耐心等待特定事件发生,然后在事件发生时立即行动
> **NOTE:** 值得注意的是,有多种方式可以创建事件监听器。你可以使用匿名函数,也可以创建命名函数。你还可以使用各种快捷方式,比如设置 `click` 属性,或者使用 `addEventListener`。在我们的练习中,我们将专注于 `addEventListener` 和匿名函数,因为这是 Web 开发者最常用的技术之一。它也是最灵活的,因为 `addEventListener` 适用于所有事件,并且事件名称可以作为参数提供。
把事件监听器想象成代码的门铃。你设置门铃(`addEventListener()`),告诉它要监听什么声音(比如“点击”或“按键”),然后指定有人按响时要执行什么(你自定义的函数)。
**事件监听器的工作原理:**
- **监听**用户的特定操作,如点击、按键或鼠标移动
- **执行**在指定事件发生时你的自定义代码
- **即时响应**用户交互,创造无缝体验
- **支持**对同一元素使用多个监听器处理不同事件
> **注意:**有很多创建事件监听器的方法。你可以使用匿名函数,也可以创建命名函数。可以使用各种快捷方式,比如设置`click`属性,或使用`addEventListener()`。本练习中我们重点使用`addEventListener()`和匿名函数,因为这是网络开发者最常用的方法。它也是最灵活的,适用于所有事件,事件名称可作为参数传入。
### 常见事件
在创建应用程序时,有[数十种事件](https://developer.mozilla.org/docs/Web/Events)可供监听。基本上,用户在页面上执行的任何操作都会触发一个事件,这为你提供了极大的灵活性来确保用户获得理想的体验。幸运的是,你通常只需要使用少数几种事件。以下是一些常见的事件(包括我们在创建游戏时会用到的两个):
虽然浏览器提供了数十种不同事件可供监听,但大多数互动应用只依赖其中几种核心事件。理解这些核心事件能为你构建复杂用户交互奠定基础。
- [click](https://developer.mozilla.org/docs/Web/API/Element/click_event):用户点击了某个元素,通常是按钮或超链接
- [contextmenu](https://developer.mozilla.org/docs/Web/API/Element/contextmenu_event):用户右键点击
- [select](https://developer.mozilla.org/docs/Web/API/Element/select_event):用户选中了某些文本
- [input](https://developer.mozilla.org/docs/Web/API/Element/input_event):用户输入了一些文本
有[数十种事件](https://developer.mozilla.org/docs/Web/Events)可供你在创建应用时监听。基本上,用户在页面上所做的任何操作都会触发事件,赋予你强大能力确保他们得到理想的体验。幸运的是,通常只需少数几个事件。下面是几个常用事件(包括我们在游戏中会用到的两个):
## 创建游戏
| 事件 | 描述 | 常见用例 |
|-------|-------------|------------------|
| `click` | 用户点击了某个元素 | 按钮、链接、互动元素 |
| `contextmenu` | 用户点击了鼠标右键 | 自定义右键菜单 |
| `select` | 用户选中了文本 | 文本编辑、复制操作 |
| `input` | 用户输入了文本 | 表单验证、实时搜索 |
我们将创建一个游戏来探索 JavaScript 中的事件是如何工作的。我们的游戏将测试玩家的打字技能,这是所有开发者都应该具备的最被低估的技能之一。我们都应该练习打字!游戏的总体流程如下:
**理解这些事件类型:**
- **在用户与页面特定元素交互时触发**
- **通过事件对象提供有关用户行为的详细信息**
- **使你能创建响应式、互动性强的网页应用**
- **在不同浏览器和设备上表现一致**
- 玩家点击开始按钮,屏幕上会显示一段需要输入的文字
- 玩家尽可能快地在文本框中输入这段文字
- 每完成一个单词,下一个单词会被高亮显示
- 如果玩家输入错误,文本框会变成红色
- 当玩家完成整段文字时,会显示成功消息以及所用时间
## 创建游戏
让我们开始构建游戏,并学习事件的相关知识!
既然了解了事件的工作原理,让我们用所学知识实践,创造点有用的东西。我们将创建一个打字速度游戏,演示事件处理的同时,帮助你培养一项重要的开发者技能。
我们要制作一个游戏探索JavaScript中事件的工作方式。游戏将考验玩家的打字技能而这正是所有开发者都应具备的一项被低估的技能。有趣的是我们今天使用的QWERTY键盘布局其实是在1870年代为打字机设计的——良好的打字技能对程序员来说仍然非常宝贵游戏的大致流程如下
```mermaid
flowchart TD
A[玩家点击开始] --> B[显示随机引用]
B --> C[玩家在文本框中输入]
C --> D{单词完成?}
D -->|是| E[高亮下一个单词]
D -->|否| F{到目前为止正确吗?}
F -->|是| G[保持正常样式]
F -->|否| H[显示错误样式]
E --> I{引用完成?}
I -->|否| C
I -->|是| J[显示成功消息和时间]
G --> C
H --> C
```
**游戏的工作方式:**
- **玩家点击开始按钮时启动,显示随机引用文本**
- **实时逐词追踪玩家的输入进度**
- **高亮当前应输入的单词以帮助集中注意力**
- **为输入错误提供即时视觉反馈**
- **引用完成时计算并显示总用时**
让我们一起搭建游戏,学习事件!
### 文件结构
我们需要创建三个文件:**index.html**、**script.js** 和 **style.css**。让我们先设置好这些文件,以便后续操作更方便。
在开始编码之前,让我们先理清文件结构!从一开始就保持文件结构清晰,会让你避免日后困扰,使项目更为专业。😊
- 打开控制台或终端窗口,输入以下命令创建一个新文件夹:
我们将保持简单,仅使用三个文件:`index.html`负责页面结构,`script.js`包含所有游戏逻辑,`style.css`负责美化页面。这是驱动大部分网页的经典组合!
**在控制台或终端窗口中执行以下命令,创建新文件夹以开始工作:**
```bash
# Linux or macOS
# Linux macOS
mkdir typing-game && cd typing-game
# Windows
md typing-game && cd typing-game
```
- 打开 Visual Studio Code
**这些命令执行了以下操作:**
- **创建**名为`typing-game`的新目录存放项目文件
- **自动切换**至新建目录
- **为游戏开发设置**一个干净的工作空间
**打开 Visual Studio Code**
```bash
code .
```
- 在 Visual Studio Code 中为文件夹添加以下三个文件:
- index.html
- script.js
- style.css
**该命令执行:**
- **在当前目录**启动 Visual Studio Code
- **打开**你的项目文件夹
- **提供**所有开发工具的访问
**在 Visual Studio Code 中为该文件夹添加三个文件,命名如下:**
- `index.html` - 包含游戏的结构和内容
- `script.js` - 处理所有游戏逻辑和事件监听
- `style.css` - 定义视觉外观和样式
## 创建用户界面
根据需求分析,我们知道 HTML 页面上需要一些元素。这有点像一个食谱,我们需要一些“原料”:
现在让我们构建游戏进行的舞台!把它想象成设计飞船的控制面板——确保玩家所需的一切都在预期位置。
让我们确定游戏到底需要哪些元素。如果你在玩打字游戏,会想在屏幕上看到什么?我们需要:
| UI 元素 | 目的 | HTML 元素 |
|------------|---------|-------------|
| 引用显示区 | 展示要打的文本 | `<p>``id="quote"` |
| 消息区 | 显示状态和成功信息 | `<p>``id="message"` |
| 文本输入框 | 玩家输入引用的地方 | `<input>``id="typed-value"` |
| 开始按钮 | 开始游戏 | `<button>``id="start"` |
- 一个显示用户需要输入的文字的区域
- 一个显示消息(如成功消息)的区域
- 一个用于输入的文本框
- 一个开始按钮
**UI结构要点**
- **内容逻辑地组织**从上到下
- **元素分配**唯一 ID 供 JavaScript 访问
- **提供**清晰的视觉层次,提升用户体验
- **包含**语义化的 HTML 元素以增强无障碍支持
每个元素都需要一个 ID以便我们在 JavaScript 中操作它们。我们还需要添加对 CSS 和 JavaScript 文件的引用。
以上每个元素都需分配 ID方便我们用JavaScript操作。我们还会添加对即将创建的CSS和JavaScript文件的引用。
创建一个名为 **index.html** 的新文件。添加以下 HTML
新建一个名为`index.html`的文件,添加如下HTML
```html
<!-- inside index.html -->
@ -105,26 +171,52 @@ code .
</html>
```
**这个HTML结构实现了**
- **在`<head>`中引入CSS样式表用于美化**
- **创建清晰的标题和用户指引**
- **建立带有特定ID的占位段落以显示动态内容**
- **包含带无障碍属性的输入框**
- **设置启动游戏的按钮**
- **在文档末尾加载JavaScript文件以优化性能**
### 启动应用程序
开发时最好采用迭代方式随时查看效果。让我们启动应用程序。Visual Studio Code 有一个非常棒的扩展 [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon),它可以在本地托管你的应用程序,并在每次保存时刷新浏览器。
开发过程中频繁测试应用能让你提前发现问题并实时看到进展。Live Server 是一个宝贵的工具,每次保存时自动刷新浏览器,使开发更高效。
采用迭代开发最为理想,方便观察效果。让我们启动应用。有一个绝佳的 Visual Studio Code 扩展叫做[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon),它既能本地托管应用,也会每次保存自动刷新浏览器。
**访问链接并点击安装[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon)**
**安装时会:**
- **提示**浏览器打开 Visual Studio Code
- **引导**你完成扩展安装过程
- **可能需要**重启 Visual Studio Code 以完成安装
**安装完成后,在 VS Code 中按 Ctrl-Shift-P或 Cmd-Shift-P打开命令面板**
**命令面板的作用:**
- **快速访问**VS Code所有命令
- **边输边搜**命令
- **节省时间**使用快捷键加快开发
**输入“Live Server: Open with Live Server”**
- 按照链接安装 [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon),点击 **Install**
- 浏览器会提示你打开 Visual Studio Code然后 Visual Studio Code 会提示你进行安装
- 如果有提示,请重启 Visual Studio Code
- 安装完成后,在 Visual Studio Code 中按 Ctrl-Shift-P或 Cmd-Shift-P打开命令面板
- 输入 **Live Server: Open with Live Server**
- Live Server 将开始托管你的应用程序
- 打开浏览器,访问 **https://localhost:5500**
- 你现在应该能看到你创建的页面了!
**Live Server 功能:**
- **启动**一个项目本地开发服务器
- **在保存文件时**自动刷新浏览器
- **通过本地地址**(通常是`localhost:5500`)提供访问
接下来让我们添加一些功能。
**打开浏览器并访问 `https://localhost:5500`**
你现在应看到你创建的页面了!让我们添加一些功能。
## 添加 CSS
HTML 创建完成后,我们需要添加核心样式的 CSS。我们需要高亮玩家应该输入的单词并在玩家输入错误时将文本框变色。我们将通过两个类来实现这些功能。
现在让界面美观起来视觉反馈从计算机早期时代起就是用户界面的关键。上世纪80年代研究发现即时视觉反馈极大提升用户效率并减少错误。正是我们要实现的。
游戏需要明确告知发生了什么。玩家应立即知道当前应该打哪个单词,若输入错误,也能立刻察觉。让我们来做一些简单却有效的样式设计:
创建一个名为 **style.css** 的新文件,并添加以下语法。
新建`style.css`文件,添加以下内容:
```css
/* inside style.css */
@ -138,40 +230,60 @@ HTML 创建完成后,我们需要添加核心样式的 CSS。我们需要高
}
```
✅ 关于 CSS你可以根据自己的喜好设计页面布局。花点时间让页面更美观
**理解这些CSS类**
- **通过黄色背景高亮**当前单词,清晰指引焦点
- **输入错误时**使用浅珊瑚色背景提示
- **即时反馈**用户输入,且不打断打字流程
- **采用有对比度的颜色**提升可访问性和视觉沟通
- 选择不同的字体
- 为标题添加颜色
✅ CSS布局可以自由发挥。花些时间让页面更美观
- 选择不同字体
- 给标题配色
- 调整元素大小
## JavaScript
用户界面创建完成后,我们将注意力转向提供逻辑的 JavaScript。我们将分几个步骤完成
接下来就是精彩的部分了!🎉 我们已经有了HTML结构和CSS样式但此时我们的游戏就像一辆漂亮但没有引擎的车。JavaScript就是这台引擎——它让一切真正运作、对玩家操作做出响应。
这里你将看到你创作的作品活起来。我们会逐步实现,避免让人感到吃力:
- [创建常量](../../../../4-typing-game/typing-game)
- [为开始游戏添加事件监听器](../../../../4-typing-game/typing-game)
- [为输入添加事件监听器](../../../../4-typing-game/typing-game)
| 步骤 | 目的 | 学习内容 |
|------|---------|------------------|
| [创建常量](../../../../4-typing-game/typing-game) | 设置引用文本和DOM引用 | 变量管理和DOM选择 |
| [绑定开始游戏事件监听](../../../../4-typing-game/typing-game) | 处理游戏初始化 | 事件处理和UI更新 |
| [绑定输入监听事件](../../../../4-typing-game/typing-game) | 实时处理用户输入 | 输入验证和动态反馈 |
首先,创建一个名为 **script.js** 的新文件。
**这种结构化方法帮助你:**
- **合理组织**代码,易于管理
- **渐进构建**功能,方便调试
- **掌握**应用中各部分如何协作
- **创造**可复用模式,助力未来项目
### 创建常量
但首先,创建一个名为`script.js`的新文件。
我们需要一些内容来简化编程。类似于一个食谱,我们需要以下内容:
### 添加常量
- 包含所有句子的数组
- 用于存储当前句子中所有单词的空数组
- 用于存储玩家当前输入单词索引的空间
- 玩家点击开始按钮的时间
在动手之前先收集所有资源就像NASA任务控制中心在发射前搭建所有监控系统一样事先准备好一切更便捷。这避免日后到处找东西也减少拼写错误。
我们还需要引用用户界面中的元素
我们首先需要设置:
- 文本框(**typed-value**
- 句子显示区域(**quote**
- 消息显示区域(**message**
| 数据类型 | 目的 | 示例 |
| 引用数组 | 存储游戏中所有可能的引用 | `['Quote 1', 'Quote 2', ...]` |
| 单词数组 | 将当前引用拆分成单个单词 | `['When', 'you', 'have', ...]` |
| 单词索引 | 跟踪玩家正在输入的单词 | `0, 1, 2, 3...` |
| 开始时间 | 计算计分的经过时间 | `Date.now()` |
**我们还需要对 UI 元素的引用:**
| 元素 | ID | 用途 |
|---------|----|---------|
| 文本输入 | `typed-value` | 玩家输入的地方 |
| 引用展示 | `quote` | 显示要输入的引用 |
| 消息区域 | `message` | 显示状态更新 |
```javascript
// inside script.js
// all of our quotes
// 在 script.js 内部
// 我们所有的引用
const quotes = [
'When you have eliminated the impossible, whatever remains, however improbable, must be the truth.',
'There is nothing more deceptive than an obvious fact.',
@ -181,166 +293,312 @@ const quotes = [
'Nothing clears up a case so much as stating it to another person.',
'Education never ends, Watson. It is a series of lessons, with the greatest for the last.',
];
// store the list of words and the index of the word the player is currently typing
// 存储单词列表和玩家当前输入的单词索引
let words = [];
let wordIndex = 0;
// the starting time
// 起始时间
let startTime = Date.now();
// page elements
// 页面元素
const quoteElement = document.getElementById('quote');
const messageElement = document.getElementById('message');
const typedValueElement = document.getElementById('typed-value');
```
✅ 为你的游戏添加更多句子
**解析这段初始化代码实现了什么:**
- **存储**一组 Sherlock Holmes 的引用,使用 `const` 因为引用不会改变
- **初始化**跟踪变量,使用 `let` 因为这些值会在游戏过程中更新
- **获取** DOM 元素引用,使用 `document.getElementById()` 以便高效访问
- **搭建**游戏所有功能的基础,变量命名清晰且具描述性
- **逻辑组织**相关数据和元素,便于维护代码
✅ 继续添加更多引用到你的游戏中吧
> **NOTE:** 我们可以通过 `document.getElementById` 在代码中随时获取元素。由于我们会经常引用这些元素,为了避免字符串字面量的拼写错误,我们使用常量。像 [Vue.js](https://vuejs.org/) 或 [React](https://reactjs.org/) 这样的框架可以帮助你更好地集中管理代码。
> 💡 **专业提示**:我们可以在代码中随时使用 `document.getElementById()` 获取元素引用。因为我们会经常用到这些元素,使用常量避免字符串字面量写错。像 [Vue.js](https://vuejs.org/) 或 [React](https://reactjs.org/) 这样的框架能帮助你更好地管理代码集中化。
>
**这种方法行之有效的原因:**
- **防止**多次引用元素时拼写错误
- **提升**代码可读性,使用描述性常量名
- **提供**更好的 IDE 支持,如自动完成与错误检查
- **便于**将来修改元素 ID 时进行重构
花点时间观看一个关于使用 `const`、`let` 和 `var` 的视频
一分钟观看关于 `const`、`let` 和 `var` 的视频
[![变量类型](https://img.youtube.com/vi/JNIXfGiDWM8/0.jpg)](https://youtube.com/watch?v=JNIXfGiDWM8 "变量类型")
[![变量类型](https://img.youtube.com/vi/JNIXfGiDWM8/0.jpg)](https://youtube.com/watch?v=JNIXfGiDWM8 "Types of variables")
> 🎥 点击上方图片观看关于变量的视频。
> 🎥 点击上方图片观看关变量的视频。
### 添加开始逻辑
游戏开始时,玩家会点击开始按钮。当然,我们不知道玩家何时会点击开始按钮。这时 [事件监听器](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) 就派上用场了。事件监听器允许我们监听某些事件的发生,并作出响应。在我们的例子中,我们希望在用户点击开始按钮时执行代码。
一切都将在这里启动!🚀 你即将编写第一个真正的事件监听器,看到代码响应按钮点击非常令人满足。
想象一下:某处有玩家点击那个“开始”按钮,你的代码必须准备就绪。我们不知道他们什么时候点击——可能立刻,也可能喝杯咖啡后——但一旦点击,游戏立即开始。
当用户点击 **开始** 时,我们需要选择一个句子,设置用户界面,并设置当前单词和计时的跟踪。以下是需要添加的 JavaScript我们将在代码块后进行讨论。
当用户点击 `start`,我们需要选择一个引用,设置用户界面,跟踪当前单词和计时。以下是你需要添加的 JavaScript我们稍后会讲解这段脚本
```javascript
// at the end of script.js
// 在 script.js 的末尾
document.getElementById('start').addEventListener('click', () => {
// get a quote
// 获取一个引用
const quoteIndex = Math.floor(Math.random() * quotes.length);
const quote = quotes[quoteIndex];
// Put the quote into an array of words
// 将引用放入一个单词数组中
words = quote.split(' ');
// reset the word index for tracking
// 重置单词索引用于跟踪
wordIndex = 0;
// UI updates
// Create an array of span elements so we can set a class
// 用户界面更新
// 创建一个 span 元素数组,以便我们可以设置类
const spanWords = words.map(function(word) { return `<span>${word} </span>`});
// Convert into string and set as innerHTML on quote display
// 转换成字符串并设置为引用显示的 innerHTML
quoteElement.innerHTML = spanWords.join('');
// Highlight the first word
// 高亮显示第一个单词
quoteElement.childNodes[0].className = 'highlight';
// Clear any prior messages
// 清除任何先前的消息
messageElement.innerText = '';
// Setup the textbox
// Clear the textbox
// 设置文本框
// 清空文本框
typedValueElement.value = '';
// set focus
// 设置焦点
typedValueElement.focus();
// set the event handler
// 设置事件处理程序
// Start the timer
// 启动计时器
startTime = new Date().getTime();
});
```
让我们分解代码!
- 设置单词跟踪
- 使用 [Math.floor](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) 和 [Math.random](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/random) 随机选择 `quotes` 数组中的一个句子
- 将 `quote` 转换为 `words` 数组,以便跟踪玩家当前输入的单词
- 将 `wordIndex` 设置为 0因为玩家将从第一个单词开始
- 设置用户界面
- 创建一个包含每个单词的 `span` 元素的 `spanWords` 数组
- 这将允许我们高亮显示显示区域中的单词
- 使用 `join` 创建一个字符串,用于更新 `quoteElement``innerHTML`
- 这将向玩家显示句子
- 将第一个 `span` 元素的 `className` 设置为 `highlight`,以将其高亮显示为黄色
- 通过将 `messageElement``innerText` 设置为 `''` 来清空消息
- 设置文本框
- 清空 `typedValueElement` 的当前 `value`
- 将焦点设置到 `typedValueElement`
- 调用 `getTime` 开始计时
**我们将代码分成以下逻辑部分:**
**📊 单词跟踪设置:**
- **随机选择**一个引用,使用 `Math.floor()``Math.random()` 实现多样性
- **拆分**引用成单词数组,使用 `split(' ')`
- **重置**`wordIndex` 为 0因为玩家从第一个单词开始
- **准备**游戏状态,迎接新一轮
**🎨 界面设置与显示:**
- **创建**一组 `<span>` 元素,分别包裹每个单词用于单独样式控制
- **合并**所有 span 元素成字符串,以高效更新 DOM
- **高亮**第一个单词,添加 `highlight` CSS 类
- **清除**之前的游戏消息,提供干净界面
**⌨️ 文本框准备:**
- **清空**输入框现有内容
- **聚焦**输入框,让玩家立刻开始打字
- **为新游戏准备**输入区域
**⏱️ 定时器初始化:**
- **捕获**当前时间戳,使用 `new Date().getTime()`
- **启用**准确计算输入速度和完成时间
- **开始**游戏计时和性能追踪
### 添加输入逻辑
当玩家输入时,会触发 `input` 事件。此事件监听器将检查玩家输入的单词是否正确,并处理游戏的当前状态。在 **script.js** 中,添加以下代码到末尾。我们将在代码块后进行讨论。
这里是游戏的核心部分!别担心,看起来多,但我们会逐步讲解,结束后你会发现逻辑非常清晰。
我们正在构建的是非常智能的逻辑:每次输入字母时,代码都会检查输入内容,给予反馈,并决定下一步操作。这与 1970 年代 WordStar 这类早期文字处理器实时反馈打字员很相似。
```javascript
// at the end of script.js
// 在 script.js 的末尾
typedValueElement.addEventListener('input', () => {
// Get the current word
// 获取当前单词
const currentWord = words[wordIndex];
// get the current value
// 获取当前值
const typedValue = typedValueElement.value;
if (typedValue === currentWord && wordIndex === words.length - 1) {
// end of sentence
// Display success
// 句子结束
// 显示成功
const elapsedTime = new Date().getTime() - startTime;
const message = `CONGRATULATIONS! You finished in ${elapsedTime / 1000} seconds.`;
messageElement.innerText = message;
} else if (typedValue.endsWith(' ') && typedValue.trim() === currentWord) {
// end of word
// clear the typedValueElement for the new word
// 单词结束
// 为新单词清除 typedValueElement
typedValueElement.value = '';
// move to the next word
// 移动到下一个单词
wordIndex++;
// reset the class name for all elements in quote
// 重置 quote 中所有元素的类名
for (const wordElement of quoteElement.childNodes) {
wordElement.className = '';
}
// highlight the new word
// 突出显示新单词
quoteElement.childNodes[wordIndex].className = 'highlight';
} else if (currentWord.startsWith(typedValue)) {
// currently correct
// highlight the next word
// 当前正确
// 突出显示下一个单词
typedValueElement.className = '';
} else {
// error state
// 错误状态
typedValueElement.className = 'error';
}
});
```
让我们分解代码!我们首先获取当前单词和玩家目前输入的值。然后,我们使用瀑布式逻辑检查以下情况:句子是否完成,单词是否完成,单词是否正确,或者是否存在错误。
**理解输入逻辑流程:**
函数采用流水线检查方法,从最具体条件到最一般的依次判断。逐条来拆解:
```mermaid
flowchart TD
A[玩家输入字符] --> B[获取当前单词和输入值]
B --> C{引号完成了吗?}
C -->|Yes| D[显示完成信息和时间]
C -->|No| E{单词通过空格完成了吗?}
E -->|Yes| F[清空输入,移动到下一个单词,更新高亮]
E -->|No| G{到目前为止输入正确吗?}
G -->|Yes| H[移除错误样式]
G -->|No| I[显示错误样式]
```
**🏁 引用完成(场景 1**
- **检查**输入内容是否等于当前单词且是最后一个单词
- **计算**经过时间,当前时间减去开始时间
- **转为**秒(除以 1,000
- **显示**完成提示及用时
**✅ 单词完成(场景 2**
- **检测**输入以空格结尾,表示单词完成
- **验证**去除空白后输入是否与当前单词完全匹配
- **清空**输入框准备下一个单词
- **前进**单词索引,指向下一个单词
- **更新**高亮样式,删除所有样式后高亮新的单词
**📝 正在输入(场景 3**
- **确认**当前单词以输入内容开头(前缀匹配)
- **移除**错误样式,表明输入正确
- **允许**继续输入不受阻碍
**❌ 错误状态(场景 4**
- **触发**输入内容不匹配当前单词开头时
- **应用**错误 CSS 类,给予即时视觉反馈
- **帮助**玩家快速识别并纠正错误
- 句子完成:当 `typedValue` 等于 `currentWord``wordIndex` 等于 `words` 长度减一时
- 通过用当前时间减去 `startTime` 计算 `elapsedTime`
- 将 `elapsedTime` 除以 1,000将毫秒转换为秒
- 显示成功消息
- 单词完成:当 `typedValue` 以空格结尾(单词结束)且 `typedValue` 等于 `currentWord`
- 将 `typedElement``value` 设置为 `''`,以便输入下一个单词
- 增加 `wordIndex`,以移动到下一个单词
- 遍历 `quoteElement` 的所有 `childNodes`,将 `className` 设置为 `''`,以恢复默认显示
- 将当前单词的 `className` 设置为 `highlight`,以标记为下一个需要输入的单词
- 单词当前输入正确(但未完成):当 `currentWord``typedValue` 开头时
- 通过清空 `className` 确保 `typedValueElement` 显示为默认状态
- 如果到这一步,说明存在错误
- 将 `typedValueElement``className` 设置为 `error`
## 测试你的应用
## 测试你的应用程序
看看你完成了什么!🎉 你刚用事件驱动编程从零构建了一个真正可用的打字游戏。好好感受这份成就——这可不容易!
你已经完成了!最后一步是确保我们的应用程序正常工作。试试看!如果有错误,不用担心;**所有开发者**都会遇到错误。检查消息并根据需要进行调试。
接下来是测试环节!游戏能否按预期工作?我们是否遗漏了什么?没关系,如果刚开始有问题很正常。即使是资深开发者也经常遇到代码错误。这是开发流程的一部分!
点击 **开始**,然后开始输入!它应该看起来像我们之前看到的动画。
点击 `start`,开始输入!它应该看起来类似我们之前看到的动画。
![游戏运行动画](../../../../4-typing-game/images/demo.gif)
**应用中要测试的内容:**
- **确认**点击开始显示随机引用
- **验证**输入时正确高亮当前单词
- **检查**输入错误时显示错误样式
- **确保**单词完成后正确切换高亮
- **测试**完成全部引用后显示含用时的完成提示
**常见调试技巧:**
- **查看**浏览器控制台F12是否有 JavaScript 错误
- **确认**所有文件名大小写完全一致
- **保证**Live Server 正常运行并自动刷新
- **测试**多个引用,确认随机选择功能正常
---
## GitHub Copilot 代理挑战 🎮
使用代理模式完成以下挑战:
**描述:** 扩展打字游戏,实现一个基于玩家表现调整难度的系统。此挑战将帮助你练习更高级的事件处理、数据分析和动态 UI 更新。
**任务:** 为打字游戏创建难度调整系统,要求:
1. 跟踪玩家打字速度(每分钟单词数)和准确率百分比
2. 自动适配三种难度级别:简单(简单引用)、中等(当前引用)、困难(带标点复杂引用)
3. 在 UI 上显示当前难度级别与玩家统计信息
4. 实现连胜计数器,连续 3 次良好表现后提升难度
5. 添加视觉反馈(颜色、动画)提示难度变化
添加必要的 HTML 元素、CSS 样式和 JavaScript 函数实现该功能。包含适当的错误处理并保证游戏具备良好可访问性ARIA 标签等)。
更多代理模式内容请见 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
添加更多功能
准备好提升你的打字游戏了吗?试着实现这些高级功能,加深对事件处理和 DOM 操作的理解:
**添加更多功能:**
| 功能 | 描述 | 练习技能 |
|---------|-------------|------------------------|
| **输入控制** | 完成时禁用 `input` 事件监听,点击按钮时重新启用 | 事件管理和状态控制 |
| **UI 状态管理** | 玩家完成引用时禁用文本框 | DOM 属性操作 |
| **模态对话框** | 显示带成功信息的模态对话框 | 高级 UI 模式和无障碍设计 |
| **最高分系统** | 使用 `localStorage` 存储最高分 | 浏览器存储 API 和数据持久化 |
**实现提示:**
- **学习** `localStorage.setItem()``localStorage.getItem()` 实现持久存储
- **练习**动态添加与移除事件监听器
- **探索** HTML dialog 元素或 CSS 模态样式方案
- **考虑**禁用和启用表单控件时的无障碍化处理
- 在完成游戏时禁用 `input` 事件监听器,并在点击按钮时重新启用
- 在玩家完成句子时禁用文本框
- 显示一个带有成功消息的模态对话框
- 使用 [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) 存储最高分
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/22)
---
## 🚀 你的打字游戏掌握时间线
### ⚡ **接下来 5 分钟你能做什么**
- [ ] 用不同引用测试打字游戏,保证流畅运行
- [ ] 试着修改 CSS 样式,改变高亮和错误颜色
- [ ] 打开浏览器开发者工具F12观察控制台输出
- [ ] 挑战尽快完成一条引用输入
### ⏰ **本小时你能完成什么**
- [ ] 向数组添加更多引用(比如你喜欢的书籍或电影中的)
- [ ] 实现挑战部分提到的 localStorage 最高分系统
- [ ] 创建一个打字速度(每分钟单词数)计算器并游戏后显示
- [ ] 为正确输入、错误和完成添加音效
### 📅 **本周你可以探索**
- [ ] 构建一个多人对战版本,朋友们可以并排竞赛
- [ ] 创建不同难度级别,包含不同复杂度的引用
- [ ] 添加进度条,显示引用完成程度
- [ ] 实现用户账户与个人统计追踪
- [ ] 设计自定义主题,让用户选择喜欢的样式
### 🗓️ **本月你的成长方向**
- [ ] 设计打字课程,逐步教学正确指法
- [ ] 构建分析工具,展示最易出错的字母或单词
- [ ] 支持多语言与不同键盘布局
- [ ] 集成教育 API从文学数据库获取引用
- [ ] 发布你的增强版打字游戏,让更多人使用和享受
### 🎯 **最终反思检查**
**继续前进前,不妨问问自己:**
- 制作这款游戏最让我满足的时刻是什么?
- 现在我对事件驱动编程的感受与刚开始时相比有什么变化?
- 有哪些功能让我兴奋,想要加入使游戏更独特?
- 我如何将事件处理概念应用到其他项目?
```mermaid
journey
title 你的事件编程信心之旅
section 今天
理解事件: 3: 你
构建界面: 4: 你
编写事件监听器: 5: 你
section 本周
添加功能: 4: 你
调试问题: 5: 你
优化用户体验: 4: 你
section 下个月
构建复杂应用: 5: 你
教导他人: 5: 你
创建框架: 5: 你
```
> 🌟 **记住**:你刚掌握了支持所有交互型网站和应用的核心概念。事件驱动编程让网页充满活力、响应迅速。每次你看到下拉菜单、输入校验表单,或响应你点击的游戏时,现在你都懂背后的魔法。你不仅学会写代码——你在创造直观且引人入胜的体验! 🎉
---
## 复习与自学
阅读[浏览器中可用的所有事件](https://developer.mozilla.org/docs/Web/Events),并思考每种事件适用的场景。
阅读关于浏览器中[所有可用事件](https://developer.mozilla.org/docs/Web/Events)的信息,思考你在哪些场景会使用它们
## 作业
@ -348,5 +606,7 @@ typedValueElement.addEventListener('input', () => {
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而导致的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们力求准确,但请注意,自动翻译可能存在错误或不准确之处。原始语言的文件应被视为权威来源。对于重要信息,建议采用专业人工翻译。我们不对因使用本翻译而产生的任何误解或错误解释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,8 +1,8 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "de5384c118e15e4d1d0eaa00fc01b112",
"translation_date": "2025-08-24T00:22:11+00:00",
"original_hash": "3eac59d70e2532a677a2ce6bf765485a",
"translation_date": "2026-01-06T11:48:41+00:00",
"source_file": "4-typing-game/typing-game/assignment.md",
"language_code": "zh"
}
@ -11,14 +11,47 @@ CO_OP_TRANSLATOR_METADATA:
## 说明
创建一个使用键盘事件完成任务的小型游戏。它可以是不同类型的打字游戏,也可以是通过按键在屏幕上绘制像素的艺术类游戏。发挥创意吧!
现在你已经掌握了使用打字游戏进行事件驱动编程的基础是时候释放你的创造力了你将设计并构建一个基于键盘的游戏展示你对事件处理、DOM 操作和用户交互模式的理解。
## 评分标准
创建一个使用键盘事件来完成特定任务的小型游戏。这可以是一种不同类型的打字游戏,一个在按键时向屏幕绘制像素的艺术应用,一个用方向键控制的简单街机风格游戏,或者任何你能想象到的创意概念。发挥创意,考虑不同的按键如何触发不同的行为!
| 标准 | 卓越表现 | 基本达标 | 需要改进 |
| -------- | ------------------------ | ------------------------ | ---------------- |
| | 提供了一个完整的游戏 | 游戏非常简单 | 游戏存在问题 |
| | | | |
**你的游戏应包含:**
| 要求 | 描述 | 目的 |
|-------------|-------------|---------|
| **事件监听器** | 响应至少 3 种不同的键盘事件 | 展示对事件处理的理解 |
| **视觉反馈** | 对用户输入提供即时视觉响应 | 展示对 DOM 操作的掌握 |
| **游戏逻辑** | 包含得分、等级或进度机制 | 练习实现应用状态 |
| **用户界面** | 清晰的说明和直观的控制 | 发展用户体验设计技能 |
**可考虑的创意项目点子:**
- **节奏游戏**:玩家按键与音乐或视觉提示同步
- **像素艺术创作者**:不同按键绘制不同颜色或图案
- **单词构建者**:玩家通过特定顺序输入字母创建单词
- **贪吃蛇游戏**:用箭头键控制蛇收集物品
- **音乐合成器**:不同按键播放不同音符或声音
- **快速打字变体**:分类打字(编程术语、外语等)
- **键盘鼓手**:通过映射键盘按键制作鼓点
**实现指南:**
- **从** 简单概念开始,逐步增加复杂度
- **聚焦** 流畅、响应迅速且自然的控制
- **包含** 清晰的视觉指示,显示游戏状态和玩家进度
- **测试** 你的游戏,用不同用户确保游戏易于理解
- **注释** 你的代码,解释你的事件处理策略
## 评估标准
| 标准 | 优秀 | 及格 | 需要改进 |
| -------- | --------- | -------- | ----------------- |
| **功能性** | 完整、精致的游戏,具备多种功能和流畅的游戏体验 | 一个工作正常、有基本功能并且展示键盘事件处理的游戏 | 功能有限或有重大缺陷的简单实现 |
| **代码质量** | 结构良好、带注释,遵循最佳实践且事件处理高效的代码 | 代码整洁、可读,合理使用事件监听器和 DOM 操作 | 基础代码结构,部分组织问题或效率欠佳 |
| **用户体验** | 直观的控制、清晰反馈和专业的游戏体验 | 功能性界面,基本的用户指导和响应控制 | 简单界面,说明不清或响应差 |
| **创造力** | 原创概念,创新地使用键盘事件和创造性解决问题 | 在常见游戏模式上有趣的变体,良好利用事件处理 | 简单实现基础概念,创意元素有限 |
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而引起的任何误解或误读不承担责任。
本文件由人工智能翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译而成。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始母语文件应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用此翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,182 +1,555 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "2326d04e194a10aa760b51f5e5a1f61d",
"translation_date": "2025-08-29T14:43:43+00:00",
"original_hash": "00aa85715e1efd4930c17a23e3012e69",
"translation_date": "2026-01-06T11:36:28+00:00",
"source_file": "5-browser-extension/1-about-browsers/README.md",
"language_code": "zh"
}
-->
# 浏览器扩展项目第一部分:关于浏览器的一切
![浏览器手绘笔记](../../../../translated_images/browser.60317c9be8b7f84adce43e30bff8d47a1ae15793beab762317b2bc6b74337c1a.zh.jpg)
> 手绘笔记由 [Wassim Chegham](https://dev.to/wassimchegham/ever-wondered-what-happens-when-you-type-in-a-url-in-an-address-bar-in-a-browser-3dob) 提供
```mermaid
journey
title 你的浏览器扩展开发之旅
section 基础
了解浏览器: 3: Student
学习扩展类型: 4: Student
设置开发环境: 4: Student
section 开发
构建界面: 4: Student
添加功能: 5: Student
处理数据: 5: Student
section 集成
浏览器测试: 5: Student
调试问题: 4: Student
优化体验: 5: Student
```
![浏览器手绘笔记](../../../../translated_images/browser.60317c9be8b7f84a.zh.jpg)
> 手绘笔记作者:[Wassim Chegham](https://dev.to/wassimchegham/ever-wondered-what-happens-when-you-type-in-a-url-in-an-address-bar-in-a-browser-3dob)
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/23)
### 简介
浏览器扩展为浏览器添加了额外的功能。但在构建扩展之前,你需要先了解一些关于浏览器如何工作的知识。
### 关于浏览器
在这一系列课程中,你将学习如何构建一个可以在 Chrome、Firefox 和 Edge 浏览器上运行的浏览器扩展。在这一部分,你将了解浏览器的工作原理,并搭建浏览器扩展的基本框架。
那么,浏览器到底是什么呢?它是一种软件应用程序,允许终端用户从服务器访问内容并将其显示在网页上。
✅ 一点历史第一个浏览器名为“WorldWideWeb”由蒂姆·伯纳斯-李爵士于1990年创建。
![早期浏览器](../../../../translated_images/earlybrowsers.d984b711cdf3a42ddac919d46c4b5ca7232f68ccfbd81395e04e5a64c0015277.zh.jpg)
> 一些早期浏览器,图片来源 [Karen McGrane](https://www.slideshare.net/KMcGrane/week-4-ixd-history-personal-computing)
当用户通过 URL统一资源定位符地址连接到互联网时通常使用超文本传输协议HTTP 或 HTTPS 地址),浏览器会与网络服务器通信并获取网页。
### 介绍
浏览器扩展是增强网页浏览体验的迷你应用程序。就像蒂姆·伯纳斯-李最初设想的互动网络一样,扩展将浏览器的功能从简单的文档查看扩展到了更多领域。从保持账户安全的密码管理器,到帮助设计师选择完美色调的拾色器,扩展解决了日常浏览中的各种挑战。
在构建你的第一个扩展之前,让我们先了解浏览器的工作原理。正如亚历山大·格雷厄姆·贝尔需要理解声音传输才能发明电话一样,掌握浏览器基础知识将帮助你创建无缝集成现有浏览器系统的扩展。
本课结束时,你将理解浏览器架构,并开始构建你的第一个扩展。
```mermaid
mindmap
root((浏览器架构))
Core Components
Rendering Engine
JavaScript Engine
Network Stack
Storage APIs
User Interface
地址栏
标签管理
书签
扩展图标
Extension System
Manifest Files
Content Scripts
Background Pages
Popup Windows
Security Model
同源策略
Permissions API
内容安全
隔离世界
Development Tools
DevTools Integration
调试控制台
性能监视
扩展检查器
```
## 理解网页浏览器
网页浏览器本质上是一个复杂的文档解析器。当你在地址栏输入“google.com”时浏览器会执行一系列复杂操作——从全球服务器请求内容然后解析并呈现成你所看到的交互式网页。
这一过程与第一款网页浏览器 WorldWideWeb 的设计理念相符,该浏览器由蒂姆·伯纳斯-李在1990年开发旨在让超链接文档人人可访问。
**一点历史**第一款浏览器名为“WorldWideWeb”由蒂姆·伯纳斯-李爵士于1990年创建。
![早期浏览器](../../../../translated_images/earlybrowsers.d984b711cdf3a42d.zh.jpg)
> 一些早期浏览器,来源:[Karen McGrane](https://www.slideshare.net/KMcGrane/week-4-ixd-history-personal-computing)
### 浏览器如何处理网页内容
从输入 URL 到看到网页,这一过程涉及几个协同步骤,几秒内完成:
```mermaid
sequenceDiagram
participant User
participant Browser
participant Extension
participant DNS
participant Server
User->>Browser: 输入网址并按下回车
Browser->>Extension: 触发 beforeRequest 事件
Extension->>Extension: 检查网址是否需要修改
Browser->>DNS: 查询服务器 IP 地址
DNS->>Browser: 返回 IP 地址
Browser->>Server: 请求网页内容
Server->>Browser: 发送 HTML、CSS 和 JavaScript
Browser->>Extension: 触发 beforeResponse 事件
Extension->>Extension: 如有需要,修改内容
Browser->>User: 渲染完整网页
Extension->>User: 显示扩展界面更新
```
**该过程实现的功能如下:**
- **通过 DNS 查询** 将易读的 URL 转换为服务器 IP 地址
- **使用 HTTP 或 HTTPS 协议** 与网页服务器建立安全连接
- **请求** 服务器上的特定网页内容
- **接收** 服务器发送的 HTML 标记、CSS 样式和 JavaScript 代码
- **渲染** 所有内容,呈现为你看到的交互式网页
### 浏览器核心功能
现代浏览器提供众多功能,扩展开发者可充分利用:
| 功能 | 目的 | 扩展的机会 |
|---------|---------|------------------------|
| **渲染引擎** | 显示 HTML、CSS 和 JavaScript | 内容修改、注入样式 |
| **JavaScript 引擎** | 执行 JavaScript 代码 | 自定义脚本、API 交互 |
| **本地存储** | 本地保存数据 | 用户偏好、缓存数据 |
| **网络栈** | 处理网络请求 | 请求监控、数据分析 |
| **安全模型** | 保护用户免受恶意内容 | 内容过滤、安全增强 |
**了解这些功能可帮助你:**
- **识别** 扩展可带来最多价值的位置
- **选择** 适合扩展功能的浏览器 API
- **设计** 与浏览器系统高效协作的扩展
- **确保** 扩展遵循浏览器安全最佳实践
### 跨浏览器开发考虑
不同浏览器对标准的实现有细微差别就像不同编程语言对同一算法的处理方式不同一样。Chrome、Firefox 和 Safari 各有特色,开发者需要在扩展开发中考虑这些差异。
> 💡 **专业提示**:使用 [caniuse.com](https://www.caniuse.com) 检查不同浏览器对网页技术的支持,这在规划扩展功能时非常有用!
**扩展开发的关键考虑点:**
- **在 Chrome、Firefox 和 Edge 上测试** 你的扩展
- **适配不同浏览器扩展 API 和 manifest 格式**
- **处理不同浏览器的性能特点和限制**
- **为可能缺失的浏览器特定功能提供备用方案**
**分析洞见**:通过在你的网页开发项目中安装分析包,可以了解用户偏好的浏览器,这有助于你优先支持特定浏览器。
## 理解浏览器扩展
浏览器扩展通过直接向浏览器界面添加功能,解决了常见的网页浏览问题。扩展无需独立应用程序或复杂流程,提供立刻访问工具和功能的能力。
这一理念类似早期计算机先驱道格拉斯·恩格尔巴特设想的通过技术增强人类能力——扩展增强了浏览器的基础功能。
```mermaid
quadrantChart
title 浏览器扩展类别
x-axis 简单 --> 复杂
y-axis 个人使用 --> 专业工具
quadrant-1 开发者工具
quadrant-2 企业解决方案
quadrant-3 个人实用工具
quadrant-4 生产力应用
Ad Blockers: [0.3, 0.2]
Password Managers: [0.7, 0.3]
Color Pickers: [0.4, 0.8]
Code Formatters: [0.8, 0.9]
Note Taking: [0.6, 0.5]
Video Downloaders: [0.5, 0.2]
Time Trackers: [0.7, 0.6]
Screenshot Tools: [0.4, 0.4]
```
**流行扩展类别及其好处:**
- **效率工具**:任务管理器、笔记应用、时间追踪器,帮助你保持条理
- **安全增强**:密码管理器、广告屏蔽、隐私工具,保护你的数据
- **开发者工具**:代码格式化器、颜色选取器、调试工具,简化开发流程
- **内容增强**:阅读模式、视频下载器、截图工具,改善你的网页体验
**反思问题**:你最喜欢哪些浏览器扩展?它们执行哪些具体任务?如何提升你的浏览体验?
### 🔄 **教学回顾**
**浏览器架构理解**:开始开发扩展前,请确保你能够:
- ✅ 解释浏览器如何处理网络请求和渲染内容
- ✅ 识别浏览器架构的主要组成部分
- ✅ 理解扩展如何与浏览器功能集成
- ✅ 认识保护用户的安全模型
**快速自测**:能否串联起从输入 URL 到看到网页的整个流程?
1. **DNS 查询** 将 URL 转换为 IP 地址
2. **HTTP 请求** 从服务器获取内容
3. **解析** 处理 HTML、CSS 和 JavaScript
4. **渲染** 显示最终网页
5. **扩展** 可在多个步骤修改内容
## 安装和管理扩展
了解扩展安装过程,有助于你预见用户安装你扩展时的体验。现代浏览器的安装流程标准化,界面设计略有差异。
![Edge 浏览器扩展页面打开及设置菜单截图](../../../../translated_images/install-on-edge.d68781acaf0b3d3d.zh.png)
> **重要提示**:测试自己的扩展时,务必开启开发者模式并允许来自其他商店的扩展。
### 开发阶段扩展安装流程
开发和测试自己的扩展时,遵循这个工作流程:
```mermaid
flowchart TD
A[编写代码] --> B[构建扩展]
B --> C{首次安装?}
C -->|是| D[加载未打包的扩展]
C -->|否| E[重新加载扩展]
D --> F[测试功能]
E --> F
F --> G{工作正常?}
G -->|否| H[调试问题]
G -->|是| I[准备好给用户]
H --> A
I --> J[发布到商店]
style A fill:#e1f5fe
style F fill:#e8f5e8
style I fill:#f3e5f5
style J fill:#fff3e0
```
```bash
# 第一步:构建您的扩展
npm run build
```
此时,浏览器的渲染引擎会将网页显示在用户的设备上,这可能是手机、台式机或笔记本电脑。
**该命令完成的操作:**
- **将源代码编译** 成浏览器可用文件
- **打包** JavaScript 模块为优化的包
- **生成** 最终扩展文件到 `/dist` 文件夹
- **准备** 扩展供安装和测试
浏览器还具有缓存内容的能力这样就不需要每次都从服务器检索内容。它们可以记录用户的浏览历史存储“Cookie”包含用户活动信息的小数据片段以及更多功能。
**步骤 2进入浏览器扩展管理页面**
1. **打开** 浏览器扩展管理页面
2. **点击** 右上角“设置和更多”按钮(`...`图标)
3. **选择** 下拉菜单中的“扩展”选项
一个非常重要的事情是,浏览器并不完全相同!每个浏览器都有其优点和缺点,专业的网页开发人员需要了解如何让网页在不同浏览器上都能良好运行。这包括处理小屏幕设备(如手机)以及离线用户的情况。
**步骤 3加载扩展**
- **新安装**:选择“加载已解压的扩展”,并选中 `/dist` 文件夹
- **更新**:在已安装扩展旁点击“重新加载”
- **测试**:启用“开发者模式”以访问额外调试功能
一个非常有用的网站是 [caniuse.com](https://www.caniuse.com),你可能需要将其加入你喜欢使用的浏览器的书签中。当你构建网页时,使用 caniuse 提供的技术支持列表可以帮助你更好地支持用户。
### 生产环境扩展安装
✅ 如何了解哪些浏览器在你的网站用户群中最受欢迎?检查你的分析数据——你可以在网页开发过程中安装各种分析工具,它们会告诉你不同浏览器的使用情况。
> ✅ **注意**:以上开发说明针对你自己构建的扩展。若安装发布的扩展,请访问官方浏览器扩展商店,如 [Microsoft Edge 附加组件商店](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home)
## 浏览器扩展
**理解差异:**
- **开发安装** 可测试未发布扩展
- **商店安装** 提供经过验证的已发布扩展,且支持自动更新
- **旁加载** 允许从非官方商店安装扩展(需开发者模式)
为什么要构建浏览器扩展?当你需要快速访问经常重复的任务时,浏览器扩展是一个非常方便的工具。例如,如果你需要检查与网页交互的颜色,你可以安装一个颜色选择器扩展。如果你难以记住密码,可以使用密码管理扩展。
## 构建你的碳足迹扩展
开发浏览器扩展也很有趣。它们通常专注于少量任务,并能很好地完成这些任务。
我们将创建一个显示你的地区能源使用碳足迹的浏览器扩展。该项目演示了扩展开发的基本概念,同时打造一个环境意识的实用工具
✅ 你最喜欢的浏览器扩展是什么?它们完成了哪些任务?
此方法遵循自约翰·杜威教育理论以来有效的“做中学”原则——结合技术技能与有意义的真实应用。
### 安装扩展
### 项目需求
在开始构建之前,先了解一下构建和部署浏览器扩展的过程。虽然每个浏览器在管理这个任务时略有不同,但 Chrome 和 Firefox 的流程与 Edge 的示例类似:
开发前,收集所需资源和依赖
![Edge 浏览器截图,显示打开的 edge://extensions 页面和设置菜单](../../../../translated_images/install-on-edge.d68781acaf0b3d3dada8b7507cde7a64bf74b7040d9818baaa9070668e819f90.zh.png)
**必备 API 访问:**
- **[CO2 Signal API 密钥](https://www.co2signal.com/)**:输入邮箱地址以免费获取 API 密钥
- **[地区代码](http://api.electricitymap.org/v3/zones)**:通过[Electricity Map](https://www.electricitymap.org/map)查找你的地区代码(例如,波士顿区域代码为 'US-NEISO'
> 注意:确保开启开发者模式并允许安装来自其他商店的扩展。
**开发工具:**
- **[Node.js 和 NPM](https://www.npmjs.com)**:用于安装项目依赖的包管理工具
- **[起始代码](../../../../5-browser-extension/start)**:下载 `start` 文件夹开始开发
基本流程如下:
**了解更多**:提升你的包管理技能,请参考此[完整学习模块](https://docs.microsoft.com/learn/modules/create-nodejs-project-dependencies/?WT.mc_id=academic-77807-sagibbon)
- 使用 `npm run build` 构建你的扩展
- 在浏览器中通过右上角的“设置和更多”按钮(`...` 图标)导航到扩展页面
- 如果是新安装,选择“加载未打包”以从构建文件夹(在我们的例子中是 `/dist`)上传新的扩展
- 或者,如果是重新加载已安装的扩展,点击“重新加载”
### 理解项目结构
✅ 这些说明适用于你自己构建的扩展;如果要安装已发布到浏览器扩展商店的扩展,你应该导航到这些 [商店](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home) 并安装你选择的扩展。
理解项目结构有助于高效组织开发工作。就像亚历山大图书馆为知识检索而布局,一个结构良好的代码库能极大提高开发效率:
### 开始构建
```
project-root/
├── dist/ # Built extension files
│ ├── manifest.json # Extension configuration
│ ├── index.html # User interface markup
│ ├── background.js # Background script functionality
│ └── main.js # Compiled JavaScript bundle
├── src/ # Source development files
│ └── index.js # Your main JavaScript code
├── package.json # Project dependencies and scripts
└── webpack.config.js # Build configuration
```
你将构建一个浏览器扩展,用于显示你所在地区的碳足迹,包括能源使用情况和能源来源。该扩展将包含一个表单,用于收集 API 密钥以访问 CO2 Signal 的 API。
**解释每个文件的功能:**
- **`manifest.json`****定义** 扩展元数据、权限和入口
- **`index.html`****创建** 用户点击扩展时呈现的界面
- **`background.js`****处理** 后台任务和浏览器事件监听
- **`main.js`****包含** 打包过程后的最终 JavaScript 代码
- **`src/index.js`****存放** 你的主要开发代码,编译成 `main.js`
**你需要:**
> 💡 **组织技巧**:将你的 API 密钥和地区代码存储在安全笔记中,便于开发时引用。你需要这些值测试扩展功能。
- [一个 API 密钥](https://www.co2signal.com/);在页面上的输入框中输入你的电子邮件,密钥将发送给你
- [你的地区代码](http://api.electricitymap.org/v3/zones),对应于 [Electricity Map](https://www.electricitymap.org/map)例如在波士顿我使用“US-NEISO”
- [起始代码](../../../../5-browser-extension/start)。下载 `start` 文件夹;你将在此文件夹中完成代码
- [NPM](https://www.npmjs.com) - NPM 是一个包管理工具;在本地安装它,`package.json` 文件中列出的包将被安装以供网页资源使用
**安全提示**:切勿将 API 密钥或敏感凭据提交至代码仓库。后续步骤会展示如何安全管理这些信息。
✅ 在这个 [优秀的学习模块](https://docs.microsoft.com/learn/modules/create-nodejs-project-dependencies/?WT.mc_id=academic-77807-sagibbon) 中了解更多关于包管理的信息。
## 创建扩展界面
花点时间浏览代码库:
现在构建用户界面组件。扩展采用两屏设计:配置屏用于初始设置,结果屏显示数据。
dist
-|manifest.json默认设置在这里
-|index.html前端 HTML 标记在这里)
-|background.js后台 JS 在这里)
-|main.js构建后的 JS
src
-|index.js你的 JS 代码写在这里)
这遵循早期计算机界面设计的渐进披露原则——按逻辑顺序展示信息和选项,避免用户不堪重负。
✅ 一旦你准备好 API 密钥和地区代码,请将它们存储在某个笔记中以备后用。
### 扩展视图概览
### 构建扩展的 HTML
**设置视图** - 首次用户配置:
![扩展完整界面截图,显示包含地区名称和 API 密钥输入的表单](../../../../translated_images/1.b6da8c1394b07491.zh.png)
这个扩展有两个视图。一个用于收集 API 密钥和地区代码:
**结果视图** - 碳足迹数据显示:
![扩展显示 US-NEISO 区域碳使用量和化石燃料百分比的截图](../../../../translated_images/2.1dae52ff08042246.zh.png)
![完成的扩展截图,显示一个包含地区名称和 API 密钥输入的表单](../../../../translated_images/1.b6da8c1394b07491afeb6b2a8e5aca73ebd3cf478e27bcc9aeabb187e722648e.zh.png)
### 构建配置表单
另一个用于显示地区的碳使用情况:
设置表单位于首次使用时收集用户配置信息。配置完成后,此信息会保存在浏览器存储以供后续使用。
![完成的扩展截图,显示 US-NEISO 地区的碳使用值和化石燃料百分比](../../../../translated_images/2.1dae52ff0804224692cd648afbf2342955d7afe3b0101b617268130dfb427f55.zh.png)
`/dist/index.html` 文件中添加以下表单结构:
我们先从构建表单的 HTML 和使用 CSS 样式化开始。
```html
<form class="form-data" autocomplete="on">
<div>
<h2>New? Add your Information</h2>
</div>
<div>
<label for="region">Region Name</label>
<input type="text" id="region" required class="region-name" />
</div>
<div>
<label for="api">Your API Key from tmrow</label>
<input type="text" id="api" required class="api-key" />
</div>
<button class="search-btn">Submit</button>
</form>
```
`/dist` 文件夹中,你将构建一个表单和一个结果区域。在 `index.html` 文件中,填充表单区域:
**表单所实现的功能:**
- **创建** 语义化的表单结构,带有适当标签和输入关联
- **启用** 浏览器自动完成功能,提升用户体验
- **必填** 两个字段均需填写,使用 `required` 属性确保
- **采用** 描述性类名组织输入,便于样式和 JS 选择
- **为首次设置的用户** 提供清晰指引
```HTML
<form class="form-data" autocomplete="on">
<div>
<h2>New? Add your Information</h2>
</div>
<div>
<label for="region">Region Name</label>
<input type="text" id="region" required class="region-name" />
</div>
<div>
<label for="api">Your API Key from tmrow</label>
<input type="text" id="api" required class="api-key" />
</div>
<button class="search-btn">Submit</button>
</form>
```
这是表单,保存的信息将被输入并存储到本地存储中。
### 构建结果显示区
接下来,创建结果区域;在最后一个表单标签下添加一些 div
接下来,创建显示碳足迹数据的结果区域。将以下 HTML 添加到表单下方:
```HTML
```html
<div class="result">
<div class="loading">loading...</div>
<div class="errors"></div>
<div class="data"></div>
<div class="result-container">
<p><strong>Region: </strong><span class="my-region"></span></p>
<p><strong>Carbon Usage: </strong><span class="carbon-usage"></span></p>
<p><strong>Fossil Fuel Percentage: </strong><span class="fossil-fuel"></span></p>
</div>
<button class="clear-btn">Change region</button>
<div class="loading">loading...</div>
<div class="errors"></div>
<div class="data"></div>
<div class="result-container">
<p><strong>Region: </strong><span class="my-region"></span></p>
<p><strong>Carbon Usage: </strong><span class="carbon-usage"></span></p>
<p><strong>Fossil Fuel Percentage: </strong><span class="fossil-fuel"></span></p>
</div>
<button class="clear-btn">Change region</button>
</div>
```
此时,你可以尝试构建。确保安装此扩展的包依赖项:
```
npm install
```
此命令将使用 npmNode 包管理器)安装 webpack用于扩展的构建过程。Webpack 是一个处理代码编译的打包工具。你可以通过查看 `/dist/main.js` 文件来看到这个过程的输出——代码已经被打包。
现在,扩展应该可以构建,并且如果你将其部署到 Edge 作为扩展,你会看到一个整齐显示的表单。
**此结构提供的功能包括:**
- **`loading`****显示** 获取 API 数据时的加载信息
- **`errors`****展示** API 调用失败或数据无效时的错误信息
- **`data`****保存** 调试用的原始数据
- **`result-container`****向用户呈现** 格式化的碳足迹信息
- **`clear-btn`****允许** 用户更改地区并重新配置扩展
恭喜你,你已经迈出了构建浏览器扩展的第一步。在后续课程中,你将使其更加功能化和实用。
---
### 设置构建流程
## 🚀 挑战
现在安装项目依赖并测试构建流程:
浏览一个浏览器扩展商店并安装一个扩展到你的浏览器。你可以用有趣的方式检查它的文件。你发现了什么?
```bash
npm install
```
## 课后测验
**该安装步骤完成的操作:**
- **下载** Webpack 及 `package.json` 中指定的其他开发依赖
- **配置** 构建工具链,编译现代 JavaScript
- **准备** 开发环境,为扩展构建与测试做好准备
- **支持** 代码打包、优化及跨浏览器兼容功能
[课后测验](https://ff-quizzes.netlify.app/web/quiz/24)
> 💡 **构建流程洞见**Webpack 会将 `/src/index.js` 中的源码打包成 `/dist/main.js`。该过程优化代码以适应生产环境,并确保浏览器兼容性。
## 复习与自学
### 测试你的进展
在本课中,你学习了一些关于网页浏览器历史的知识;利用这个机会,通过阅读更多关于其历史的内容来了解万维网发明者对其使用的设想。一些有用的网站包括:
此时,你可以开始测试你的扩展了:
1. **运行** 构建命令以编译代码
2. **加载** 扩展到浏览器中,使用开发者模式
3. **验证** 表单是否正确显示且外观专业
4. **检查** 所有表单元素是否正确对齐且功能正常
**你已完成:**
- **构建** 了扩展的基础 HTML 结构
- **创建** 了配置和结果界面,使用了正确的语义标记
- **搭建** 了使用行业标准工具的现代开发流程
- **准备** 了添加交互式 JavaScript 功能的基础
### 🔄 **教学核验**
**扩展开发进度**:继续前请确认理解:
- ✅ 你能解释项目结构中每个文件的目的吗?
- ✅ 你理解构建过程如何转换源代码吗?
- ✅ 为什么我们将配置和结果分到不同的用户界面部分?
- ✅ 表单结构如何支持可用性和可访问性?
**开发工作流理解**:现在你应该能:
1. **修改** 扩展界面相关的 HTML 和 CSS
2. **运行** 构建命令编译更改
3. **重新加载** 浏览器中的扩展以测试更新
4. **使用**浏览器开发者工具调试问题
你已完成浏览器扩展开发的第一阶段。就像莱特兄弟在实现飞行前需要了解空气动力学一样,理解这些基础概念将助你构建下一课中更复杂的交互功能。
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 通过添加表单验证和用户反馈功能来增强浏览器扩展,提升输入 API 密钥和地区代码时的用户体验。
**提示:** 创建 JavaScript 验证函数,检查 API 密钥字段是否至少包含 20 个字符,以及地区代码是否符合正确格式(如 'US-NEISO')。通过改变输入框边框颜色来提供视觉反馈,输入有效时为绿色,无效时为红色。还要添加切换功能以显示/隐藏 API 密钥以保证安全。
了解更多关于[agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
查看浏览器扩展商店并安装一个扩展到浏览器。你可以用有趣的方式检查其文件。你发现了什么?
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/24)
## 复习与自学
本课中你了解了浏览器的一些历史;借此机会通过阅读更多有关万维网发明者的历史,了解他们对其使用的设想。一些有用网站包括:
[浏览器历史](https://www.mozilla.org/firefox/browsers/browser-history/)
[万维网历史](https://webfoundation.org/about/vision/history-of-the-web/)
[蒂姆·伯纳斯-李访谈](https://www.theguardian.com/technology/2019/mar/12/tim-berners-lee-on-30-years-of-the-web-if-we-dream-a-little-we-can-get-the-web-we-want)
### ⚡ **你接下来 5 分钟能做什么**
- [ ] 打开 Chrome/Edge 扩展页面 (chrome://extensions) 并浏览已安装扩展
- [ ] 在加载网页时查看浏览器开发者工具 Network 标签页
- [ ] 尝试查看页面源代码Ctrl+U以了解 HTML 结构
- [ ] 检查任意网页元素并在开发者工具中修改其 CSS
### 🎯 **你这小时能完成什么**
- [ ] 完成课后测验,理解浏览器基础知识
- [ ] 创建基本的 manifest.json 文件用于浏览器扩展
- [ ] 构建显示弹出窗口的简单 “Hello World” 扩展
- [ ] 测试以开发者模式加载你的扩展
- [ ] 探索目标浏览器的扩展文档
### 📅 **你的为期一周的扩展之旅**
- [ ] 完成一个具备实际用途的功能性浏览器扩展
- [ ] 了解内容脚本、后台脚本和弹出交互
- [ ] 掌握浏览器 API 如存储、标签页和消息传递
- [ ] 设计对用户友好的扩展界面
- [ ] 在不同网站和场景测试你的扩展
- [ ] 将扩展发布到浏览器扩展商店
### 🌟 **你的为期一个月的浏览器开发规划**
- [ ] 构建多款解决不同用户问题的扩展
- [ ] 学习高级浏览器 API 和安全最佳实践
- [ ] 贡献开源浏览器扩展项目
- [ ] 精通跨浏览器兼容和渐进增强
- [ ] 为他人创建扩展开发工具和模板
- [ ] 成为帮助其他开发者的浏览器扩展专家
## 🎯 你的浏览器扩展掌握时间表
```mermaid
timeline
title 浏览器扩展开发进度
section 基础15分钟
浏览器理解: 核心架构
: 渲染进程
: 扩展集成点
section 环境搭建20分钟
开发环境: 项目结构
: 构建工具配置
: 浏览器开发者模式
: 扩展加载流程
section 界面设计25分钟
用户体验: HTML结构
: CSS样式
: 表单验证
: 响应式设计
section 核心功能35分钟
JavaScript集成: 事件处理
: API交互
: 数据存储
: 错误处理
section 浏览器API45分钟
平台集成: 权限系统
: 存储API
: 标签管理
: 上下文菜单
section 高级功能1周
专业扩展: 后台脚本
: 内容脚本
: 跨浏览器兼容
: 性能优化
section 发布2周
分发: 商店提交
: 审核流程
: 用户反馈
: 更新管理
section 专家级别1个月
扩展生态系统: 高级API
: 安全最佳实践
: 企业功能
: 框架集成
```
### 🛠️ 你的扩展开发工具包总结
[网页浏览器的历史](https://www.mozilla.org/firefox/browsers/browser-history/)
完成本课后,你现拥有:
- **浏览器架构知识**:理解渲染引擎、安全模型和扩展集成
- **开发环境**:现代工具链,包含 Webpack、NPM 和调试能力
- **UI/UX 基础**:语义 HTML 结构与渐进披露模式
- **安全意识**:了解浏览器权限和安全开发实践
- **跨浏览器概念**:兼容性考虑和测试方法
- **API 集成**:与外部数据源交互的基础
- **专业工作流程**:行业标准的开发和测试流程
[万维网的历史](https://webfoundation.org/about/vision/history-of-the-web/)
**现实应用**:这些技能直接适用于:
- **网页开发**:单页应用和渐进式网页应用
- **桌面应用**Electron 及基于网页的桌面软件
- **移动开发**:混合应用和基于网页的移动解决方案
- **企业工具**:内部生产力应用和工作流自动化
- **开源项目**:参与浏览器扩展项目和网络标准
[蒂姆·伯纳斯-李访谈](https://www.theguardian.com/technology/2019/mar/12/tim-berners-lee-on-30-years-of-the-web-if-we-dream-a-little-we-can-get-the-web-we-want)
**下一步**:你已准备好添加交互功能,使用浏览器 API并创建解决真实用户问题的扩展
## 作业
## 作业
[重新设计你的扩展](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威版本。对于关键信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,146 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "e3c6f2a03c2336e60412612d870af547",
"translation_date": "2025-08-23T23:44:41+00:00",
"original_hash": "b6897c02603d0045dd6d8256e8714baa",
"translation_date": "2026-01-06T11:37:53+00:00",
"source_file": "5-browser-extension/1-about-browsers/assignment.md",
"language_code": "zh"
}
-->
# 重新设计你的扩展
# 作业:重新设计你的浏览器扩展样式
## 指南
## 概述
这个扩展的代码库已经包含了样式,但你不必使用它们;通过编辑其 CSS 文件,重新设计样式,让你的扩展独具特色
现在你已经构建了碳足迹浏览器扩展的 HTML 结构,是时候让它在视觉上更吸引人且更易于使用了。优秀的设计可以提升用户体验,让你的扩展看起来更专业、更有吸引力
## 评分标准
你的扩展附带了基本的 CSS 样式,但本次作业挑战你创建一种独特的视觉识别,既能体现你的个人风格,又能保持良好的可用性。
| 标准 | 优秀 | 合格 | 需要改进 |
| -------- | -------------------------------------------- | --------------------- | ----------------- |
| | 提交的代码包含功能完善的新样式 | 样式不完整 | 样式存在问题 |
## 指导说明
### 第 1 部分:分析当前设计
在进行更改前,先检查现有的 CSS 结构:
1. **定位**你扩展项目中的 CSS 文件
2. **审查**当前的样式方法和配色方案
3. **识别**布局、排版和视觉层次中可改进的部分
4. **考虑**设计如何支持用户目标(方便填写表单和清晰展示数据)
### 第 2 部分:设计你的自定义样式
创建一个整体统一的视觉设计,包括:
**配色方案:**
- 选择反映环保主题的主色调
- 保证充足的对比度以确保无障碍(可使用 WebAIM 的对比度检查工具)
- 考虑颜色在不同浏览器主题下的表现
**排版:**
- 选择在小尺寸扩展界面中易读的字体
- 通过合适的字体大小和粗细建立清晰的层次结构
- 确保文本在亮暗主题浏览器中均清晰可见
**布局与间距:**
- 优化表单元素和数据展示的视觉组织
- 添加合适的内边距和外边距提升可读性
- 考虑响应式设计,适应不同屏幕尺寸
### 第 3 部分:实现你的设计
修改 CSS 文件来应用你的设计:
```css
/* Example starting points for customization */
.form-data {
/* Style the configuration form */
background: /* your choice */;
padding: /* your spacing */;
border-radius: /* your preference */;
}
.result-container {
/* Style the data display area */
background: /* complementary color */;
border: /* your border style */;
margin: /* your spacing */;
}
/* Add your custom styles here */
```
**关键样式区域:**
- **表单元素**:输入框、标签和提交按钮
- **结果展示**:数据容器、文本样式和加载状态
- **交互元素**:悬停效果、按钮状态及过渡动画
- **整体布局**:容器间距、背景颜色和视觉层次
### 第 4 部分:测试与调整
1. 使用 `npm run build` **构建**你的扩展
2. **加载**更新后的扩展到浏览器
3. **测试**所有视觉状态(表单输入、加载、结果展示、错误提示)
4. 使用浏览器开发者工具**验证**无障碍功能
5. 根据实际使用情况**调整**你的样式
## 创意挑战
### 基础级别
- 更新颜色和字体,打造统一主题
- 改善界面内的间距和对齐
- 给交互元素添加细腻的悬停效果
### 中级
- 设计定制图标或图形元素
- 实现不同状态间的平滑过渡动画
- 为 API 调用创建独特的加载动画
### 高级
- 设计多种主题选项(亮色/暗色/高对比度)
- 实现针对不同浏览器窗口尺寸的响应式设计
- 添加提升用户体验的微交互
## 提交指南
提交内容应包括:
- **修改后的 CSS 文件**,体现你的自定义样式
- 显示扩展不同状态(表单、加载、结果)的**截图**
- 简短说明2-3 句),解释你的设计选择及其如何提升用户体验
## 评估标准
| 评估项目 | 杰出 (4) | 熟练 (3) | 发展中 (2) | 初学 (1) |
|----------|----------|----------|------------|----------|
| **视觉设计** | 创意且整体统一,增强可用性,体现强设计原则 | 良好的设计选择,样式一致,视觉层次清晰 | 基础设计改进,有一些一致性问题 | 样式修改有限或设计不一致 |
| **功能性** | 所有样式在各种状态和浏览器环境中完美运行 | 样式运作良好,边缘情况有轻微问题 | 大部分样式可用,有一些显示问题 | 样式问题严重影响可用性 |
| **代码质量** | 清晰有序的 CSS类名有意义选择器高效 | 良好 CSS 结构,选择器和属性使用合适 | CSS 可以接受,有些组织问题 | CSS 结构差或样式过于复杂 |
| **无障碍** | 优秀的颜色对比度、易读字体,考虑到残障用户 | 良好的无障碍实践,少许改进空间 | 基本无障碍考虑,有些问题 | 无障碍关注有限 |
## 成功提示
> 💡 **设计提示**:从细微变化开始,逐步构建更显著的样式调整。排版和间距的小提升往往对质感影响很大。
**最佳实践包括:**
- 在亮色和暗色浏览器主题中都**测试**扩展
- 使用相对单位em, rem提升可扩展性
- 使用 CSS 自定义属性保持间距一致
- 考虑不同视觉需求用户的观感
- 验证 CSS 以确保符合正确语法
> ⚠️ **常见错误**:不要为了美观牺牲可用性。扩展应兼具美观与实用。
**记得:**
- 保持重要信息易于阅读
- 确保按钮和交互元素易于点击
- 保持用户操作的明确视觉反馈
- 用真实数据测试设计,而非仅用占位文本
祝你成功打造既实用又视觉出色的浏览器扩展!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意,自动翻译可能存在错误或不准确之处。原始文件以其本地语言版本为权威来源。对于重要信息,建议采用专业人工翻译。我们不对因使用本翻译而产生的任何误解或误释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,37 +1,114 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a7587943d38d095de8613e1b508609f5",
"translation_date": "2025-08-29T14:45:24+00:00",
"original_hash": "2b6203a48c48d8234e0948353b47d84e",
"translation_date": "2026-01-06T11:32:52+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/README.md",
"language_code": "zh"
}
-->
# 浏览器扩展项目第二部分:调用 API使用本地存储
```mermaid
journey
title 你的 API 集成与存储旅程
section 基础
设置 DOM 引用: 3: Student
添加事件监听器: 4: Student
处理表单提交: 4: Student
section 数据管理
实现本地存储: 4: Student
构建 API 调用: 5: Student
处理异步操作: 5: Student
section 用户体验
添加错误处理: 5: Student
创建加载状态: 4: Student
优化交互: 5: Student
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/25)
### 介绍
在本课中,你将通过提交浏览器扩展的表单来调用 API并在浏览器扩展中显示结果。此外你还将学习如何将数据存储在浏览器的本地存储中以供将来参考和使用。
✅ 按照相关文件中的编号段落,了解代码应该放置的位置。
### 设置扩展中需要操作的元素:
到目前为止,你已经为浏览器扩展构建了表单和结果 `<div>` 的 HTML。从现在开始你需要在 `/src/index.js` 文件中工作,并逐步构建你的扩展。参考[上一课](../1-about-browsers/README.md)了解项目设置和构建过程。
`index.js` 文件中工作,首先创建一些 `const` 变量来保存与各个字段相关的值:
```JavaScript
// form fields
## 介绍
还记得你刚开始构建的浏览器扩展吗?现在你拥有一个看起来很不错的表单,但它本质上是静态的。今天我们将通过连接真实数据并赋予它记忆功能来让它变得生动。
想想阿波罗任务控制计算机——它们不仅仅展示固定信息。它们不断与航天器通信,更新遥测数据,并记住关键的任务参数。这就是我们今天要构建的动态行为。你的扩展将连接互联网,抓取真实的环境数据,并记住你下次的设置。
API 集成听起来可能很复杂,但实际上就是教你的代码如何与其他服务通信。无论你是在获取天气数据、社交媒体信息流,还是像今天一样获取碳足迹信息,关键都是建立这些数字连接。我们还将探讨浏览器如何持久保存信息——类似于图书馆如何使用卡片目录来记住书本位置。
完成本课后,你将拥有一个能够获取真实数据、保存用户偏好设置并提供流畅体验的浏览器扩展。让我们开始吧!
```mermaid
mindmap
root((动态扩展))
DOM Manipulation
Element Selection
Event Handling
State Management
UI Updates
Local Storage
Data Persistence
Key-Value Pairs
Session Management
User Preferences
API Integration
HTTP Requests
Authentication
Data Parsing
Error Handling
Async Programming
Promises
Async/Await
Error Catching
Non-blocking Code
User Experience
Loading States
Error Messages
Smooth Transitions
Data Validation
```
✅ 按照对应文件中的编号段落知道在哪里放置你的代码
## 设置扩展中要操作的元素
在你的 JavaScript 操作界面之前,需要先获取特定的 HTML 元素引用。就像望远镜需要对准特定的星星一样——伽利略研究木星的卫星前必须先定位并聚焦于木星。
在你的 `index.js` 文件中,我们将创建 `const` 变量来捕获每个重要表单元素的引用。这类似于科学家给他们的设备贴标签——这样他们不必每次都在整个实验室中搜索,就可以直接访问需要的东西。
```mermaid
flowchart LR
A[JavaScript 代码] --> B[document.querySelector]
B --> C[CSS 选择器]
C --> D[HTML 元素]
D --> E[".form-data"]
D --> F[".region-name"]
D --> G[".api-key"]
D --> H[".loading"]
D --> I[".errors"]
D --> J[".result-container"]
E --> K[表单元素]
F --> L[输入字段]
G --> M[输入字段]
H --> N[UI 元素]
I --> O[UI 元素]
J --> P[UI 元素]
style A fill:#e1f5fe
style D fill:#e8f5e8
style K fill:#fff3e0
style L fill:#fff3e0
style M fill:#fff3e0
```
```javascript
// 表单字段
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
const apiKey = document.querySelector('.api-key');
// results
// 结果
const errors = document.querySelector('.errors');
const loading = document.querySelector('.loading');
const results = document.querySelector('.result-container');
@ -41,186 +118,429 @@ const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');
```
所有这些字段都是通过它们的 CSS 类引用的,这是你在上一课的 HTML 中设置的。
### 添加监听器
接下来,为表单和重置按钮添加事件监听器,这样当用户提交表单或点击重置按钮时,会触发相应的操作,并在文件底部添加初始化应用的调用:
```JavaScript
**这段代码的作用:**
- **捕获** 表单元素,使用 `document.querySelector()` 结合 CSS 类选择器
- **创建** 了区域名称和 API 密钥输入字段的引用
- **建立** 结果显示元素的连接,用于展示碳使用相关数据
- **设置** 访问 UI 元素,如加载指示器和错误信息
- **存储** 每个元素引用在 `const` 变量中,便于代码中反复使用
## 添加事件监听器
现在我们让你的扩展响应用户操作。事件监听器是你的代码监控用户交互的方式。想象早期电话交换机的操作员——他们监听来电,当有人想要通话时连接正确的线路。
```mermaid
sequenceDiagram
participant User
participant Form
participant JavaScript
participant API
participant Storage
User->>Form: 填写区域/API密钥
User->>Form: 点击提交
Form->>JavaScript: 触发提交事件
JavaScript->>JavaScript: handleSubmit(e)
JavaScript->>Storage: 保存用户偏好
JavaScript->>API: 获取碳数据
API->>JavaScript: 返回数据
JavaScript->>Form: 用结果更新界面
User->>Form: 点击清除按钮
Form->>JavaScript: 触发点击事件
JavaScript->>Storage: 清除保存的数据
JavaScript->>Form: 重置到初始状态
```
```javascript
form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();
```
✅ 注意这里使用了简写方式来监听提交或点击事件,以及事件如何传递给 `handleSubmit``reset` 函数。你能写出这种简写的等效长格式吗?你更喜欢哪种方式?
**理解这些概念:**
- **绑定** 表单提交事件监听器,当用户按下回车或点击提交时触发
- **连接** 清除按钮的点击监听器,用于重置表单
- **传递** 事件对象 `(e)` 给处理函数以实现额外控制
- **立即调用** `init()` 函数,用于设置扩展的初始状态
✅ 注意这里使用的箭头函数简写语法。这种现代 JavaScript 写法比传统函数表达式更简洁,不过两者都有效!
### 🔄 **教学检查点**
**事件处理理解**:在进行初始化之前,请确保你能:
- ✅ 解释 `addEventListener` 如何将用户操作连接到 JavaScript 函数
- ✅ 理解为何要将事件对象 `(e)` 传给处理函数
- ✅ 认识 `submit``click` 事件的区别
- ✅ 描述 `init()` 函数何时运行及其原因
### 构建 `init()``reset()` 函数:
**快速自测**:如果忘记在表单提交时调用 `e.preventDefault()` 会怎么样?
*答案:页面会重新加载,所有 JavaScript 状态丢失,用户体验中断*
现在你将构建初始化扩展的函数 `init()`
## 构建初始化和重置函数
```JavaScript
让我们创建扩展的初始化逻辑。`init()` 函数就像船舶的导航系统检查仪器——它判断当前状态并相应调整界面。它会检查用户是否之前使用过你的扩展,并加载他们之前的设置。
`reset()` 函数则为用户提供一个重新开始的机会——类似科学家在实验间隙重置仪器以保证数据清洁。
```javascript
function init() {
//if anything is in localStorage, pick it up
// 检查用户是否之前保存过API凭证
const storedApiKey = localStorage.getItem('apiKey');
const storedRegion = localStorage.getItem('regionName');
//set icon to be generic green
//todo
// 将扩展图标设置为通用绿色(未来课程的占位符)
// 待办事项:在下一课实现图标更新
if (storedApiKey === null || storedRegion === null) {
//if we don't have the keys, show the form
// 初次使用者:显示设置表单
form.style.display = 'block';
results.style.display = 'none';
loading.style.display = 'none';
clearBtn.style.display = 'none';
errors.textContent = '';
} else {
//if we have saved keys/regions in localStorage, show results when they load
displayCarbonUsage(storedApiKey, storedRegion);
// 回访用户:自动加载他们保存的数据
displayCarbonUsage(storedApiKey, storedRegion);
results.style.display = 'none';
form.style.display = 'none';
clearBtn.style.display = 'block';
}
};
}
function reset(e) {
e.preventDefault();
//clear local storage for region only
// 清除存储的区域以允许用户选择新位置
localStorage.removeItem('regionName');
// 重新启动初始化过程
init();
}
```
在这个函数中,有一些有趣的逻辑。阅读代码后,你能看出发生了什么吗?
- 设置两个 `const` 来检查用户是否在本地存储中保存了 APIKey 和区域代码。
- 如果其中任何一个为 null通过将表单样式设置为 'block' 来显示表单。
- 隐藏结果、加载状态和清除按钮,并将任何错误文本设置为空字符串。
- 如果存在 key 和 region则启动以下流程
- 调用 API 获取碳使用数据。
- 隐藏结果区域。
- 隐藏表单。
- 显示重置按钮。
在继续之前,了解浏览器中一个非常重要的概念是很有用的:[LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage)。LocalStorage 是一种在浏览器中以 `key-value` 对形式存储字符串的有用方式。这种类型的 Web 存储可以通过 JavaScript 操作来管理浏览器中的数据。LocalStorage 不会过期,而另一种 Web 存储 SessionStorage 会在浏览器关闭时清除。这些存储类型在使用上各有优缺点。
> 注意 - 你的浏览器扩展有自己的本地存储;主浏览器窗口是一个不同的实例,行为独立。
你可以将 APIKey 设置为一个字符串值,例如,你可以通过“检查”网页(右键单击浏览器并选择检查)并转到应用程序选项卡查看存储内容来在 Edge 上看到它。
![本地存储面板](../../../../translated_images/localstorage.472f8147b6a3f8d141d9551c95a2da610ac9a3c6a73d4a1c224081c98bae09d9.zh.png)
**这里发生的事情分解:**
- **从浏览器本地存储获取** 保存的 API 密钥和区域数据
- **检测** 是否为首次使用(无存储凭据)或是回访用户
- **为新用户显示** 设置表单,并隐藏其他界面元素
- **为回访用户自动加载** 保存的数据并显示重置选项
- **基于是否有数据** 管理用户界面的状态
**关于本地存储的关键概念:**
- **数据持久保存**,跨浏览器会话有效(与会话存储不同)
- **以键值对方式保存**,使用 `getItem()``setItem()`
- **当指定键无数据时返回** `null`
- **提供简单方式** 存储用户偏好和设置
> 💡 **理解浏览器存储**[LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) 就像赋予你的扩展持久记忆。想象古代亚历山大图书馆如何保存卷轴——信息在学者离开再回来时依然可用。
>
> **关键特点:**
> - **关闭浏览器后依然保存数据**
> - **重启计算机和浏览器崩溃后数据依然存在**
> - **提供丰富存储空间保存用户偏好**
> - **无需网络延迟即可即时访问**
> **重要提示**:你的浏览器扩展有自己的独立本地存储,独立于普通网页。这保证了安全且避免与其他网站冲突。
你可以通过打开浏览器开发者工具F12进入 **Application** 选项卡,展开 **Local Storage** 部分查看存储的数据。
```mermaid
stateDiagram-v2
[*] --> CheckStorage: 扩展启动
CheckStorage --> FirstTime: 无存储数据
CheckStorage --> Returning: 发现数据
FirstTime --> ShowForm: 显示设置表单
ShowForm --> UserInput: 用户输入数据
UserInput --> SaveData: 存储到 localStorage
SaveData --> FetchAPI: 获取碳数据
Returning --> LoadData: 从 localStorage 读取
LoadData --> FetchAPI: 获取碳数据
FetchAPI --> ShowResults: 显示数据
ShowResults --> UserAction: 用户交互
UserAction --> Reset: 点击清除按钮
UserAction --> ShowResults: 查看数据
Reset --> ClearStorage: 删除保存的数据
ClearStorage --> FirstTime: 返回设置
```
![本地存储面板](../../../../translated_images/localstorage.472f8147b6a3f8d1.zh.png)
✅ 思考哪些情况下你不应该将某些数据存储在 LocalStorage 中。通常,将 APIKey 放在 LocalStorage 中是一个糟糕的主意!你能看出原因吗?在我们的案例中,由于我们的应用仅用于学习且不会部署到应用商店,我们将使用这种方法。
> ⚠️ **安全注意事项**:在生产环境中,将 API 密钥存储在 LocalStorage 存在安全风险,因为 JavaScript 代码可以访问这些数据。学习用途这样做可以,但实际应用应使用安全的服务器端存储敏感凭证
注意,你使用 Web API 操作 LocalStorage可以通过 `getItem()`、`setItem()` 或 `removeItem()`。它在各个浏览器中都得到了广泛支持。
## 处理表单提交
在构建 `displayCarbonUsage()` 函数(在 `init()` 中调用)之前,让我们先构建处理初始表单提交的功能。
接下来我们处理用户提交表单时的行为。默认情况下,浏览器表单提交会重新加载页面,但我们要拦截这种行为,使体验更加流畅
### 处理表单提交
这种做法类似任务控制对航天器通信的处理——不是每次传输都重置整个系统,而是持续运行同时处理新信息。
创建一个名为 `handleSubmit` 的函数,该函数接受一个事件参数 `(e)`。阻止事件传播(在这种情况下,我们希望阻止浏览器刷新),并调用一个新函数 `setUpUser`,传入 `apiKey.value``region.value` 作为参数。通过这种方式,你可以使用通过初始表单填充的字段中获取的两个值。
创建一个函数,捕获表单提交事件并提取用户输入内容:
```JavaScript
```javascript
function handleSubmit(e) {
e.preventDefault();
setUpUser(apiKey.value, region.value);
}
```
✅ 回顾一下 - 你在上一课中设置的 HTML 有两个输入字段,其 `values` 是通过你在文件顶部设置的 `const` 捕获的,并且它们都是 `required`,因此浏览器会阻止用户输入空值。
**以上我们做了:**
- **阻止** 表单默认提交行为避免刷新页面
- **提取** 用户在 API 密钥和区域字段中的输入值
- **将** 表单数据传递给 `setUpUser()` 函数进行处理
- **保持** 单页面应用行为,避免页面重新加载
✅ 请记得你的 HTML 表单字段带有 `required` 属性,所以浏览器会自动验证用户必须填写 API 密钥和区域后,才会执行此函数。
### 设置用户
## 设置用户偏好
接下来是 `setUpUser` 函数,这里你将为 apiKey 和 regionName 设置本地存储值。添加一个新函数:
`setUpUser` 函数负责保存用户凭据并启动第一次 API 调用。这样实现从设置到展示结果的平滑过渡。
```JavaScript
```javascript
function setUpUser(apiKey, regionName) {
// 保存用户凭证以供将来会话使用
localStorage.setItem('apiKey', apiKey);
localStorage.setItem('regionName', regionName);
// 更新界面以显示加载状态
loading.style.display = 'block';
errors.textContent = '';
clearBtn.style.display = 'block';
//make initial call
// 使用用户凭证获取碳排放使用数据
displayCarbonUsage(apiKey, regionName);
}
```
这个函数会在调用 API 时显示加载消息。到此为止,你已经到达了创建这个浏览器扩展最重要的函数!
### 显示碳使用数据
最后,是时候查询 API 了!
在进一步操作之前,我们应该讨论一下 API。API即[应用程序编程接口](https://www.webopedia.com/TERM/A/API.html),是 Web 开发人员工具箱中的关键元素。它们为程序之间的交互和接口提供了标准方式。例如,如果你正在构建一个需要查询数据库的网站,可能有人已经为你创建了一个 API 可以使用。虽然 API 有很多种类型,其中一种最流行的是 [REST API](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/)。
**一步步过程为:**
- **保存** API 密钥和区域名到本地存储以便未来使用
- **显示** 加载指示器告知用户正在获取数据
- **清除** 任何先前显示的错误信息
- **显示** 清除按钮,供用户以后重置设置
- **发起** API 调用获取真实的碳使用数据
这个函数通过协调数据持久化和界面更新,创造了无缝的用户体验。
## 显示碳使用数据
现在我们将扩展连接到外部数据源,通过 API 获取数据。这使你的扩展从独立工具变成可以访问互联网上实时信息的应用。
**理解 API**
[API](https://www.webopedia.com/TERM/A/API.html) 是不同应用间通信的方式。可以把它想象成 19 世纪连接远距离城市的电报系统——操作员会向远方电报站发送请求,并收取返回的信息。每次你查看社交媒体、问语音助手问题、或用送货应用时,都离不开 API 帮助完成数据交换。
```mermaid
flowchart TD
A[您的扩展] --> B[HTTP 请求]
B --> C[CO2 信号 API]
C --> D{请求有效吗?}
D -->|是| E[查询数据库]
D -->|否| F[返回错误]
E --> G[碳排放数据]
G --> H[JSON 响应]
H --> I[您的扩展]
F --> I
I --> J[更新界面]
subgraph "API 请求"
K[请求头: auth-token]
L[参数: countryCode]
M[方法: GET]
end
subgraph "API 响应"
N[碳强度]
O[化石燃料百分比]
P[时间戳]
end
style C fill:#e8f5e8
style G fill:#fff3e0
style I fill:#e1f5fe
```
**关于 REST API 的关键概念:**
- **REST** 表示“表述性状态转移”
- **使用** 标准 HTTP 方法 GET、POST、PUT、DELETE来操作数据
- **返回** 通常是 JSON 这类可预测格式的数据
- **提供** 对不同请求的一致 URL 端点
✅ “REST” 的全称是“表述性状态转移”,它通过各种配置的 URL 来获取数据。研究一下开发人员可用的各种 API 类型。哪种格式对你更有吸引力?
我们使用的 [CO2 Signal API](https://www.co2signal.com/) 提供全球电网的实时碳强度数据。帮助用户了解用电对环境的影响!
关于这个函数,有一些重要的事情需要注意。首先,注意 [`async` 关键字](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function)。将函数写成异步运行意味着它会等待某个操作(例如数据返回)完成后再继续。
> 💡 **理解异步 JavaScript**[`async` 关键字](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) 让你的代码同时处理多个操作。当你向服务器请求数据时,不希望整个扩展卡住——那就像空中交通管制在等待一架飞机响应时停止所有操作。
>
> **主要好处:**
> - **保持** 扩展在数据加载期间依然响应
> - **允许** 在网络请求时执行其他代码
> - **提升** 代码可读性,相较传统回调模式更易懂
> - **支持** 网络异常时优雅错误处理
这里有一个关于 `async` 的简短视频:
这里有个关于 `async` 的视频:
[![管理 Promise 的 Async 和 Await](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "管理 Promise 的 Async 和 Await")
> 🎥 点击上方图片观看关于 async/await 的视频。
创建一个新函数来查询 C02Signal API
```JavaScript
import axios from '../node_modules/axios';
> 🎥 点击上图观看 async/await 相关视频。
### 🔄 **教学检查点**
**异步编程理解**:开始写 API 函数之前,请确认你理解:
- ✅ 为什么使用 `async/await`,而非阻塞整个扩展
- ✅ `try/catch` 块如何优雅处理网络错误
- ✅ 同步与异步操作的区别
- ✅ API 调用失败时会发生什么,如何应对
**现实生活的异步连接:**
- **点外卖**:你不会一直待在厨房旁边,会拿到收据后继续其他活动
- **发邮件**:发送时应用不会卡死,你可以继续写邮件
- **网页加载**:图片边加载边显示,你已经可以看文本了
**API 认证流程**
```mermaid
sequenceDiagram
participant Ext as 扩展
participant API as CO2 信号 API
participant DB as 数据库
Ext->>API: 使用认证令牌请求
API->>API: 验证令牌
API->>DB: 查询碳数据
DB->>API: 返回数据
API->>Ext: JSON 响应
Ext->>Ext: 更新界面
```
创建获取并展示碳使用数据的函数:
```javascript
// 现代的 fetch API 方法(不需要外部依赖)
async function displayCarbonUsage(apiKey, region) {
try {
await axios
.get('https://api.co2signal.com/v1/latest', {
params: {
countryCode: region,
},
headers: {
'auth-token': apiKey,
},
})
.then((response) => {
let CO2 = Math.floor(response.data.data.carbonIntensity);
//calculateColor(CO2);
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region;
usage.textContent =
Math.round(response.data.data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)';
fossilfuel.textContent =
response.data.data.fossilFuelPercentage.toFixed(2) +
'% (percentage of fossil fuels used to generate electricity)';
results.style.display = 'block';
});
// 从 CO2 Signal API 获取碳强度数据
const response = await fetch('https://api.co2signal.com/v1/latest', {
method: 'GET',
headers: {
'auth-token': apiKey,
'Content-Type': 'application/json'
},
// 添加特定区域的查询参数
...new URLSearchParams({ countryCode: region }) && {
url: `https://api.co2signal.com/v1/latest?countryCode=${region}`
}
});
// 检查 API 请求是否成功
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
const carbonData = data.data;
// 计算四舍五入的碳强度值
const carbonIntensity = Math.round(carbonData.carbonIntensity);
// 使用获取到的数据更新用户界面
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region.toUpperCase();
usage.textContent = `${carbonIntensity} grams (grams CO₂ emitted per kilowatt hour)`;
fossilfuel.textContent = `${carbonData.fossilFuelPercentage.toFixed(2)}% (percentage of fossil fuels used to generate electricity)`;
results.style.display = 'block';
// 待办calculateColor(carbonIntensity) - 在下一节课中实现
} catch (error) {
console.log(error);
console.error('Error fetching carbon data:', error);
// 显示用户友好的错误信息
loading.style.display = 'none';
results.style.display = 'none';
errors.textContent = 'Sorry, we have no data for the region you have requested.';
errors.textContent = 'Sorry, we couldn\'t fetch data for that region. Please check your API key and region code.';
}
}
```
这是一个较大的函数。这里发生了什么?
**详细解析:**
- **使用** 现代的 `fetch()` API替代外部库如 Axios代码更简洁且无依赖
- **实现** 使用 `response.ok` 做适当错误检查,及早捕捉 API 失败
- **通过** `async/await` 处理异步操作,使代码流程更易读
- **使用** `auth-token` 头部进行 CO2 Signal API 认证
- **解析** JSON 响应数据并提取碳强度信息
- **更新** 多个 UI 元素,格式化显示环保数据
- **提供** 当 API 调用失败时易理解的错误提示
**示例中展示的现代 JavaScript 技巧:**
- **模板字符串** 用 `${}` 语法,更清晰字符串格式化
- **try/catch 错误处理** 让应用更健壮
- **async/await 异步模式** 优雅调用网络接口
- **对象解构** 提取 API 响应中需要的数据
- **链式方法调用** 实现多步 DOM 操作
✅ 这个函数展示了多个重要的网页开发概念——与外部服务器通信,认证处理,数据解析,界面更新,以及错误管理。这些是专业开发者日常使用的基础技能。
```mermaid
flowchart TD
A[开始 API 调用] --> B[获取请求]
B --> C{网络成功?}
C -->|否| D[网络错误]
C -->|是| E{响应正常?}
E -->|否| F[API 错误]
E -->|是| G[解析 JSON]
G --> H{数据有效?}
H -->|否| I[数据错误]
H -->|是| J[更新界面]
D --> K[显示错误信息]
F --> K
I --> K
J --> L[隐藏加载]
K --> L
style A fill:#e1f5fe
style J fill:#e8f5e8
style K fill:#ffebee
style L fill:#f3e5f5
```
### 🔄 **教学检查点**
**完整系统理解**:确认你掌握整个流程:
- ✅ DOM 引用为什么能让 JavaScript 控控界面
- ✅ 本地存储如何实现跨浏览器会话的数据持久化
- ✅ async/await 如何让 API 调用不冻结扩展
- ✅ API 请求失败时会怎样,以及如何处理异常
- ✅ 用户体验为何包含加载状态和错误提示
🎉 **你已经完成了:**
一个浏览器扩展,它:
- **连接** 互联网,获取真实环保数据
- **持久保存** 用户设置跨会话
- **优雅处理** 错误,避免崩溃
- **提供** 流畅且专业的用户体验
通过运行 `npm run build` 并刷新浏览器扩展测试你的成果。你现在拥有一个功能齐全的碳足迹追踪器。下一课将添加动态图标功能,完善此扩展。
---
- 遵循最佳实践,你使用了 `async` 关键字使这个函数异步运行。函数包含一个 `try/catch` 块,因为当 API 返回数据时它会返回一个 Promise。由于你无法控制 API 响应的速度(它可能根本不响应!),你需要通过异步调用来处理这种不确定性。
- 你正在查询 co2signal API 以获取区域数据,使用你的 APIKey。要使用该 key你需要在请求头参数中使用一种身份验证方式。
- 一旦 API 响应,你将其响应数据的各个元素分配给屏幕上设置的显示数据的部分。
- 如果出现错误或没有结果,你会显示错误消息。
## GitHub Copilot Agent 挑战 🚀
✅ 使用异步编程模式是工具箱中另一个非常有用的工具。阅读[各种配置方式](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function)了解这种代码类型。
使用 Agent 模式完成以下挑战:
**描述:** 通过添加错误处理改进和用户体验功能来增强浏览器扩展。本挑战将帮助你练习使用现代 JavaScript 模式进行 API 调用、本地存储和 DOM 操作。
恭喜你!如果你构建了扩展(`npm run build`)并在扩展面板中刷新它,你就有了一个可用的扩展!唯一没有工作的部分是图标,你将在下一课中修复它。
**提示:** 创建一个增强版的 displayCarbonUsage 函数包含1) 失败 API 调用的指数退避重试机制2) 调用 API 前对区域代码的输入验证3) 带有进度指示器的加载动画4) 在 localStorage 中缓存 API 响应及过期时间戳缓存时长30分钟及 5) 显示先前 API 调用历史数据的功能。同时为所有函数参数和返回类型添加适当的 TypeScript 风格 JSDoc 注释
---
在[此处](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)了解更多关于 agent 模式的信息。
## 🚀 挑战
我们在这些课程中讨论了几种类型的 API。选择一个 Web API深入研究它提供的功能。例如查看浏览器中可用的 API如 [HTML 拖放 API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API)。在你看来,什么样的 API 是优秀的?
通过探索大量浏览器 API扩展你对 API 的理解,选择以下浏览器 API 之一并构建一个小示范:
- [Geolocation API](https://developer.mozilla.org/docs/Web/API/Geolocation_API) - 获取用户当前位置信息
- [Notification API](https://developer.mozilla.org/docs/Web/API/Notifications_API) - 发送桌面通知
- [HTML Drag and Drop API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) - 创建交互式拖放界面
- [Web Storage API](https://developer.mozilla.org/docs/Web/API/Web_Storage_API) - 高级本地存储技巧
- [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) - XMLHttpRequest 的现代替代方案
**研究问题:**
- 该 API 解决了哪些现实世界的问题?
- API 如何处理错误和边界情况?
- 使用该 API 有哪些安全考虑?
- 该 API 在不同浏览器中的支持程度如何?
研究后,确定一个 API 具备哪些特性才是开发者友好且可靠的。
## 课后测验
@ -228,13 +548,117 @@ async function displayCarbonUsage(apiKey, region) {
## 复习与自学
在本课中你学习了 LocalStorage 和 API它们对专业的 Web 开发人员来说都非常有用。你能想到这两者如何协同工作吗?思考一下如何设计一个网站来存储供 API 使用的项目。
本课你学习了 LocalStorage 和 API这两者对专业 web 开发人员都非常有用。你能想到这两者是如何协同工作的吗?思考如何架构一个网站,该网站会存储供 API 使用的项目。
### ⚡ **你在接下来的 5 分钟内可以做什么**
- [ ] 打开开发者工具中的 Application 标签,探索任意网站的 localStorage
- [ ] 创建一个简单的 HTML 表单,测试浏览器的表单验证
- [ ] 尝试在浏览器控制台中存储和检索 localStorage 数据
- [ ] 使用 Network 标签检查提交的表单数据
### 🎯 **你在本小时内可以完成的任务**
- [ ] 完成课后测验并理解表单处理概念
- [ ] 构建一个保存用户偏好的浏览器扩展表单
- [ ] 实现带有友好错误提示的客户端表单验证
- [ ] 练习使用 chrome.storage API 持久化扩展数据
- [ ] 创建响应已保存用户设置的用户界面
### 📅 **你一周的扩展开发计划**
- [ ] 完成一个具备表单功能的完整浏览器扩展
- [ ] 掌握不同存储选项:本地、同步和会话存储
- [ ] 实现高级表单功能,如自动完成和验证
- [ ] 添加用户数据的导入/导出功能
- [ ] 跨不同浏览器彻底测试你的扩展
- [ ] 优化扩展的用户体验和错误处理机制
### 🌟 **你一个月的 Web API 掌握计划**
- [ ] 使用多种浏览器存储 API 构建复杂应用
- [ ] 学习离线优先开发模式
- [ ] 参与开源项目,推动数据持久化
- [ ] 掌握隐私保护开发和 GDPR 合规
- [ ] 创建用于表单处理和数据管理的可重用库
- [ ] 分享关于 Web API 和扩展开发的知识
## 🎯 你的扩展开发大师时间线
```mermaid
timeline
title API 集成与存储学习进度
section DOM 基础 (15 分钟)
元素引用: querySelector 掌握
: 事件监听器设置
: 状态管理基础
section 本地存储 (20 分钟)
数据持久化: 键值存储
: 会话管理
: 用户偏好处理
: 存储检查工具
section 表单处理 (25 分钟)
用户输入: 表单验证
: 事件阻止
: 数据提取
: UI 状态切换
section API 集成 (35 分钟)
外部通信: HTTP 请求
: 认证模式
: JSON 数据解析
: 响应处理
section 异步编程 (40 分钟)
现代 JavaScript: Promise 处理
: Async/await 模式
: 错误管理
: 非阻塞操作
section 错误处理 (30 分钟)
稳健应用: Try/catch 块
: 用户友好信息
: 优雅降级
: 调试技术
section 高级模式 (1 周)
专业发展: 缓存策略
: 速率限制
: 重试机制
: 性能优化
section 生产技能 (1 个月)
企业功能: 安全最佳实践
: API 版本管理
: 监控与日志
: 可扩展架构
```
### 🛠️ 你的全栈开发工具包总结
完成本课后,你已经具备:
- **DOM 精通**:精确定位和操作元素
- **存储专长**:使用 localStorage 进行持久化数据管理
- **API 集成**:实时数据获取和认证
- **异步编程**:使用现代 JavaScript 实现非阻塞操作
- **错误处理**:构建稳健且能优雅处理失败的应用
- **用户体验**:加载状态、验证及流畅交互
- **现代模式**fetch API、async/await 和 ES6+ 特性
**获得的专业技能**:你已实现以下模式:
- **Web 应用**:单页应用并连接外部数据源
- **移动开发**:具备离线能力的 API 驱动应用
- **桌面软件**:带持久存储的 Electron 应用
- **企业系统**:认证、缓存和错误处理
- **现代框架**React/Vue/Angular 数据管理模式
**下一个阶段**:你已准备好探索高级主题,如缓存策略、实时 WebSocket 连接或复杂状态管理!
## 作业
## 任务
[选择一个 API](assignment.md)
[采用一个 API](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译完成。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原文文件的母语版本应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,109 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "a0c78d1dd9d1acdbf7f52e7cc3ebe1a7",
"translation_date": "2025-08-23T23:40:36+00:00",
"original_hash": "25b8d28b8531352d4eb67291fd7824c4",
"translation_date": "2026-01-06T11:34:27+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/assignment.md",
"language_code": "zh"
}
-->
# 采用一个 API
## 概述
API 开启了无限的创意网页开发可能性!在本次作业中,你将选择一个外部 API并构建一个浏览器扩展以解决真实问题或为用户提供有价值的功能。
## 说明
使用 API 可以非常有趣。这里有一个[许多免费 API 的列表](https://github.com/public-apis/public-apis)。选择一个 API并构建一个解决问题的浏览器扩展。这个问题可以很小比如没有足够的宠物图片那么可以试试 [dog CEO API](https://dog.ceo/dog-api/)),也可以是更大的问题——尽情享受吧!
### 第一步:选择你的 API
从此精选的 [免费公共 API 列表](https://github.com/public-apis/public-apis) 中选择一个 API。考虑以下类别
**适合初学者的热门选项:**
- **娱乐**:用于随机狗狗图片的 [Dog CEO API](https://dog.ceo/dog-api/)
- **天气**:用于当前天气数据的 [OpenWeatherMap](https://openweathermap.org/api)
- **名言**:用于励志名言的 [Quotable API](https://quotable.io/)
- **新闻**:用于当前头条的 [NewsAPI](https://newsapi.org/)
- **趣味知识**:用于有趣数字知识的 [Numbers API](http://numbersapi.com/)
### 第二步:规划你的扩展
在编码之前回答以下规划问题:
- 你的扩展解决了什么问题?
- 目标用户是谁?
- 你将存储哪些数据在本地存储中?
- 如何处理 API 失败或速率限制?
### 第三步:构建你的扩展
你的扩展应包括:
**必备功能:**
- 用于任何必需 API 参数的表单输入
- 带有适当错误处理的 API 集成
- 本地存储用户偏好或 API 密钥
- 清晰且响应式的用户界面
- 加载状态和用户反馈
**代码要求:**
- 使用现代 JavaScript (ES6+) 特性
- 使用 async/await 进行 API 调用
- 使用 try/catch 块进行适当错误处理
- 添加有意义的注释解释代码
- 遵循一致的代码格式
### 第四步:测试和完善
- 使用各种输入测试你的扩展
- 处理边缘情况(无网络、无效 API 响应)
- 确保扩展在浏览器重启后仍然可用
- 添加用户友好的错误信息
## 额外挑战
提升你的扩展至更高层次:
- 增加多个 API 端点以实现更丰富的功能
- 实现数据缓存以减少 API 调用
- 创建常用操作的键盘快捷键
- 添加数据导出/导入功能
- 实现用户定制选项
## 提交要求
1. **可正常工作的浏览器扩展**,成功集成你选定的 API
2. **README 文件**,说明:
- 你选择了哪个 API 以及原因
- 如何安装和使用你的扩展
- 任何 API 密钥或设置需求
- 扩展运行截图
3. **干净、注释完善的代码**,符合现代 JavaScript 规范
## 评分标准
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | -------------------------------------------------------------------------- | ---------------------------------------- | ----------------------- |
| | 提交了一个完整的使用上述列表中 API 的浏览器扩展 | 提交了一个部分完成的浏览器扩展 | 提交内容存在问题或错误 |
| 评价标准 | 优秀 (90-100%) | 熟练 (80-89%) | 进展中 (70-79%) | 入门 (60-69%) |
|----------|----------------|---------------|-----------------|---------------|
| **API 集成** | 完美的 API 集成,包含全面错误处理和边缘情况管理 | 成功集成 API 并有基本错误处理 | API 可用但错误处理有限 | API 集成有严重问题 |
| **代码质量** | 干净、注释充分的现代 JavaScript符合最佳实践 | 代码结构良好,注释充足 | 代码能运行但组织需改进 | 代码质量差,注释少 |
| **用户体验** | 界面精致,加载状态和用户反馈优秀 | 界面良好,提供基本用户反馈 | 基本界面,功能正常 | 用户体验差,界面混乱 |
| **本地存储** | 高级使用本地存储,含数据验证和管理 | 正确实现本地存储关键功能 | 基础本地存储实现 | 本地存储使用少或不当 |
| **文档** | 完整 README含设置说明和截图 | 良好文档,涵盖大部分要求 | 基础文档,缺少细节 | 文档缺失或不足 |
## 入门提示
1. **从简单开始**:选择不需复杂认证的 API
2. **阅读文档**:彻底了解所选 API 的端点和响应
3. **规划界面**:先手绘扩展界面再编码
4. **频繁测试**:分步构建,完成每一功能即测试
5. **处理错误**:始终假设 API 调用可能失败并做好应对
## 资源
- [浏览器扩展文档](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions)
- [Fetch API 指南](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch)
- [本地存储教程](https://developer.mozilla.org/docs/Web/API/Window/localStorage)
- [JSON 解析与处理](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON)
祝你构建出有用且富有创意的作品!🚀
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件由人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译。尽管我们努力确保准确性,但请注意,自动翻译可能存在错误或不准确之处。原始语言的文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。因使用此翻译而产生的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,159 +1,460 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "b91cbf14240ee59411b96448b994ace1",
"translation_date": "2025-10-03T12:15:56+00:00",
"original_hash": "b275fed2c6fc90d2b9b6661a3225faa2",
"translation_date": "2026-01-06T11:34:42+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/README.md",
"language_code": "zh"
}
-->
# 浏览器扩展项目第三部分:了解后台任务和性能
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/27)
### 简介
在本模块的前两节课中,你学习了如何构建一个表单和一个用于显示从 API 获取的数据的区域。这是一种非常标准的创建网页的方式。你甚至学会了如何异步获取数据。你的浏览器扩展几乎已经完成了。
接下来需要管理一些后台任务,包括刷新扩展图标的颜色,因此这是一个很好的时机来讨论浏览器如何管理这类任务。在构建网页资源时,我们可以从性能的角度来思考这些浏览器任务。
## 网页性能基础
> “网站性能主要涉及两件事:页面加载速度和页面代码运行速度。” -- [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
如何让你的网站在各种设备、各种用户和各种情况下都能快速运行,这个话题自然非常广泛。以下是一些在构建标准网页项目或浏览器扩展时需要注意的要点。
确保网站高效运行的第一步是收集其性能数据。首选工具是网页浏览器的开发者工具。在 Edge 浏览器中,你可以点击右上角的“三点”图标(设置和更多按钮),然后导航到“更多工具 > 开发者工具”,打开“性能”选项卡。你也可以使用快捷键 `Ctrl` + `Shift` + `I`Windows`Option` + `Command` + `I`Mac打开开发者工具。
“性能”选项卡包含一个分析工具。打开一个网站(例如 [https://www.microsoft.com](https://www.microsoft.com/?WT.mc_id=academic-77807-sagibbon)),点击“记录”按钮,然后刷新网站。随时停止记录,你将能够看到生成的脚本、渲染和绘制网站的例程:
![Edge 分析工具](../../../../translated_images/profiler.5a4a62479c5df01cfec9aab74173dba13f91d2c968e1a1ae434c26165792df15.zh.png)
✅ 访问 [Microsoft 文档](https://docs.microsoft.com/microsoft-edge/devtools-guide/performance/?WT.mc_id=academic-77807-sagibbon),了解 Edge 中性能面板的使用方法。
> 提示:为了获得网站启动时间的准确读数,请清除浏览器缓存。
选择性能时间轴中的元素,放大页面加载时发生的事件。
通过选择性能时间轴的一部分并查看摘要面板,获取页面性能的快照:
![Edge 分析工具快照](../../../../translated_images/snapshot.97750180ebcad73794a3594b36925eb5c8dbaac9e03fec7f9b974188c9ac63c7.zh.png)
检查事件日志面板,查看是否有任何事件耗时超过 15 毫秒:
![Edge 事件日志](../../../../translated_images/log.804026979f3707e00eebcfa028b2b5a88cec6292f858767bb6703afba65a7d9c.zh.png)
✅ 熟悉分析工具!打开本网站的开发者工具,看看是否存在瓶颈。加载最慢的资源是什么?最快的又是什么?
## 性能检查
通常来说,每个网页开发者在构建网站时都应该注意一些“问题区域”,以避免在部署到生产环境时出现意外。
**资源大小**:近年来,网页变得“更重”,因此加载速度也变慢了。这种“重量”部分是由于图片的使用。
✅ 浏览 [互联网档案馆](https://httparchive.org/reports/page-weight),查看网页重量的历史变化及更多信息。
一个好的做法是确保图片经过优化,并以适合用户的大小和分辨率进行传输。
**DOM 遍历**:浏览器需要根据你编写的代码构建其文档对象模型,因此为了良好的页面性能,应该尽量简化标签,仅使用和样式化页面所需的内容。例如,与页面相关的多余 CSS 可以进行优化,仅在某些页面需要的样式不需要包含在主样式表中。
**JavaScript**:每个 JavaScript 开发者都应该注意“渲染阻塞”脚本,这些脚本必须在浏览器能够遍历和绘制 DOM 之前加载。考虑在内联脚本中使用 `defer`(如在 Terrarium 模块中所做)。
# 浏览器扩展项目 第3部分了解后台任务与性能
```mermaid
journey
title 你的性能优化之旅
section 基础
学习浏览器工具: 3: Student
理解性能分析: 4: Student
识别瓶颈: 4: Student
section 扩展功能
构建配色系统: 4: Student
创建后台任务: 5: Student
动态更新图标: 5: Student
section 优化
监控性能: 5: Student
调试问题: 4: Student
精细体验: 5: Student
```
有没有想过为什么有些浏览器扩展感觉响应迅速而灵敏,而另一些则显得迟缓?秘诀就在幕后。在用户点击扩展界面时,后台有一系列进程静静管理数据获取、图标更新和系统资源。
✅ 在 [网站速度测试网站](https://www.webpagetest.org/) 上尝试一些网站,了解常见的性能检查方法
这是浏览器扩展系列的最后一课,我们将让你的碳足迹追踪器流畅运行。你将添加动态图标更新,并学习如何在性能问题出现前发现它们。这就像调校赛车——小优化能大幅提升整体运行表现。
现在你已经了解了浏览器如何渲染你发送的资源,让我们看看完成扩展所需的最后几步:
完成后,你将拥有一个打磨完善的扩展,并理解区分优秀及卓越 web 应用的性能原则。让我们探索浏览器优化的世界吧。
### 创建一个计算颜色的函数
## 课前测验
`/src/index.js` 中,在你设置的用于访问 DOM 的一系列 `const` 变量之后,添加一个名为 `calculateColor()` 的函数:
[课前测验](https://ff-quizzes.netlify.app/web/quiz/27)
```JavaScript
### 介绍
在之前的课程中,你已搭建了表单,连接 API并处理异步数据获取。你的扩展已初具雏形。
现在我们需要添加最后的润色 —— 比如让扩展图标根据碳数据变换颜色。这让我想起 NASA 优化阿波罗飞船每个系统时的状态。它们必须最大化利用每个周期和内存,因为性能关乎生命。虽然我们的浏览器扩展没那么关键,但同样原则适用——高效代码带来更佳用户体验。
```mermaid
mindmap
root((性能与后台任务))
Browser Performance
渲染管线
资源优化
DOM 操作
JavaScript 执行
Profiling Tools
开发者工具
性能标签页
时间线分析
瓶颈检测
Extension Architecture
后台脚本
内容脚本
消息传递
图标管理
Optimization Strategies
代码拆分
延迟加载
缓存
资源压缩
Visual Feedback
动态图标
颜色编码
实时更新
用户体验
```
## Web 性能基础
当代码高效运行时,人们真的能*感受到*区别。你知道页面瞬间加载或者动画流畅时的那种感觉吗?这就是良好性能的体现。
性能不仅是速度而是打造自然流畅而非笨拙挫败的网页体验。在计算机早期Grace Hopper 著名地将一根约一英尺长的细线放在桌上,演示光在十亿分之一秒内的传播距离,用以说明每一微秒在计算中的重要性。让我们探索帮助你找出性能瓶颈的侦查工具吧。
> “网站性能关乎两个方面:页面加载的速度,以及代码运行的速度。” —— [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
让网站在各种设备、各种用户、各种情况下极速运行的话题自然非常庞杂。以下是你构建普通网页项目或浏览器扩展时需牢记的要点。
优化网站的第一步是理解底层的实际运作。幸运的是,浏览器内置了强大的侦查工具。
```mermaid
flowchart LR
A[HTML] --> B[解析]
B --> C[DOM树]
D[CSS] --> E[解析]
E --> F[CSSOM]
G[JavaScript] --> H[执行]
C --> I[渲染树]
F --> I
H --> I
I --> J[布局]
J --> K[绘制]
K --> L[合成]
L --> M[显示]
subgraph "关键渲染路径"
N["1. 解析HTML"]
O["2. 解析CSS"]
P["3. 执行JS"]
Q["4. 构建渲染树"]
R["5. 布局元素"]
S["6. 绘制像素"]
T["7. 合成图层"]
end
style M fill:#e8f5e8
style I fill:#fff3e0
style H fill:#ffebee
```
在 Edge 中打开开发者工具,点击右上角的三点菜单,选择 更多工具 > 开发者工具。或者使用快捷键Windows 上为 `Ctrl` + `Shift` + `I`Mac 上为 `Option` + `Command` + `I`。进入后点击 Performance性能标签页 —— 这里是你的调查现场。
**这是你的性能侦查工具箱:**
- **打开** 开发者工具(开发者必备!)
- **切换** 到 Performance 标签页,想象它是你的网页健康追踪器
- **点击** 录制按钮,然后观察页面动作
- **分析** 结果以发现性能瓶颈
试试吧。打开一个网站(例如 Microsoft.com点击“录制”然后刷新页面查看性能分析器捕捉的一切。当停止录制你会看到浏览器如何“脚本执行”scripts、“渲染”renders和“绘制”paints的详细分解。这让我想起火箭发射时指挥中心监控所有系统——你获取实时且详细的操作数据。
![Edge profiler](../../../../translated_images/profiler.5a4a62479c5df01c.zh.png)
✅ 若想深入了解,请查阅 [微软文档](https://docs.microsoft.com/microsoft-edge/devtools-guide/performance/?WT.mc_id=academic-77807-sagibbon)
> 专业提示:测试前请清理浏览器缓存,查看首次访问者的页面性能——通常与重复访问完全不同!
选取时间线上的部分,放大查看加载时发生的事件。
通过选取时间线片段,查看摘要面板,获得页面性能快照:
![Edge profiler snapshot](../../../../translated_images/snapshot.97750180ebcad737.zh.png)
查看事件日志面板是否有事件耗时超过15毫秒
![Edge event log](../../../../translated_images/log.804026979f3707e0.zh.png)
✅ 熟悉你的分析器!在本站打开开发者工具,看看是否存在瓶颈。加载最慢和最快的资源分别是什么?
```mermaid
flowchart TD
A[打开开发者工具] --> B[导航到性能标签]
B --> C[点击录制按钮]
C --> D[执行操作]
D --> E[停止录制]
E --> F{分析结果}
F --> G[检查时间线]
F --> H[审核网络]
F --> I[检查脚本]
F --> J[识别绘制事件]
G --> K{长任务?}
H --> L{大型资源?}
I --> M{渲染阻塞?}
J --> N{昂贵的绘制?}
K -->|是| O[优化JavaScript]
L -->|是| P[压缩资源]
M -->|是| Q[添加异步/延迟]
N -->|是| R[简化样式]
O --> S[重新测试]
P --> S
Q --> S
R --> S
style A fill:#e1f5fe
style F fill:#fff3e0
style S fill:#e8f5e8
```
## 分析时要注意什么
运行分析器只是第一步——真正的技能是理解这些彩色图表告诉你的信息。不用怕,你会学会解读它们。经验丰富的开发者已能提前发现警示信号,防止问题加剧。
让我们聊聊常见的嫌疑犯——那种经常潜入网页项目的性能杀手。正如玛丽·居里在实验室细致监测辐射水平,我们也须警惕表明潜在麻烦的模式。及早发现会省去你和用户大量麻烦。
**资源大小**:随着时间推移,网站变得“越来越重”,大部分增长来自图片。就像我们在数码行李箱里塞了越来越多东西。
✅ 请浏览 [Internet Archive](https://httparchive.org/reports/page-weight) 看看页面大小的历史增长——颇有启发。
**保持资源优化的小窍门:**
- **压缩** 图片!现代格式如 WebP 会大幅减小文件体积
- **根据设备** 提供合适尺寸的图片——不必给手机发送庞大的桌面图片
- **压缩** CSS 和 JavaScript——每个字节都重要
- **使用** 延迟加载,让图片只有在用户滚动到时才下载
**DOM 遍历**浏览器基于你写的代码构建文档对象模型DOM为了良好的页面性能应保持标签最少仅使用和样式化必须的元素。过多的 CSS 也能优化;例如,只在某页使用的样式无需包含在主样式表中。
**DOM 优化关键策略:**
- **减少** HTML 元素和嵌套层级数量
- **移除** 未使用的 CSS 规则并高效合并样式表
- **组织** CSS 只加载每页所需样式
- **语义化** HTML 结构以协助浏览器解析
**JavaScript**:每位 JS 开发者需警惕“阻塞渲染”的脚本——须在 DOM 遍历与绘制前加载完毕。可以考虑用 `defer` 属性延迟内联脚本加载(如 Terrarium 模块所用)。
**现代 JavaScript 优化技巧:**
- **使用** `defer` 属性让脚本在 DOM 解析后加载
- **实现** 代码拆分,只加载必要的 JS
- **应用** 延迟加载非关键功能
- **尽量减少** 依赖重量级库与框架
✅ 可通过 [Site Speed Test 网站](https://www.webpagetest.org/) 试测一些站点,了解常规的性能检测点。
### 🔄 **教学回顾**
**性能理解**:在构建扩展功能前,确保你能:
- ✅ 解释从HTML到像素的关键渲染路径
- ✅ 识别网页应用常见性能瓶颈
- ✅ 使用浏览器开发工具分析页面性能
- ✅ 理解资源大小和 DOM 复杂度如何影响速度
**快速自测**:遇到阻塞渲染的 JavaScript 会发生什么?
*答:浏览器必须先下载并执行脚本,才能继续解析 HTML 并渲染页面。*
**现实世界性能影响**
- **100毫秒延迟**:用户能感知到缓慢
- **1秒延迟**:用户开始失去注意力
- **3秒以上**40% 用户离开页面
- **移动网络**:性能更为重要
了解浏览器如何渲染你发送的资源后,来看完成扩展还需做的几件事:
### 创建颜色计算函数
现在我们创建一个函数,将数值数据转成有意义的颜色。就像交通灯系统——绿色表示清洁能源,红色代表高碳强度。
该函数将以 API 返回的 CO2 数据为基础,确定最能反映环境影响的颜色。这类似科学家使用色彩编码的热力图,可视化复杂数据模式——从海洋温度到恒星形成。把这个函数加到 `/src/index.js`,紧跟前面声明的 `const` 变量之后:
```mermaid
flowchart LR
A[二氧化碳值] --> B[找到最近的刻度点]
B --> C[获取刻度索引]
C --> D[映射到颜色]
D --> E[发送到后台]
subgraph "颜色刻度"
F["0-150: 绿色(清洁)"]
G["150-600: 黄色(中等)"]
H["600-750: 橙色(高)"]
I["750+: 棕色(非常高)"]
end
subgraph "消息传递"
J[内容脚本]
K[chrome.runtime.sendMessage]
L[后台脚本]
M[图标更新]
end
style A fill:#e1f5fe
style D fill:#e8f5e8
style E fill:#fff3e0
```
```javascript
function calculateColor(value) {
let co2Scale = [0, 150, 600, 750, 800];
let colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
// 定义二氧化碳强度尺度(克/千瓦时)
const co2Scale = [0, 150, 600, 750, 800];
// 对应颜色从绿色(清洁)到深棕色(高碳)
const colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
let closestNum = co2Scale.sort((a, b) => {
// 找到与输入值最接近的尺度值
const closestNum = co2Scale.sort((a, b) => {
return Math.abs(a - value) - Math.abs(b - value);
})[0];
console.log(value + ' is closest to ' + closestNum);
let num = (element) => element > closestNum;
let scaleIndex = co2Scale.findIndex(num);
let closestColor = colors[scaleIndex];
console.log(`${value} is closest to ${closestNum}`);
// 查找颜色映射的索引
const num = (element) => element > closestNum;
const scaleIndex = co2Scale.findIndex(num);
const closestColor = colors[scaleIndex];
console.log(scaleIndex, closestColor);
// 向后台脚本发送颜色更新消息
chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } });
}
```
这里发生了什么?你传入一个值(来自上节课完成的 API 调用的碳强度),然后计算其值与颜色数组中索引的接近程度。接着,你将最接近的颜色值发送到 chrome runtime。
chrome.runtime 有一个 [API](https://developer.chrome.com/extensions/runtime),可以处理各种后台任务,而你的扩展正在利用它:
> “使用 chrome.runtime API 检索后台页面,返回有关清单的详细信息,并监听和响应应用或扩展生命周期中的事件。你还可以使用此 API 将 URL 的相对路径转换为完全限定的 URL。”
✅ 如果你正在为 Edge 开发此浏览器扩展,可能会惊讶于你正在使用 chrome API。较新的 Edge 浏览器版本运行在 Chromium 浏览器引擎上,因此你可以利用这些工具。
> 注意,如果你想分析浏览器扩展,请从扩展本身内部启动开发者工具,因为它是一个独立的浏览器实例。
**解析这巧妙函数:**
- **初始化了** 两个数组——一个存 CO2 级别,另一个存颜色(绿代表清洁,棕色代表污染)
- **通过数组排序** 找到最接近实际 CO2 值的匹配
- **用 findIndex() 方法** 获取对应的颜色索引
- **向 Chrome 后台脚本发送** 选定颜色的消息
- **借助模板字符串** (反引号)简化字符串格式化
- **用 const** 保持代码整洁有序
`chrome.runtime` [API](https://developer.chrome.com/extensions/runtime) 就像扩展的神经系统——负责幕后通信和任务处理:
> “使用 chrome.runtime API 可以访问后台页面,获取清单详情,监听并响应应用或扩展生命周期中的事件。此 API 还可将 URL 相对路径转换为完整 URL。”
**Chrome Runtime API 的便捷之处:**
- **让** 扩展各部分相互通信
- **处理** 后台工作,避免冻结用户界面
- **管理** 扩展生命周期事件
- **简化** 脚本间消息传递
✅ 如果你在 Edge 浏览器上开发此扩展,可能会惊讶于使用的是 chrome API。新版 Edge 基于 Chromium 引擎,因此能利用这些工具。
```mermaid
architecture-beta
group browser(logos:chrome)[浏览器]
service popup(logos:html5)[弹出界面] in browser
service content(logos:javascript)[内容脚本] in browser
service background(database)[后台脚本] in browser
service api(logos:api)[外部API] in browser
popup:R -- L:content
content:R -- L:background
background:T -- B:api
content:T -- B:api
junction junctionCenter in browser
popup:R -- L:junctionCenter
junctionCenter:R -- L:background
```
> **专业提示**:要分析浏览器扩展性能,从扩展自身启动开发者工具。因为它是独立的浏览器实例,可查看扩展特定性能指标。
### 设置默认图标颜色
现在,在 `init()` 函数中,通过调用 chrome 的 `updateIcon` 操作,将图标设置为初始的绿色:
在开始获取真实数据前,给扩展一个初始状态。没人喜欢看空白或损坏的图标。我们先用绿色,保证安装即可见扩展正常工作。
在你的 `init()` 函数里,配置默认的绿色图标:
```JavaScript
```javascript
chrome.runtime.sendMessage({
action: 'updateIcon',
value: {
color: 'green',
},
value: {
color: 'green',
},
});
```
### 调用函数并执行调用
接下来,通过将其添加到 C02Signal API 返回的 promise 中,调用你刚刚创建的函数:
**此初始化实现了:**
- **设为** 中性绿色作为默认状态
- **加载时** 立即提供视觉反馈
- **建立** 与后台脚本的通信模式
- **确保** 数据加载前用户见到的是正常的扩展图标
```JavaScript
//let CO2...
### 调用函数,执行更新
现在将各部分连线,等到有最新 CO2 数据时,图标能自动变色。就像装置电路接通,组件齐心协力。
在拿到 API 返回的 CO2 数据后,加上这条调用语句:
```javascript
// 从API获取CO2数据后
// 让CO2 = data.data[0].intensity.actual;
calculateColor(CO2);
```
最后,在 `/dist/background.js` 中,为这些后台操作调用添加监听器:
**该整合实现了:**
- **连接** API 数据流和视觉指示器系统
- **当新数据到来时** 触发图标自动更新
- **保证** 依据当前碳强度实时反馈视觉效果
- **保持** 数据获取与显示逻辑分离
最后,在 `/dist/background.js` 里添加监听这些后台操作的监听器:
```JavaScript
```javascript
// 监听来自内容脚本的消息
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.action === 'updateIcon') {
chrome.action.setIcon({ imageData: drawIcon(msg.value) });
}
});
//borrowed from energy lollipop extension, nice feature!
// 使用 Canvas API 绘制动态图标
// 借鉴自 energy lollipop 扩展 - 很棒的功能!
function drawIcon(value) {
let canvas = new OffscreenCanvas(200, 200);
let context = canvas.getContext('2d');
// 创建一个离屏画布以获得更好的性能
const canvas = new OffscreenCanvas(200, 200);
const context = canvas.getContext('2d');
// 绘制一个代表碳强度的彩色圆圈
context.beginPath();
context.fillStyle = value.color;
context.arc(100, 100, 50, 0, 2 * Math.PI);
context.fill();
// 返回浏览器图标的图像数据
return context.getImageData(50, 50, 100, 100);
}
```
在这段代码中,你为任何发送到后台任务管理器的消息添加了一个监听器。如果消息名为 'updateIcon',则运行接下来的代码,使用 Canvas API 绘制正确颜色的图标。
**这个后台脚本功能是:**
- **监听** 来自主脚本的消息(像前台接听电话)
- **处理** “updateIcon” 请求,更新工具栏图标
- **用 Canvas API** 动态创建图标
- **绘制** 一个位彩色圆,展示当前碳强度
- **更新** 浏览器工具栏图标
- **利用 OffscreenCanvas** 保持流畅性能(无界面阻塞)
✅ 你将在 [太空游戏课程](../../6-space-game/2-drawing-to-canvas/README.md) 中学到更多 Canvas API 知识。
```mermaid
sequenceDiagram
participant CS as 内容脚本
participant BG as 后台脚本
participant Canvas as 离屏画布
participant Browser as 浏览器图标
CS->>BG: sendMessage({action: 'updateIcon', color})
BG->>Canvas: new OffscreenCanvas(200, 200)
Canvas->>Canvas: getContext('2d')
Canvas->>Canvas: beginPath() + fillStyle + arc()
Canvas->>Canvas: fill() + getImageData()
Canvas->>BG: 返回图像数据
BG->>Browser: chrome.action.setIcon(imageData)
Browser->>Browser: 更新工具栏图标
```
### 🔄 **教学回顾**
**完整扩展理解**:确认你已掌握整个系统:
- ✅ 不同扩展脚本间怎样进行消息传递?
- ✅ 为什么为性能考虑使用 OffscreenCanvas 而不是普通 Canvas
- ✅ Chrome Runtime API 在扩展架构中扮演什么角色?
- ✅ 颜色计算算法如何将数据映射到视觉反馈?
✅ 你将在 [太空游戏课程](../../6-space-game/2-drawing-to-canvas/README.md) 中学习更多关于 Canvas API 的内容。
**性能考虑**:您的扩展现在展示了:
- **高效消息传递**:脚本上下文间清晰通信
- **优化渲染**OffscreenCanvas 防止界面阻塞
- **实时更新**:基于实时数据的动态图标变化
- **内存管理**:适当的清理和资源处理
现在,重新构建你的扩展(`npm run build`),刷新并启动你的扩展,观察颜色变化。是时候去跑个腿或洗碗了吗?现在你知道了!
**是时候测试您的扩展了:**
- **通过** `npm run build` 构建所有内容
- **重新加载** 浏览器中的扩展(别忘了这一步)
- **打开** 您的扩展,观察图标的颜色变化
- **检查** 它如何响应来自全球的实时碳数据
恭喜你,你已经构建了一个实用的浏览器扩展,并进一步了解了浏览器的工作原理以及如何分析其性能。
现在您可以一目了然地知道,洗这批衣服是否合适,或者是否应该等待更清洁的能源。您刚刚构建了一个真正有用的东西,并在过程中学习了浏览器性能。
---
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 通过添加跟踪并显示扩展不同组件加载时间的功能,增强浏览器扩展的性能监控能力。
**提示:** 创建一个性能监控系统,用于测量和记录从 API 获取 CO2 数据、计算颜色和更新图标所需的时间。添加一个名为 `performanceTracker` 的函数,使用 Performance API 测量这些操作,并在浏览器控制台以时间戳和持续时间指标的形式显示结果。
了解更多关于[agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)的信息。
## 🚀 挑战
调查一些存在已久的开源网站,并根据其 GitHub 历史记录,看看它们是否在性能方面进行了优化。如果有,是什么时候进行的?最常见的痛点是什么?
这是一个有趣的侦探任务:挑选一些存在多年的开源网站(如 Wikipedia、GitHub 或 Stack Overflow深入研究它们的提交历史。你能发现它们在哪里做出了性能改进吗反复出现了哪些问题
**你的调查方法:**
- **搜索** 包含“优化”、“性能”或“更快”等关键词的提交信息
- **观察** 有无模式 —— 它们是否持续修复相同类型的问题?
- **识别** 影响网站性能的常见元凶
- **分享** 你的发现 —— 让其他开发者从真实案例中学习
## 课后测验
@ -161,9 +462,128 @@ function drawIcon(value) {
## 复习与自学
考虑订阅一个 [性能新闻简报](https://perf.email/)
通过浏览器的开发者工具中的性能选项卡,调查浏览器评估网页性能的一些方法。你发现了哪些主要差异?
考虑订阅一个[性能通讯](https://perf.email/)
通过浏览器开发工具中的性能标签页,调查浏览器衡量网页性能的一些方法。你发现了哪些主要差异?
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开浏览器任务管理器Chrome 中按 Shift+Esc查看扩展资源使用情况
- [ ] 使用 DevTools 的性能标签页录制并分析网页性能
- [ ] 检查浏览器的扩展页,查看哪些扩展影响启动时间
- [ ] 尝试暂时禁用扩展,观察性能变化
### 🎯 **本小时你可以完成什么**
- [ ] 完成课后测验,理解性能概念
- [ ] 为你的浏览器扩展实现一个后台脚本
- [ ] 学习使用 browser.alarms 进行高效后台任务
- [ ] 练习内容脚本与后台脚本之间的消息传递
- [ ] 测量并优化扩展的资源使用
### 📅 **你的为期一周的性能之旅**
- [ ] 完成一个具有后台功能的高性能浏览器扩展
- [ ] 精通 service workers 和现代扩展架构
- [ ] 实现高效的数据同步与缓存策略
- [ ] 学习扩展性能的高级调试技术
- [ ] 优化扩展的功能与资源效率
- [ ] 创建全面的扩展性能测试方案
### 🌟 **你为期一个月的优化精通**
- [ ] 构建企业级高性能浏览器扩展
- [ ] 学习 Web Workers、Service Workers 和现代网页性能
- [ ] 参与性能优化相关的开源项目
- [ ] 掌握浏览器内部原理和高级调试技术
- [ ] 创建性能监控工具和最佳实践指南
- [ ] 成为帮助优化网页应用的性能专家
## 🎯 你的浏览器扩展精通时间线
```mermaid
timeline
title 完整扩展开发进度
section 性能基础20分钟
浏览器分析: DevTools 掌握
: 时间线分析
: 瓶颈识别
: 关键渲染路径
section 后台任务25分钟
扩展架构: 消息传递
: 后台脚本
: 运行时API使用
: 跨上下文通信
section 视觉反馈30分钟
动态UI: 颜色计算算法
: Canvas API集成
: 图标生成
: 实时更新
section 性能优化35分钟
高效代码: 异步操作
: 内存管理
: 资源清理
: 性能监控
section 生产准备45分钟
打磨与测试: 跨浏览器兼容性
: 错误处理
: 用户体验
: 性能验证
section 高级功能1周
扩展生态系统: Chrome 网上应用店
: 用户反馈
: 分析集成
: 更新管理
section 职业发展2周
企业扩展: 团队协作
: 代码审查
: CI/CD 流水线
: 安全审计
section 专家精通1个月
平台专长: 高级 Chrome API
: 性能优化
: 架构模式
: 开源贡献
```
### 🛠️ 你的完整扩展开发工具包
完成本三部曲后,你已经掌握:
- **浏览器架构**:深入理解扩展如何与浏览器系统集成
- **性能分析**:使用开发者工具识别并修复瓶颈
- **异步编程**:现代 JavaScript 模式实现响应式、非阻塞操作
- **API 集成**:带认证和错误处理的外部数据获取
- **视觉设计**:动态 UI 更新和基于 Canvas 的图形生成
- **消息传递**:扩展架构中脚本间通信
- **用户体验**:加载状态、错误处理与直观交互
- **生产技能**:面向真实场景的测试、调试与优化
**真实应用场景**:你的扩展开发技能直接应用于:
- **渐进式网页应用**:相似的架构与性能模式
- **Electron 桌面应用**:使用网页技术的跨平台应用
- **移动混合应用**:基于 Cordova/PhoneGap 的网页 API 应用
- **企业网页应用**:复杂的仪表盘和生产力工具
- **Chrome DevTools 扩展**:高级开发者工具与调试
- **网页 API 集成**:与外部服务通信的任何应用
**职业影响力**:你现在可以:
- **构建** 从概念到部署的生产级浏览器扩展
- **优化** 使用行业标准分析工具提升网页性能
- **设计** 可扩展且关注点分离良好的系统架构
- **调试** 复杂的异步操作和跨上下文通信
- **贡献** 于开源扩展项目和浏览器标准
**升级机会**
- **Chrome 网上应用店开发者**:发布面向数百万用户的扩展
- **网页性能工程师**:专注优化和用户体验
- **浏览器平台开发者**:参与浏览器引擎开发
- **扩展框架创建者**:构建辅助开发者的工具
- **开发者关系**:通过教学和内容创作分享知识
🌟 **成就解锁**:你已经构建了一个完整、功能齐全的浏览器扩展,展示了专业开发实践和现代网页标准!
## 作业
@ -171,5 +591,7 @@ function drawIcon(value) {
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
本文件由人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译而成。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能存在错误或不准确之处。原始语言的文件应视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,21 +1,109 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "fc09b0fb314a5ab0507ba99216e6a843",
"translation_date": "2025-08-23T23:47:38+00:00",
"original_hash": "a203e560e58ccc6ba68bffc40c7c8676",
"translation_date": "2026-01-06T11:36:13+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/assignment.md",
"language_code": "zh"
}
-->
# 分析网站性能
提供一个网站的详细报告,指出性能存在问题的区域。分析网站为何运行缓慢,并提出加速的解决方案。不仅仅依赖浏览器工具,还要研究其他可以帮助完成报告的工具。
## 任务概述
性能分析是现代网页开发者的一项关键技能。在本任务中,你将使用浏览器内置工具和第三方服务,对一个真实网站进行全面的性能审计,识别性能瓶颈并提出优化策略。
你的任务是提交一份详细的性能报告,展示你对网页性能原理的理解以及有效使用专业分析工具的能力。
## 任务说明
**选择一个网站**进行分析——可从以下选项中选择:
- 你经常使用的热门网站(新闻站点、社交媒体、电商)
- 开源项目网站GitHub Pages、文档站点
- 本地商家网站或个人作品集
- 你自己的项目或以往课程作业
**多工具分析**,至少使用三种不同的方法:
- **浏览器开发者工具**——使用 Chrome/Edge 的 Performance 选项卡进行详细性能分析
- **在线审计工具**——尝试 Lighthouse、GTmetrix 或 WebPageTest
- **网络分析**——检查资源加载、文件大小和请求模式
**在报告中详细记录发现内容**,应包含:
### 性能指标分析
- 多工具、多角度的**加载时间测量**
- **核心网页指标**得分LCP、FID、CLS及其影响
- **资源细分**,显示哪些资源对加载时间贡献最大
- **网络瀑布图分析**,识别阻塞资源
### 问题识别
- **具体性能瓶颈**,并附带数据支持
- **根本原因分析**,解释问题产生原因
- **用户影响评估**,描述问题如何影响真实用户体验
- **优先级排序**,基于严重程度和修复难度排列问题优先级
### 优化建议
- **具体可行的改进措施**及预期效果
- **每项改进的实施方案**
- 可采用的**现代最佳实践**(懒加载、压缩等)
- **持续性能监控**的工具和技术
## 研究要求
**不要仅依靠浏览器工具**,扩展分析使用:
**第三方审计服务:**
- [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) — 综合审计
- [GTmetrix](https://gtmetrix.com/) — 性能和优化洞察
- [WebPageTest](https://www.webpagetest.org/) — 真实环境测试
- [Pingdom](https://tools.pingdom.com/) — 全球性能监控
**专业分析工具:**
- [Bundle Analyzer](https://bundlephobia.com/) — JavaScript 包大小分析
- [Image optimization tools](https://squoosh.app/) — 资源优化机会
- [Security headers analysis](https://securityheaders.com/) — 安全性能影响
## 成果格式
制作一份专业报告2-3 页),包含:
1. **执行摘要** — 关键发现和建议概述
2. **方法论** — 使用的工具和测试方法
3. **当前性能评估** — 基线指标和测量结果
4. **识别的问题** — 详细的问题分析和数据支持
5. **建议方案** — 优先级改进策略
6. **实施路线图** — 逐步的优化计划
**包含视觉证据:**
- 性能工具及指标的截图
- 显示性能数据的图表
- 可能的前后对比
- 网络瀑布图和资源细分图
## 评分标准
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | ---------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------- |
| | 报告详细,信息不仅来源于浏览器工具,还包括可用的第三方工具的分析 | 提供了基本的报告 | 报告内容非常简略 |
| 标准 | 优秀 (90-100%) | 及格 (70-89%) | 有待改进 (50-69%) |
| -------- | ------------------- | ----------------- | -------------------------- |
| **分析深度** | 使用4+工具的全面分析,包含详细指标、根因分析和用户影响评估 | 使用3个工具有清晰指标和基本问题识别 | 使用2个工具分析浅显问题识别有限 |
| **工具多样性** | 使用浏览器工具+3个以上第三方服务包含比较分析和洞察 | 使用浏览器工具+2个第三方服务有一定比较分析 | 使用浏览器工具+1个第三方服务比较有限 |
| **问题识别** | 识别5个以上具体性能问题包含详细根因分析和量化影响 | 识别3-4个性能问题具备良好分析及部分影响测量 | 识别1-2个性能问题分析基础 |
| **建议方案** | 提供具体、可行建议,附实施细节、预期效果及现代最佳实践 | 提供良好建议,含部分实施指导和预期成果 | 提供基础建议,实施细节有限 |
| **专业呈现** | 报告结构清晰,层次分明,附视觉证据和执行摘要,格式专业 | 报告组织良好,有部分视觉证据和清晰结构 | 组织基础,视觉证据有限 |
## 学习成果
完成本任务后,你将能:
- **应用**专业性能分析工具和方法
- **识别**基于数据分析的性能瓶颈
- **分析**代码质量与用户体验之间的关系
- **推荐**具体且可实施的优化方案
- **以专业格式**传达技术发现
该任务加深了你对课程中性能概念的理解,同时培养了你在网页开发职业生涯中将持续用到的实用技能。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对于因使用此翻译而引起的任何误解或误读不承担责任。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们致力于保证准确性,但请注意自动翻译可能存在错误或不准确之处。原始文件的原语言版本应被视为权威来源。对于关键信息,建议采用专业人工翻译。对于因使用本翻译导致的任何误解或误读,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,50 +1,142 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "979cfcce2413a87d9e4c67eb79234bc3",
"translation_date": "2025-08-29T14:47:35+00:00",
"original_hash": "a6332a7bb4d0be3bfd24199c83993777",
"translation_date": "2026-01-06T11:29:06+00:00",
"source_file": "6-space-game/1-introduction/README.md",
"language_code": "zh"
}
-->
# 构建太空游戏第一部分:介绍
![video](../../../../6-space-game/images/pewpew.gif)
# 构建一个太空游戏 第一部分: 介绍
```mermaid
journey
title 你的游戏开发旅程
section 基础
Learn game architecture: 3: Student
Understand inheritance: 4: Student
Explore composition: 4: Student
section 通信
Build pub/sub system: 4: Student
Design event flow: 5: Student
Connect components: 5: Student
section 应用
Create game objects: 5: Student
Implement patterns: 5: Student
Plan game structure: 5: Student
```
![太空游戏动画显示游戏玩法](../../../../6-space-game/images/pewpew.gif)
就像美国宇航局的任务控制中心在发射过程中协调多个系统一样,我们将构建一个太空游戏,展示程序的不同部分如何无缝协作。在创建一个你可以实际玩的项目时,你将学习适用于任何软件项目的基本编程概念。
我们将探索组织代码的两种基本方法:继承和组合。这不仅仅是学术概念——它们是驱动从视频游戏到银行系统所有内容的相同模式。我们还将实现一个名为发布/订阅pub/sub的通信系统它类似于航天器中使用的通信网络允许不同组件共享信息而不产生依赖关系。
通过本系列课程的结束你将理解如何构建可扩展和演进的应用程序——无论你是开发游戏、Web应用程序还是任何其他软件系统。
```mermaid
mindmap
root((游戏架构))
Object Organization
继承
组合
类层次结构
行为混合
Communication Patterns
发布/订阅系统
事件发射器
消息传递
松耦合
Game Objects
属性 (x, y)
行为 (移动, 碰撞)
生命周期管理
状态管理
Design Patterns
工厂函数
观察者模式
组件系统
事件驱动架构
Scalability
模块化设计
可维护代码
测试策略
性能优化
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/29)
### 游戏开发中的继承与组合
## 游戏开发中的继承与组合
在之前的课程中,由于项目规模较小,几乎不需要考虑应用程序的设计架构。然而,当你的应用程序规模和范围扩大时,架构决策就变得更加重要。在 JavaScript 中创建大型应用程序有两种主要方法:*组合* 或 *继承*。两者各有优缺点,但我们可以通过游戏的背景来解释它们。
随着项目复杂度增大,代码组织变得尤为关键。最初简单的脚本如果没有良好的结构,维护会变得困难——就像阿波罗任务需要对上千个组件进行细致协作一样
✅ 最著名的编程书籍之一与[设计模式](https://en.wikipedia.org/wiki/Design_Patterns)有关。
我们将探索两种组织代码的基本方式:继承和组合。每种都有独特的优点,理解它们有助于你在不同情况下选择合适的方式。我们将通过太空游戏进行演示,其中英雄、敌人、道具以及其他对象必须高效互动
在游戏中,你有 `游戏对象`,它们是屏幕上的对象。这意味着它们在笛卡尔坐标系中有一个位置,由 `x``y` 坐标来表示。当你开发游戏时,你会注意到所有的游戏对象都有一个标准属性,这些属性在你创建的每个游戏中都很常见,即:
✅ 一本最著名的编程书籍就讲述了[设计模式](https://en.wikipedia.org/wiki/Design_Patterns)。
- **基于位置** 大多数游戏元素都是基于位置的。这意味着它们有一个位置,即 `x``y`
- **可移动** 这些对象可以移动到新位置。通常是英雄、怪物或 NPC非玩家角色但例如树这样的静态对象则不是。
- **自我销毁** 这些对象只存在一段时间,然后设置自己为删除状态。通常通过一个 `dead``destroyed` 的布尔值来表示,告诉游戏引擎该对象不再需要渲染。
- **冷却时间** “冷却时间”是短生命周期对象的典型属性。一个典型的例子是文本或图形效果(如爆炸),它们只需要显示几毫秒。
在任何游戏中,你都有 `游戏对象`——填充游戏世界的交互元素。英雄、敌人、道具和视觉特效都是游戏对象。它们都存在于特定屏幕坐标,用 `x``y` 值表示,类似于在坐标平面上绘点。
✅ 想想像吃豆人这样的游戏。你能在这个游戏中识别出上述四种对象类型吗?
尽管外观不同,这些对象通常共享基本行为:
### 表达行为
- **它们存在于某处** —— 每个对象都有 x 和 y 坐标,游戏才能知道在哪里绘制它
- **许多对象可以移动** —— 英雄奔跑,敌人追逐,子弹飞过屏幕
- **它们有生命周期** —— 有些永久存在,另一些(比如爆炸)短暂出现后消失
- **它们对事件做出反应** —— 碰撞发生时,道具被拾取,血条更新
✅ 想想像吃豆人这样的游戏。你能在游戏中识别上面提到的四种对象类型吗?
```mermaid
classDiagram
class GameObject {
+x: number
+y: number
+type: string
+exists_somewhere()
}
class MovableObject {
+moveTo(x, y)
+can_move_around()
}
class TemporaryObject {
+lifespan: number
+has_lifespan()
}
class InteractiveObject {
+onCollision()
+reacts_to_stuff()
}
GameObject <|-- MovableObject
GameObject <|-- TemporaryObject
GameObject <|-- InteractiveObject
MovableObject <|-- Hero
MovableObject <|-- Enemy
MovableObject <|-- Bullet
TemporaryObject <|-- PowerUp
TemporaryObject <|-- Explosion
InteractiveObject <|-- Collectible
InteractiveObject <|-- Obstacle
```
### 通过代码表达行为
我们上面描述的都是游戏对象可以拥有的行为。那么我们如何编码这些行为呢?我们可以通过与类或对象相关联的方法来表达这些行为。
现在你理解了游戏对象共有的行为,让我们探索如何用 JavaScript 实现这些行为。你可以通过添加到类或单个对象的方法来表达对象行为,且有多种实现方式
**类**
**基于的方法**
使用 `类``继承` 的想法可以为类添加特定的行为。
类和继承为组织游戏对象提供了一种结构化的方式。就像卡尔·林奈所构建的生物分类系统一样,你从一个含有共有属性的基础类开始,然后创建派生类继承这些基本功能并添加特定能力
✅ 继承是一个重要的概念。可以通过[MDN关于继承的文章](https://developer.mozilla.org/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)了解更多。
✅ 继承是一个重要概念,更多内容请见[MDN关于继承的文章](https://developer.mozilla.org/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)。
通过代码表达,一个游戏对象通常看起来像这样:
下面是如何使用类和继承实现游戏对象的示例
```javascript
//set up the class GameObject
// 第一步:创建基础的 GameObject 类
class GameObject {
constructor(x, y, type) {
this.x = x;
@ -52,173 +144,390 @@ class GameObject {
this.type = type;
}
}
```
**我们逐步拆解理解:**
- 我们创建了一个基础模板,所有游戏对象都能使用它
- 构造函数保存对象的位置(`x`, `y`)和类型
- 这成为所有游戏对象构建的基础
//this class will extend the GameObject's inherent class properties
```javascript
// 第2步通过继承添加移动功能
class Movable extends GameObject {
constructor(x,y, type) {
super(x,y, type)
constructor(x, y, type) {
super(x, y, type); // 调用父类构造函数
}
//this movable object can be moved on the screen
// 添加移动到新位置的能力
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
```
**在上例中,我们:**
- **扩展**了 GameObject 类以添加移动功能
- **使用** `super()` 调用父类构造函数初始化继承的属性
- **添加**了 `moveTo()` 方法来更新对象位置
//this is a specific class that extends the Movable class, so it can take advantage of all the properties that it inherits
```javascript
// 第3步创建特定的游戏对象类型
class Hero extends Movable {
constructor(x,y) {
super(x,y, 'Hero')
constructor(x, y) {
super(x, y, 'Hero'); // 自动设置类型
}
}
//this class, on the other hand, only inherits the GameObject properties
class Tree extends GameObject {
constructor(x,y) {
super(x,y, 'Tree')
constructor(x, y) {
super(x, y, 'Tree'); // 树木不需要移动
}
}
//a hero can move...
const hero = new Hero();
hero.moveTo(5,5);
// 第4步使用您的游戏对象
const hero = new Hero(0, 0);
hero.moveTo(5, 5); // 英雄可以移动!
//but a tree cannot
const tree = new Tree();
const tree = new Tree(10, 15);
// tree.moveTo() 会导致错误——树木不能移动
```
✅ 花几分钟重新构想一个吃豆人英雄(例如 Inky、Pinky 或 Blinky并思考它如何用 JavaScript 编写。
**理解这些概念:**
- **创建**继承适当行为的专门对象类型
- **展示**继承如何选择性包含功能
- **说明**英雄可以移动,而树木保持静止
- **演示**类层级防止不恰当操作
✅ 花几分钟重新构思吃豆人中的英雄(比如 Inky、Pinky 或 Blinky如何用 JavaScript 编写。
**组合**
**组合方法**
处理对象继承的另一种方法是使用 *组合*。然后,对象可以这样表达它们的行为:
组合遵循模块化设计理念,类似于工程师设计航天器时使用可互换组件。你不是继承父类,而是组合特定行为来创建具有所需功能的对象。这种方法提供了灵活性,不受严格层级限制。
```javascript
//create a constant gameObject
// 第一步:创建基础行为对象
const gameObject = {
x: 0,
y: 0,
type: ''
};
//...and a constant movable
const movable = {
moveTo(x, y) {
this.x = x;
this.y = y;
}
}
//then the constant movableObject is composed of the gameObject and movable constants
const movableObject = {...gameObject, ...movable};
};
```
//then create a function to create a new Hero who inherits the movableObject properties
**这段代码的作用:**
- **定义**了一个带有位置和类型的基础 `gameObject`
- **创建**了一个独立的 `movable` 行为对象,实现移动功能
- **分离**了位置数据和移动逻辑,使职责独立
```javascript
// 第2步通过组合行为来组合对象
const movableObject = { ...gameObject, ...movable };
// 第3步为不同类型的对象创建工厂函数
function createHero(x, y) {
return {
...movableObject,
x,
y,
type: 'Hero'
}
};
}
//...and a static object that inherits only the gameObject properties
function createStatic(x, y, type) {
return {
...gameObject
...gameObject,
x,
y,
type
}
};
}
//create the hero and move it
const hero = createHero(10,10);
hero.moveTo(5,5);
//and create a static tree which only stands around
const tree = createStatic(0,0, 'Tree');
```
**我应该使用哪种模式?**
**在上面,我们:**
- **通过扩展语法**组合基础对象属性和移动行为
- **创建**工厂函数返回定制对象
- **实现**了无需复杂类层级即可灵活创建对象
- **使**对象恰好拥有所需行为
选择哪种模式完全取决于你自己。JavaScript 支持这两种范式。
```javascript
// 第4步创建并使用你组合的对象
const hero = createHero(10, 10);
hero.moveTo(5, 5); // 工作完美!
--
const tree = createStatic(0, 0, 'Tree');
// tree.moveTo() 未定义 - 未组合任何移动行为
```
在游戏开发中,还有一种常见模式用于处理游戏的用户体验和性能问题。
**记住关键点:**
- **通过混合行为组合对象,而非继承**
- **提供**比严格继承层级更大的灵活性
- **允许**对象恰好拥有它们需要的特性
- **使用**现代 JavaScript 扩展语法实现干净合并
```
## 发布/订阅模式
**Which Pattern Should You Choose?**
**Which Pattern Should You Choose?**
```mermaid
quadrantChart
title Code Organization Patterns
x-axis Simple --> Complex
y-axis Rigid --> Flexible
quadrant-1 Advanced Composition
quadrant-2 Hybrid Approaches
quadrant-3 Basic Inheritance
quadrant-4 Modern Composition
Class Inheritance: [0.3, 0.2]
Interface Implementation: [0.6, 0.4]
Mixin Patterns: [0.7, 0.7]
Pure Composition: [0.8, 0.9]
Factory Functions: [0.5, 0.8]
Prototype Chain: [0.4, 0.3]
```
> 💡 **专业提示**:两种模式在现代 JavaScript 开发中各有用武之地。类适合明确定义的层级结构,而组合在需要最大灵活性时表现出色。
>
**何时使用:**
- **当存在明确的“是一个”关系时选择继承**(例如,英雄 *是一个* 可移动对象)
- **当存在“有一个”关系时选择组合**(例如,英雄 *拥有* 移动能力)
- **考虑**团队偏好和项目需求
- **记住**可以在同一应用中混合使用两者
### 🔄 **教学自检**
**对象组织理解**:在进入通信模式之前,确保你能:
- ✅ 解释继承与组合的区别
- ✅ 识别何时使用类还是工厂函数
- ✅ 理解继承中 `super()` 关键字的作用
- ✅ 认识每种方法对游戏开发的优势
**快速自测**:你如何创建一个既可移动又能飞行的敌人?
- **继承方法**: `class FlyingEnemy extends Movable`
- **组合方法**: `{ ...movable, ...flyable, ...gameObject }`
**现实联系**:这些模式无处不在:
- **React 组件**:属性(组合)与类继承
- **游戏引擎**:实体组件系统使用组合
- **移动应用**UI 框架常用继承层级
## 通信模式:发布/订阅系统
随着应用复杂度提升,管理组件间通信变得困难。发布-订阅模式pub/sub用类似广播的原理解决这个问题——一个发射器能触达多个接收器无需知道谁在监听。
考虑英雄受伤时的情况:血条更新,音效播放,视觉反馈出现。英雄对象不用直接耦合这些系统,而是广播一个“受伤”消息。任何需要响应的系统都能订阅该消息并做出反应。
**Pub/Sub** 代表“发布-订阅”
```mermaid
flowchart TD
A[英雄受到伤害] --> B[发布HERO_DAMAGED]
B --> C[事件系统]
C --> D[生命值条订阅者]
C --> E[声音系统订阅者]
C --> F[视觉效果订阅者]
C --> G[成就系统订阅者]
D --> H[更新生命值显示]
E --> I[播放伤害音效]
F --> J[显示红色闪光]
G --> K[检查存活成就]
style A fill:#ffebee
style B fill:#e1f5fe
style C fill:#e8f5e8
style H fill:#fff3e0
style I fill:#fff3e0
style J fill:#fff3e0
style K fill:#fff3e0
```
### 理解 Pub/Sub 架构
✅ Pub/Sub 代表“发布-订阅”
pub/sub 模式使应用的不同部分松散耦合,即它们能协作而不直接依赖彼此。这种分离让代码更易维护、测试和灵活应对变化。
这种模式解决了应用程序的不同部分不应该相互了解的问题。为什么呢?如果各部分是分离的,整体上会更容易理解发生了什么。同时,如果需要突然改变行为,也会更容易实现。我们如何做到这一点呢?通过建立以下概念:
**pub/sub 的关键角色:**
- **消息** —— 简单的文本标签,例如 `'PLAYER_SCORED'` ,描述发生的事件(含额外信息)
- **发布者** —— 向所有监听者“大声宣布”发生了什么
- **订阅者** —— 说“我关注这个事件”,并在事件发生时响应
- **事件系统** —— 确保消息送达正确监听者的中间人
- **消息**:消息通常是一个文本字符串,伴随一个可选的负载(用于说明消息内容的一段数据)。游戏中的典型消息可以是 `KEY_PRESSED_ENTER`
- **发布者**:这个元素*发布*消息并将其发送给所有订阅者。
- **订阅者**:这个元素*监听*特定消息,并在接收到消息后执行某些任务,例如发射激光。
### 构建事件系统
这种模式的实现虽然代码量很小,但却非常强大。以下是它的实现方式:
让我们创建一个简单而强大的事件系统,演示这些概念:
```javascript
//set up an EventEmitter class that contains listeners
// 第一步:创建 EventEmitter 类
class EventEmitter {
constructor() {
this.listeners = {};
this.listeners = {}; // 存储所有事件监听器
}
//when a message is received, let the listener to handle its payload
// 为特定消息类型注册监听器
on(message, listener) {
if (!this.listeners[message]) {
this.listeners[message] = [];
}
this.listeners[message].push(listener);
}
//when a message is sent, send it to a listener with some payload
// 向所有注册的监听器发送消息
emit(message, payload = null) {
if (this.listeners[message]) {
this.listeners[message].forEach(l => l(message, payload))
this.listeners[message].forEach(listener => {
listener(message, payload);
});
}
}
}
```
使用上述代码,我们可以创建一个非常小的实现:
**拆解发生的事情:**
- **创建**一个简单类实现的中心事件管理系统
- **按消息类型**在对象中存储监听器
- **使用** `on()` 方法注册新监听器
- **用** `emit()` 方法广播消息到所有感兴趣的监听者
- **支持**可选的数据负载以传递相关信息
### 综合示例演示
好,让我们看看实际应用!我们构建一个简单的移动系统,展示 pub/sub 的清晰灵活性:
```javascript
//set up a message structure
// 第一步:定义你的消息类型
const Messages = {
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT'
HERO_MOVE_LEFT: 'HERO_MOVE_LEFT',
HERO_MOVE_RIGHT: 'HERO_MOVE_RIGHT',
ENEMY_SPOTTED: 'ENEMY_SPOTTED'
};
//invoke the eventEmitter you set up above
// 第二步:创建你的事件系统和游戏对象
const eventEmitter = new EventEmitter();
//set up a hero
const hero = createHero(0,0);
//let the eventEmitter know to watch for messages pertaining to the hero moving left, and act on it
const hero = createHero(0, 0);
```
**这段代码作用:**
- **定义**常量对象防止消息名拼写错误
- **创建**事件发射器实例处理所有通信
- **初始化**位于起始位置的英雄对象
```javascript
// 第三步:设置事件监听器(订阅者)
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
hero.moveTo(hero.x - 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
//set up the window to listen for the keyup event, specifically if the left arrow is hit, emit a message to move the hero left
window.addEventListener('keyup', (evt) => {
if (evt.key === 'ArrowLeft') {
eventEmitter.emit(Messages.HERO_MOVE_LEFT)
}
eventEmitter.on(Messages.HERO_MOVE_RIGHT, () => {
hero.moveTo(hero.x + 5, hero.y);
console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});
```
在上面的代码中,我们连接了一个键盘事件 `ArrowLeft` 并发送了 `HERO_MOVE_LEFT` 消息。我们监听该消息并将 `hero` 移动作为结果。这种模式的优势在于事件监听器和英雄彼此互不知晓。你可以将 `ArrowLeft` 重新映射到 `A` 键。此外,通过对事件发射器的 `on` 函数进行一些编辑,还可以在 `ArrowLeft` 上实现完全不同的行为:
**上述代码实现:**
- **注册**响应移动消息的事件监听器
- **根据移动方向**更新英雄位置
- **添加**控制台日志跟踪英雄位置变化
- **移动逻辑**与输入处理分离
```javascript
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
hero.move(5,0);
// 第4步将键盘输入连接到事件发布者
window.addEventListener('keydown', (event) => {
switch(event.key) {
case 'ArrowLeft':
eventEmitter.emit(Messages.HERO_MOVE_LEFT);
break;
case 'ArrowRight':
eventEmitter.emit(Messages.HERO_MOVE_RIGHT);
break;
}
});
```
随着游戏规模的扩大和复杂性的增加,这种模式的复杂性保持不变,而你的代码仍然保持简洁。强烈推荐采用这种模式。
**进一步理解:**
- **连接**键盘输入与游戏事件,避免紧耦合
- **使**输入系统可间接与游戏对象通信
- **允许**多个系统响应同一键盘事件
- **便于**更改键绑定或添加新输入方法
```mermaid
sequenceDiagram
participant User
participant Keyboard
participant EventEmitter
participant Hero
participant SoundSystem
participant Camera
User->>Keyboard: 按下 左箭头
Keyboard->>EventEmitter: emit('HERO_MOVE_LEFT')
EventEmitter->>Hero: 向左移动5像素
EventEmitter->>SoundSystem: 播放脚步声
EventEmitter->>Camera: 跟随英雄
Hero->>Hero: 更新位置
SoundSystem->>SoundSystem: 播放音频
Camera->>Camera: 调整视口
```
> 💡 **专业提示**:此模式的美妙在于灵活性!你只需添加更多事件监听器即可添加音效、屏幕抖动或粒子效果——无需修改现有的键盘或移动代码。
>
**你会喜欢此方法的原因:**
- 新功能添加变得非常简单——只需监听感兴趣事件
- 多个模块可响应同一事件,互不干扰
- 测试更加简单,因为各部分独立工作
- 出现问题时,知道准确排查位置
### Pub/Sub 为什么能有效扩展
随着应用复杂性增加pub/sub 模式保持简洁。无论是管理数十个敌人、动态 UI 更新还是音效系统,该模式在不改变架构的情况下处理规模增大。新功能可无缝集成进现有事件系统,不影响已建立功能。
> ⚠️ **常见错误**:早期不要创建过多具体消息类型。先用大类分类,随着游戏需求明确再细化。
>
**最佳实践:**
- **将相关消息分组归类**
- **使用描述性名称清晰表达事件**
- **保持消息负载简单聚焦**
- **为团队协作记录消息类型文档**
### 🔄 **教学自检**
**事件驱动架构理解**:确认你掌握整体系统:
- ✅ pub/sub 模式如何防止组件间紧耦合?
- ✅ 为什么事件驱动架构更易添加新功能?
- ✅ EventEmitter 在通信流程中起什么作用?
- ✅ 消息常量如何防止错误并提升可维护性?
**设计挑战**:你如何用 pub/sub 处理这些游戏场景?
1. **敌人死亡**:更新得分,播放音效,生成道具,移除屏幕
2. **关卡完成**:停止音乐,显示 UI保存进度加载下一关
3. **道具收集**:增强能力,更新 UI播放效果启动计时
**专业联系**:此模式应用于:
- **前端框架**React/Vue 事件系统
- **后端服务**:微服务通信
- **游戏引擎**Unity 事件系统
- **移动开发**iOS/Android 通知系统
---
## 🚀 挑战
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
思考发布-订阅模式如何增强游戏。哪些部分应该发出事件,游戏应该如何对它们做出反应?现在是发挥创意的机会,想象一个新游戏以及它的各个部分可能如何表现。
**描述:** 使用继承和发布/订阅模式创建一个简单的游戏对象系统。你将实现一个基本游戏,其中不同对象通过事件进行通信而无需直接了解彼此。
**提示:** 创建一个 JavaScript 游戏系统要求如下1创建一个基础 GameObject 类,含 x, y 坐标和 type 属性。2创建一个继承自 GameObject 且可以移动的 Hero 类。3创建一个继承自 GameObject 且能追踪英雄的 Enemy 类。4实现一个用于发布/订阅模式的 EventEmitter 类。5设置事件监听器当英雄移动时附近敌人接收 'HERO_MOVED' 事件并更新位置向英雄移动。使用 console.log 展示对象间的通信。
了解更多[Agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
考虑发布-订阅模式如何增强游戏架构。确定哪些组件应发出事件以及系统应如何响应。设计一个游戏概念并绘制其组件之间的通信模式。
## 课后测验
@ -226,13 +535,128 @@ eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
## 复习与自学
通过[阅读相关内容](https://docs.microsoft.com/azure/architecture/patterns/publisher-subscriber/?WT.mc_id=academic-77807-sagibbon)了解更多关于发布/订阅模式的信息。
## 作业
通过[阅读相关内容](https://docs.microsoft.com/azure/architecture/patterns/publisher-subscriber/?WT.mc_id=academic-77807-sagibbon)深入了解发布/订阅。
### ⚡ **接下来5分钟你可以做的事情**
- [ ] 打开任何在线HTML5游戏使用开发者工具检查其代码
- [ ] 创建一个简单的HTML5 Canvas元素并绘制基本形状
- [ ] 尝试使用`setInterval`创建简单动画循环
- [ ] 浏览Canvas API文档尝试某个绘图方法
### 🎯 **本小时你可以完成的任务**
- [ ] 完成课后测验并理解游戏开发概念
- [ ] 搭建包含HTML、CSS和JavaScript文件的游戏项目结构
- [ ] 创建一个持续更新和渲染的基础游戏循环
- [ ] 在画布上绘制你的第一个游戏精灵
- [ ] 实现基础的图片和声音资源加载
### 📅 **你的一周游戏创作计划**
- [ ] 完成包含所有计划功能的完整太空游戏
- [ ] 添加精细的图形、音效和流畅动画
- [ ] 实现游戏状态(开始界面、游戏中、游戏结束)
- [ ] 创建计分系统和玩家进度追踪
- [ ] 让游戏响应式兼容多设备
- [ ] 在线分享游戏并收集玩家反馈
### 🌟 **你的一月游戏开发计划**
- [ ] 开发多个不同类型和机制的游戏
- [ ] 学习使用像Phaser或Three.js这样的游戏开发框架
- [ ] 参与开源游戏开发项目
- [ ] 精通高级游戏编程模式和优化技巧
- [ ] 创建展示游戏开发技能的作品集
- [ ] 指导对游戏开发和互动媒体感兴趣的新人
## 🎯 你的游戏开发精通时间表
```mermaid
timeline
title 游戏架构学习进度
section 对象模式20分钟
代码组织:类继承
:组合模式
:工厂函数
:行为混合
section 通信系统25分钟
事件架构:发布/订阅实现
:消息设计
:事件发射器
:松耦合
section 游戏对象设计30分钟
实体系统:属性管理
:行为组合
:状态处理
:生命周期管理
section 架构模式35分钟
系统设计:组件系统
:观察者模式
:命令模式
:状态机
section 高级概念45分钟
可扩展架构:性能优化
:内存管理
:模块化设计
:测试策略
section 游戏引擎概念1周
专业开发:场景图
:资源管理
:渲染管线
:物理整合
section 框架精通2周
现代游戏开发React游戏模式
Canvas优化
WebGL基础
PWA游戏
section 行业实践1个月
专业技能:团队协作
:代码审查
:游戏设计模式
:性能剖析
```
### 🛠️ 你的游戏架构工具包总结
完成本课后,你已有:
- **设计模式精通**:理解继承与组合的权衡
- **事件驱动架构**:发布/订阅实现的可扩展通信
- **面向对象设计**:类层级和行为组合
- **现代JavaScript**工厂函数、展开语法以及ES6+模式
- **可扩展架构**:低耦合和模块化设计原则
- **游戏开发基础**:实体系统和组件模式
- **专业模式**:业界标准代码组织方法
**现实应用场景**:这些模式适用于:
- **前端框架**React/Vue组件架构和状态管理
- **后端服务**:微服务通信和事件驱动系统
- **移动开发**iOS/Android应用架构和通知系统
- **游戏引擎**Unity、Unreal及基于Web的游戏开发
- **企业软件**:事件溯源和分布式系统设计
- **API设计**RESTful服务和实时通信
**获得的专业技能**:你现在能:
- **设计**可扩展的软件架构,使用成熟的设计模式
- **实现**能够处理复杂交互的事件驱动系统
- **选择**适合不同场景的代码组织策略
- **调试**并维护低耦合系统
- **沟通**使用业界标准术语表达技术决策
**下一步**:你已准备好在实际游戏中实现这些模式,探索高级游戏开发主题,或将这些架构理念应用于网页应用!
🌟 **成就解锁**:你已掌握支持从简单游戏到复杂企业系统的基础软件架构模式!
## 任务
[设计一个游戏](assignment.md)
---
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译而成。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译而成。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始语言版本的文件应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们不对因使用本翻译而产生的任何误解或误释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,102 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "009bdedee9cc82988264be8cb31f9bf4",
"translation_date": "2025-08-23T23:06:09+00:00",
"original_hash": "c8fc39a014d08247c082878122e2ba73",
"translation_date": "2026-01-06T11:30:50+00:00",
"source_file": "6-space-game/1-introduction/assignment.md",
"language_code": "zh"
}
-->
# 模拟一个游戏
# 模拟游戏:应用设计模式
## 作业概述
运用你新学的设计模式知识,创建一个简单的游戏原型!本作业将帮助你练习架构模式(继承或组合)以及本课中介绍的发布/订阅通信系统。
## 说明
使用课程中的代码示例,创建一个你喜欢的游戏的表示形式。游戏需要足够简单,但目标是使用类或组合模式以及发布/订阅模式来展示游戏如何启动。发挥你的创造力!
创建一个简单的游戏表示,展示本课的设计模式。你的游戏应当是可运行的,但不需要复杂的图形——重点放在底层架构和通信模式上。
### 要求
**选择你的架构模式:**
- **选项 A**:使用基于类的继承(如 `GameObject``Movable``Hero` 示例)
- **选项 B**:使用组合(如带混合行为的工厂函数方法)
**实现通信:**
- **包含** 一个 `EventEmitter` 类用于发布/订阅消息
- **设置** 至少 2-3 种不同的消息类型(如 `PLAYER_MOVE`、`ENEMY_SPAWN`、`SCORE_UPDATE`
- **将** 用户输入(键盘/鼠标)通过事件系统连接到游戏事件
**游戏元素包括:**
- 至少一个玩家控制的角色
- 至少一个其他游戏对象(敌人、可收集物或环境元素)
- 对象之间的基本交互(碰撞、收集或通信)
### 推荐游戏思路
**可参考的简单游戏:**
- **贪吃蛇游戏** —— 蛇身节段跟随蛇头,食物随机生成
- **乒乓球变体** —— 球拍响应输入,球在墙壁反弹
- **收集者游戏** —— 玩家移动收集物品同时避开障碍
- **塔防基础** —— 塔检测并射击移动敌人
### 代码结构指导
```javascript
// 示例起始结构
const Messages = {
// 在这里定义你的游戏消息
};
class EventEmitter {
// 你的事件系统实现
}
// 选择基于类或组合的方法
// 基于类的示例:
class GameObject { /* base properties */ }
class Player extends GameObject { /* player-specific behavior */ }
// 或组合的示例:
const gameObject = { /* base properties */ };
const movable = { /* movement behavior */ };
function createPlayer() { /* combine behaviors */ }
```
### 测试你的实现
**验证代码运行方法:**
- **测试** 事件触发后对象是否移动或变化
- **确认** 多个对象能响应同一事件
- **检查** 可否在不修改已有代码前提下添加新行为
- **确保** 键盘/鼠标输入能正确触发游戏事件
## 提交指南
**你的提交应包含:**
1. 实现游戏的 **JavaScript 文件**
2. 用于运行和测试游戏的 **HTML 文件**(可以简单)
3. 说明你选择的设计模式及原因的 **注释**
4. 简要说明你的消息类型及其作用的 **文档**
## 评分标准
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | ------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------- |
| | 屏幕上放置三个元素并进行操作 | 屏幕上放置两个元素并进行操作 | 屏幕上放置一个元素并进行操作 |
| 评价标准 | 优秀3分 | 合格2分 | 需改进1分 |
|----------|-------------|-------------|---------------|
| **架构模式** | 正确实现继承或组合,具备清晰的类/对象层次 | 选用的模式基本正确,存在细微问题或不一致 | 尝试使用模式但实现有较大问题 |
| **发布/订阅实现** | EventEmitter 正确支持多消息类型和事件流 | 基础发布/订阅系统可用,但事件处理有限 | 实现了事件系统但不可靠 |
| **游戏功能** | 有三种及以上通过事件通信的交互元素 | 两种交互元素并实现基本事件通信 | 单一元素响应事件或基础交互 |
| **代码质量** | 代码整洁、有注释、组织合理,使用现代 JS | 代码一般组织良好,有足够注释 | 代码可用但缺乏组织或注释 |
**加分项:**
- **有创造性的游戏机制**,展示设计模式的有趣用法
- **多种输入方式**(键盘及鼠标事件)
- **可扩展架构**,便于未来增加新功能
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译而成。尽管我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始文件的原文版本应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或错误解释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,230 +1,624 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "056641280211e52fd0adb81b6058ec55",
"translation_date": "2025-08-29T14:46:46+00:00",
"original_hash": "7994743c5b21fdcceb36307916ef249a",
"translation_date": "2026-01-06T11:24:04+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/README.md",
"language_code": "zh"
}
-->
# 构建太空游戏第二部分:将英雄和怪物绘制到画布上
```mermaid
journey
title 你的画布图形之旅
section 基础
了解画布API: 3: Student
学习坐标系统: 4: Student
绘制基本形状: 4: Student
section 图像处理
加载游戏资源: 4: Student
处理异步加载: 5: Student
定位精灵: 5: Student
section 游戏渲染
创建游戏界面: 5: Student
构建布阵: 5: Student
优化性能: 4: Student
```
Canvas API 是网页开发中用于在浏览器中创建动态交互图形的最强大功能之一。在本课中,我们将把那个空白的 HTML `<canvas>` 元素变成一个充满英雄和怪物的游戏世界。把画布想象成你的数字画板,代码变成视觉效果。
我们将基于上一课的内容,现在深入视觉方面。你将学习如何加载和显示游戏精灵,精确定位元素,并为你的太空游戏创建视觉基础。这桥接了静态网页与动态交互体验之间的差距。
本课结束时,你将拥有一个完整的游戏场景,准确定位的英雄飞船和准备战斗的敌人阵型。你会理解现代游戏如何在浏览器中渲染图形,并获得制作自己交互式视觉体验的技能。让我们一起探索画布图形,赋予你的太空游戏生命吧!
```mermaid
mindmap
root((画布图形))
Canvas Element
HTML5 功能
2D 上下文
坐标系统
像素控制
Drawing Operations
基本形状
文本渲染
图像显示
路径绘制
Asset Management
图像加载
异步操作
错误处理
性能
Game Rendering
精灵定位
阵型布局
场景组成
帧更新
Visual Effects
颜色与样式
变换
动画
图层
```
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/31)
## 画布
画布是一个默认没有内容的 HTML 元素,它就像一块空白的画板。你需要通过在上面绘制来添加内容。
那么,这个 `<canvas>` 元素到底是什么呢?它是 HTML5 用于在网页浏览器中创建动态图形和动画的解决方案。与静态的普通图像或视频不同画布让你能够像素级别地控制屏幕上显示的一切。这使它非常适合游戏、数据可视化和交互艺术。把它想象成一个可编程的绘图表面JavaScript 成为你的画笔。
默认情况下canvas 元素看起来像页面上的一个空白透明矩形。但潜力就在这里!当你用 JavaScript 绘制形状、加载图像、创建动画并让事物响应用户交互时,它的真正威力就显现出来。这类似于 1960 年代贝尔实验室的早期计算机图形先驱——他们必须编程控制每个像素,才能创建第一批数字动画。
✅ 阅读 [Canvas API 的更多信息](https://developer.mozilla.org/docs/Web/API/Canvas_API)(来自 MDN
在 MDN 上阅读[更多关于 Canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API)。
以下是它通常的声明方式,作为页面主体的一部分:
它通常这样声明,作为页面主体的一部分:
```html
<canvas id="myCanvas" width="200" height="100"></canvas>
```
上面我们设置了 `id`、`width` 和 `height`
- `id`:设置这个属性以便在需要与其交互时获取引用。
- `width`:这是元素的宽度。
- `height`:这是元素的高度。
**这段代码做了什么:**
- **设置** `id` 属性,以便你在 JavaScript 中引用这个特定的画布元素
- **定义** `width`(宽度)以像素为单位,控制画布的水平尺寸
- **设置** `height`(高度)以像素为单位,确定画布的垂直尺寸
## 绘制简单几何图形
画布使用笛卡尔坐标系来绘制内容,因此它使用 x 轴和 y 轴来表示某物的位置。位置 `0,0` 是画布的左上角,而右下角则是你设置的画布的宽度和高度。
既然你知道了 canvas 元素是什么,接下来我们来探索如何真正地在上面绘图!画布使用的坐标系统你可能从数学课上见过,但有一个针对计算机图形的重要区别。
画布使用笛卡尔坐标系,包含 x 轴(水平轴)和 y 轴(垂直轴)来定位所有绘制内容。但关键的不同点是:与数学课上的坐标系不同,原点 `(0,0)` 从左上角开始x 值向右增加y 值向下增加。这种方式源于早期计算机显示器的电子束从上到下扫描,使得左上角成为自然的起点。
```mermaid
quadrantChart
title 画布坐标系
x-axis 左 --> 右
y-axis 上 --> 下
quadrant-1 第一象限
quadrant-2 第二象限
quadrant-3 第三象限
quadrant-4 第四象限
Origin Point: [0.1, 0.1]
Hero Center: [0.5, 0.8]
Enemy Formation: [0.3, 0.2]
Power-up: [0.7, 0.6]
UI Elements: [0.9, 0.1]
```
![canvas 网格](../../../../translated_images/canvas_grid.5f209da785ded492.zh.png)
> 图片来自 [MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)
要在 canvas 元素上绘图,你需要遵循所有画布图形基础的三个步骤。重复几次后,会变得很自然:
```mermaid
flowchart LR
A[HTML 画布元素] --> B[获取画布引用]
B --> C[获取2D上下文]
C --> D[绘图操作]
D --> E[绘制形状]
D --> F[绘制文本]
D --> G[绘制图像]
D --> H[应用样式]
E --> I[渲染到屏幕]
F --> I
G --> I
H --> I
style A fill:#e1f5fe
style C fill:#e8f5e8
style I fill:#fff3e0
```
1. **获取引用**:从 DOM 获取你的 Canvas 元素(就像任何其他 HTML 元素一样)
2. **获取 2D 渲染上下文** — 它提供了所有绘图方法
3. **开始绘制!** 使用上下文的内建方法创建图形
![画布的网格](../../../../translated_images/canvas_grid.5f209da785ded492a01ece440e3032afe51efa500cc2308e5ea4252487ceaf0b.zh.png)
> 图片来源:[MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)
代码示例如下:
要在画布元素上绘制内容,你需要完成以下步骤:
```javascript
// 第一步:获取画布元素
const canvas = document.getElementById("myCanvas");
1. **获取画布元素的引用**。
2. **获取画布上的 Context 元素的引用**。
3. **使用 Context 元素执行绘制操作**。
// 第二步获取2D渲染上下文
const ctx = canvas.getContext("2d");
上述步骤的代码通常如下所示:
// 第三步:设置填充颜色并绘制矩形
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 200, 200); // xy宽度高度
```
```javascript
// draws a red rectangle
//1. get the canvas reference
canvas = document.getElementById("myCanvas");
**逐步解析:**
- 我们 **获取** 了画布元素,使用它的 ID 并存储在变量中
- 我们 **获得** 2D 渲染上下文,它是我们的绘图工具箱
- 我们 **告诉** 画布用红色填充,设置填充样式 `fillStyle`
- 我们 **绘制** 了一个矩形,从左上角(0,0)开始宽高均为200像素
//2. set the context to 2D to draw basic shapes
ctx = canvas.getContext("2d");
✅ Canvas API 主要关注于二维形状,但你也可以用它在网站上绘制三维元素;为此,你可能会用到 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API)。
//3. fill it with the color red
ctx.fillStyle = 'red';
你可以用 Canvas API 绘制各种内容,例如:
//4. and draw a rectangle with these parameters, setting location and size
ctx.fillRect(0,0, 200, 200) // x,y,width, height
```
- **几何图形**,我们已经展示了如何绘制矩形,但还有很多形状你可以画。
- **文本**,你可以以任何字体和颜色绘制文字。
- **图像**,你可以根据图像资源(如 .jpg 或 .png绘制图像。
✅ Canvas API 主要专注于 2D 图形,但你也可以在网页上绘制 3D 元素;为此,你可以使用 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API)。
试试吧!你已经会画矩形了,你能画一个圆形吗?看看 CodePen 上的一些有趣 Canvas 绘图。这里有一个[特别棒的示例](https://codepen.io/dissimulate/pen/KrAwx)。
使用 Canvas API你可以绘制各种内容例如
### 🔄 **教学检查点**
**Canvas 基础理解**:在学习加载图像之前,确保你能够:
- ✅ 解释画布坐标系与数学坐标系的不同
- ✅ 理解画布绘图操作的三步流程
- ✅ 识别 2D 渲染上下文提供了什么
- ✅ 描述 fillStyle 和 fillRect 如何协作工作
- **几何图形**,我们已经展示了如何绘制矩形,但还有更多可以绘制的内容。
- **文本**,你可以绘制任何字体和颜色的文本。
- **图像**,你可以基于图像资源(例如 .jpg 或 .png绘制图像。
**快速自测**:如何在位置 (100, 50) 画一个半径为 25 的蓝色圆圈?
```javascript
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(100, 50, 25, 0, 2 * Math.PI);
ctx.fill();
```
✅ 试试吧!你已经知道如何绘制矩形,能否尝试在页面上绘制一个圆形?看看 CodePen 上一些有趣的 Canvas 绘图。这里有一个[特别令人印象深刻的例子](https://codepen.io/dissimulate/pen/KrAwx)。
**你现在知道的 Canvas 绘图方法:**
- **fillRect()**:绘制填充矩形
- **fillStyle**:设置颜色和图案
- **beginPath()**:开始新绘图路径
- **arc()**:创建圆和曲线
## 加载并绘制图像资源
通过创建一个 `Image` 对象并设置其 `src` 属性来加载图像资源。然后监听 `load` 事件,以便知道图像何时可以使用。代码如下:
### 加载资源
绘制基础形状有助于入门,但大多数游戏需要真实的图像!精灵、背景和纹理赋予游戏视觉魅力。在画布上加载和显示图像的方式与绘制几何形状不同,但一旦掌握过程就很简单。
你需要创建一个 `Image` 对象,加载你的图像文件(这是异步的,即“后台”加载),然后图像准备好后再绘制到画布上。这样做能保证图像正确显示,同时不阻塞应用程序加载。
```mermaid
sequenceDiagram
participant JS as JavaScript
participant Img as 图像对象
participant Server as 文件服务器
participant Canvas as 画布上下文
JS->>Img: new Image()
JS->>Img: 设置 src 属性
Img->>Server: 请求图像文件
Server->>Img: 返回图像数据
Img->>JS: 触发 onload 事件
JS->>Canvas: drawImage(img, x, y)
Canvas->>Canvas: 渲染到屏幕
Note over JS,Canvas: 异步加载防止界面阻塞
```
### 基本图像加载
```javascript
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// image loaded and ready to be used
}
// 图像已加载并准备好使用
console.log('Image loaded successfully!');
};
```
### 加载资源模式
**这段代码发生了什么:**
- 我们 **创建** 了一个新的 Image 对象来存放我们的精灵或纹理
- 我们 **指明** 它要加载的图像文件路径
- 我们 **监听** 加载完成事件,确保图像准备好使用
### 更好的图像加载方式
建议将上述代码封装在一个结构中,这样更容易使用,并且只有在图像完全加载后才尝试操作它:
这是专业开发者常用的更健壮图像加载方法。我们将图像加载包装成基于 Promise 的函数——这种方法自 ES6 引入 JavaScript Promise 后变得流行,让代码更有条理且能优雅处理错误
```javascript
function loadAsset(path) {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = path;
img.onload = () => {
// image loaded and ready to be used
resolve(img);
}
})
};
img.onerror = () => {
reject(new Error(`Failed to load image: ${path}`));
};
});
}
// use like so
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
// 使用 async/await 的现代用法
async function initializeGame() {
try {
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// 图像现在可以使用了
} catch (error) {
console.error('Failed to load game assets:', error);
}
}
```
要将游戏资源绘制到屏幕上,代码如下:
**这里做的事情:**
- **用 Promise 封装** 图像加载逻辑,更好地管理它
- **添加** 错误处理,能告诉我们什么时候出了问题
- **使用** 现代 async/await 语法,阅读起来更简洁
- **包括** try/catch 块优雅处理加载异常
图像加载完成后,将它绘制到画布其实很简单:
```javascript
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.drawImage(heroImg, canvas.width/2,canvas.height/2);
ctx.drawImage(monsterImg, 0,0);
async function renderGameScreen() {
try {
// 加载游戏资源
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// 获取画布和上下文
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 在特定位置绘制图像
ctx.drawImage(heroImg, canvas.width / 2, canvas.height / 2);
ctx.drawImage(monsterImg, 0, 0);
} catch (error) {
console.error('Failed to render game screen:', error);
}
}
```
**逐步讲解:**
- 我们用 await 在后台加载了英雄和怪物的图像
- 我们获取画布元素及其 2D 渲染上下文
- 通过简单的坐标计算,把英雄图像放到画布中心
- 将怪物图像放置在左上角,开始敌人阵型
- 使用 try/catch 捕捉任何加载或渲染时可能出现的错误
```mermaid
flowchart TD
A[加载资源] --> B{所有图片加载完成?}
B -->|否| C[显示加载中]
B -->|是| D[获取画布上下文]
C --> B
D --> E[清除屏幕]
E --> F[绘制背景]
F --> G[绘制敌军编队]
G --> H[绘制英雄飞船]
H --> I[应用视觉效果]
I --> J[渲染帧]
subgraph "渲染管线"
K[资源管理]
L[场景构成]
M[绘图操作]
N[帧输出]
end
style A fill:#e1f5fe
style J fill:#e8f5e8
style I fill:#fff3e0
```
## 现在开始构建你的游戏
现在我们把所有内容整合,创建太空游戏的视觉基础。你已经掌握了画布基础和图像加载技巧,这部分将引导你构建一个完整的游戏画面,实现精灵正确定位。
### 要构建什么
你将构建一个包含 Canvas 元素的网页。它应该渲染一个黑色屏幕,大小为 `1024*768`。我们为你提供了两张图片:
你将构建一个包含 Canvas 元素的网页。它应该渲染一个黑色画面,大小为 `1024*768`。我们给你提供了两张图片:
- 英雄飞船
![英雄飞船](../../../../translated_images/player.dd24c1afa8c71e9b82b2958946d4bad13308681392d4b5ddcc61a0e818ef8088.zh.png)
![英雄飞船](../../../../translated_images/player.dd24c1afa8c71e9b.zh.png)
- 5*5 怪物
- 5*5 怪物阵型
![怪物飞船](../../../../translated_images/enemyShip.5df2a822c16650c2fb3c06652e8ec8120cdb9122a6de46b9a1a56d54db22657f.zh.png)
![怪物飞船](../../../../translated_images/enemyShip.5df2a822c16650c2.zh.png)
### 推荐的开发步骤
### 推荐开发步骤
找到在 `your-work` 子文件夹中为你创建的文件。它应该包含以下内容:
找到为你准备好的启动文件,放在 `your-work` 子文件夹。你的项目结构应包含
```bash
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
your-work/
├── assets/
│ ├── enemyShip.png
│ └── player.png
├── index.html
├── app.js
└── package.json
```
在 Visual Studio Code 中打开该文件夹的副本。你需要设置一个本地开发环境,最好使用安装了 NPM 和 Node 的 Visual Studio Code。如果你的电脑上还没有设置 `npm`[这里是设置方法](https://www.npmjs.com/get-npm)。
**你会使用这些资源:**
- **游戏精灵**存在于 `assets/` 文件夹,保持组织有序
- **主 HTML 文件**负责设置画布元素及环境
- **JavaScript 文件**中你将编写所有游戏渲染代码
- **package.json** 配置了开发服务器,支持本地测试
用 Visual Studio Code 打开此文件夹开始开发。你需要在本地环境安装 Visual Studio Code、NPM 和 Node.js。如果电脑未安装 `npm`[这里有安装指南](https://www.npmjs.com/get-npm)。
通过导航到 `your_work` 文件夹来启动你的项目:
进入 `your-work` 文件夹启动开发服务器
```bash
cd your-work
npm start
```
上述命令将在地址 `http://localhost:5000` 上启动一个 HTTP 服务器。打开浏览器并输入该地址。现在页面是空白的,但很快会有所变化。
**这个命令做了很酷的事情:**
- **启动**本地服务器 `http://localhost:5000`,方便测试游戏
- **正确服务**所有文件,浏览器能正常加载
- **监视**文件修改,保证开发顺畅
- **提供**专业开发环境,测试所有功能
> 注意:要查看屏幕上的更改,请刷新浏览器。
> 💡 **注意**:浏览器初次会显示空白页——这很正常!随着你添加代码,刷新浏览器即可看到变化。这种迭代开发方式类似 NASA 构建阿波罗制导计算机——逐步测试每个组成部分后再集成
### 添加代码
`your-work/app.js` 中添加所需代码以完成以下任务:
`your-work/app.js` 中添加代码,完成以下任务:
1. **绘制黑色背景的画布**
> 💡 **操作示范**:找到 `/app.js` 中的 TODO添加两行即可。设置 `ctx.fillStyle` 为黑色,再调用 `ctx.fillRect()`,起点(0,0),尺寸与画布相符,简单易懂!
2. **加载游戏纹理**
> 💡 **操作示范**:使用 `await loadAsset()` 加载英雄和敌人图像,存入变量以备后用。记住——只有实际绘制才能看到它们!
1. **绘制**一个黑色背景的画布
> 提示:在 `/app.js` 中适当的 TODO 下添加两行代码,将 `ctx` 元素设置为黑色,并将顶部/左侧坐标设置为 0,0高度和宽度等于画布的大小。
2. **加载**纹理
> 提示:使用 `await loadTexture` 并传入图像路径来添加玩家和敌人的图像。你暂时还看不到它们出现在屏幕上!
3. **绘制**英雄到屏幕底部中央
> 提示:使用 `drawImage` API 将 heroImg 绘制到屏幕上,设置 `canvas.width / 2 - 45``canvas.height - canvas.height / 4)`
4. **绘制** 5*5 的怪物
> 提示:现在你可以取消注释代码以在屏幕上绘制敌人。接下来,进入 `createEnemies` 函数并完成它。
3. **将英雄飞船绘制在中心下部**
> 💡 **操作示范**:用 `ctx.drawImage()` 放置英雄。x 坐标尝试 `canvas.width / 2 - 45` 使其居中y 坐标使用 `canvas.height - canvas.height / 4` 放到底部区域。
首先,设置一些常量:
4. **绘制 5×5 阵型敌人舰队**
> 💡 **操作示范**:找到 `createEnemies` 函数,设置嵌套循环。你将进行一些间距和定位计算,别担心,我会引导你完成!
```javascript
const MONSTER_TOTAL = 5;
const MONSTER_WIDTH = MONSTER_TOTAL * 98;
const START_X = (canvas.width - MONSTER_WIDTH) / 2;
const STOP_X = START_X + MONSTER_WIDTH;
```
首先,定义常量以便合理布局敌人阵型:
```javascript
const ENEMY_TOTAL = 5;
const ENEMY_SPACING = 98;
const FORMATION_WIDTH = ENEMY_TOTAL * ENEMY_SPACING;
const START_X = (canvas.width - FORMATION_WIDTH) / 2;
const STOP_X = START_X + FORMATION_WIDTH;
```
**这些常量实现了什么:**
- 设定每行每列 5 个敌人(整齐的 5×5 网格)
- 定义敌人之间的间距,避免紧凑不适
- 计算整阵型的宽度
- 计算起止坐标,令阵型居中
```mermaid
flowchart LR
A["画布宽度1024px"] --> B["编队宽度490px"]
B --> C["开始X267px"]
C --> D["敌人间距98px"]
subgraph "5x5敌人编队"
E["第1行Y=0"]
F["第2行Y=50"]
G["第3行Y=100"]
H["第4行Y=150"]
I["第5行Y=200"]
end
subgraph "列间距"
J["第1列X=267"]
K["第2列X=365"]
L["第3列X=463"]
M["第4列X=561"]
N["第5列X=659"]
end
style A fill:#e1f5fe
style B fill:#e8f5e8
style C fill:#fff3e0
```
然后,使用嵌套循环绘制敌人阵型:
然后,创建一个循环,将怪物数组绘制到屏幕上:
```javascript
for (let x = START_X; x < STOP_X; x += ENEMY_SPACING) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
```
```javascript
for (let x = START_X; x < STOP_X; x += 98) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
```
**这个嵌套循环做了什么:**
- 外层循环从左往右遍历阵型
- 内层循环垂直遍历,创建整齐行列
- 在计算的精确 x,y 坐标绘制每个敌人精灵
- 保持均匀间距,效果专业有序
### 🔄 **教学检查点**
**游戏渲染掌握情况**:验证你对完整渲染系统的理解:
- ✅ 异步图像加载如何防止游戏启动时阻塞用户界面?
- ✅ 为什么用常量计算敌人阵型位置而非硬编码?
- ✅ 2D 渲染上下文在绘图操作中扮演什么角色?
- ✅ 嵌套循环如何创建有序的精灵阵型?
**性能考量**:你的游戏现展示了:
- **高效资源加载**:基于 Promise 的图像管理
- **有序渲染**:结构化绘图操作
- **数学定位**:计算精灵摆放
- **错误处理**:优雅的失败管理
**视觉编程概念**:你已经学会了:
- **坐标系统**:将数学转换为屏幕位置
- **精灵管理**:加载和显示游戏图形
- **阵型算法**:组织布局的数学模式
- **异步操作**:现代 JavaScript 实现流畅的用户体验
## 结果
完成后的结果应该如下所示:
完成的结果应如下所示:
![黑色屏幕,带有一个英雄和 5*5 的怪物](../../../../translated_images/partI-solution.36c53b48c9ffae2a5e15496b23b604ba5393433e4bf91608a7a0a020eb7a2691.zh.png)
![带有英雄和 5*5 怪物的黑屏](../../../../translated_images/partI-solution.36c53b48c9ffae2a.zh.png)
## 解决方案
请先尝试自己解决,但如果遇到困难,可以查看[解决方案](../../../../6-space-game/2-drawing-to-canvas/solution/app.js)。
请先尝试自己解决,但如果遇到困难,可以查看[解决方案](../../../../6-space-game/2-drawing-to-canvas/solution/app.js)
---
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 使用你学到的 Canvas API 技术,通过添加视觉效果和交互元素来增强你的太空游戏画布。
**提示:** 创建一个名为 `enhanced-canvas.html` 的新文件,画布中显示背景中动画的星星、英雄飞船的脉动生命条,以及缓慢向下移动的敌船。包含使用随机位置和不透明度绘制闪烁星星的 JavaScript 代码,实现根据生命值变化颜色(绿色 > 黄色 > 红色)的生命条,并让敌船以不同速度在屏幕上向下移动。
在这里了解更多关于[Agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode)。
## 🚀 挑战
你已经学习了使用专注于 2D 的 Canvas API看看 [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API),尝试绘制一个 3D 对象。
你已经学会了使用专注于2D的 Canvas API 绘图;看看[WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API)尝试绘制一个3D对象。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/32)
## 复习与自学
## 复习与自
通过[阅读相关内容](https://developer.mozilla.org/docs/Web/API/Canvas_API)了解更多关于 Canvas API 的知识。
### ⚡ **接下来 5 分钟你可以做什么**
- [ ] 打开浏览器控制台,用 `document.createElement('canvas')` 创建画布元素
- [ ] 试着使用画布上下文的 `fillRect()` 绘制矩形
- [ ] 通过 `fillStyle` 属性尝试不同颜色
- [ ] 使用 `arc()` 方法绘制简单的圆形
### 🎯 **本小时你可以完成什么**
- [ ] 完成课后测验,理解画布基础
- [ ] 创建一个具有多种形状和颜色的画布绘图应用
- [ ] 实现你的游戏图像加载和精灵渲染
- [ ] 构建一个简单动画,让对象在画布上移动
- [ ] 练习画布变换,如缩放、旋转和平移
### 📅 **你的一周画布学习旅程**
- [ ] 完成太空游戏,拥有精致图形和精灵动画
- [ ] 精通高级画布技术,如渐变、图案和合成
- [ ] 使用画布创建数据交互可视化
- [ ] 了解画布性能优化技术,确保流畅运行
- [ ] 构建具有多种工具的绘图或绘画应用
- [ ] 探索创意编程模式和生成艺术与画布结合
### 🌟 **你的一月图形大师之路**
- [ ] 使用 Canvas 2D 和 WebGL 构建复杂视觉应用
- [ ] 学习图形编程概念与着色器基础
- [ ] 为开源图形库和可视化工具做贡献
- [ ] 精通图形密集应用的性能优化
- [ ] 制作关于画布编程和计算机图形学的教学内容
- [ ] 成为图形编程专家,帮助他人打造视觉体验
## 🎯 你的画布图形大师时间线
```mermaid
timeline
title Canvas API 学习进度
section Canvas 基础 (15 分钟)
基本操作: 元素引用
: 2D 上下文访问
: 坐标系统
: 简单图形绘制
section 绘图技巧 (20 分钟)
图形原语: 矩形和圆形
: 颜色和样式
: 文本渲染
: 路径操作
section 图像处理 (25 分钟)
资源管理: 图像对象创建
: 异步加载模式
: 错误处理
: 性能优化
section 游戏图形 (30 分钟)
精灵渲染: 位置算法
: 阵型计算
: 场景组合
: 帧渲染
section 高级技巧 (40 分钟)
视觉效果: 变换
: 动画
: 分层
: 状态管理
section 性能 (35 分钟)
优化: 高效绘制
: 内存管理
: 帧率控制
: 资源缓存
section 专业技能 (1 周)
生产图形: WebGL 集成
: Canvas 库
: 游戏引擎
: 跨平台考虑
section 高级图形 (1 个月)
专业应用: 数据可视化
: 交互艺术
: 实时效果
: 3D 图形
```
### 🛠️ 你的画布图形工具包总结
完成本课程后,你现在拥有:
- **Canvas API 掌握**完全理解2D图形编程
- **坐标数学**:精准定位和布局算法
- **资源管理**:专业的图像加载与错误处理
- **渲染管线**:结构化场景组成方法
- **游戏图形**:精灵定位和阵型计算
- **异步编程**:现代 JavaScript 模式实现流畅性能
- **视觉编程**:将数学概念转换为屏幕图形
**现实应用**:你的 Canvas 技能可广泛应用于:
- **数据可视化**:图表、图形和互动仪表盘
- **游戏开发**2D游戏、模拟和交互体验
- **数字艺术**:创意编程和生成艺术项目
- **UI/UX 设计**:自定义图形和交互元素
- **教育软件**:视觉学习工具和模拟
- **Web 应用**:动态图形和实时可视化
**所获专业技能**:你现在可以:
- **构建** 无需外部库的定制图形解决方案
- **优化** 渲染性能,实现流畅用户体验
- **调试** 使用浏览器开发工具排查复杂视觉问题
- **设计** 采用数学原理的可扩展图形系统
- **整合** Canvas 图形与现代 Web 应用框架
**你已掌握的 Canvas API 方法**
- **元素管理**getElementById、getContext
- **绘图操作**fillRect、drawImage、fillStyle
- **资源加载**图像对象、Promise 模式
- **数学定位**:坐标计算、阵型算法
**下一步**:你已经准备好添加动画、用户交互、碰撞检测,或探索 WebGL 实现3D图形
🌟 **成就解锁**:你已用基础 Canvas API 技术构建完整游戏渲染系统!
## 作业
[尝试使用 Canvas API](assignment.md)
[玩转 Canvas API](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原文应被视为权威来源。对于重要信息,建议采用专业人工翻译。我们概不对因使用本翻译而导致的任何误解或误释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -1,23 +1,83 @@
<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "ca1cf78a4c60df77ab32a154ec024d7f",
"translation_date": "2025-08-23T22:59:50+00:00",
"original_hash": "87cd43afe5b69dbbffb5c4b209ea6791",
"translation_date": "2026-01-06T11:25:39+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/assignment.md",
"language_code": "zh"
}
-->
# 玩转 Canvas API
# 作业:探索 Canvas API
## 学习目标
通过完成此作业,您将展示对 Canvas API 基础知识的理解,并运用创造性的问题解决能力,使用 JavaScript 和 HTML5 canvas 构建视觉元素。
## 说明
选择 Canvas API 的一个元素,并围绕它创建一些有趣的内容。你能否创建一个由重复星星组成的小银河?或者创建一个由彩色线条组成的有趣纹理?你可以在 CodePen 上寻找灵感(但不要直接复制)。
选择 Canvas API 中您感兴趣的一个方面,围绕它创建一个有趣的视觉项目。此作业鼓励您在构建独具个人特色的内容时,尝试您所学的绘图功能。
### 项目灵感
**几何图案:**
- **创建** 一个使用随机定位的动画闪烁星空
- **设计** 一种使用重复几何形状的有趣纹理
- **构建** 一个带有旋转多彩图案的万花筒效果
**交互元素:**
- **开发** 一款响应鼠标移动的绘图工具
- **实现** 点击时改变颜色的形状
- **设计** 一个带有移动元素的简单动画循环
**游戏相关图形:**
- **制作** 一个太空游戏的滚动背景
- **构建** 爆炸或魔法效果的粒子效果
- **创建** 带有多帧动画的精灵
### 开发指导
**研究与灵感:**
- **浏览** CodePen 上的创意 canvas 示例(用于灵感,不可抄袭)
- **学习** [Canvas API 文档](https://developer.mozilla.org/docs/Web/API/Canvas_API) 以了解更多方法
- **尝试** 不同的绘图函数、颜色和动画
**技术要求:**
- **使用** 合适的 canvas 设置和 `getContext('2d')`
- **包含** 有意义的注释,说明您的思路
- **充分测试** 代码,确保无错误运行
- **应用** 现代 JavaScript 语法const/let箭头函数
**创造表达:**
- **专注** 于一个 Canvas API 特性,但深入探索
- **加入** 您自己的创意元素,令项目个性化
- **思考** 您的作品如何融入更大的应用中
### 提交要求
将完成的项目作为单个包含嵌入 CSS 和 JavaScript 的 HTML 文件提交,或作为文件夹中的多个单独文件提交。附上一段简要注释,说明您的创意选择以及您探索的 Canvas API 功能。
## 评分标准
| 标准 | 卓越表现 | 合格表现 | 需要改进 |
| -------- | ----------------------------------------------------- | ------------------------------- | --------------------- |
| | 提交的代码展示了有趣的纹理或形状 | 提交了代码,但无法运行 | 未提交代码 |
| 评估标准 | 卓越 | 及格 | 需改进 |
|----------|-------|------|---------|
| **技术实现** | 创意性地使用 Canvas API 多种功能,代码无误运行,应用现代 JavaScript 语法 | 正确使用 Canvas API代码运行有轻微问题基础实现 | 试图使用 Canvas API但代码存在错误或无法执行 |
| **创意与设计** | 极具原创性,视觉效果精致,深入探索所选 Canvas 功能 | Canvas 功能使用良好,具备一定创意,视觉效果稳健 | 基础实现,创意和视觉吸引力有限 |
| **代码质量** | 代码结构良好,有注释,遵循最佳实践,算法高效 | 代码整洁,有部分注释,遵循基本编码规范 | 代码缺乏组织,注释少,实现效率低 |
## 反思问题
完成项目后,请思考以下问题:
1. **您选择了哪个 Canvas API 功能,为什么?**
2. **在构建项目时遇到了哪些挑战?**
3. **您如何将此项目扩展为更大的应用或游戏?**
4. **您接下来想探索哪些其他 Canvas API 功能?**
> 💡 **专业提示**:从简单开始,逐步增加复杂度。一个执行良好的简单项目,比一个雄心勃勃但无法正常工作的项目更好!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。
本文件由AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威来源。对于重要信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误译,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->
Loading…
Cancel
Save