chore(i18n): sync translations with latest source changes (chunk 2/2, 266 changes)

update-translations
localizeflow[bot] 5 days ago
parent a3e935d78c
commit f123f4aab4

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@ -0,0 +1,584 @@
{
"1-getting-started-lessons/1-intro-to-programming-languages/README.md": {
"original_hash": "d45ddcc54eb9232a76d08328b09d792e",
"translation_date": "2025-11-03T12:59:41+00:00",
"source_file": "1-getting-started-lessons/1-intro-to-programming-languages/README.md",
"language_code": "ur"
},
"1-getting-started-lessons/1-intro-to-programming-languages/assignment.md": {
"original_hash": "17b8ec8e85d99e27dcb3f73842e583be",
"translation_date": "2025-10-20T20:45:48+00:00",
"source_file": "1-getting-started-lessons/1-intro-to-programming-languages/assignment.md",
"language_code": "ur"
},
"1-getting-started-lessons/2-github-basics/README.md": {
"original_hash": "5c383cc2cc23bb164b06417d1c107a44",
"translation_date": "2025-11-25T11:50:03+00:00",
"source_file": "1-getting-started-lessons/2-github-basics/README.md",
"language_code": "ur"
},
"1-getting-started-lessons/3-accessibility/README.md": {
"original_hash": "7f2c48e04754724123ea100a822765e5",
"translation_date": "2025-11-03T13:03:16+00:00",
"source_file": "1-getting-started-lessons/3-accessibility/README.md",
"language_code": "ur"
},
"1-getting-started-lessons/3-accessibility/assignment.md": {
"original_hash": "e6d0f456dfc22afb41bbdefeb5ec179d",
"translation_date": "2025-10-20T20:48:34+00:00",
"source_file": "1-getting-started-lessons/3-accessibility/assignment.md",
"language_code": "ur"
},
"1-getting-started-lessons/README.md": {
"original_hash": "770d9f83dddc841c19f210dee5fe0712",
"translation_date": "2025-10-03T13:25:49+00:00",
"source_file": "1-getting-started-lessons/README.md",
"language_code": "ur"
},
"10-ai-framework-project/README.md": {
"original_hash": "3925b6a1c31c60755eaae4d578232c25",
"translation_date": "2025-11-03T13:07:43+00:00",
"source_file": "10-ai-framework-project/README.md",
"language_code": "ur"
},
"10-ai-framework-project/solution/README.md": {
"original_hash": "d41d8cd98f00b204e9800998ecf8427e",
"translation_date": "2026-01-29T17:41:28+00:00",
"source_file": "10-ai-framework-project/solution/README.md",
"language_code": "ur"
},
"2-js-basics/1-data-types/README.md": {
"original_hash": "672b0bb6e8b431075f3bdb7130590d2d",
"translation_date": "2025-11-03T12:52:12+00:00",
"source_file": "2-js-basics/1-data-types/README.md",
"language_code": "ur"
},
"2-js-basics/1-data-types/assignment.md": {
"original_hash": "6fd645e97c48cd5eb5a3d290815ec8b5",
"translation_date": "2025-10-22T14:32:15+00:00",
"source_file": "2-js-basics/1-data-types/assignment.md",
"language_code": "ur"
},
"2-js-basics/2-functions-methods/README.md": {
"original_hash": "71f7d7dafa1c7194d79ddac87f669ff9",
"translation_date": "2025-11-03T12:53:48+00:00",
"source_file": "2-js-basics/2-functions-methods/README.md",
"language_code": "ur"
},
"2-js-basics/2-functions-methods/assignment.md": {
"original_hash": "8328f58f4593b4671656ff8f4b2edbd9",
"translation_date": "2025-10-22T14:32:55+00:00",
"source_file": "2-js-basics/2-functions-methods/assignment.md",
"language_code": "ur"
},
"2-js-basics/3-making-decisions/README.md": {
"original_hash": "c688385d15dd3645e924ea0ffee8967f",
"translation_date": "2025-11-03T12:55:10+00:00",
"source_file": "2-js-basics/3-making-decisions/README.md",
"language_code": "ur"
},
"2-js-basics/3-making-decisions/assignment.md": {
"original_hash": "ffe366b2d1f037b99fbadbe1dc81083d",
"translation_date": "2025-10-22T14:34:18+00:00",
"source_file": "2-js-basics/3-making-decisions/assignment.md",
"language_code": "ur"
},
"2-js-basics/4-arrays-loops/README.md": {
"original_hash": "1710a50a519a6e4a1b40a5638783018d",
"translation_date": "2025-11-03T12:54:29+00:00",
"source_file": "2-js-basics/4-arrays-loops/README.md",
"language_code": "ur"
},
"2-js-basics/4-arrays-loops/assignment.md": {
"original_hash": "8abcada0534e0fb3a7556ea3c5a2a8a4",
"translation_date": "2025-10-22T14:33:38+00:00",
"source_file": "2-js-basics/4-arrays-loops/assignment.md",
"language_code": "ur"
},
"2-js-basics/README.md": {
"original_hash": "cc9e70a2f096c67389c8acff1521fc27",
"translation_date": "2025-08-25T21:31:58+00:00",
"source_file": "2-js-basics/README.md",
"language_code": "ur"
},
"3-terrarium/1-intro-to-html/README.md": {
"original_hash": "3fcfa99c4897e051b558b5eaf1e8cc74",
"translation_date": "2025-11-03T13:16:50+00:00",
"source_file": "3-terrarium/1-intro-to-html/README.md",
"language_code": "ur"
},
"3-terrarium/1-intro-to-html/assignment.md": {
"original_hash": "650e63282e1dfa032890fcf5c1c4119d",
"translation_date": "2025-10-22T14:56:03+00:00",
"source_file": "3-terrarium/1-intro-to-html/assignment.md",
"language_code": "ur"
},
"3-terrarium/2-intro-to-css/README.md": {
"original_hash": "e39f3a4e3bcccf94639e3af1248f8a4d",
"translation_date": "2025-11-03T13:15:52+00:00",
"source_file": "3-terrarium/2-intro-to-css/README.md",
"language_code": "ur"
},
"3-terrarium/2-intro-to-css/assignment.md": {
"original_hash": "bee6762d4092a13fc7c338814963f980",
"translation_date": "2025-10-22T14:54:16+00:00",
"source_file": "3-terrarium/2-intro-to-css/assignment.md",
"language_code": "ur"
},
"3-terrarium/3-intro-to-DOM-and-closures/README.md": {
"original_hash": "973e48ad87d67bf5bb819746c9f8e302",
"translation_date": "2025-11-03T13:13:52+00:00",
"source_file": "3-terrarium/3-intro-to-DOM-and-closures/README.md",
"language_code": "ur"
},
"3-terrarium/3-intro-to-DOM-and-closures/assignment.md": {
"original_hash": "947ca5ce7c94aee9c7de7034e762bc17",
"translation_date": "2025-10-22T14:53:12+00:00",
"source_file": "3-terrarium/3-intro-to-DOM-and-closures/assignment.md",
"language_code": "ur"
},
"3-terrarium/README.md": {
"original_hash": "bc5c5550f79d10add90ce419ee34abb3",
"translation_date": "2026-01-06T11:01:29+00:00",
"source_file": "3-terrarium/README.md",
"language_code": "ur"
},
"3-terrarium/solution/README.md": {
"original_hash": "6329fbe8bd936068debd78cca6f09c0a",
"translation_date": "2025-08-25T21:30:26+00:00",
"source_file": "3-terrarium/solution/README.md",
"language_code": "ur"
},
"4-typing-game/README.md": {
"original_hash": "efa2ab875b8bb5a7883816506da6b6d2",
"translation_date": "2025-11-03T13:27:08+00:00",
"source_file": "4-typing-game/README.md",
"language_code": "ur"
},
"4-typing-game/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-26T00:54:31+00:00",
"source_file": "4-typing-game/solution/README.md",
"language_code": "ur"
},
"4-typing-game/typing-game/README.md": {
"original_hash": "da8bc72041a2bb3826a54654ee1a8844",
"translation_date": "2025-11-03T13:28:28+00:00",
"source_file": "4-typing-game/typing-game/README.md",
"language_code": "ur"
},
"4-typing-game/typing-game/assignment.md": {
"original_hash": "3eac59d70e2532a677a2ce6bf765485a",
"translation_date": "2025-10-22T15:07:02+00:00",
"source_file": "4-typing-game/typing-game/assignment.md",
"language_code": "ur"
},
"5-browser-extension/1-about-browsers/README.md": {
"original_hash": "00aa85715e1efd4930c17a23e3012e69",
"translation_date": "2025-11-03T13:42:16+00:00",
"source_file": "5-browser-extension/1-about-browsers/README.md",
"language_code": "ur"
},
"5-browser-extension/1-about-browsers/assignment.md": {
"original_hash": "b6897c02603d0045dd6d8256e8714baa",
"translation_date": "2025-10-22T15:16:12+00:00",
"source_file": "5-browser-extension/1-about-browsers/assignment.md",
"language_code": "ur"
},
"5-browser-extension/2-forms-browsers-local-storage/README.md": {
"original_hash": "2b6203a48c48d8234e0948353b47d84e",
"translation_date": "2025-11-03T13:40:35+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/README.md",
"language_code": "ur"
},
"5-browser-extension/2-forms-browsers-local-storage/assignment.md": {
"original_hash": "25b8d28b8531352d4eb67291fd7824c4",
"translation_date": "2025-10-22T15:14:39+00:00",
"source_file": "5-browser-extension/2-forms-browsers-local-storage/assignment.md",
"language_code": "ur"
},
"5-browser-extension/3-background-tasks-and-performance/README.md": {
"original_hash": "b275fed2c6fc90d2b9b6661a3225faa2",
"translation_date": "2025-11-03T13:38:52+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/README.md",
"language_code": "ur"
},
"5-browser-extension/3-background-tasks-and-performance/assignment.md": {
"original_hash": "a203e560e58ccc6ba68bffc40c7c8676",
"translation_date": "2025-10-22T15:13:04+00:00",
"source_file": "5-browser-extension/3-background-tasks-and-performance/assignment.md",
"language_code": "ur"
},
"5-browser-extension/README.md": {
"original_hash": "b121a279a6ab39878491f3e572673515",
"translation_date": "2025-08-25T23:26:02+00:00",
"source_file": "5-browser-extension/README.md",
"language_code": "ur"
},
"5-browser-extension/solution/README.md": {
"original_hash": "fab4e6b4f0efcd587a9029d82991f597",
"translation_date": "2025-08-25T23:50:11+00:00",
"source_file": "5-browser-extension/solution/README.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.es.md": {
"original_hash": "cbaf73f94a9ab4c680a10ef871e92948",
"translation_date": "2025-08-25T23:52:00+00:00",
"source_file": "5-browser-extension/solution/translation/README.es.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.fr.md": {
"original_hash": "9361268ca430b2579375009e1eceb5e5",
"translation_date": "2025-08-25T23:57:21+00:00",
"source_file": "5-browser-extension/solution/translation/README.fr.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.hi.md": {
"original_hash": "dd58ae1b7707034f055718c1b68bc8de",
"translation_date": "2025-08-25T23:53:44+00:00",
"source_file": "5-browser-extension/solution/translation/README.hi.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.it.md": {
"original_hash": "9a6b22a2eff0f499b66236be973b24ad",
"translation_date": "2025-08-25T23:59:07+00:00",
"source_file": "5-browser-extension/solution/translation/README.it.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.ja.md": {
"original_hash": "3f5e6821e0febccfc5d05e7c944d9e3d",
"translation_date": "2025-08-26T00:00:54+00:00",
"source_file": "5-browser-extension/solution/translation/README.ja.md",
"language_code": "ur"
},
"5-browser-extension/solution/translation/README.ms.md": {
"original_hash": "21b364c158c8e4f698de65eeac16c9fe",
"translation_date": "2025-08-25T23:55:33+00:00",
"source_file": "5-browser-extension/solution/translation/README.ms.md",
"language_code": "ur"
},
"5-browser-extension/start/README.md": {
"original_hash": "26fd39046d264ba185dcb086d3a8cf3e",
"translation_date": "2025-08-25T23:34:52+00:00",
"source_file": "5-browser-extension/start/README.md",
"language_code": "ur"
},
"6-space-game/1-introduction/README.md": {
"original_hash": "a6332a7bb4d0be3bfd24199c83993777",
"translation_date": "2025-11-03T13:36:40+00:00",
"source_file": "6-space-game/1-introduction/README.md",
"language_code": "ur"
},
"6-space-game/1-introduction/assignment.md": {
"original_hash": "c8fc39a014d08247c082878122e2ba73",
"translation_date": "2025-10-22T15:11:57+00:00",
"source_file": "6-space-game/1-introduction/assignment.md",
"language_code": "ur"
},
"6-space-game/2-drawing-to-canvas/README.md": {
"original_hash": "7994743c5b21fdcceb36307916ef249a",
"translation_date": "2025-11-03T13:32:20+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/README.md",
"language_code": "ur"
},
"6-space-game/2-drawing-to-canvas/assignment.md": {
"original_hash": "87cd43afe5b69dbbffb5c4b209ea6791",
"translation_date": "2025-10-22T15:09:25+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/assignment.md",
"language_code": "ur"
},
"6-space-game/3-moving-elements-around/README.md": {
"original_hash": "8c55a2bd4bc0ebe4c88198fd563a9e09",
"translation_date": "2025-11-03T13:30:35+00:00",
"source_file": "6-space-game/3-moving-elements-around/README.md",
"language_code": "ur"
},
"6-space-game/3-moving-elements-around/assignment.md": {
"original_hash": "c162b3b3a1cafc1483c8015e9b266f0d",
"translation_date": "2025-10-22T15:08:43+00:00",
"source_file": "6-space-game/3-moving-elements-around/assignment.md",
"language_code": "ur"
},
"6-space-game/4-collision-detection/README.md": {
"original_hash": "039b4d8ce65f5edd82cf48d9c3e6728c",
"translation_date": "2025-11-03T13:35:53+00:00",
"source_file": "6-space-game/4-collision-detection/README.md",
"language_code": "ur"
},
"6-space-game/4-collision-detection/assignment.md": {
"original_hash": "124efddbb65166cddb38075ad6dae324",
"translation_date": "2025-10-22T15:11:17+00:00",
"source_file": "6-space-game/4-collision-detection/assignment.md",
"language_code": "ur"
},
"6-space-game/4-collision-detection/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:28:03+00:00",
"source_file": "6-space-game/4-collision-detection/solution/README.md",
"language_code": "ur"
},
"6-space-game/4-collision-detection/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:27:14+00:00",
"source_file": "6-space-game/4-collision-detection/your-work/README.md",
"language_code": "ur"
},
"6-space-game/5-keeping-score/README.md": {
"original_hash": "2ed9145a16cf576faa2a973dff84d099",
"translation_date": "2025-11-03T13:37:22+00:00",
"source_file": "6-space-game/5-keeping-score/README.md",
"language_code": "ur"
},
"6-space-game/5-keeping-score/assignment.md": {
"original_hash": "81f292dbda01685b91735e0398dc0504",
"translation_date": "2025-08-25T22:06:15+00:00",
"source_file": "6-space-game/5-keeping-score/assignment.md",
"language_code": "ur"
},
"6-space-game/5-keeping-score/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:08:15+00:00",
"source_file": "6-space-game/5-keeping-score/solution/README.md",
"language_code": "ur"
},
"6-space-game/5-keeping-score/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:07:21+00:00",
"source_file": "6-space-game/5-keeping-score/your-work/README.md",
"language_code": "ur"
},
"6-space-game/6-end-condition/README.md": {
"original_hash": "a4b78043f4d64bf3ee24e0689b8b391d",
"translation_date": "2025-11-03T13:33:58+00:00",
"source_file": "6-space-game/6-end-condition/README.md",
"language_code": "ur"
},
"6-space-game/6-end-condition/assignment.md": {
"original_hash": "232d592791465c1678cab3a2bb6cd3e8",
"translation_date": "2025-10-22T15:10:11+00:00",
"source_file": "6-space-game/6-end-condition/assignment.md",
"language_code": "ur"
},
"6-space-game/6-end-condition/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:39:49+00:00",
"source_file": "6-space-game/6-end-condition/solution/README.md",
"language_code": "ur"
},
"6-space-game/6-end-condition/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:39:00+00:00",
"source_file": "6-space-game/6-end-condition/your-work/README.md",
"language_code": "ur"
},
"6-space-game/README.md": {
"original_hash": "c40a698395ee5102715f7880bba3f2e7",
"translation_date": "2025-08-25T22:01:25+00:00",
"source_file": "6-space-game/README.md",
"language_code": "ur"
},
"6-space-game/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-25T22:40:36+00:00",
"source_file": "6-space-game/solution/README.md",
"language_code": "ur"
},
"7-bank-project/1-template-route/README.md": {
"original_hash": "351678bece18f07d9daa987a881fb062",
"translation_date": "2025-11-03T13:23:42+00:00",
"source_file": "7-bank-project/1-template-route/README.md",
"language_code": "ur"
},
"7-bank-project/1-template-route/assignment.md": {
"original_hash": "df0dcecddcd28ea8cbf6ede0ad57d673",
"translation_date": "2025-10-22T15:03:16+00:00",
"source_file": "7-bank-project/1-template-route/assignment.md",
"language_code": "ur"
},
"7-bank-project/2-forms/README.md": {
"original_hash": "7cbdbd132d39a2bb493e85bc2a9387cc",
"translation_date": "2025-11-03T13:26:00+00:00",
"source_file": "7-bank-project/2-forms/README.md",
"language_code": "ur"
},
"7-bank-project/2-forms/assignment.md": {
"original_hash": "efb01fcafd2ef40c593a6e662fc938a8",
"translation_date": "2025-10-22T15:05:35+00:00",
"source_file": "7-bank-project/2-forms/assignment.md",
"language_code": "ur"
},
"7-bank-project/3-data/README.md": {
"original_hash": "86ee5069f27ea3151389d8687c95fac9",
"translation_date": "2025-11-03T13:21:06+00:00",
"source_file": "7-bank-project/3-data/README.md",
"language_code": "ur"
},
"7-bank-project/3-data/assignment.md": {
"original_hash": "d0a02cb117e91a5b5f24178080068a3d",
"translation_date": "2025-10-22T15:00:56+00:00",
"source_file": "7-bank-project/3-data/assignment.md",
"language_code": "ur"
},
"7-bank-project/4-state-management/README.md": {
"original_hash": "b807b09df716dc48a2b750835bf8e933",
"translation_date": "2025-11-03T13:18:39+00:00",
"source_file": "7-bank-project/4-state-management/README.md",
"language_code": "ur"
},
"7-bank-project/4-state-management/assignment.md": {
"original_hash": "50a7783473b39a2e0f133e271a102231",
"translation_date": "2025-10-22T14:58:15+00:00",
"source_file": "7-bank-project/4-state-management/assignment.md",
"language_code": "ur"
},
"7-bank-project/README.md": {
"original_hash": "830359535306594b448db6575ce5cdee",
"translation_date": "2025-08-26T00:02:42+00:00",
"source_file": "7-bank-project/README.md",
"language_code": "ur"
},
"7-bank-project/api/README.md": {
"original_hash": "9884f8c8a61cf56214450f8b16a094ce",
"translation_date": "2025-08-26T00:04:13+00:00",
"source_file": "7-bank-project/api/README.md",
"language_code": "ur"
},
"7-bank-project/solution/README.md": {
"original_hash": "461aa4fc74c6b1789c3a13b5d82c0cd9",
"translation_date": "2025-08-26T00:39:14+00:00",
"source_file": "7-bank-project/solution/README.md",
"language_code": "ur"
},
"8-code-editor/1-using-a-code-editor/README.md": {
"original_hash": "a9a3bcc037a447e2d8994d99e871cd9f",
"translation_date": "2025-11-03T12:56:53+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/README.md",
"language_code": "ur"
},
"8-code-editor/1-using-a-code-editor/assignment.md": {
"original_hash": "effe56ba51c38d7bdfad1ea38288666b",
"translation_date": "2025-10-22T14:36:54+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/assignment.md",
"language_code": "ur"
},
"9-chat-project/README.md": {
"original_hash": "2066c17078e9d18b5e309f31d8e8bc24",
"translation_date": "2025-11-03T13:10:45+00:00",
"source_file": "9-chat-project/README.md",
"language_code": "ur"
},
"9-chat-project/solution/README.md": {
"original_hash": "cb549dcad8eea3221cb89793aeaa3bb3",
"translation_date": "2025-09-01T15:21:26+00:00",
"source_file": "9-chat-project/solution/README.md",
"language_code": "ur"
},
"9-chat-project/solution/backend/README.md": {
"original_hash": "bcd2c2bbaae71151b1ed1b9170aa78af",
"translation_date": "2025-09-01T15:42:19+00:00",
"source_file": "9-chat-project/solution/backend/README.md",
"language_code": "ur"
},
"9-chat-project/solution/backend/python/README.md": {
"original_hash": "0aaa930f076f2d83cc872ad157f8ffd3",
"translation_date": "2025-10-22T14:51:21+00:00",
"source_file": "9-chat-project/solution/backend/python/README.md",
"language_code": "ur"
},
"9-chat-project/solution/frontend/README.md": {
"original_hash": "7746a470be8fc7f736eb1b43ebb710ee",
"translation_date": "2025-09-01T15:51:05+00:00",
"source_file": "9-chat-project/solution/frontend/README.md",
"language_code": "ur"
},
"AGENTS.md": {
"original_hash": "a362efd06d64d4134a0cfe8515a86d34",
"translation_date": "2025-10-03T11:15:55+00:00",
"source_file": "AGENTS.md",
"language_code": "ur"
},
"CODE_OF_CONDUCT.md": {
"original_hash": "b0a9b4cccd918195f58224d5793da1a6",
"translation_date": "2025-08-25T20:58:01+00:00",
"source_file": "CODE_OF_CONDUCT.md",
"language_code": "ur"
},
"CONTRIBUTING.md": {
"original_hash": "777400e9f0336c7ee2f9a1200a88478f",
"translation_date": "2025-08-25T21:02:32+00:00",
"source_file": "CONTRIBUTING.md",
"language_code": "ur"
},
"Git-Basics/README.md": {
"original_hash": "5cf5e1ed51455fefed4895fcc4d6ba2a",
"translation_date": "2025-10-03T15:46:23+00:00",
"source_file": "Git-Basics/README.md",
"language_code": "ur"
},
"README.md": {
"original_hash": "490c83786552d7fab6390991517bef09",
"translation_date": "2026-01-29T17:43:12+00:00",
"source_file": "README.md",
"language_code": "ur"
},
"SECURITY.md": {
"original_hash": "4ecc3bf2e27983d4c780be6f26ee6228",
"translation_date": "2025-08-25T21:00:13+00:00",
"source_file": "SECURITY.md",
"language_code": "ur"
},
"SUPPORT.md": {
"original_hash": "c9d207ff77b4bb46e46dc2b607a8ec1a",
"translation_date": "2025-08-25T20:54:24+00:00",
"source_file": "SUPPORT.md",
"language_code": "ur"
},
"_404.md": {
"original_hash": "ea9f0804bd62f46d9808e953ec7fc459",
"translation_date": "2025-08-25T20:59:04+00:00",
"source_file": "_404.md",
"language_code": "ur"
},
"docs/_navbar.md": {
"original_hash": "3bd2f51ecf4ac9b39277cba748943793",
"translation_date": "2025-08-25T22:00:10+00:00",
"source_file": "docs/_navbar.md",
"language_code": "ur"
},
"docs/_sidebar.md": {
"original_hash": "655c91b5979de46f1d70d97f0c5f1d14",
"translation_date": "2025-08-25T21:58:33+00:00",
"source_file": "docs/_sidebar.md",
"language_code": "ur"
},
"for-teachers.md": {
"original_hash": "71009af209f81cc01a1f2d324200375f",
"translation_date": "2025-10-03T08:42:38+00:00",
"source_file": "for-teachers.md",
"language_code": "ur"
},
"lesson-template/README.md": {
"original_hash": "0494be70ad7fadd13a8c3d549c23e355",
"translation_date": "2025-08-26T00:50:45+00:00",
"source_file": "lesson-template/README.md",
"language_code": "ur"
},
"lesson-template/assignment.md": {
"original_hash": "b5f62ec256c7e43e771f0d3b4e1a9130",
"translation_date": "2025-08-26T00:52:01+00:00",
"source_file": "lesson-template/assignment.md",
"language_code": "ur"
},
"memory-game/README.md": {
"original_hash": "ff47271e53637b2ba6ba72ad2b70f6d7",
"translation_date": "2025-10-03T11:53:51+00:00",
"source_file": "memory-game/README.md",
"language_code": "ur"
},
"quiz-app/README.md": {
"original_hash": "5301875c55bb305e6046bed3a4fd06d2",
"translation_date": "2025-08-26T01:11:36+00:00",
"source_file": "quiz-app/README.md",
"language_code": "ur"
}
}

@ -0,0 +1,584 @@
{
"1-getting-started-lessons/1-intro-to-programming-languages/README.md": {
"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-CN"
},
"1-getting-started-lessons/1-intro-to-programming-languages/assignment.md": {
"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-CN"
},
"1-getting-started-lessons/2-github-basics/README.md": {
"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-CN"
},
"1-getting-started-lessons/3-accessibility/README.md": {
"original_hash": "7f2c48e04754724123ea100a822765e5",
"translation_date": "2026-01-06T11:54:52+00:00",
"source_file": "1-getting-started-lessons/3-accessibility/README.md",
"language_code": "zh-CN"
},
"1-getting-started-lessons/3-accessibility/assignment.md": {
"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-CN"
},
"1-getting-started-lessons/README.md": {
"original_hash": "770d9f83dddc841c19f210dee5fe0712",
"translation_date": "2025-10-03T13:25:55+00:00",
"source_file": "1-getting-started-lessons/README.md",
"language_code": "zh-CN"
},
"10-ai-framework-project/README.md": {
"original_hash": "3925b6a1c31c60755eaae4d578232c25",
"translation_date": "2026-01-06T11:03:16+00:00",
"source_file": "10-ai-framework-project/README.md",
"language_code": "zh-CN"
},
"10-ai-framework-project/solution/README.md": {
"original_hash": "d41d8cd98f00b204e9800998ecf8427e",
"translation_date": "2026-01-29T17:41:28+00:00",
"source_file": "10-ai-framework-project/solution/README.md",
"language_code": "zh-CN"
},
"2-js-basics/1-data-types/README.md": {
"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-CN"
},
"2-js-basics/1-data-types/assignment.md": {
"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-CN"
},
"2-js-basics/2-functions-methods/README.md": {
"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-CN"
},
"2-js-basics/2-functions-methods/assignment.md": {
"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-CN"
},
"2-js-basics/3-making-decisions/README.md": {
"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-CN"
},
"2-js-basics/3-making-decisions/assignment.md": {
"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-CN"
},
"2-js-basics/4-arrays-loops/README.md": {
"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-CN"
},
"2-js-basics/4-arrays-loops/assignment.md": {
"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-CN"
},
"2-js-basics/README.md": {
"original_hash": "cc9e70a2f096c67389c8acff1521fc27",
"translation_date": "2025-08-23T22:36:41+00:00",
"source_file": "2-js-basics/README.md",
"language_code": "zh-CN"
},
"3-terrarium/1-intro-to-html/README.md": {
"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-CN"
},
"3-terrarium/1-intro-to-html/assignment.md": {
"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-CN"
},
"3-terrarium/2-intro-to-css/README.md": {
"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-CN"
},
"3-terrarium/2-intro-to-css/assignment.md": {
"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-CN"
},
"3-terrarium/3-intro-to-DOM-and-closures/README.md": {
"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-CN"
},
"3-terrarium/3-intro-to-DOM-and-closures/assignment.md": {
"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-CN"
},
"3-terrarium/README.md": {
"original_hash": "bc5c5550f79d10add90ce419ee34abb3",
"translation_date": "2026-01-06T11:06:19+00:00",
"source_file": "3-terrarium/README.md",
"language_code": "zh-CN"
},
"3-terrarium/solution/README.md": {
"original_hash": "6329fbe8bd936068debd78cca6f09c0a",
"translation_date": "2025-08-23T22:35:49+00:00",
"source_file": "3-terrarium/solution/README.md",
"language_code": "zh-CN"
},
"4-typing-game/README.md": {
"original_hash": "efa2ab875b8bb5a7883816506da6b6d2",
"translation_date": "2026-01-06T11:05:33+00:00",
"source_file": "4-typing-game/README.md",
"language_code": "zh-CN"
},
"4-typing-game/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-24T00:17:41+00:00",
"source_file": "4-typing-game/solution/README.md",
"language_code": "zh-CN"
},
"4-typing-game/typing-game/README.md": {
"original_hash": "da8bc72041a2bb3826a54654ee1a8844",
"translation_date": "2026-01-06T11:47:12+00:00",
"source_file": "4-typing-game/typing-game/README.md",
"language_code": "zh-CN"
},
"4-typing-game/typing-game/assignment.md": {
"original_hash": "3eac59d70e2532a677a2ce6bf765485a",
"translation_date": "2026-01-06T11:48:41+00:00",
"source_file": "4-typing-game/typing-game/assignment.md",
"language_code": "zh-CN"
},
"5-browser-extension/1-about-browsers/README.md": {
"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-CN"
},
"5-browser-extension/1-about-browsers/assignment.md": {
"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-CN"
},
"5-browser-extension/2-forms-browsers-local-storage/README.md": {
"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-CN"
},
"5-browser-extension/2-forms-browsers-local-storage/assignment.md": {
"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-CN"
},
"5-browser-extension/3-background-tasks-and-performance/README.md": {
"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-CN"
},
"5-browser-extension/3-background-tasks-and-performance/assignment.md": {
"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-CN"
},
"5-browser-extension/README.md": {
"original_hash": "b121a279a6ab39878491f3e572673515",
"translation_date": "2025-08-23T23:37:05+00:00",
"source_file": "5-browser-extension/README.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/README.md": {
"original_hash": "fab4e6b4f0efcd587a9029d82991f597",
"translation_date": "2025-08-23T23:48:13+00:00",
"source_file": "5-browser-extension/solution/README.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.es.md": {
"original_hash": "cbaf73f94a9ab4c680a10ef871e92948",
"translation_date": "2025-08-23T23:49:06+00:00",
"source_file": "5-browser-extension/solution/translation/README.es.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.fr.md": {
"original_hash": "9361268ca430b2579375009e1eceb5e5",
"translation_date": "2025-08-23T23:51:49+00:00",
"source_file": "5-browser-extension/solution/translation/README.fr.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.hi.md": {
"original_hash": "dd58ae1b7707034f055718c1b68bc8de",
"translation_date": "2025-08-23T23:50:02+00:00",
"source_file": "5-browser-extension/solution/translation/README.hi.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.it.md": {
"original_hash": "9a6b22a2eff0f499b66236be973b24ad",
"translation_date": "2025-08-23T23:52:42+00:00",
"source_file": "5-browser-extension/solution/translation/README.it.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.ja.md": {
"original_hash": "3f5e6821e0febccfc5d05e7c944d9e3d",
"translation_date": "2025-08-23T23:53:33+00:00",
"source_file": "5-browser-extension/solution/translation/README.ja.md",
"language_code": "zh-CN"
},
"5-browser-extension/solution/translation/README.ms.md": {
"original_hash": "21b364c158c8e4f698de65eeac16c9fe",
"translation_date": "2025-08-23T23:50:56+00:00",
"source_file": "5-browser-extension/solution/translation/README.ms.md",
"language_code": "zh-CN"
},
"5-browser-extension/start/README.md": {
"original_hash": "26fd39046d264ba185dcb086d3a8cf3e",
"translation_date": "2025-08-23T23:41:12+00:00",
"source_file": "5-browser-extension/start/README.md",
"language_code": "zh-CN"
},
"6-space-game/1-introduction/README.md": {
"original_hash": "a6332a7bb4d0be3bfd24199c83993777",
"translation_date": "2026-01-06T11:29:06+00:00",
"source_file": "6-space-game/1-introduction/README.md",
"language_code": "zh-CN"
},
"6-space-game/1-introduction/assignment.md": {
"original_hash": "c8fc39a014d08247c082878122e2ba73",
"translation_date": "2026-01-06T11:30:50+00:00",
"source_file": "6-space-game/1-introduction/assignment.md",
"language_code": "zh-CN"
},
"6-space-game/2-drawing-to-canvas/README.md": {
"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-CN"
},
"6-space-game/2-drawing-to-canvas/assignment.md": {
"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-CN"
},
"6-space-game/3-moving-elements-around/README.md": {
"original_hash": "8c55a2bd4bc0ebe4c88198fd563a9e09",
"translation_date": "2026-01-06T11:31:07+00:00",
"source_file": "6-space-game/3-moving-elements-around/README.md",
"language_code": "zh-CN"
},
"6-space-game/3-moving-elements-around/assignment.md": {
"original_hash": "c162b3b3a1cafc1483c8015e9b266f0d",
"translation_date": "2026-01-06T11:32:45+00:00",
"source_file": "6-space-game/3-moving-elements-around/assignment.md",
"language_code": "zh-CN"
},
"6-space-game/4-collision-detection/README.md": {
"original_hash": "039b4d8ce65f5edd82cf48d9c3e6728c",
"translation_date": "2026-01-06T11:22:28+00:00",
"source_file": "6-space-game/4-collision-detection/README.md",
"language_code": "zh-CN"
},
"6-space-game/4-collision-detection/assignment.md": {
"original_hash": "124efddbb65166cddb38075ad6dae324",
"translation_date": "2026-01-06T11:23:55+00:00",
"source_file": "6-space-game/4-collision-detection/assignment.md",
"language_code": "zh-CN"
},
"6-space-game/4-collision-detection/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T23:03:54+00:00",
"source_file": "6-space-game/4-collision-detection/solution/README.md",
"language_code": "zh-CN"
},
"6-space-game/4-collision-detection/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T23:03:24+00:00",
"source_file": "6-space-game/4-collision-detection/your-work/README.md",
"language_code": "zh-CN"
},
"6-space-game/5-keeping-score/README.md": {
"original_hash": "2ed9145a16cf576faa2a973dff84d099",
"translation_date": "2026-01-06T11:28:05+00:00",
"source_file": "6-space-game/5-keeping-score/README.md",
"language_code": "zh-CN"
},
"6-space-game/5-keeping-score/assignment.md": {
"original_hash": "81f292dbda01685b91735e0398dc0504",
"translation_date": "2025-08-23T22:53:29+00:00",
"source_file": "6-space-game/5-keeping-score/assignment.md",
"language_code": "zh-CN"
},
"6-space-game/5-keeping-score/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T22:54:32+00:00",
"source_file": "6-space-game/5-keeping-score/solution/README.md",
"language_code": "zh-CN"
},
"6-space-game/5-keeping-score/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T22:54:04+00:00",
"source_file": "6-space-game/5-keeping-score/your-work/README.md",
"language_code": "zh-CN"
},
"6-space-game/6-end-condition/README.md": {
"original_hash": "a4b78043f4d64bf3ee24e0689b8b391d",
"translation_date": "2026-01-06T11:25:54+00:00",
"source_file": "6-space-game/6-end-condition/README.md",
"language_code": "zh-CN"
},
"6-space-game/6-end-condition/assignment.md": {
"original_hash": "232d592791465c1678cab3a2bb6cd3e8",
"translation_date": "2026-01-06T11:27:43+00:00",
"source_file": "6-space-game/6-end-condition/assignment.md",
"language_code": "zh-CN"
},
"6-space-game/6-end-condition/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T23:09:58+00:00",
"source_file": "6-space-game/6-end-condition/solution/README.md",
"language_code": "zh-CN"
},
"6-space-game/6-end-condition/your-work/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T23:09:28+00:00",
"source_file": "6-space-game/6-end-condition/your-work/README.md",
"language_code": "zh-CN"
},
"6-space-game/README.md": {
"original_hash": "c40a698395ee5102715f7880bba3f2e7",
"translation_date": "2025-08-23T22:51:01+00:00",
"source_file": "6-space-game/README.md",
"language_code": "zh-CN"
},
"6-space-game/solution/README.md": {
"original_hash": "068cbb9b3c10a96d503f6cdd6c9ace8c",
"translation_date": "2025-08-23T23:10:27+00:00",
"source_file": "6-space-game/solution/README.md",
"language_code": "zh-CN"
},
"7-bank-project/1-template-route/README.md": {
"original_hash": "351678bece18f07d9daa987a881fb062",
"translation_date": "2026-01-06T11:40:39+00:00",
"source_file": "7-bank-project/1-template-route/README.md",
"language_code": "zh-CN"
},
"7-bank-project/1-template-route/assignment.md": {
"original_hash": "df0dcecddcd28ea8cbf6ede0ad57d673",
"translation_date": "2026-01-06T11:42:27+00:00",
"source_file": "7-bank-project/1-template-route/assignment.md",
"language_code": "zh-CN"
},
"7-bank-project/2-forms/README.md": {
"original_hash": "7cbdbd132d39a2bb493e85bc2a9387cc",
"translation_date": "2026-01-06T11:38:09+00:00",
"source_file": "7-bank-project/2-forms/README.md",
"language_code": "zh-CN"
},
"7-bank-project/2-forms/assignment.md": {
"original_hash": "efb01fcafd2ef40c593a6e662fc938a8",
"translation_date": "2026-01-06T11:40:21+00:00",
"source_file": "7-bank-project/2-forms/assignment.md",
"language_code": "zh-CN"
},
"7-bank-project/3-data/README.md": {
"original_hash": "86ee5069f27ea3151389d8687c95fac9",
"translation_date": "2026-01-06T11:42:36+00:00",
"source_file": "7-bank-project/3-data/README.md",
"language_code": "zh-CN"
},
"7-bank-project/3-data/assignment.md": {
"original_hash": "d0a02cb117e91a5b5f24178080068a3d",
"translation_date": "2026-01-06T11:44:49+00:00",
"source_file": "7-bank-project/3-data/assignment.md",
"language_code": "zh-CN"
},
"7-bank-project/4-state-management/README.md": {
"original_hash": "b807b09df716dc48a2b750835bf8e933",
"translation_date": "2026-01-06T11:45:06+00:00",
"source_file": "7-bank-project/4-state-management/README.md",
"language_code": "zh-CN"
},
"7-bank-project/4-state-management/assignment.md": {
"original_hash": "50a7783473b39a2e0f133e271a102231",
"translation_date": "2026-01-06T11:46:54+00:00",
"source_file": "7-bank-project/4-state-management/assignment.md",
"language_code": "zh-CN"
},
"7-bank-project/README.md": {
"original_hash": "830359535306594b448db6575ce5cdee",
"translation_date": "2025-08-23T23:54:25+00:00",
"source_file": "7-bank-project/README.md",
"language_code": "zh-CN"
},
"7-bank-project/api/README.md": {
"original_hash": "9884f8c8a61cf56214450f8b16a094ce",
"translation_date": "2025-08-23T23:55:10+00:00",
"source_file": "7-bank-project/api/README.md",
"language_code": "zh-CN"
},
"7-bank-project/solution/README.md": {
"original_hash": "461aa4fc74c6b1789c3a13b5d82c0cd9",
"translation_date": "2025-08-24T00:10:23+00:00",
"source_file": "7-bank-project/solution/README.md",
"language_code": "zh-CN"
},
"8-code-editor/1-using-a-code-editor/README.md": {
"original_hash": "a9a3bcc037a447e2d8994d99e871cd9f",
"translation_date": "2026-01-06T11:19:40+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/README.md",
"language_code": "zh-CN"
},
"8-code-editor/1-using-a-code-editor/assignment.md": {
"original_hash": "effe56ba51c38d7bdfad1ea38288666b",
"translation_date": "2026-01-06T11:21:50+00:00",
"source_file": "8-code-editor/1-using-a-code-editor/assignment.md",
"language_code": "zh-CN"
},
"9-chat-project/README.md": {
"original_hash": "2066c17078e9d18b5e309f31d8e8bc24",
"translation_date": "2026-01-06T11:06:24+00:00",
"source_file": "9-chat-project/README.md",
"language_code": "zh-CN"
},
"9-chat-project/solution/README.md": {
"original_hash": "cb549dcad8eea3221cb89793aeaa3bb3",
"translation_date": "2025-09-01T15:22:00+00:00",
"source_file": "9-chat-project/solution/README.md",
"language_code": "zh-CN"
},
"9-chat-project/solution/backend/README.md": {
"original_hash": "bcd2c2bbaae71151b1ed1b9170aa78af",
"translation_date": "2025-09-01T15:42:23+00:00",
"source_file": "9-chat-project/solution/backend/README.md",
"language_code": "zh-CN"
},
"9-chat-project/solution/backend/python/README.md": {
"original_hash": "0aaa930f076f2d83cc872ad157f8ffd3",
"translation_date": "2026-01-06T12:03:23+00:00",
"source_file": "9-chat-project/solution/backend/python/README.md",
"language_code": "zh-CN"
},
"9-chat-project/solution/frontend/README.md": {
"original_hash": "7746a470be8fc7f736eb1b43ebb710ee",
"translation_date": "2025-09-01T15:51:09+00:00",
"source_file": "9-chat-project/solution/frontend/README.md",
"language_code": "zh-CN"
},
"AGENTS.md": {
"original_hash": "a362efd06d64d4134a0cfe8515a86d34",
"translation_date": "2025-10-03T11:16:34+00:00",
"source_file": "AGENTS.md",
"language_code": "zh-CN"
},
"CODE_OF_CONDUCT.md": {
"original_hash": "b0a9b4cccd918195f58224d5793da1a6",
"translation_date": "2025-08-23T22:20:05+00:00",
"source_file": "CODE_OF_CONDUCT.md",
"language_code": "zh-CN"
},
"CONTRIBUTING.md": {
"original_hash": "777400e9f0336c7ee2f9a1200a88478f",
"translation_date": "2025-08-23T22:22:20+00:00",
"source_file": "CONTRIBUTING.md",
"language_code": "zh-CN"
},
"Git-Basics/README.md": {
"original_hash": "5cf5e1ed51455fefed4895fcc4d6ba2a",
"translation_date": "2025-10-03T15:46:50+00:00",
"source_file": "Git-Basics/README.md",
"language_code": "zh-CN"
},
"README.md": {
"original_hash": "490c83786552d7fab6390991517bef09",
"translation_date": "2026-01-29T17:44:53+00:00",
"source_file": "README.md",
"language_code": "zh-CN"
},
"SECURITY.md": {
"original_hash": "4ecc3bf2e27983d4c780be6f26ee6228",
"translation_date": "2025-08-23T22:21:13+00:00",
"source_file": "SECURITY.md",
"language_code": "zh-CN"
},
"SUPPORT.md": {
"original_hash": "c9d207ff77b4bb46e46dc2b607a8ec1a",
"translation_date": "2025-08-23T22:18:28+00:00",
"source_file": "SUPPORT.md",
"language_code": "zh-CN"
},
"_404.md": {
"original_hash": "ea9f0804bd62f46d9808e953ec7fc459",
"translation_date": "2025-08-23T22:20:41+00:00",
"source_file": "_404.md",
"language_code": "zh-CN"
},
"docs/_navbar.md": {
"original_hash": "3bd2f51ecf4ac9b39277cba748943793",
"translation_date": "2025-08-23T22:50:22+00:00",
"source_file": "docs/_navbar.md",
"language_code": "zh-CN"
},
"docs/_sidebar.md": {
"original_hash": "655c91b5979de46f1d70d97f0c5f1d14",
"translation_date": "2025-08-23T22:49:23+00:00",
"source_file": "docs/_sidebar.md",
"language_code": "zh-CN"
},
"for-teachers.md": {
"original_hash": "71009af209f81cc01a1f2d324200375f",
"translation_date": "2025-10-03T08:46:37+00:00",
"source_file": "for-teachers.md",
"language_code": "zh-CN"
},
"lesson-template/README.md": {
"original_hash": "0494be70ad7fadd13a8c3d549c23e355",
"translation_date": "2025-08-24T00:15:43+00:00",
"source_file": "lesson-template/README.md",
"language_code": "zh-CN"
},
"lesson-template/assignment.md": {
"original_hash": "b5f62ec256c7e43e771f0d3b4e1a9130",
"translation_date": "2025-08-24T00:16:24+00:00",
"source_file": "lesson-template/assignment.md",
"language_code": "zh-CN"
},
"memory-game/README.md": {
"original_hash": "ff47271e53637b2ba6ba72ad2b70f6d7",
"translation_date": "2025-10-03T11:53:59+00:00",
"source_file": "memory-game/README.md",
"language_code": "zh-CN"
},
"quiz-app/README.md": {
"original_hash": "5301875c55bb305e6046bed3a4fd06d2",
"translation_date": "2025-08-24T00:22:46+00:00",
"source_file": "quiz-app/README.md",
"language_code": "zh-CN"
}
}

@ -0,0 +1,853 @@
# 编程语言与现代开发工具简介
嗨,未来的开发者!👋 我能告诉你一件每天都会让我激动不已的事情吗?你即将发现,编程不仅仅是关于计算机——它是一种具有真正超能力的方式,能让你把最狂野的创意变成现实!
你知道用自己最喜欢的应用时那种一切完美契合的时刻吗?当你点击一个按钮,发生了某种神奇的事情,让你忍不住惊叹“哇,他们到底是怎么做到的?”那么,就像你一样的人——可能正坐在他们最喜欢的咖啡馆,凌晨两点喝着第三杯浓咖啡——写出了创造那个魔法的代码。更震撼的是:到本课结束时,你不仅会理解他们是怎么做到的,还会急切想亲自尝试一番!
听我说,我完全理解如果现在编程看起来让你感到害怕。当我刚开始时,我真的以为你得是某种数学天才,或者从五岁起就开始编程。但有件事彻底改变了我的看法:编程就像学习用一门新语言交谈。你从“你好”和“谢谢”开始,然后学会点咖啡,再到后面能谈天说地!只不过这次,你是在和计算机对话,而说实话?它们是你遇到过的最有耐心的对话伙伴——从不批评你的错误,并且永远乐意再试一次!
今天,我们将探索那些让现代网页开发不仅可行而且极其上瘾的令人难以置信的工具。我说的是 Netflix、Spotify 和你最喜欢的独立应用工作室每天使用的同样的编辑器、浏览器和工作流程。最棒的是,这些专业级、行业标准的工具大多数是完全免费的!
![Intro Programming](../../../../translated_images/zh-CN/webdev101-programming.d6e3f98e61ac4bff.webp)
> 速写笔记由 [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 内容
- **编程语言和它们令人惊讶的个性**——想象参加一个派对,每个人都有完全不同的超能力和解决问题的方式。这就是编程语言的世界,你一定会喜欢认识它们!
- **数字魔法发生的基本构建块**——把它们当作终极创意的乐高积木。一旦你理解这些零件是如何拼合的,你会发现你完全可以构建任何你想象中的东西
- **能让你感觉像拿到巫师魔杖的专业工具**——我一点都不夸张,这些工具真的会让你感觉拥有超能力,更棒的是?它们正是专业人士使用的工具!
> 💡 **温馨提示**:今天别想着把所有内容都记住!此刻,我只希望你感受到可能性的火花。细节会随着我们的实践自然沉淀——这才是真正的学习过程!
> 你也可以在 [Microsoft Learn](https://docs.microsoft.com/learn/modules/web-development-101/introduction-programming/?WT.mc_id=academic-77807-sagibbon) 上学习本课程!
## 那么,什么是*编程*
好,让我们来攻克这个价值百万美元的问题:编程究竟是什么?
我来给你讲一个让我完全改变看法的故事。上周,我试图向我妈妈解释如何使用我们的新智能电视遥控器。我发现自己说着“按那个红色按钮,不是大红按钮,是左边的小红按钮……不,你那边的左边……好了,现在按住两秒,不是一秒,也不是三秒……”是不是很熟悉?😅
这就是编程!它是向一个非常强大的对象给出极其详细、逐步的指令的艺术,但必须清楚准确。只不过你不是向妈妈(她可能会问“哪个红色按钮?!”)解释,而是向计算机(它只做你说的,即使不完全是你想要的)。
当我第一次学会这点时真是震惊到不行计算机其实很简单。它们字面上只懂两种东西——1和0也就是“是”和“否”或“开”和“关”。就是这么简单但魔幻的地方在这里——我们不必像电影《黑客帝国》一样说1和0。这时**编程语言**就派上用场了。它们就像世界上最棒的翻译官,把你完全正常的人类想法转换成计算机语言。
每天早上醒来,这点仍然让我激动不已:你生活中所有的数字事物,最初都是像你一样的人,可能穿着睡衣,手拿咖啡,在笔记本上敲代码。那个让你看起来完美无瑕的 Instagram 滤镜?有人写了那段代码。带你发现新歌的推荐算法?开发者设计了它。帮助你和朋友均摊晚餐账单的应用?没错,有人想着“真烦人,我一定能改进它”,结果……他们做到了!
学会编程,你不仅仅是习得一项新技能——你正在加入这样一个令人敬佩的群体,这群解决问题的人用他们的每一天思考,“如果我能造出点东西,让某个人的一天更美好一点,会怎么样?”说真的,有什么比这更酷的吗?
**趣味小调查**:闲暇时看看这个超酷的内容——你认为世界上第一位计算机程序员是谁?提示:她可能不是你想象中的那样!这位人士背后的故事极其精彩,说明编程从一开始就是关于创造性解决问题和跳出框架思考。
### 🧠 **情绪检查:你感觉如何?**
**花点时间想想:**
- “向计算机下指令”的想法你现在能理解了吗?
- 你能想到想用编程自动化的日常任务吗?
- 关于编程,你脑海中冒出了哪些问题?
> **记住**:某些概念暂时模糊完全正常。学编程就像学新语言——需要时间让大脑建立神经回路。你做得很棒!
## 编程语言就像不同风味的魔法
嗯,这听起来可能有点怪,但请坚持听我说——编程语言很像不同类型的音乐。想想看:有爵士乐,流畅且即兴;摇滚,强劲直接;古典,优雅而有结构;还有嘻哈,创意和富于表现力。每种风格都有自己的气质和热情的拥护者社区,同时适合不同的心情和场合。
编程语言也是一样!你不会用同一种语言去造一个有趣的手机游戏和处理庞大的气候数据,就像你不会在瑜伽课上听死亡金属(嗯,大多数瑜伽课都是这样!😄)。
但每次一想到这点我都震惊不已这些语言就像世界上最耐心、最聪明的口译员坐在你旁边。你可以用适合你人脑的方式表达想法语言帮你完成把这些转换成计算机说的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
// 第一步:基本斐波那契设置
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;
}
```
**代码运行过程中:**
- **用`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
adr r0,thumb+1
bx r0
code16
thumb
mov r0,#00
sub r0,r0,#01
mov r1,#01
mov r4,#10
ldr r2,=0x40000000
back add r0,r1
str r0,[r2]
add r2,#04
mov r3,r0
mov r0,r1
mov r1,r3
sub r4,#01
cmp r4,#00
bne back
end
```
注意JavaScript 版本读起来几乎像英语指令,而汇编使用的是直接控制处理器的神秘命令。它们完成的是完全相同的任务,但高级语言更易于人类理解、编写和维护。
**你会注意到的主要区别:**
- **可读性**JavaScript 用像 `fibonacciCount` 这样的描述性名称,而汇编使用像 `r0`、`r1` 这样晦涩的标签
- **注释**:高级语言鼓励解释性注释,使代码具备自我说明性
- **结构**JavaScript 的逻辑流程与人类逐步思考问题的方式相匹配
- **维护**:针对不同需求更新 JavaScript 版本简单明了
**关于斐波那契数列**这个绝美的数字模式每个数字都是前两个数字之和0, 1, 1, 2, 3, 5, 8……在自然界里无处不在你会在向日葵的螺旋、松果的排列、鹦螺壳的弯曲方式甚至树枝的生长方式中发现它。数学和代码帮我们理解并重现自然界用来创造美丽的模式真是令人震撼
## 构成魔法的基石
好了,现在你已经看到了编程语言的实际运作,让我们分解构成所有程序的基础部分。把它们看作你最喜欢的食谱中的基本成分——只要你了解每个成分的作用,就能在几乎任何语言中读写代码!
这有点像学习编程的语法。还记得你在学校学名词、动词和如何组成句子吗?编程也有自己的语法版本,说实话,比英语语法更加合乎逻辑和宽容!😄
### 语句:一步步的指令
先从**语句**开始——它们就像你和电脑对话中的单句。每条语句告诉电脑做一件具体的事,就像给出方向指令:“这里左转”、“红绿灯处停下”、“在那个地方停车”。
我喜欢语句的地方是它们通常很易读。看看这个:
```javascript
// 执行单个操作的基本语句
const userName = "Alex";
console.log("Hello, world!");
const sum = 5 + 3;
```
**这段代码做了什么:**
- **声明**一个常量变量存储用户的名字
- **向控制台输出**问候消息
- **计算**并存储一个数学运算的结果
```javascript
// 与网页交互的语句
document.title = "My Awesome Website";
document.body.style.backgroundColor = "lightblue";
```
**一步步讲解发生了什么:**
- **修改**浏览器标签页显示的网页标题
- **更改**整个页面主体的背景颜色
### 变量:程序的记忆系统
好,**变量**说实话是我最喜欢讲的概念之一,因为它们就像你每天使用的东西!
想想你手机的联系人列表。你不会记住每个人的号码——你保存的是“妈妈”、“死党”或者“凌晨2点前送餐的披萨店”然后让手机记住实际号码。变量就是这样它们是带标签的容器程序可以用名字存储信息并在需要时取出。
更酷的是:变量会随着程序运行而改变(这也解释了它名字的意义)。就像你发现更好的披萨店会更新联系人一样,变量可以随着程序获取新信息或发生变化而更新!
让我给你演示一下多么简单漂亮:
```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
};
```
**上面代码中,我们:**
- **创建了一个对象**将相关的天气信息归类在一起
- **将多条数据组织在一个变量名下**
- **用键值对清楚地标注每条信息**
```javascript
// 第3步使用和更新变量
console.log(`${siteName}: Today is ${currentWeather} and ${temperature}°F`);
console.log(`Wind speed: ${weatherData.windSpeed} mph`);
// 更新可变变量
currentWeather = "cloudy";
temperature = 68;
```
**逐一理解各部分:**
- **用模板字面量 `${}` 语法展示信息**
- **用点号访问对象属性**(如 `weatherData.windSpeed`
- **更新用 `let` 声明的变量**以响应变化的情况
- **组合多个变量创造有意义的消息**
```javascript
// 第4步使用现代解构赋值使代码更简洁
const { location, humidity } = weatherData;
console.log(`${location} humidity: ${humidity}%`);
```
**你需要知道的是:**
- **用解构赋值提取对象中的特定属性**
- **自动创建与对象键同名的新变量**
- **避免重复点号访问简化代码**
### 控制流:教你的程序学会思考
这里编程就开始绝对让人疯狂了!**控制流**本质上是教你的程序像你每天无意识做的那样,做出聪明的决策。
想象一下:今天早上你大概经历的是“如果下雨,我带伞;如果冷,我穿夹克;如果迟到,我就不吃早饭顺路买杯咖啡”。你的大脑自然地遵循这种如果-那么的逻辑,每天数十次!
这就是让程序显得智能、有生命力的原因,而不是死板执行无聊脚本。它们可以识别情况,评估发生了什么,并做出恰当反应。就像赋予程序一个能适应和做选择的大脑!
想看看这多美妙?我来给你演示:
```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)获取全面概览。
#### 推荐的网络开发编辑器
**[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) - 捕捉代码拼写错误
**[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/) - 极速全栈网页开发
> 💡 **入门小贴士**:先用 Visual Studio Code —— 它免费、业界广泛使用,且有庞大社区制作的教程和扩展。
### 网络浏览器:你的秘密开发实验室
准备好被彻底震撼了吗!你平常用浏览器刷社媒、看视频,对吧?实际上它们一直藏着个神奇的开发者实验室,等你去发现!
每次你右键点击网页选“检查元素”,就打开了一个隐藏的开发者工具世界,这些工具比我以前花大钱买的专业软件都强大多了。就像发现自己平常用的厨房背后藏着一间专业大厨的实验室!
第一次有人给我展示浏览器开发者工具时,我光是点击四处查看,就花了大约三个小时不停地惊呼:“等等,它居然还能做这个?!”你真的可以实时编辑任何网站,准确看到加载速度,测试你的网站在不同设备上的展示效果,甚至像个专业人士一样调试 JavaScript。简直令人震惊
**浏览器是你秘密武器的原因:**
当你创建一个网站或网络应用时,你需要看到它在现实中的外观和表现。浏览器不仅展示你的作品,还会提供性能、可访问性和潜在问题的详细反馈。
#### 浏览器开发者工具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。列举三个功能或扩展说明它们如何帮助你更高效地编写、调试或维护代码并简要解释它们带来的好处。
---
## 🚀 挑战
**侦探,准备好第一个案子了吗?**
现在你已经有了很棒的基础,我有一个冒险任务,将帮你领略编程世界的多样与魅力。听好了,这不涉及写代码,所以别紧张!把自己当作编程语言侦探,接下你的第一个激动人心的案子!
**你的任务,如果你愿意接受:**
1. **成为语言探险家**:挑选三种来自截然不同领域的编程语言 —— 比如一种建网站,一种写移动应用,还有一种给科学家用来数据处理。找出它们都完成同样简单任务的示例。保证你会惊叹同样的事一个用法大不相同!
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) 翻译完成。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应视为权威来源。对于重要信息,建议采用专业人工翻译。因使用本翻译内容而引起的任何误解或错误理解,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,69 @@
# Assignment: 探索现代网络开发工具
## Instructions
网络开发生态系统包含数百种专门的工具,帮助开发者高效地构建、测试和维护应用程序。你的任务是研究并了解补充本课所涵盖内容的工具。
**你的任务:**选择**三个工具**,这些工具**未在本课中涵盖**(避免选择已列出的代码编辑器、浏览器或命令行工具)。重点关注解决现代网站开发工作流中特定问题的工具。
**针对每个工具,请提供:**
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) 进行翻译。虽然我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原始语言版本的文件应视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,767 @@
# GitHub简介
嗨,未来的开发者!👋 准备好加入全球数百万程序员的行列了吗我真心兴奋地向你介绍GitHub——把它想象成程序员的社交媒体平台不过我们分享的不是午餐照片而是代码共同构建令人难以置信的东西
让我大开眼界的是你手机上的每个应用、你访问的每个网站以及你将学会使用的大多数工具都是由开发团队在类似GitHub的平台上协作完成的。你喜欢的那个音乐应用就有像你一样的人参与其中。那个让你爱不释手的游戏没错可能就是通过GitHub协作完成的。现在你将学会如何成为这个惊人社区的一员
我知道一开始可能觉得信息量很大——说实话我第一次看到GitHub页面时也懵了“这到底是啥意思”但事实是每一个开发者都从你现在的位置开始。课程结束时你将拥有自己的GitHub仓库把它想象成云端的个人项目展示你会知道如何保存工作与他人分享甚至为数百万用户使用的项目做贡献。
我们将一步步一起出发。没有急躁,没有压力——只有你我和一些即将成为你新朋友的酷炫工具!
![Intro to GitHub](../../../../translated_images/zh-CN/webdev101-github.8846d7971abef6f9.webp)
> 速记图由 [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基本上就像一个超级智能的助理能记录你代码的每一次改动——比你两秒按一次Ctrl+S强多了我们都有过
在终端输入这个魔法命令看一下Git是否安装
`git --version`
如果还没安装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是否已经配置
```bash
git config --list
```
你还需要一个GitHub账户一个代码编辑器比如Visual Studio Code并打开你的终端命令提示符也可以
访问 [github.com](https://github.com/) ,如果还没有账户就创建一个,或者登录并完善你的个人资料。
💡 **现代建议**:考虑设置[SSH密钥](https://docs.github.com/en/authentication/connecting-to-github-with-ssh)或使用[GitHub CLI](https://cli.github.com/)实现无需密码的更便捷认证。
✅ GitHub不是唯一的代码仓库但它是最知名的。
### 准备工作
你需要在本地笔记本或PC有一个包含代码项目的文件夹并且在GitHub有一个公开仓库这将作为学习如何为他人项目做贡献的范例。
### 保护你的代码安全
聊聊安全——别担心,我们不会让你听得头疼!把这些安全措施想象成锁车或锁门,是简单易养成的习惯,能保护你的辛勤成果。
我们将从一开始就用现代、安全的方式使用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找到那个醒目的绿色 **New** 按钮(或者右上角的 **+** 号)。点击,选择 **New repository**
操作步骤:
1. 给你的仓库起个名字——起一个对你有意义的名字!
1. 可以添加描述(帮助别人了解你的项目)
1. 选定公开(所有人可见)或私有(仅你可见)
1. 建议勾选添加README文件——它是项目的首页介绍
1. 点击 **Create repository**,庆祝一下——你刚刚创建了第一个仓库!🎉
2. **进入你的项目文件夹**。现在打开终端(别怕,其实没那么吓人!)。告诉电脑你的项目文件在哪儿,输入命令:
```bash
cd [name of your folder]
```
**这里做了什么:**
- 我们实质上是在告诉电脑“带我到项目文件夹”
- 就像在桌面打开特定文件夹,只不过用文本命令做这件事
- 把`[name of your folder]`替换成你项目文件夹的真实名称
3. **把你的文件夹变成Git仓库**。神奇时刻来了!输入:
```bash
git init
```
**发生了什么(很酷!):**
- 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 restore <file>..." to discard changes in working directory)
modified: file.txt
modified: file2.txt
```
**别慌!它的意思是:**
- 红色的文件是有改动但还没准备好保存的
- 绿色的文件(如果看到)是已准备好保存的
- Git会提示你下一步该做什么很贴心
> 💡 **小贴士**`git status`命令是你的好帮手不懂时就问它就像让Git告诉你“现在状况如何”。
5. **准备文件保存(也叫“暂存”)**
```bash
git add .
```
**刚刚做了什么:**
- 告诉Git“把所有文件都加到下一次保存里”
- `.`表示“这个文件夹下的所有东西”
- 现在你的文件已经“暂存”好,可以进行下一步
**想更挑剔地选择?** 你可以只添加特定文件:
```bash
git add [file or folder name]
```
**为什么这样做?**
- 有时候你想把相关改动分批提交
- 有利于把工作整理成有逻辑的小块
- 让日后更容易理解改动内容和时间
**想撤销选择?** 可以这样取消暂存:
```bash
# 取消暂存所有内容
git reset
# 只取消暂存一个文件
git reset [file name]
```
不用担心——这不会删掉你的内容,只是把文件从“准备提交”的列表里移除。
6. **永久保存工作提交你的第一次commit**
```bash
git commit -m "first commit"
```
**🎉 恭喜你你完成了第一次commit**
**发生了什么:**
- Git对所有暂存的文件做了“快照”记录当前状态
- 你的提交信息“first commit”说明了保存点的内容
- Git给这个快照一个唯一ID你随时能找到它
- 你正式开始管理项目历史了!
> 💡 **今后的提交信息**写得更有描述性别写“updated stuff”试试“给首页添加联系表单”或“修复导航菜单bug”。未来的你会感谢自己的
7. **连接本地项目到GitHub**。现在你的项目只存在电脑里连接到GitHub仓库才能分享给全世界
先打开你的GitHub仓库页面复制URL。回到这里输入
```bash
git remote add origin https://github.com/username/repository_name.git
```
把这个URL换成你的仓库实际地址
**刚刚做了什么:**
- 我们在你的本地项目和你的 GitHub 仓库之间建立了连接
- “origin” 只是你的 GitHub 仓库的一个昵称——就像给你的手机添加联系人一样
- 现在你的本地 Git 知道在你准备好分享代码时该把代码发送到哪里
💡 **更简单的方法**:如果你安装了 GitHub CLI可以用一条命令完成这一步
```bash
gh repo create my-repo --public --push --source=.
```
8. **将代码上传到 GitHub**(激动人心的时刻!):
```bash
git push -u origin main
```
**🚀 就是这一步!你正在把代码上传到 GitHub**
**发生了什么:**
- 你的提交正从电脑传送到 GitHub
- `-u` 参数建立了永久连接,方便以后推送
- “main” 是你的主分支名称(类似主文件夹)
- 之后你只需输入 `git push` 来上传修改!
💡 **小提示**:如果分支叫其他名字(如 “master”用那个名字替代。可用 `git branch --show-current` 查看当前名字。
9. **你的新日常编码节奏**(上瘾的时候到了!):
从现在开始,只要你修改项目,都遵循简单的三步流程:
```bash
git add .
git commit -m "describe what you changed"
git push
```
**这将成为你的编码心跳:**
- 编写精彩代码 ✨
- 用 `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 提交主题行能完成下面句子:
如果应用该提交,它将 <你的主题>
主题用祈使句现在时态“change”不是 “changed” 或 “changes”。正文可选也用祈使句现在时。正文应说明改动的动机并与之前的行为对比。你是在解释“为什么”不是“怎么做”。
✅ 花几分钟逛逛 GitHub能找到一个特别棒的提交信息吗能找到特别简洁的吗你觉得提交信息中最重要有用的信息是什么
## 与他人合作(有趣部分!)
抓紧你的帽子,因为这里是 GitHub 真正神奇的时候!🪄 你已经学会管理自己的代码,现在我们进入我最喜欢的部分——与来自世界各地的优秀人才协作。
想象一下:你第二天醒来发现东京有人改进了你的代码;柏林有人修复了你一直卡住的 Bug下午时圣保罗的开发者添加了你从没想过的功能。这不是科幻——这只是 GitHub 世界里的普通一天!
让我激动的是,你将学到的协作技能正是谷歌、微软和你喜欢的创业公司每天都在用的工作流程。这不仅仅是学一个酷工具——你学会了让整个软件世界协同工作的秘密语言。
说真的,一旦你体验过别人合并你的第一次拉取请求的激动,你会明白开发者为何对开源项目如此热情。这就像参与了全世界最大最有创意的团队项目!
> 查看视频
>
> [![Git and GitHub basics video](https://img.youtube.com/vi/bFCM-PC3cu8/0.jpg)](https://www.youtube.com/watch?v=bFCM-PC3cu8)
把东西放到 GitHub 的主要原因就是让与其他开发者的协作成为可能。
```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`,查看你的项目如何对照推荐的社区标准进行比较。
想让你的仓库看起来专业且有吸引力?去仓库点击 `Insights > Community`。这个酷功能会显示你的项目与 GitHub 社区认可的“好仓库实践”相比的情况。
> 🎯 **让你的项目闪耀**:结构良好的仓库和完善的文档就像干净欢迎的店铺。它告诉大家你重视你的工作,也会让别人想来贡献!
**一个棒仓库的要点:**
| 应该添加的内容 | 重要性 | 对你的作用 |
|-------------|-------------------|---------------------|
| **描述** | 第一印象很重要! | 让人立刻知道项目做什么 |
| **README** | 项目的主页 | 就像对新访客的友好导览 |
| **贡献指南** | 表明欢迎帮助 | 让人知道如何参与贡献 |
| **行为准则** | 营造友好氛围 | 确保每个人都感到受欢迎 |
| **许可证** | 法律明确 | 让别人知道怎么使用你的代码 |
| **安全政策** | 表明你负责任 | 展示专业规范 |
> 💡 **小窍门**GitHub 提供了所有这些文件的模板。创建新仓库时,可以勾选自动生成这些文件。
**值得探索的现代 GitHub 功能:**
🤖 **自动化 & CI/CD**
- **GitHub Actions**:自动化测试和部署
- **Dependabot**:依赖自动更新
💬 **社区 & 项目管理:**
- **GitHub Discussions**:议题以外的社区对话
- **GitHub Projects**:看板式项目管理
- **分支保护规则**:维护代码质量标准
所有这些资源都能帮助新成员快速入职。新贡献者通常先看这些东西,再决定项目是否值得投入时间。
✅ README 虽然准备需要时间,但常被繁忙的维护者忽视。你能找到一个特别详细的 README 作为例子吗?提示:有些[工具能帮你创建优秀的 README](https://www.makeareadme.com/),可以试试。
### 任务:合并代码
贡献文档帮助别人参与项目。它说明你期待的贡献类型和流程。贡献者需要经过一系列步骤,才能在 GitHub 上为你的仓库做贡献:
1. **Fork 你的仓库**。你可能希望别人 _fork_ 你的项目。Fork 是在他们的 GitHub 账号上创建你仓库的副本。
1. **克隆**。然后他们将项目克隆到本地机器。
1. **创建分支**。你会希望他们为自己的工作创建一个 _分支_
1. **把修改聚焦在一件事**。让贡献者每次专注一件事——这样更容易 _合并_ 他们的工作。假设他们写了 bug 修复、添加新功能并更新多个测试——如果你只能合并其中两个或一个怎么办?
✅ 想想有哪些场景分支对写出和发布高质量代码特别关键?
> 注意,成为你希望看到的改变,也为你自己的工作创建分支。任何提交都发生在你当前“签出”的分支上。用 `git status` 查看当前分支。
我们来看贡献者的工作流程。假设贡献者已经 _fork__clone_ 了仓库,拥有一个可本地操作的 Git 仓库:
1. **创建分支**。用命令 `git branch` 创建将用于贡献的分支:
```bash
git branch [branch-name]
```
> 💡 **现代做法**:你也可以用一条命令创建并切换分支:
```bash
git switch -c [branch-name]
```
1. **切换到工作分支**。用 `git switch` 切换到指定分支并更新工作区:
```bash
git switch [branch-name]
```
> 💡 **现代提示**`git switch` 是替代 `git checkout` 修改分支的现代命令,更清晰也更安全适合新手。
1. **开始工作**。此时你添加修改。别忘了用下面命令告诉 Git
```bash
git add .
git commit -m "my changes"
```
> ⚠️ **提交信息质量**:确保给你的提交起个好名字,为自己和仓库维护者负责。具体说明你的改动!
1. **`main` 分支合并**。完成工作后,你想把改动合并回 `main`。由于 `main` 可能已变动,先用以下命令更新它:
```bash
git switch main
git pull
```
接下来确保任何冲突,即 Git 无法轻松合并的情况发生在你的工作分支上。运行以下命令:
```bash
git switch [branch_name]
git merge main
```
`git merge main` 命令将 `main` 的所有改动合入你的分支。希望你可以直接继续。如果不能VS Code 会告诉你哪里有冲突,你只需编辑相关文件,决定哪些内容是正确的。
💡 **现代替代**:考虑用 `git rebase` 保持历史清晰:
```bash
git rebase main
```
它将你的提交放到最新的 `main` 之上,创建线性历史。
1. **将你的工作推送到 GitHub**。推送工作到 GitHub 包含两步:推送分支到你的仓库,然后打开 PR拉取请求
```bash
git push --set-upstream origin [branch-name]
```
上面命令会在你的 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"
```
🔧 **PR 最佳实践**
- 使用关键词关联相关 issues如 “Fixes #123
- 为界面改动添加截图
- 指定特定评审人
- 对进行中的工作使用草稿 PR
- 确保所有 CI 检查通过再请求评审
1. **清理**。在你成功合并一个 PR 之后进行_清理_工作被认为是一种良好习惯。你需要清理你的本地分支以及你推送到 GitHub 的分支。首先,用以下命令在本地删除它:
```bash
git branch -d [branch-name]
```
确保接下来访问 Fork 的 GitHub 页面,删除你刚刚推送的远程分支。
“拉取请求”Pull request这个术语看起来有些奇怪实际上你是想将你的变更推送到项目里。但项目维护者项目所有者或者核心团队需要先审查你的变更才会将它合并到项目的“主”分支所以你实际上是在请求维护者做出变更的决定。
拉取请求是一个比较和讨论某个分支引入的差异的地方,带有评审、评论、集成测试等等功能。一个好的拉取请求大致遵循提交信息的相同规则。当你的工作修复了某个问题时,你可以添加该问题追踪器中问题的引用。方法是用 `#` 加上你的问题编号。例如 `#97`
🤞 希望所有检查都通过,项目所有者能将你的改动合并进项目 🤞
使用以下命令更新你当前本地工作分支,使其包含 GitHub 上对应远程分支的所有新提交:
`git pull`
## 为开源贡献(您改变世界的机会!)
你准备好迎接将彻底震撼你心灵的事情了吗?🤯 让我们聊聊如何为开源项目做贡献——想到与您分享这些我都热血沸腾!
这是你成为真正非凡事物一部分的机会。想象一下,改进数百万开发者每天使用的工具,或者修复你朋友喜欢的应用中的一个 bug。这不仅仅是梦想——这就是开源贡献的意义
让我每次想到都会激动的是:你学习过的每一个工具——代码编辑器、我们将探索的框架,甚至你现在用来阅读这篇文章的浏览器——最初都是由和你一样的人首次做出贡献而开始的。那个打造你最喜欢的 VS Code 插件的优秀开发者?他们也曾是一个初学者,用颤抖的手点下“创建拉取请求”,就像你即将做的那样。
最美妙的是开源社区就像互联网最大的集体拥抱。大多数项目都会积极欢迎新人而且有专门标记为“good first issue”好入门问题的任务就是为像你这样的人准备的维护者看到新贡献者会非常兴奋因为他们记得自己的第一步。
```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
```
你不仅仅是在学编程——你正在准备加入一个每天醒来都想着“我们如何让数字世界变得更好一点”的全球建设者家庭。欢迎加入!🌟
首先,让我们找到一个你感兴趣且想贡献变更的 GitHub 代码库(**repo**)。你需要把它的内容复制到你的电脑上。
✅ 一个很好的寻找“初学者友好”仓库的方法是[通过“good-first-issue”标签搜索](https://github.blog/2020-01-22-browse-good-first-issues-to-start-contributing-to-open-source/)。
![在本地复制仓库](../../../../translated_images/zh-CN/clone_repo.5085c48d666ead57.webp)
有几种方式可以复制代码。一种是使用 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`
你也可以用以下方式打开整个项目:
- **[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 上的公共仓库加星、关注和/或“Fork”派生。你可以在右上角的下拉菜单中找到你加星的仓库。它就像收藏书签但针对代码。
项目通常有一个问题追踪器,通常在 GitHub 的“Issues”标签页除非另有说明这是人们讨论与项目有关问题的地方。拉取请求页是人们讨论和复审正在进行的改动的地方。
项目还可能有论坛、邮件列表,或者像 Slack、Discord、IRC 这样的聊天频道。
🔧 **现代 GitHub 功能**
- **GitHub Discussions** —— 内置社区讨论论坛
- **GitHub Sponsors** —— 金融支持维护者
- **安全标签** —— 漏洞报告与安全公告
- **Actions 标签** —— 查看自动化工作流和 CI/CD 管道
- **Insights 标签** —— 关于贡献者、提交和项目健康的数据分析
- **Projects 标签** —— GitHub 内置的项目管理工具
✅ 试着熟悉你的新 GitHub 仓库,尝试编辑设置、为仓库添加信息、创建项目(如看板),以及设置 GitHub Actions 实现自动化。你可以做很多事情!
---
## 🚀 挑战
好了,是时候检验你闪亮的新 GitHub 超能力了!🚀 这项挑战会让一切以最令人满意的方式水到渠成:
找一个朋友(或者一直问你“你那些电脑玩意儿在干嘛”的亲戚)一起开始一场协作编程冒险!这才是真正的魔法所在——创建项目,让他们 Fork创建几个分支然后像专业人士一样合并变更。
我说实话——你们很可能会哈哈大笑(尤其是当你们俩试图同时改同一行代码时),也许会一起摸不着头脑,但你们肯定会有那些令人激动的“啊哈!”时刻,让所有学习都物有所值。而且,和别人分享第一次成功合并总是特别的——就像是对你来之不易进步的一次小小庆祝!
还没有编程伙伴没关系GitHub 社区里有无数热情欢迎的成员他们都记得自己刚开始时是什么样子。寻找带有“good first issue”标签的仓库——它们基本上是在说“嘿初学者来和我们一起学习吧”多棒啊
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/en/)
## 复习与持续学习
呼!🎉 看你——你刚刚像个绝对的高手一样掌握了 GitHub 基础!如果现在感觉大脑有点满,那很正常,老实说这其实是好现象。你刚刚学会的工具,我当初花了好几周才熟悉。
Git 和 GitHub 非常强大(真的非常强大),我认识的每个开发者——包括现在看起来像个高手的那帮人——都必须不断练习、跌跌撞撞才能完全掌握。你能完成这课说明你已经在向掌握开发者工具箱里最重要的东西迈进了。
这里有一些绝佳资源,帮你练习且变得更棒:
- [开源软件贡献指南](https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution) —— 你的改变之路地图
- [Git 速查表](https://training.github.com/downloads/github-git-cheat-sheet/) —— 随时备查!
记住:练习带来进步,不是完美!你用 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 掌握时间线
### ⚡ **接下来 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) 进行翻译。尽管我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原文以其母语版本为准。对于重要信息,建议采用专业人工翻译。因使用本翻译引起的任何误解或错误解读,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,252 @@
# 综合网站无障碍审计
## 说明
在本作业中,你将对一个真实网站进行专业级别的无障碍审计,应用你所学的原则和技术。这一实操经验将加深你对无障碍障碍及解决方案的理解。
选择一个看起来存在无障碍问题的网站——这比分析已经完美的网站能带来更多学习机会。合适的候选包括较旧的网站、复杂的网络应用或含有丰富多媒体内容的网站。
### 第一阶段:战略性手动评估
在使用自动化工具之前,先进行全面的手动评估。这种以人为中心的方法常常能发现工具未能检测到的问题,并帮助你理解真实的用户体验。
**🔍 关键评估标准:**
**导航与结构:**
- 能否仅用键盘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) 翻译。尽管我们努力保证准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用此翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,22 @@
# Web开发入门
在本课程的这一部分中,您将学习成为专业开发人员所需的重要非项目概念。
### 主题
1. [编程语言介绍及开发工具](1-intro-to-programming-languages/README.md)
2. [GitHub基础知识](2-github-basics/README.md)
3. [无障碍设计基础](3-accessibility/README.md)
### 致谢
《编程语言介绍及开发工具》由 [Jasmine Greenaway](https://twitter.com/paladique) 倾情撰写。
《GitHub基础知识》由 [Floor Drees](https://twitter.com/floordrees) 倾情撰写。
《无障碍设计基础》由 [Christopher Harrison](https://twitter.com/geektrainer) 倾情撰写。
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误读,我们概不负责。

File diff suppressed because it is too large Load Diff

@ -0,0 +1,609 @@
# JavaScript 基础:数据类型
![JavaScript Basics - Data types](../../../../translated_images/zh-CN/webdev101-js-datatypes.4cc470179730702c.webp)
> 手绘笔记,作者 [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 以类似的方式组织信息,不同类别用于不同类型的数据。
在本课中,我们将探索让 JavaScript 工作的核心数据类型。你将学会如何处理数字、文本、真/假值,并理解为什么为程序选择正确的数据类型至关重要。这些概念起初可能看起来抽象,但通过练习,它们将变成你第二天性。
理解数据类型会让 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`,对保持不变的值使用 `const`
- **变量名**,是你自己选择的描述性名称。
✅ 关键字 `let` 是在 ES6 中引入的,赋予变量所谓的 _块作用域_。推荐使用 `let``const` 替代旧的 `var` 关键字。我们将在后续部分更深入地讲解块作用域。
### 任务 - 使用变量
1. **声明变量**。让我们先创建第一个变量:
```javascript
let myVariable;
```
**这样做的效果:**
- 告诉 JavaScript 创建一个叫做 `myVariable` 的存储位置
- JavaScript 在内存中为该变量分配空间
- 变量当前没有值undefined
2. **赋值**。现在给变量赋一个值:
```javascript
myVariable = 123;
```
**赋值的工作原理:**
- `=` 操作符将值 123 赋给了变量
- 变量现在包含该值,不再是 undefined
- 你可以在代码中使用 `myVariable` 引用这个值
> 注意:本课中 `=` 表示“赋值操作符”,用于给变量设置值,不表示等号。
3. **聪明做法**。实际上,我们可以把这两个步骤合并:
```javascript
let myVariable = 123;
```
**这种做法更高效:**
- 在一条语句中声明变量并赋值
- 这是开发者的标准实践
- 代码更简洁且保持清晰
4. **改变想法**。如果想存储不同的数字呢?
```javascript
myVariable = 321;
```
**重新赋值的理解:**
- 变量现在包含 321 而不是 123
- 之前的值被替换 —— 变量一次只存储一个值
- 这种可变性是用 `let` 声明变量的关键特征
✅ 试试看!你可以直接在浏览器中写 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` 关键字。常量通常用全大写字母声明。
```javascript
const MY_VARIABLE = 123;
```
**这段代码做了什么:**
- **创建** 一个名为 `MY_VARIABLE` 的常量,值为 123
- **使用** 常量的全大写命名惯例
- **防止** 未来对该值的任何更改
常量的两条主要规则:
- **必须立即赋值** —— 不允许定义空常量!
- **值永远不能更改** —— 任何尝试更改都会导致错误。来看例子:
**简单值** - 以下做法是不被允许的:
```javascript
const PI = 3;
PI = 4; // 不允许
```
**你需要记住的:**
- **尝试重新赋值常量会导致错误**
- **保护** 重要的数值不被意外更改
- **确保** 程序中值的一致性
**对象引用是被保护的** - 以下做法不被允许:
```javascript
const obj = { a: 3 };
obj = { b: 5 } // 不允许
```
**这些概念的理解:**
- **防止** 用新对象替换整个原对象
- **保护** 原始对象的引用
- **保持** 对象在内存中的身份
**对象值是不被保护的** - 以下做法是允许的:
```javascript
const obj = { a: 3 };
obj.a = 5; // 允许
```
**这里发生了什么:**
- **修改** 对象内部的属性值
- **保持** 相同的对象引用
- **表明** 对象内容可以改变,但引用保持不变
> 注意,`const` 保护的是引用不被重新赋值。值本身不是不可变的,尤其是当它是复杂类型如对象时,值可以改变。
## 数据类型
JavaScript 将信息组织成不同的类别,称为数据类型。这个概念类似于古代学者如何分类知识 —— 亚里士多德区分了不同的推理类型,知道逻辑原则不能统一运用于诗歌、数学和自然哲学。
数据类型很重要因为不同的操作处理不同种类的信息。就像你不能对一个人的名字进行算术运算或对数学方程排序一样JavaScript 需要对每个操作使用合适的数据类型。理解这一点可以避免错误,让代码更可靠。
变量可以存储许多不同类型的值,比如数字和文本。这些不同类型的值统称为**数据类型**。数据类型是软件开发的重要一环,因为它帮助开发者决定如何编写代码以及软件如何运行。此外,某些数据类型具有独特的特性,能够帮助转换或提取值中的附加信息。
✅ 数据类型也称为 JavaScript 的原始数据类型,因为它们是语言提供的最低级别数据类型。共有 7 种原始数据类型string字符串、number数字、bigint大整数、boolean布尔值、undefined未定义、null空值和 symbol符号。花点时间想象这些原始类型分别代表什么。什么是 `zebra``0` 是什么?`true` 呢?
### 数字
数字是 JavaScript 中最直接的数据类型。无论你操作像 42 这样整数,还是 3.14 这样的小数,或 -5 这样的负数JavaScript 都统一处理。
还记得我们之前的变量吗?我们存储的 123 实际上是数字类型:
```javascript
let myVariable = 123;
```
**主要特征:**
- JavaScript 自动识别数字值
- 你可以对这些变量执行数学运算
- 不需要显式声明类型
变量可以存储所有类型的数字,包括小数和负数。数字也可以与算术运算符一起使用,详见[下一节](../../../../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` |
✅ 试试看!在浏览器的控制台尝试一个算术运算,结果有没有让你感到惊讶?
### 🧮 **数学技能检测:自信计算**
**测试你的算术理解:**
- `/`(除法)和 `%`(取余)有什么区别?
- 你能预测 `10 % 3` 的结果吗?(提示:不是 3.33……)
- 为什么在编程中取余运算符很有用?
```mermaid
pie title "JavaScript 数字操作使用情况"
"加法 (+)" : 35
"减法 (-)" : 20
"乘法 (*)" : 20
"除法 (/)" : 15
"取余 (%)" : 10
```
> **现实世界的启示**:取余运算符 % 非常有用,可以用来检查数字的偶奇性,创建模式,或在数组中循环!
### 字符串
在 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 + "!"; //你好,世界!
myString1 + " " + myString2 + "!"; //你好,世界!
myString1 + ", " + myString2 + "!"; //你好,世界!
```
**一步步来看,发生了什么:**
- 使用 `+` 运算符合并多个字符串
- 第一个例子中**直接连接**字符串,中间没有空格
- 在字符串之间**添加**空格字符 `" "` 以增加可读性
- **插入**逗号等标点符号以创建正确的格式
✅ 为什么在 JavaScript 中 `1 + 1 = 2`,但 `'1' + '1' = 11`?想一想。那 `'1' + 1` 会怎样?
**模板字符串**是另一种格式化字符串的方式,不同于引号,使用反引号 `` ` ``。所有非纯文本内容都必须放在占位符 `${ }` 内。这包括任何可能是字符串的变量。
```javascript
let myString1 = "Hello";
let myString2 = "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`。这种二元逻辑系统可追溯到19世纪数学家乔治·布尔George Boole开发的布尔代数。
尽管简单,布尔值对程序逻辑至关重要。它们让代码能基于条件做出决策——比如用户是否已登录,是否点击了按钮,或是否满足某些条件。
布尔值只能是两个值之一:`true` 或 `false`。布尔值有助于根据特定条件决定哪些代码行应该运行。在许多情况下,[运算符](../../../../2-js-basics/1-data-types)帮助设置布尔值的值,而你也常会看到并写出变量初始化或使用运算符更新其值。
```javascript
let myTrueBool = true;
let myFalseBool = false;
```
**在上例中,我们:**
- **创建**了一个存储布尔值 `true` 的变量
- **演示**了如何存储布尔值 `false`
- **使用**了准确的关键字 `true``false`(无需引号)
- **准备**了这些变量供条件语句使用
✅ 如果变量计算结果为布尔 `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 行为熟悉这些怪癖将帮助你写出更可靠的代码,更高效地调试问题。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app)
## 复习与自学
看看[这份 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 世界! 🎉
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用人工智能翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。应以原始语言的原版文件为权威来源。对于关键信息,建议寻求专业人工翻译。因使用本翻译而产生的任何误解或误译,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,94 @@
# 数据类型练习:电子商务购物车
## 说明
想象你正在构建一个现代的电子商务购物车系统。此作业将帮助你理解不同的 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) 翻译完成。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始文件的母语版本应被视为权威来源。对于关键内容,建议使用专业人工翻译。因使用本翻译所引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,574 @@
# JavaScript 基础:方法与函数
![JavaScript Basics - Functions](../../../../translated_images/zh-CN/webdev101-js-functions.be049c4726e94f8b.webp)
> 速记图由 [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) 上学习本课内容!
```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` 关键字告诉 JavaScript “嘿,我正在创建一个函数!”
- `nameOfFunction` 是你给函数起的描述性名字
- 括号 `()` 是你可以添加参数的位置(我们稍后会讲)
- 花括号 `{}` 包含当你调用函数时执行的实际代码
让我们创建一个简单的问候函数,看看效果:
```javascript
function displayGreeting() {
console.log('Hello, world!');
}
```
这个函数会在控制台打印 "Hello, world!"。定义之后,你可以根据需要多次使用它。
要执行或“调用”函数写函数名后接括号。JavaScript 允许你先调用函数后定义JavaScript 引擎会处理执行顺序。
```javascript
// 调用我们的函数
displayGreeting();
```
运行这行代码时,它会执行 `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!”。参数让函数更灵活更有用。
**参数** 就像占位符,每次调用函数时可以传入不同的值。这样同一个函数每次调用可以使用不同的信息。
定义函数时,你在括号里列出参数,多个参数用逗号分隔:
```javascript
function name(param, param2, param3) {
}
```
每个参数像个占位符——调用函数时,调用者会提供实际值,填入这些位置。
让我们把问候函数改造一下,能接收一个人的名字:
```javascript
function displayGreeting(name) {
const message = `Hello, ${name}!`;
console.log(message);
}
```
你会注意到我们使用了反引号 (`` ` ``) 和 `${}` 来直接把名字插入消息中——这叫模板字符串,是构建带变量字符串的很方便方式。
现在调用时,我们可以传入任意名字:
```javascript
displayGreeting('Christopher');
// 运行时显示 “你好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
```
## 默认值
如果我们想让某些参数可选怎么办?这时默认值很有用!
假设我们希望用户能自定义问候语,但如果没指定,就默认用 "Hello"。你可以用等号设置默认值,就像变量赋值一样:
```javascript
function displayGreeting(name, salutation='Hello') {
console.log(`${salutation}, ${name}`);
}
```
这里,`name` 仍是必需的,`salutation` 则有默认的 `'Hello'`,如果调用者不传就用默认值。
这样我们可以用两种方式调用函数:
```javascript
displayGreeting('Christopher');
// 显示 "Hello, Christopher"
displayGreeting('Christopher', 'Hi');
// 显示 "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
```
> **专业提示**:默认参数让函数对用户更友好,用户可以快速开始,用合适的默认值,但也能按需自定义!
## 返回值
到目前为止我们的函数只是打印消息,但万一你想让函数计算并返回结果呢?
这就用到**返回值**。函数不仅可以显示内容,还能返回值,你可以把返回值存到变量里,或者用于代码的其他部分。
使用 `return` 关键字,后面跟你想返回的值:
```javascript
return myVariable;
```
这里需要注意的是:函数遇到 `return` 语句,会立即停止执行,并把那个值返回给调用它的人。
来修改一下问候函数,不打印只返回消息:
```javascript
function createGreetingMessage(name) {
const message = `Hello, ${name}`;
return message;
}
```
这个函数不打印消息,而是构造消息并返回给调用方。
要用返回值,我们可以像处理其他值一样,把它存到变量里:
```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`,这是一个内置函数,会等待一段时间再运行代码。你得告诉它跑什么代码——传函数给它就是完美用法!
试试这段代码3秒后你会看到消息
```javascript
function displayDone() {
console.log('3 seconds has elapsed');
}
// 定时器值以毫秒为单位
setTimeout(displayDone, 3000);
```
注意我们把 `displayDone`(没有括号)传给 `setTimeout`。我们不是自己调用它,而是把函数交给 `setTimeout`让它3秒后调用。
### 匿名函数
有时候你只用一次函数,不想给它起名字。想想看——只用一次,为何要额外起一个名字占用代码空间?
JavaScript 支持**匿名函数**——没有名字的函数,你可以直接在需要的地方定义它们。
改写上面计时例子,使用匿名函数:
```javascript
setTimeout(function() {
console.log('3 seconds has elapsed');
}, 3000);
```
效果一样,但函数定义直接写在 `setTimeout` 调用里,不需分开声明函数。
### 箭头函数
现代 JavaScript 有更简短的函数写法,叫**箭头函数**。它用 `=>`(看起来像箭头——你懂的)表示,开发者极其喜欢用。
箭头函数省略了 `function` 关键字,写起代码更简洁。
这就是用箭头函数写的计时例子:
```javascript
setTimeout(() => {
console.log('3 seconds has elapsed');
}, 3000);
```
`()` 里放参数(这里空着),接箭头 `=>`,最后是花括号里的函数体。功能一样,语法更紧凑。
```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)的内容,因为它们在代码库中用得越来越多。练习写函数,然后用这种语法改写。
## 作业
[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: 你
```
> 🎉 **你已掌握编程中最强大的概念之一!** 函数是更大程序的构建模块。你将创建的每个应用程序都会使用函数来组织、重用和结构化代码。你现在理解了如何将逻辑打包成可重用的组件,这使你成为一个更高效、更有效的程序员。欢迎来到模块化编程的世界!🚀
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)翻译完成。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。应以原始语言的文档为权威来源。对于重要信息,建议采用专业人工翻译。我们对因使用本翻译而产生的任何误解或误释不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,73 @@
# 有趣的函数
## 说明
在本次作业中,你将练习创建不同类型的函数,以巩固你所学的 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()` 语句的输出!
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始语言版本的文件应被视为权威来源。对于重要信息,建议使用专业人工翻译。因使用此翻译而引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,663 @@
# JavaScript基础做出决策
![JavaScript Basics - Making decisions](../../../../translated_images/zh-CN/webdev101-js-decisions.69e1b20f272dd1f0.webp)
> 速写笔记由 [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程序也需要根据不同的情况做出选择。分支和决策的能力使得静态代码变成响应型的智能应用程序。
在本课中,你将学习如何在程序中实现条件逻辑。我们将探讨条件语句、比较运算符和逻辑表达式,让你的代码能够评估情况并做出恰当响应。
## 课前小测
[课前小测](https://ff-quizzes.netlify.app/web/quiz/11)
做出决策和控制程序流程的能力是编程的基础部分。本节涵盖如何使用布尔值和条件逻辑来控制JavaScript程序的执行路径。
[![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)上学习本课程!
```mermaid
mindmap
root((决策制定))
Boolean Logic
true/false
比较结果
逻辑表达式
Conditional Statements
if statements
单一条件
代码执行
if-else
两个路径
替代操作
switch
多个选项
清晰结构
Operators
Comparison
=== !== < > <= >=
值关系
Logical
&& || !
组合条件
Advanced Patterns
Ternary
? : 语法
内联决策
Complex Logic
嵌套条件
多重标准
```
## 布尔值简要回顾
在探讨决策制定前,让我们回顾上一节课提到的布尔值。布尔值以数学家乔治·布尔命名,代表两个二进制状态——`true` 或 `false`。没有模糊,没有中间状态。
这些二进制值构成了所有计算逻辑的基础。你程序中每个决策最终都归结为一次布尔值判断。
创建布尔变量非常简单:
```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` |
✅ 通过在浏览器控制台里写一些比较语句来检验你的理解。有返回结果让你感到惊讶吗?
```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 语句
`if` 语句就像在你的代码中提出一个问题。“如果这个条件为真,那么就执行这件事。” 这可能是你在JavaScript中做决策时用得最重要的工具。
运作方式如下:
```javascript
if (condition) {
// 条件为真。此代码块中的代码将会执行。
}
```
条件放在括号内,如果结果为 `true`JavaScript会执行大括号中的代码。如果是 `false`JavaScript会跳过这整个代码块。
你经常会用比较运算符来组成这些条件。来看一个实际的例子:
```javascript
let currentMoney = 1000;
let laptopPrice = 800;
if (currentMoney >= laptopPrice) {
// 条件为真。此块中的代码将会运行。
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 语句
但是如果你想在条件为假时执行不同的操作呢?这时就用到 `else` —— 就像有备选方案一样。
`else` 语句让你说“如果这个条件不为真,那就执行另一件事情。”
```javascript
let currentMoney = 500;
let laptopPrice = 800;
if (currentMoney >= laptopPrice) {
// 条件为真。此代码块中的代码将运行。
console.log("Getting a new laptop!");
} else {
// 条件为假。此代码块中的代码将运行。
console.log("Can't afford a new laptop, yet!");
}
```
现在由于 `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 语句
有时你需要把一个值和多个选项进行比较。虽然可以串联多个 `if..else` 语句,但代码会变得难以管理。`switch` 语句为多个离散值提供了更清晰的结构。
这个概念类似于早期电话交换机中的机械切换系统 — 一个输入值决定执行哪个具体路径。
```javascript
switch (expression) {
case x:
// 代码块
break;
case y:
// 代码块
break;
default:
// 代码块
}
```
它的结构如下:
- JavaScript只计算表达式一次
- 遍历每个 `case` 寻找匹配项
- 找到匹配时执行该代码块
- `break` 使JavaScript停止并退出switch
- 如果没有匹配项执行 `default` 块(如果存在)
```javascript
// 使用 switch 语句的周日程序
let dayNumber = 2;
let dayName;
switch (dayNumber) {
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
default:
dayName = "Unknown day";
break;
}
console.log(`Today is ${dayName}`);
```
在该例中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` 情况仍然有用?
```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
```
## 逻辑运算符的条件与决策
来看一个更现实的例子,演示这些逻辑运算符的用法:
```javascript
let currentMoney = 600;
let laptopPrice = 800;
let laptopDiscountPrice = laptopPrice - (laptopPrice * 0.2); // 笔记本电脑价格打八折
if (currentMoney >= laptopPrice || currentMoney >= laptopDiscountPrice) {
// 条件为真。此代码块中的代码将被执行。
console.log("Getting a new laptop!");
} else {
// 条件为假。此代码块中的代码将被执行。
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不会被计算。利用这一点可以优化代码
### 取反运算符
有时更容易思考某事“不成立”的情况。比如不问“用户是否登录?”,而是问“用户是否未登录?”。感叹号(`!`)运算符就帮你翻转逻辑。
```javascript
if (!condition) {
// 如果条件为假则执行
} else {
// 如果条件为真则执行
}
```
`!` 运算符就像说“相反的……”,如果条件是 `true``!` 使它变成 `false`,反之亦然。
### 三元表达式
对于简单的条件赋值JavaScript提供了**三元运算符**。这种简洁写法允许你在一行中写出条件表达式,在需要根据条件赋值两种情形时特别有用。
```javascript
let variable = condition ? returnThisIfTrue : returnThisIfFalse;
```
它读起来像个问题:“这个条件成立吗?如果是,用这个值。不成立,用那个值。”
下面是更具体的例子:
```javascript
let firstNumber = 20;
let secondNumber = 10;
let biggestNumber = firstNumber > secondNumber ? firstNumber : secondNumber;
```
✅ 花点时间多读几遍这段代码。你理解这些运算如何工作吗?
这句代码相当于:“`firstNumber` 是否大于 `secondNumber`?如果是,把 `firstNumber` 赋给 `biggestNumber`,否则赋 `secondNumber`。”
三元运算符是传统 `if..else` 语句的简写方式:
```javascript
let biggestNumber;
if (firstNumber > secondNumber) {
biggestNumber = firstNumber;
} else {
biggestNumber = 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 语句、逻辑运算符和三元表达式。
**提示:** 编写一个 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 之间
使用多种分数测试你的程序,包括临界值如 59、60、89、90 以及无效输入。
在此处了解更多关于 [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 的信息。
## 课后测验
[课后测验](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
```
> 🧠 **你已经掌握了数字决策的艺术!** 每个交互式应用都依赖条件逻辑来智能地响应用户操作和变化的环境。你现在理解了如何让程序进行思考、评估并选择适当的响应。这一逻辑基础将为你构建的每一个动态应用提供强大动力! 🎉
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们努力确保准确性,但请注意自动翻译可能包含错误或不准确之处。原始语言版本的文件应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或错误理解,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,111 @@
# 做决策:学生成绩处理器
## 学习目标
在此作业中,您将通过构建一个处理来自不同评分系统的学生成绩的程序来练习本课的决策概念。您将使用 `if...else` 语句、比较运算符和逻辑运算符来确定哪些学生通过了课程。
## 挑战
您供职的学校最近与另一所学校合并。现在,您需要处理来自两种完全不同评分系统的学生成绩,并确定哪些学生及格。这是练习条件逻辑的绝佳机会!
### 理解评分系统
#### 第一评分系统(数字)
- 成绩以 1-5 数字表示
- **及格分数**3 及以上3、4 或 5
- **不及格分数**:低于 31 或 2
#### 第二评分系统(字母等级)
- 成绩使用字母:`A`、`A-`、`B`、`B-`、`C`、`C-`
- **及格等级**`A`、`A-`、`B`、`B-`、`C`、`C-`(列出的所有等级均为及格)
- **注意**:该系统不包含像 `D``F` 这样的不及格等级
### 您的任务
给定以下数组 `allStudents`,表示所有学生及其成绩,构建一个新数组 `studentsWhoPass`,包含根据各自评分系统及格的所有学生。
```javascript
let allStudents = [
'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) 进行翻译。虽然我们努力保证准确性,但请注意自动翻译可能存在错误或不准确之处。原始文档的母语版本应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用本翻译而产生的任何误解或误释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,741 @@
# JavaScript 基础知识:数组和循环
![JavaScript Basics - Arrays](../../../../translated_images/zh-CN/webdev101-js-arrays.439d7528b8a29455.webp)
> 速写笔记,作者:[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)
有没有想过网站是如何跟踪购物车商品或者显示你的好友列表的?这就涉及到了数组和循环。数组就像是存放多条信息的数字容器,而循环则让你能高效地处理所有数据,而不需要重复写代码。
这两个概念共同构成了处理程序中信息的基础。你将学会如何从手动编写每一步,转变为创建智能、高效的代码,可以快速处理数百甚至数千个条目。
到本课结束时,你将懂得如何用几行代码完成复杂的数据任务。让我们一起探索这些基本的编程概念。
[![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
列表
菜单
图册
```
## 数组
把数组想象为数字化的文件柜——不是每个抽屉只存放一份文档,而是可以把多个相关项目组织到一个结构化的容器中。用编程术语来说,数组让你可以把多条信息存储在一个有序的包裹里。
无论你是在构建图片库、管理待办事项,还是统计游戏中的最高分,数组都为数据组织提供了基础。让我们来看它们是如何工作的。
✅ 数组无处不在!你能想到一个现实生活中的数组例子吗,比如太阳能电池板阵列?
### 创建数组
创建数组非常简单——只需用方括号!
```javascript
// 空数组——就像一个等待添加商品的空购物车
const myArray = [];
```
**这里发生了什么?**
你用这对方括号 `[]` 创建了一个空容器。把它想象成一个空的书架,它已经准备好放你想存放的任何书籍了。
你还可以一开始就给数组填入初始值:
```javascript
// 你的冰淇淋店口味菜单
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 用户的个人资料信息(混合不同类型的数据)
const userData = ["John", 25, true, "developer"];
// 你最喜欢的课程的考试成绩
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" | 第五个元素 |
✅ 你是否对数组从零开始编号感到惊讶?在某些编程语言中,索引是从 1 开始的。这里有一段有趣的历史,你可以在 [Wikipedia 上阅读](https://en.wikipedia.org/wiki/Zero-based_numbering)。
**访问数组元素:**
```javascript
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";
console.log(iceCreamFlavors[4]); // “黄油山核桃”
// 在末尾添加一个新元素
iceCreamFlavors[5] = "Cookie Dough";
console.log(iceCreamFlavors[5]); // “曲奇面团”
```
**以上操作包括:**
- **将** 索引 4 处的元素从 "Rocky Road" 修改为 "Butter Pecan"
- **在** 索引 5 添加新元素 "Cookie Dough"
- **自动** 在添加超出当前边界时扩展数组长度
### 数组长度和常用方法
数组自带了属性和方法,让处理数据变得更加轻松。
**获取数组长度:**
```javascript
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
console.log(iceCreamFlavors.length); // 5
// 随着数组变化长度自动更新
iceCreamFlavors.push("Mint Chip");
console.log(iceCreamFlavors.length); // 6
```
**要点:**
- **返回** 数组中元素的总数
- **自动更新**,元素增加或删除时动态改变
- **提供** 动态计数,适用于循环和验证
**常用数组方法:**
```javascript
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
```
> **现实世界见解**:在编程中数组无处不在!社交媒体信息流、购物车、图片库、播放列表歌曲——背后都是数组!
## 循环
想象一下狄更斯小说里的惩罚,一个学生要反复在黑板上写同一句话。假如你能简单告诉别人“写这句话 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` 循环就像设置了一个计时器——你知道任务要执行多少次。它非常有序且可预测,非常适合处理数组或需要计数的场合。
**For 循环结构:**
| 组成部分 | 作用 | 示例 |
|-----------|---------|----------|
| **初始化** | 设定起点 | `let i = 0` |
| **条件** | 继续执行的条件 | `i < 10` |
| **增量** | 如何更新 | `i++` |
```javascript
// 从0数到9
for (let i = 0; i < 10; 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 循环
`while` 循环相当于“持续做这件事直到……”,你不一定知道会执行多少次,但知道什么时候停止。它非常适合用户输入验证,或者在找到想要的数据前不断搜索。
**While 循环特征:**
- **在条件为真时** 持续执行
- **需要** 手动管理计数变量
- **在每次执行前** 判断条件
- **风险** 条件永远为真则发生死循环
```javascript
// 基本计数示例
let i = 0;
while (i < 10) {
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...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
const iceCreamFlavors = ["Chocolate", "Strawberry", "Vanilla", "Pistachio", "Rocky Road"];
// 经典的for循环方法
for (let i = 0; i < iceCreamFlavors.length; i++) {
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)。
**你的挑战:** 使用至少三种不同的数组方法重构学生成绩示例。注意使用现代 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
## 作业
[遍历数组](assignment.md)
---
## 📊 **你的数组与循环工具包总结**
```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)翻译而成。虽然我们致力于准确性,但请注意自动翻译可能包含错误或不准确之处。应以原始语言版本的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用本翻译而产生的任何误解或错误解读承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,115 @@
# 数组与循环作业
## 说明
完成以下练习以练习数组和循环的使用。每个练习都建立在课程的概念基础上,并鼓励你应用不同的循环类型和数组方法。
### 练习 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. 如果需要优化代码性能,你会如何做?
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件由AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。如涉及重要信息,建议采用专业人工翻译。因使用本翻译而引起的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,17 @@
# JavaScript简介
JavaScript是网页的语言。在这四节课中你将学习它的基础知识。
### 主题
1. [变量和数据类型](1-data-types/README.md)
2. [函数和方法](2-functions-methods/README.md)
3. [使用JavaScript进行决策](3-making-decisions/README.md)
4. [数组和循环](4-arrays-loops/README.md)
### 致谢
这些课程由[Jasmine Greenaway](https://twitter.com/paladique)、[Christopher Harrison](https://twitter.com/geektrainer)和[Chris Noring](https://twitter.com/chris_noring)倾情编写。
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。我们对于因使用本翻译而引起的任何误解或误读不承担责任。

@ -0,0 +1,585 @@
# Terrarium 项目第一部分HTML 入门
```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/zh-CN/webdev101-html.4389c2067af68e98.webp)
> 速记图由 [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)
> 📺 **观看学习**:查看这段有帮助的视频综述
>
> [![HTML 基础视频](https://img.youtube.com/vi/1TvxJKBzhyQ/0.jpg)](https://www.youtube.com/watch?v=1TvxJKBzhyQ)
## 设置你的项目
在开始编写 HTML 代码之前,让我们为你的玻璃植物箱项目搭建一个合适的工作空间。从一开始创建一个有序的文件结构是一个非常重要的习惯,它将在你整个网页开发旅程中为你带来帮助。
### 任务:创建你的项目结构
你将为玻璃植物箱项目创建专用文件夹,并添加你的第一个 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 资源管理器显示新建文件](../../../../translated_images/zh-CN/vs-code-index.e2986cf919471eb9.webp)
**选项 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
<!DOCTYPE html>
<html></html>
```
**理解这段代码做了什么:**
- **声明** 文档类型为 HTML5使用 `<!DOCTYPE html>`
- **创建** 含有所有页面内容的根 `<html>` 元素
- **确立** 现代网页标准,确保浏览器正确渲染
- **保证** 各种浏览器和设备上的一致显示效果
> 💡 **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>` 根元素包含了什么
- ✅ 这种结构如何帮助浏览器正确渲染页面
**快速自测**:你能用自己的话解释“标准兼容渲染”是什么意思吗?
## 添加必要的文档元数据
HTML 文档的 `<head>` 部分包含了浏览器和搜索引擎需要的关键信息,但访客不会直接看到它。这部分可以看作是“幕后”信息,帮助你的网页正常工作且在不同设备和平台上正确显示。
这段元数据告诉浏览器如何显示页面,使用什么字符编码,以及如何处理不同屏幕尺寸 —— 这些都是构建专业且可访问网页的重要因素。
### 任务:添加文档头部
将以下 `<head>` 部分插入到 `<html>` 标签的开头和结尾之间:
```html
<head>
<title>Welcome to my Virtual Terrarium</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
```
**拆解每个元素的作用:**
- **设置** 在浏览器标签和搜索结果中显示的页面标题
- **指定** UTF-8 字符编码,确保文本能正确显示全球字符
- **保证** 兼容现代版本的 Internet Explorer
- **通过设置视口匹配设备宽度** 来实现响应式设计
- **控制** 页面初始缩放,保证内容按自然大小显示
> 🤔 **思考这个问题**:如果你设置了 `<meta name="viewport" content="width=600">` 会发生什么?页面会被强制固定为 600 像素宽,打破响应式设计!了解更多关于[正确视口配置](https://developer.mozilla.org/docs/Web/HTML/Viewport_meta_tag)。
## 构建文档主体
`<body>` 元素包含网页所有的可见内容 —— 用户将看到并与之交互的一切。虽然 `<head>` 向浏览器提供指令,`<body>` 才是真正持有内容:文字、图片、按钮及其他创建用户界面的元素。
让我们添加主体结构,理解 HTML 标签如何协作创建有意义内容。
### 理解 HTML 标签结构
HTML 使用成对标签定义元素。大多数标签有开标签如 `<p>` 和闭标签如 `</p>`,中间包含内容:`<p>Hello, world!</p>`表示一个包含文本“Hello, world!”的段落元素。
### 任务:添加 `<body>` 元素
更新你的 HTML 文件,加入 `<body>` 元素:
```html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to my Virtual Terrarium</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body></body>
</html>
```
**该完整结构提供了:**
- **建立** 基本的 HTML5 文档框架
- **包含** 正确渲染所必须的元数据
- **创建** 一个空白主体,为你的可见内容准备位置
- **符合** 现代网页开发的最佳实践
现在你可以开始添加玻璃植物箱的可见元素了。我们将用 `<div>` 元素作为容器来组织不同内容区域,并用 `<img>` 标签显示植物图片。
### 使用图片和布局容器
图片在 HTML 中比较特殊,因为它们使用“自闭合”标签。与像 `<p></p>` 这类包裹内容的元素不同,`<img>` 标签在标签内部通过属性(如 `src` 指向图片文件路径,`alt` 用于无障碍访问)包含了所需全部信息。
添加图片前,你需要通过创建图片文件夹并添加植物图形来合理组织项目文件。
**首先,设置你的图片:**
1. 在玻璃植物箱项目文件夹中创建一个名为 `images` 的文件夹
2. 从 [solution folder](../../../../3-terrarium/solution/images) 下载植物图片共14张
3. 将所有植物图片复制到你的新 `images` 文件夹中
### 任务:创建植物展示布局
现在,在你的 `<body></body>` 标签之间,添加组织成两列的植物图片:
```html
<div id="page">
<div id="left-container" class="container">
<div class="plant-holder">
<img class="plant" alt="plant" id="plant1" src="../../../../translated_images/zh-CN/plant1.d87946a2ca70cc43.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant2" src="../../../../translated_images/zh-CN/plant2.8daa1606c9c1ad89.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant3" src="../../../../translated_images/zh-CN/plant3.8b0d484381a2a2a7.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant4" src="../../../../translated_images/zh-CN/plant4.656e16ae1df37be2.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant5" src="../../../../translated_images/zh-CN/plant5.2b41b9355f11ebcc.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant6" src="../../../../translated_images/zh-CN/plant6.3d1827d03b656994.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant7" src="../../../../translated_images/zh-CN/plant7.8152c302ac97f621.png" />
</div>
</div>
<div id="right-container" class="container">
<div class="plant-holder">
<img class="plant" alt="plant" id="plant8" src="../../../../translated_images/zh-CN/plant8.38d6428174ffa850.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant9" src="../../../../translated_images/zh-CN/plant9.f0e38d3327c37fc2.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant10" src="../../../../translated_images/zh-CN/plant10.b159d6d6e985595f.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant11" src="../../../../translated_images/zh-CN/plant11.2a03a1c2ec8ea84e.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant12" src="../../../../translated_images/zh-CN/plant12.60e9b53e538fbaf3.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant13" src="../../../../translated_images/zh-CN/plant13.07a51543c820bcf5.png" />
</div>
<div class="plant-holder">
<img class="plant" alt="plant" id="plant14" src="../../../../translated_images/zh-CN/plant14.6e486371ba7d36ba.png" />
</div>
</div>
</div>
```
**这段代码的步骤说明如下:**
- **创建** 一个主页面容器,`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>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 样式,这些元素暂时不可见。
玻璃植物箱标记使用了描述性很强的类名,方便下一课 CSS 直观且易维护的设计。
### 任务:添加玻璃植物箱结构
将以下标记插入到最后一个 `</div>` 标签之前(即页面容器关闭标签之前):
```html
<div id="terrarium">
<div class="jar-top"></div>
<div class="jar-walls">
<div class="jar-glossy-long"></div>
<div class="jar-glossy-short"></div>
</div>
<div class="dirt"></div>
<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 挑战
使用 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) ,了解网页标准如何发展以提升用户体验。
## 课后测验
[课后测验](https://ff-quizzes.netlify.app/web/quiz/16)
## 复习与自学
**加深你的 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 交互搭建坚实基础
**下一步**:你的 HTML 结构已准备好进行 CSS 样式设计!你所构建的语义基础将使下一课更加易懂。
## 作业
[练习你的 HTML构建博客模拟页面](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始文件的母语版本应被视为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而产生的任何误解或误读,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,145 @@
# HTML 练习作业:构建博客原型
## 学习目标
通过设计和编码一个完整的博客主页结构,应用您的 HTML 知识。这个实践作业将强化语义 HTML 概念、无障碍最佳实践以及专业代码组织技能,这些技能将在您的整个网页开发旅程中使用。
**完成此作业后,您将能够:**
- 练习在编码前规划网站布局
- 适当地应用语义 HTML 元素
- 创建可访问的、结构良好的标记
- 培养带有注释和组织的专业编码习惯
## 项目要求
### 第 1 部分:设计规划(视觉原型)
**创建您的博客主页的视觉原型,包括:**
- 带有网站标题和导航的页眉
- 具有至少 2-3 篇博客文章预览的主内容区
- 包含附加信息的侧边栏(关于部分、最近帖子、分类)
- 带有联系信息或链接的页脚
**原型创建选项:**
- **手绘草图**:使用纸和铅笔,然后拍照或扫描您的设计
- **数字工具**Figma、Adobe XD、Canva、PowerPoint 或任何绘图应用
- **线框工具**Balsamiq、MockFlow 或类似的线框软件
**在您的原型部分标注您计划使用的 HTML 元素**(例如,“页眉 - `<header>`”、“博客文章 - `<article>`”)。
### 第 2 部分HTML 元素规划
**创建一个列表,将您的原型的每个部分映射到特定的 HTML 元素:**
```
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)进行翻译。虽然我们力求准确,但请注意,自动翻译可能存在错误或不准确之处。原始文本应被视为权威来源。对于重要信息,建议采用专业人工翻译。我们不对因使用本翻译内容而引起的任何误解或错误解释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,726 @@
# 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/zh-CN/webdev101-css.3f7af5991bf53a20.webp)
> 速写笔记作者 [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 就像电影导演——你不仅控制一切的外观,还控制其运动、响应交互以及适应不同情况。
现代 CSS 非常强大。你可以编写代码,自动调整手机、平板和桌面电脑的布局。你可以创建平滑动画,引导用户注意力。所有功能协同工作时效果非常惊人。
> 💡 **小贴士**CSS 持续演进,增加新特性和功能。使用新 CSS 特性前,请务必访问 [CanIUse.com](https://caniuse.com) 检查浏览器支持情况。
**本课目标:**
- **创建** 用现代 CSS 技术完整设计你的生态瓶视觉效果
- **探索** 级联、继承和 CSS 选择器等基础概念
- **实现** 响应式定位和布局策略
- **构建** 生态瓶容器,使用 CSS 形状和样式
### 先修条件
你应该完成了上一课的生态瓶 HTML 结构,准备好进行样式设计。
> 📺 **视频资源**:观看此视频讲解
>
> [![CSS 基础教程](https://img.youtube.com/vi/6yIdOIV9p1I/0.jpg)](https://www.youtube.com/watch?v=6yIdOIV9p1I)
### 设置你的 CSS 文件
开始样式设计前,我们需要将 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>` 标签添加行内样式:
```html
<h1 style="color: red">My Terrarium</h1>
```
**代码做了什么:**
- **直接** 用行内样式将 `<h1>` 设置为红色
- **使用** `style` 属性直接在 HTML 中嵌入 CSS
- **创建** 该元素的最高优先级样式规则
接着,在你的 `style.css` 文件中添加以下规则:
```css
h1 {
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>` 元素设置字体:
```css
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
```
**解释这里发生的事情:**
- **设置** 全页面字体,针对 `<body>` 元素
- **使用** 字体栈托底,提升浏览器兼容性
- **应用** 现代系统字体,跨操作系统表现良好
- **确保** 所有子元素继承字体,除非被特别覆盖
打开浏览器开发者工具F12切换到 Elements 面板,检查 `<h1>` 元素,你会看到它继承自 body 的字体:
![inherited font](../../../../translated_images/zh-CN/1.cc07a5cbe114ad1d.webp)
**试验时间**:尝试给 `<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 提供了多种定位方式,选择正确选择器就像选对工具。你有时要给整个街区的每扇门统一造型,有时只对某一扇特殊的门操作。
### 元素选择器(标签)
元素选择器通过标签名称定位 HTML 元素。很适合设置页面全局基础样式:
```css
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
}
h1 {
color: #3a241d;
text-align: center;
font-size: 2.5rem;
margin-bottom: 1rem;
}
```
**这些样式做了什么:**
- **用** `body` 选择器设置统一字体排版
- **清除** 浏览器默认的外边距和内边距,方便精准控制
- **给所有标题元素** 设定颜色、对齐和间距
- **使用** `rem` 单位,提升字体大小的可伸缩性与无障碍性
虽然元素选择器适合通用样式,但针对生态瓶里的具体植物组件,你需要更具体的选择器。
### ID 选择器用于唯一元素
ID 选择器用 `#` 符号,定位具有唯一 `id` 属性的元素。ID 在页面中唯一,非常适合样式化单个特定元素,比如生态瓶左、右侧的植物容器。
为你的生态瓶侧边容器创建样式:
```css
#left-container {
background-color: #f5f5f5;
width: 15%;
left: 0;
top: 0;
position: absolute;
height: 100vh;
padding: 1rem;
box-sizing: border-box;
}
#right-container {
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` 单位,使代码简洁
- **设置** 柔和背景色,比生硬灰色更舒适
**代码质量挑战**:此 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;
}
```
### 类选择器用于可复用样式
类选择器用 `.` 符号,适合给多个元素应用相同样式。不同于 ID类可以在 HTML 中多次使用,适合统一样式模式。
在生态瓶中,每株植物样式相似但定位不同。我们会用类做共享样式,用 ID 做单独定位。
**各植物的 HTML 结构如下:**
```html
<div class="plant-holder">
<img class="plant" alt="Decorative plant for terrarium" id="plant1" src="../../../../translated_images/zh-CN/plant1.d18b18ffe73da18f.png" />
</div>
```
**关键元素说明:**
- **`class="plant-holder"`** 用于各植物容器,统一样式
- **`class="plant"`** 用于植物图片,共享样式和行为
- **`id="plant1"`** 唯一 ID用于定位和 JS 交互
- **提供** alt 文本,提升屏幕阅读器可访问性
现在将这些样式添加到 `style.css`
```css
.plant-holder {
position: relative;
height: 13%;
left: -0.6rem;
}
.plant {
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 ... */
}
/* Plant holder positioning */
.plant-holder {
position: relative; /* Creates positioning context */
/* ... other styles ... */
}
/* Plant positioning */
.plant {
position: absolute; /* Allows precise placement within holder */
/* ... other styles ... */
}
```
**定位策略说明:**
- **绝对容器** 从正常文档流移除,被钉在屏幕边缘
- **相对植物容器** 保持文档流,同时创建定位上下文
- **绝对植物** 可在相对容器内精准定位
- **组合使用** 允许植物垂直堆叠,且能单独定位
> 🎯 **为什么重要**`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
```
### 创建玻璃罐组件
让我们逐个构建生态瓶的罐体部分。每个部分都使用绝对定位和百分比尺寸以实现响应式设计:
```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);
}
.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;
}
```
**理解生态瓶构建:**
- **使用** 基于百分比的尺寸,实现所有屏幕尺寸的响应式缩放
- **绝对定位** 元素,以精确地堆叠和对齐
- **应用** 不同的不透明度值,创造玻璃透明效果
- **实现** `z-index` 分层,使植物显示在瓶子内部
- **添加** 细微的盒阴影和圆角边框,增强真实感
### 百分比响应式设计
注意所有尺寸都是用百分比,而非固定像素值:
**为什么重要:**
- **确保** 生态瓶在任何屏幕尺寸下成比例缩放
- **维护** 瓶子各部件间的视觉关系
- **提供** 从手机到大型桌面显示器的一致体验
- **允许** 设计自适应且不破坏视觉布局
### CSS 单位示范
我们使用 `rem` 单位来设置圆角,它相对于根字体大小缩放。这样创建的设计更易访问,尊重用户的字体偏好。详见官方规范中的 [CSS 相对单位](https://www.w3.org/TR/css-values-3/#font-relative-lengths)。
**视觉实验**:尝试修改这些数值,观察效果:
- 将罐子的透明度从 0.5 改为 0.8——这如何影响玻璃外观?
- 将土壤颜色从 `#3a241d` 改为 `#8B4513`——视觉效果怎样改变?
- 修改土壤的 `z-index` 为 2——分层效果发生了什么
### 🔄 **教学检查点**
**CSS 视觉设计理解**:确认你对视觉 CSS 的掌握:
- ✅ 百分比尺寸如何实现响应式设计?
- ✅ 为什么透明度能创建玻璃透明效果?
- ✅ `z-index` 在分层中起什么作用?
- ✅ 圆角值如何塑造罐子形状?
**设计原则**:注意我们如何用简单形状构建复杂视觉:
1. **矩形** → **圆角矩形** → **罐子组件**
2. **纯色** → **透明度** → **玻璃效果**
3. **单个元素** → **分层组合** → **三维效果**
---
## GitHub Copilot Agent 挑战 🚀
使用 Agent 模式完成以下挑战:
**描述:** 创建一个 CSS 动画,使生态瓶中的植物轻柔地摇摆,模拟自然微风效果。帮助你练习 CSS 动画、变换和关键帧,同时增强生态瓶的视觉吸引力。
**提示:** 添加 CSS 关键帧动画,使生态瓶内的植物缓慢地左右摇摆。创建一个摇摆动画,让每棵植物左右旋转约 2-3 度,持续时间为 3-4 秒,应用于 `.plant` 类。确保动画无限循环,且采用缓动函数以获得自然流畅的动作。
了解更多关于 [agent 模式](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) 。
## 🚀 挑战:添加玻璃反光效果
准备好用真实的玻璃反光效果增强你的生态瓶吗?这项技术将为设计添加深度和真实感。
你将创建细腻的高光模拟光在玻璃表面的反射。这与文艺复兴画家扬·凡·艾克Jan van Eyck使用光线和反射使绘画玻璃呈现三维感的手法类似。你的目标如下
![finished terrarium](../../../../translated_images/zh-CN/terrarium-final.2f07047ffc597d0a.webp)
**你的挑战:**
- **创建** 微妙的白色或浅色椭圆形反光
- **将其定位** 在罐子的左侧恰当位置
- **应用** 适当的不透明度和模糊效果,实现真实光反射
- **用** `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 结构
- **现代实践**:使用相对单位和无障碍设计模式
**下一步**你的生态瓶现在有了结构HTML和样式CSS。最后一课将添加交互功能JavaScript
## 作业
[CSS 重构](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件通过 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的原始文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,127 @@
# CSS 重构作业
## 目标
将您的微型生态瓶项目转换为使用现代 CSS 布局技术!重构当前的绝对定位方法,改用 **Flexbox****CSS Grid** 实现更易维护、响应式的设计。此作业挑战您在保持生态瓶视觉美感的同时,应用现代 CSS 标准。
理解何时及如何使用不同的布局方法,是现代网页开发的关键技能。本练习架起传统定位技术与现代 CSS 布局系统之间的桥梁。
## 作业说明
### 阶段 1分析与规划
1. **审查当前生态瓶代码** - 识别哪些元素当前使用绝对定位
2. **选择布局方法** - 决定 Flexbox 还是 CSS Grid 更适合您的设计目标
3. **绘制新布局结构图** - 规划容器及植物元素如何组织
### 阶段 2实现
1. **创建生态瓶项目的新版本**,放在单独文件夹中
2. **根据需要更新 HTML 结构**,以支持所选布局方法
3. **重构 CSS**,使用 Flexbox 或 CSS Grid 替代绝对定位
4. **保持视觉一致性** - 确保植物与生态瓶罐保持相同位置
5. **实现响应式行为** - 使布局能优雅适应不同屏幕尺寸
### 阶段 3测试与文档
1. **跨浏览器测试** - 验证设计在 Chrome、Firefox、Edge 和 Safari 中表现正常
2. **响应式测试** - 检查布局在移动设备、平板和桌面屏幕尺寸上的表现
3. **文档编写** - 在 CSS 中添加注释,说明布局设计选择
4. **截图** - 捕捉生态瓶在不同浏览器及屏幕尺寸下的效果
## 技术要求
### 布局实现
- **选择一项**:仅实现 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) 翻译完成。虽然我们力求准确,但请注意自动翻译可能存在错误或不准确之处。原始语言版本应被视为权威来源。如涉及重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,762 @@
# 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/zh-CN/webdev101-js.10280393044d7eaa.webp)
> 草图笔记作者:[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/zh-CN/dom-tree.7daf0e763cbbba92.webp)
> 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 树结构表示](../../../../translated_images/zh-CN/dom-tree.7daf0e763cbbba92.webp)
> DOM 及其关联 HTML 标记的表示。来自 [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
本节课,我们将完善交互生态瓶项目,创建 JavaScript 代码让用户能够操作页面上的植物。
## 开始之前:成功准备
你需要之前生态瓶课程中的 HTML 和 CSS 文件——我们将让那个静态设计变得可交互。如果你是首次加入,建议先完成那些课程以获得重要背景。
我们将实现的功能:
- **流畅的拖放操作**,适用于所有生态瓶中的植物
- **坐标跟踪**,让植物记住它们的位置
- **完整的交互界面**,使用纯 JavaScript 实现
- **清晰有序的代码结构**,运用闭包设计模式
## 设置你的 JavaScript 文件
让我们创建使生态瓶具备交互性的 JavaScript 文件。
**步骤 1创建脚本文件**
在你的生态瓶文件夹中,新建一个名为 `script.js` 的文件。
**步骤 2将 JavaScript 关联到 HTML**
在你的 `index.html` 文件的 `<head>` 部分添加以下脚本标签:
```html
<script src="./script.js" defer></script>
```
**为什么 `defer` 属性很重要:**
- **确保** JavaScript 脚本等到 HTML 完全加载后再执行
- **防止** JavaScript 访问尚未准备好的元素时出错
- **保证** 所有植物元素可交互
- **相比将脚本放在页面底部,提供更好的性能**
> ⚠️ **重要提示**`defer` 属性避免了常见的时序问题。没有它JavaScript 可能在 HTML 元素加载前就开始访问,引发错误。
---
## 关联 JavaScript 与 HTML 元素
在让元素可拖动之前JavaScript 需要定位它们在 DOM 中的位置。想象这像图书馆的目录系统——拿到适合的目录号,才能准确找到你需要的那本书并浏览其内容。
我们将使用 `document.getElementById()` 方法建立这些连接。它就像精准的文件系统——你提供 ID它就能准确找到 HTML 中对应元素。
### 为所有植物启用拖动功能
将以下代码添加到你的 `script.js` 文件中:
```javascript
// 为所有14种植物启用拖动功能
dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
dragElement(document.getElementById('plant4'));
dragElement(document.getElementById('plant5'));
dragElement(document.getElementById('plant6'));
dragElement(document.getElementById('plant7'));
dragElement(document.getElementById('plant8'));
dragElement(document.getElementById('plant9'));
dragElement(document.getElementById('plant10'));
dragElement(document.getElementById('plant11'));
dragElement(document.getElementById('plant12'));
dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));
```
**这段代码完成了以下任务:**
- **定位** DOM 中每个植物元素,基于它们独特的 ID
- **获取** 每个 HTML 元素的 JavaScript 引用
- **将** 每个元素传入 `dragElement` 函数(我们接着会创建)
- **为** 所有植物准备拖放交互功能
- **将** HTML 结构与 JavaScript 功能连接起来
> 🎯 **为什么用 ID 而不用类?** ID 为特定元素提供唯一标识,而 CSS 类用于样式分组。当 JavaScript 需要操作单个元素时ID 提供精准且高效的定位。
> 💡 **实用小贴士**:注意我们为每株植物单独调用了 `dragElement()`。这种方式确保每个植物拥有独立的拖动行为,是流畅交互的关键。
### 🔄 **教学小结**
**DOM 连接理解检查**:在继续拖动功能前,确认你能:
- ✅ 解释 `document.getElementById()` 如何定位 HTML 元素
- ✅ 理解为何每个植物需要唯一 ID
- ✅ 描述 `defer` 属性在 script 标签中的作用
- ✅ 识别 JavaScript 与 HTML 如何通过 DOM 关联
**快速自测**:如果两个元素拥有相同 ID会发生什么为何 `getElementById()` 只返回一个元素?
*回答ID 应该唯一;如果重复,只返回第一个匹配元素*
---
## 构建拖拽元素的闭包
现在我们创建拖动功能的核心:一个闭包,负责管理每株植物的拖动行为。这个闭包内部包含多个函数,协同工作以追踪鼠标移动并更新元素位置。
闭包非常适合该任务,因为它们允许创建“私有”变量,在函数调用之间保持状态,使每个植物拥独立的坐标跟踪系统。
### 用简单例子理解闭包
用一个简单示例演示闭包:
```javascript
function createCounter() {
let count = 0; // 这就像是一个私有变量
function increment() {
count++; // 内部函数记住了外部变量
return count;
}
return increment; // 我们返回内部函数
}
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 函数
接下来编写处理拖动逻辑的主函数。将此函数添加到植物元素声明代码之后:
```javascript
function dragElement(terrariumElement) {
// 初始化位置跟踪变量
let pos1 = 0, // 之前的鼠标X位置
pos2 = 0, // 之前的鼠标Y位置
pos3 = 0, // 当前的鼠标X位置
pos4 = 0; // 当前的鼠标Y位置
// 设置初始拖动事件监听器
terrariumElement.onpointerdown = pointerDrag;
}
```
**理解位置追踪系统:**
- **`pos1``pos2`**:存储旧鼠标位置和新鼠标位置的差值
- **`pos3``pos4`**:追踪当前鼠标坐标
- **`terrariumElement`**:特定的植物元素,我们要让它可拖动
- **`onpointerdown`**:触发用户开始拖动的事件
**闭包模式运作方式:**
- **为每株植物** 创建私有位置变量
- **在拖动生命周期中** 保持这些变量
- **确保** 每株植物独立追踪自身坐标
- **通过 `dragElement` 函数** 提供清晰接口
### 为什么使用指针事件?
你可能好奇为何用 `onpointerdown`而不是更熟悉的 `onclick`。原因如下:
| 事件类型 | 适用场景 | 缺点 |
|------------|----------|-------------|
| `onclick` | 简单按钮点击 | 只能处理点击和释放,无法拖动 |
| `onpointerdown` | 鼠标和触摸均适用 | 新技术,但现已广泛支持 |
| `onmousedown` | 仅限桌面鼠标 | 移动端用户体验不足 |
**指针事件为何对我们构建的功能完美契合:**
- **适用于** 鼠标、手指甚至触控笔
- **在** 笔记本、平板和手机上体验一致
- **负责** 拖动实际过程(不仅是点击)
- **打造** 用户期望的流畅现代体验
> 💡 **面向未来**:指针事件是处理用户交互的现代方法。无需为鼠标和触控分别写代码,二者兼得。很棒,对吧?
### 🔄 **教学小结**
**事件处理理解测试**:停顿确认你已理解事件:
- ✅ 为什么用指针事件而非鼠标事件?
- ✅ 闭包变量如何在函数调用间持续?
- ✅ `preventDefault()` 在流畅拖动中起什么作用?
- ✅ 为什么监听器绑定到 document而非直接绑定元素
**现实连接**:思考你每天用到的拖放界面:
- **文件上传**:将文件拖入浏览器窗口
- **看板工具**:任务列间拖动卡片
- **图片库**:调整图片排序
- **移动端界面**:触屏滑动和拖动操作
---
## pointerDrag 函数:捕获拖动开始
当用户按下植物(无论鼠标点击还是手指触摸),`pointerDrag` 函数启动。它捕获初始坐标并搭建拖动系统。
将该函数添加到 `dragElement` 闭包内,紧接 `terrariumElement.onpointerdown = pointerDrag;` 行之后:
```javascript
function pointerDrag(e) {
// 防止默认的浏览器行为(如文本选择)
e.preventDefault();
// 捕捉初始的鼠标/触摸位置
pos3 = e.clientX; // 拖动开始时的 X 坐标
pos4 = e.clientY; // 拖动开始时的 Y 坐标
// 设置拖动过程的事件监听器
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
}
```
**步骤说明:**
- **阻止** 浏览器默认行为,避免干扰拖动
- **记录** 用户开始拖动的准确坐标
- **建立** 后续拖动移动事件监听器
- **准备** 跟踪鼠标/手指在整个文档上的移动
### 理解事件阻止
`e.preventDefault()` 是保证拖动流畅的关键所在:
**不阻止的话,浏览器可能会:**
- **选中文本**,导致拖动时页面出现不适视觉
- **触发** 右键上下文菜单
- **干扰** 我们自定义的拖动行为
- **造成** 拖动过程中的视觉异常
> 🔍 **实验**:完成本节后,试试去掉 `e.preventDefault()`,观察拖动体验如何变化。你将直观感受到该代码的重要性!
### 坐标追踪系统
`e.clientX``e.clientY` 属性提供精准鼠标/触摸坐标:
| 属性 | 测量内容 | 用途 |
|----------|------------------|----------|
| `clientX` | 相对于视口的水平位置 | 跟踪左右移动 |
| `clientY` | 相对于视口的垂直位置 | 跟踪上下移动 |
**理解这些坐标:**
- **提供**像素级精准定位信息
- **随着用户移动指针**实时更新
- **在不同屏幕尺寸和缩放级别**下保持一致
- **实现**流畅且响应迅速的拖拽交互
### 设置文档级事件监听器
注意我们把移动和停止事件绑定到整个 `document`,而不仅仅是植物元素:
```javascript
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
```
**为什么绑定到 document**
- **即使鼠标离开植物元素也能继续跟踪**
- **防止用户快速移动时拖拽中断**
- **提供整个屏幕范围内的流畅拖拽**
- **处理光标移出浏览器窗口的边缘情况**
> ⚡ **性能提示**:拖拽停止时,我们会清理这些文档级监听器以避免内存泄漏和性能问题。
## 完成拖拽系统:移动与清理
现在我们将添加剩余两个函数,分别处理实际拖动移动和拖拽停止时的清理。这些函数协同工作,实现花园中植物的平滑、响应式移动。
### elementDrag 函数:跟踪移动
`pointerDrag` 函数的闭括号之后添加 `elementDrag` 函数:
```javascript
function elementDrag(e) {
// 计算自上次事件以来移动的距离
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';
}
```
**理解坐标数学:**
- **`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` 函数闭括号后添加清理函数:
```javascript
function stopElementDrag() {
// 移除文档级别的事件监听器
document.onpointerup = null;
document.onpointermove = null;
}
```
**为什么清理至关重要:**
- **防止遗留事件监听器导致内存泄漏**
- **用户松开植物时停止拖拽行为**
- **允许其他元素独立拖拽**
- **为下一次拖拽操作重置系统**
**不清理会带来什么问题:**
- 拖拽停止后事件监听器依旧运行
- 未使用监听器堆积导致性能下降
- 交互其他元素时出现异常行为
- 浏览器资源被无用事件处理占用
### 理解 CSS 定位属性
我们的拖拽系统操作两个关键 CSS 属性:
| 属性 | 控制内容 | 用途 |
|----------|------------------|---------------|
| `top` | 距顶部边缘距离 | 拖拽过程中的垂直定位 |
| `left` | 距左侧边缘距离 | 拖拽过程中的水平定位 |
**关于 offset 属性的关键点:**
- **`offsetTop`**:当前相对于定位父元素顶部的距离
- **`offsetLeft`**:当前相对于定位父元素左侧的距离
- **定位上下文**:这些数值相对于最近的定位祖先元素
- **实时更新**:当我们修改 CSS 属性时立即生效
> 🎯 **设计理念**:该拖拽系统故意保持灵活——没有“放置区”或限制。用户可以将植物放置于任意位置,完全自由设计他们的花园。
## 整合:完整的拖拽系统
恭喜!你刚刚用原生 JavaScript 构建了一个复杂的拖放系统。你完整的 `dragElement` 函数包含强大的闭包控件,实现:
**闭包的功能点:**
- **为每个植物独立维护私有位置变量**
- **管理从开始到结束的完整拖拽生命周期**
- **提供整个屏幕范围内顺畅且响应迅速的移动**
- **正确清理资源避免内存泄漏**
- **创建直观且富有创意的花园设计界面**
### 测试你的交互式花园
现在测试你的交互式花园吧!在浏览器打开 `index.html`,试试这些操作:
1. **点击并按住**任意植物开始拖动
2. **移动鼠标或手指**,观察植物平滑跟随
3. **松开**以放置植物到新位置
4. **尝试不同布局**,探索界面可能性
🥇 **成就**你创建了一个完整的交互式网页应用运用了专业开发者每日使用的核心概念。这个拖放功能与文件上传、看板kanban和其他交互界面背后的原理相同。
### 🔄 **教学检查点**
**完整系统理解**:验证你对整个拖拽系统的掌握:
- ✅ 闭包如何为每棵植物维护独立状态?
- ✅ 为什么坐标计算对于流畅移动是必需的?
- ✅ 忘记清理事件监听器会有什么后果?
- ✅ 这种模式如何扩展到更复杂的交互?
**代码质量反思**:检查你的完整方案:
- **模块化设计**:每棵植物拥有自己的闭包实例
- **事件效率**:正确设置和清理监听器
- **跨设备支持**:兼容桌面和移动端
- **性能意识**:无内存泄漏或冗余计算
![完成的花园](../../../../translated_images/zh-CN/terrarium-final.0920f16e87c13a84.webp)
---
## 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 工具箱总结
完成本课后,你已经掌握:
- **DOM 精通**:元素选取、属性操作及树结构导航
- **事件专业**:跨设备指针事件交互处理
- **闭包理解**:私有状态管理与函数持久性
- **交互系统**:从零实现完整拖拽功能
- **性能意识**:正确事件清理与内存管理
- **现代模式**:专业开发中应用的代码组织技术
- **用户体验**:创建直观、响应迅速的界面
**获得的专业技能**:你构建的功能使用了与以下相同技术:
- **Trello/看板**:卡片拖拽跨列操作
- **文件上传系统**:拖放文件处理
- **图片库**:照片排列界面
- **移动应用**:基于触摸的交互模式
**下一步**:你已准备好学习如 React、Vue 或 Angular 等基于这些 DOM 基础概念构建的现代框架!
## 任务
[继续练习 DOM](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意自动翻译可能包含错误或不准确之处。原始语言的原文应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误释,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,130 @@
# DOM 元素调查作业
## 概述
既然你已经亲身体验了 DOM 操作的强大功能,现在是时候探索更广泛的 DOM 接口世界了。本作业将加深你对不同网络技术如何与 DOM 交互的理解,而不仅仅是拖拽元素。
## 学习目标
完成此作业后,你将能够:
- **研究**并深入理解特定的 DOM 接口
- **分析**现实世界中 DOM 操作的实现
- **将**理论概念与实际应用相连接
- **培养**技术文档编写和分析的能力
## 说明
### 第一步:选择你的 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 如何支持我们日常使用的交互式网页体验的理解。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文档使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力确保准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文档的母语版本应视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用此翻译而产生的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,21 @@
## 部署您的 Terrarium
您可以使用 **Azure Static Web Apps** 将您的 Terrarium 部署或发布到网络上。
1. Fork 此仓库
2. 按下此按钮 👇
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.StaticApp)
3. 按照设置向导创建您的应用。
- 将 **应用根目录** 设置为 `/solution` 或您的代码库根目录。
- 此应用没有 API您可以跳过 API 配置。
- 系统会自动创建一个 `.github` 文件夹,帮助 Azure Static Web Apps 构建和发布您的应用。
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们力求准确,但请注意,自动翻译可能包含错误或不准确之处。原始语言的原始文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误释,我们概不负责。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,28 @@
# 我的微型生态瓶一个学习HTML、CSS和使用JavaScript操作DOM的项目 🌵🌱
一个小型的拖放代码冥想项目。通过一些HTML、JS和CSS你可以构建一个网页界面为其设计样式并添加交互功能。
![我的微型生态瓶](../../../../3-terrarium/images/screenshot_gray.png)
## 致谢
由[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。
**免责声明**
本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用本翻译而引起的任何误解或误读不承担责任。

@ -0,0 +1,281 @@
# 事件驱动编程 - 构建一个打字游戏
```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
```
想知道提升这项技能的最佳方法之一吗?没错——我们要做一个游戏!
```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 样式
- 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 美化游戏界面
### 📅 **你一周内的游戏开发计划**
- [ ] 完善完整的打字游戏及其所有功能和细节
- [ ] 添加难度等级,提供不同复杂度的词汇
- [ ] 实现用户统计跟踪(字数速度、准确率随时间变化)
- [ ] 制作音效和动画提升用户体验
- [ ] 使游戏支持移动设备响应和触摸操作
- [ ] 在线分享你的游戏并收集用户反馈
### 🌟 **你一个月的互动开发计划**
- [ ] 构建多个游戏,探索不同的交互模式
- [ ] 学习游戏循环、状态管理和性能优化
- [ ] 参与开源游戏开发项目
- [ ] 精通高级计时概念和平滑动画
- [ ] 创建展示各类交互应用的作品集
- [ ] 指导对游戏开发和用户交互感兴趣的其他人
## 🎯 你的打字游戏精通时间线
```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) 用 ♥️ 撰写
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。虽然我们努力保证译文的准确性,但请注意,自动翻译可能存在错误或不准确之处。原始文档的原文版本应被视为权威来源。对于重要信息,建议采用专业人工翻译。对于因使用本翻译而产生的任何误解或曲解,我们不承担任何责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,4 @@
这是一个占位符,故意留空
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于重要信息,建议使用专业人工翻译。我们对因使用此翻译而产生的任何误解或误读不承担责任。

@ -0,0 +1,603 @@
# 使用事件创建游戏
你有没有想过网站是如何知道你点击了按钮或在文本框中输入的?这就是事件驱动编程的魔力!还有什么比通过构建一个能够响应你每一次按键的打字速度游戏来学习这项关键技能更好的方法呢。
你将亲眼见证网页浏览器如何“与”你的JavaScript代码“对话”。每当你点击、输入或移动鼠标时浏览器都会向你的代码发送小信息我们称之为事件而你来决定如何响应
完成本教程后,你将创建一个能够跟踪你的打字速度和准确率的真实打字游戏。更重要的是,你将理解支撑每个互动网站的基本概念。让我们开始吧!
## 课前测验
[课前测验](https://ff-quizzes.netlify.app/web/quiz/21)
## 事件驱动编程
想想你最喜欢的应用或网站——是什么让它感觉生动且响应灵敏?这全在于它如何对你的操作做出反应!每次点击、敲击、滑动或按键都会产生我们所说的“事件”,真正的网页开发魔力就在这里。
让网页编程如此有趣的是:我们永远不知道别人什么时候会点击按钮或开始在文本框中输入。他们可能马上点击,等待五分钟,甚至可能从不点击!这种不可预测性意味着我们需要用不同的思路写代码。
我们不再写那种像食谱一样自上而下执行的代码而是写一段坐在那里耐心等待事情发生的代码。这有点像19世纪的电报操作员坐在设备旁准备在信息通过电线传来时立刻响应。
那么什么是“事件”呢?简单来说,它就是发生的事情!你点击按钮——那是一个事件。你输入一个字母——那是一个事件。你移动鼠标——又是一个事件。
事件驱动编程让我们可以设置代码去“监听”和响应这些事件。我们创建称为**事件监听器**的特殊函数,它们耐心等待特定事件发生,然后在事件发生时立即行动。
把事件监听器想象成代码的门铃。你设置门铃(`addEventListener()`),告诉它要监听什么声音(比如“点击”或“按键”),然后指定有人按响时要执行什么(你自定义的函数)。
**事件监听器的工作原理:**
- **监听**用户的特定操作,如点击、按键或鼠标移动
- **执行**在指定事件发生时你的自定义代码
- **即时响应**用户交互,创造无缝体验
- **支持**对同一元素使用多个监听器处理不同事件
> **注意:**有很多创建事件监听器的方法。你可以使用匿名函数,也可以创建命名函数。可以使用各种快捷方式,比如设置`click`属性,或使用`addEventListener()`。本练习中我们重点使用`addEventListener()`和匿名函数,因为这是网络开发者最常用的方法。它也是最灵活的,适用于所有事件,事件名称可作为参数传入。
### 常见事件
虽然浏览器提供了数十种不同事件可供监听,但大多数互动应用只依赖其中几种核心事件。理解这些核心事件能为你构建复杂用户交互奠定基础。
有[数十种事件](https://developer.mozilla.org/docs/Web/Events)可供你在创建应用时监听。基本上,用户在页面上所做的任何操作都会触发事件,赋予你强大能力确保他们得到理想的体验。幸运的是,通常只需少数几个事件。下面是几个常用事件(包括我们在游戏中会用到的两个):
| 事件 | 描述 | 常见用例 |
|-------|-------------|------------------|
| `click` | 用户点击了某个元素 | 按钮、链接、互动元素 |
| `contextmenu` | 用户点击了鼠标右键 | 自定义右键菜单 |
| `select` | 用户选中了文本 | 文本编辑、复制操作 |
| `input` | 用户输入了文本 | 表单验证、实时搜索 |
**理解这些事件类型:**
- **在用户与页面特定元素交互时触发**
- **通过事件对象提供有关用户行为的详细信息**
- **使你能创建响应式、互动性强的网页应用**
- **在不同浏览器和设备上表现一致**
## 创建游戏
既然了解了事件的工作原理,让我们用所学知识实践,创造点有用的东西。我们将创建一个打字速度游戏,演示事件处理的同时,帮助你培养一项重要的开发者技能。
我们要制作一个游戏探索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`负责美化页面。这是驱动大部分网页的经典组合!
**在控制台或终端窗口中执行以下命令,创建新文件夹以开始工作:**
```bash
# Linux 或 macOS
mkdir typing-game && cd typing-game
# Windows
md typing-game && cd typing-game
```
**这些命令执行了以下操作:**
- **创建**名为`typing-game`的新目录存放项目文件
- **自动切换**至新建目录
- **为游戏开发设置**一个干净的工作空间
**打开 Visual Studio Code**
```bash
code .
```
**该命令执行:**
- **在当前目录**启动 Visual Studio Code
- **打开**你的项目文件夹
- **提供**所有开发工具的访问
**在 Visual Studio Code 中为该文件夹添加三个文件,命名如下:**
- `index.html` - 包含游戏的结构和内容
- `script.js` - 处理所有游戏逻辑和事件监听
- `style.css` - 定义视觉外观和样式
## 创建用户界面
现在让我们构建游戏进行的舞台!把它想象成设计飞船的控制面板——确保玩家所需的一切都在预期位置。
让我们确定游戏到底需要哪些元素。如果你在玩打字游戏,会想在屏幕上看到什么?我们需要:
| UI 元素 | 目的 | HTML 元素 |
|------------|---------|-------------|
| 引用显示区 | 展示要打的文本 | `<p>``id="quote"` |
| 消息区 | 显示状态和成功信息 | `<p>``id="message"` |
| 文本输入框 | 玩家输入引用的地方 | `<input>``id="typed-value"` |
| 开始按钮 | 开始游戏 | `<button>``id="start"` |
**UI结构要点**
- **内容逻辑地组织**从上到下
- **元素分配**唯一 ID 供 JavaScript 访问
- **提供**清晰的视觉层次,提升用户体验
- **包含**语义化的 HTML 元素以增强无障碍支持
以上每个元素都需分配 ID方便我们用JavaScript操作。我们还会添加对即将创建的CSS和JavaScript文件的引用。
新建一个名为`index.html`的文件添加如下HTML
```html
<!-- inside index.html -->
<html>
<head>
<title>Typing game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Typing game!</h1>
<p>Practice your typing skills with a quote from Sherlock Holmes. Click **start** to begin!</p>
<p id="quote"></p> <!-- This will display our quote -->
<p id="message"></p> <!-- This will display any status messages -->
<div>
<input type="text" aria-label="current word" id="typed-value" /> <!-- The textbox for typing -->
<button type="button" id="start">Start</button> <!-- To start the game -->
</div>
<script src="script.js"></script>
</body>
</html>
```
**这个HTML结构实现了**
- **在`<head>`中引入CSS样式表用于美化**
- **创建清晰的标题和用户指引**
- **建立带有特定ID的占位段落以显示动态内容**
- **包含带无障碍属性的输入框**
- **设置启动游戏的按钮**
- **在文档末尾加载JavaScript文件以优化性能**
### 启动应用程序
开发过程中频繁测试应用能让你提前发现问题并实时看到进展。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 功能:**
- **启动**一个项目本地开发服务器
- **在保存文件时**自动刷新浏览器
- **通过本地地址**(通常是`localhost:5500`)提供访问
**打开浏览器并访问 `https://localhost:5500`**
你现在应看到你创建的页面了!让我们添加一些功能。
## 添加 CSS
现在让界面美观起来视觉反馈从计算机早期时代起就是用户界面的关键。上世纪80年代研究发现即时视觉反馈极大提升用户效率并减少错误。正是我们要实现的。
游戏需要明确告知发生了什么。玩家应立即知道当前应该打哪个单词,若输入错误,也能立刻察觉。让我们来做一些简单却有效的样式设计:
新建`style.css`文件,添加以下内容:
```css
/* inside style.css */
.highlight {
background-color: yellow;
}
.error {
background-color: lightcoral;
border: red;
}
```
**理解这些CSS类**
- **通过黄色背景高亮**当前单词,清晰指引焦点
- **输入错误时**使用浅珊瑚色背景提示
- **即时反馈**用户输入,且不打断打字流程
- **采用有对比度的颜色**提升可访问性和视觉沟通
✅ CSS布局可以自由发挥。花些时间让页面更美观
- 选择不同字体
- 给标题配色
- 调整元素大小
## JavaScript
接下来就是精彩的部分了!🎉 我们已经有了HTML结构和CSS样式但此时我们的游戏就像一辆漂亮但没有引擎的车。JavaScript就是这台引擎——它让一切真正运作、对玩家操作做出响应。
这里你将看到你创作的作品活起来。我们会逐步实现,避免让人感到吃力:
| 步骤 | 目的 | 学习内容 |
|------|---------|------------------|
| [创建常量](../../../../4-typing-game/typing-game) | 设置引用文本和DOM引用 | 变量管理和DOM选择 |
| [绑定开始游戏事件监听](../../../../4-typing-game/typing-game) | 处理游戏初始化 | 事件处理和UI更新 |
| [绑定输入监听事件](../../../../4-typing-game/typing-game) | 实时处理用户输入 | 输入验证和动态反馈 |
**这种结构化方法帮助你:**
- **合理组织**代码,易于管理
- **渐进构建**功能,方便调试
- **掌握**应用中各部分如何协作
- **创造**可复用模式,助力未来项目
但首先,创建一个名为`script.js`的新文件。
### 添加常量
在动手之前先收集所有资源就像NASA任务控制中心在发射前搭建所有监控系统一样事先准备好一切更便捷。这避免日后到处找东西也减少拼写错误。
我们首先需要设置:
| 数据类型 | 目的 | 示例 |
| 引用数组 | 存储游戏中所有可能的引用 | `['Quote 1', 'Quote 2', ...]` |
| 单词数组 | 将当前引用拆分成单个单词 | `['When', 'you', 'have', ...]` |
| 单词索引 | 跟踪玩家正在输入的单词 | `0, 1, 2, 3...` |
| 开始时间 | 计算计分的经过时间 | `Date.now()` |
**我们还需要对 UI 元素的引用:**
| 元素 | ID | 用途 |
|---------|----|---------|
| 文本输入 | `typed-value` | 玩家输入的地方 |
| 引用展示 | `quote` | 显示要输入的引用 |
| 消息区域 | `message` | 显示状态更新 |
```javascript
// 在 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.',
'I ought to know by this time that when a fact appears to be opposed to a long train of deductions it invariably proves to be capable of bearing some other interpretation.',
'I never make exceptions. An exception disproves the rule.',
'What one man can invent another can discover.',
'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.',
];
// 存储单词列表和玩家当前输入的单词索引
let words = [];
let wordIndex = 0;
// 起始时间
let startTime = Date.now();
// 页面元素
const quoteElement = document.getElementById('quote');
const messageElement = document.getElementById('message');
const typedValueElement = document.getElementById('typed-value');
```
**解析这段初始化代码实现了什么:**
- **存储**一组 Sherlock Holmes 的引用,使用 `const` 因为引用不会改变
- **初始化**跟踪变量,使用 `let` 因为这些值会在游戏过程中更新
- **获取** DOM 元素引用,使用 `document.getElementById()` 以便高效访问
- **搭建**游戏所有功能的基础,变量命名清晰且具描述性
- **逻辑组织**相关数据和元素,便于维护代码
✅ 继续添加更多引用到你的游戏中吧
> 💡 **专业提示**:我们可以在代码中随时使用 `document.getElementById()` 获取元素引用。因为我们会经常用到这些元素,使用常量避免字符串字面量写错。像 [Vue.js](https://vuejs.org/) 或 [React](https://reactjs.org/) 这样的框架能帮助你更好地管理代码集中化。
>
**这种方法行之有效的原因:**
- **防止**多次引用元素时拼写错误
- **提升**代码可读性,使用描述性常量名
- **提供**更好的 IDE 支持,如自动完成与错误检查
- **便于**将来修改元素 ID 时进行重构
花一分钟观看关于 `const`、`let` 和 `var` 的视频
[![变量类型](https://img.youtube.com/vi/JNIXfGiDWM8/0.jpg)](https://youtube.com/watch?v=JNIXfGiDWM8 "Types of variables")
> 🎥 点击上方图片观看有关变量的视频。
### 添加开始逻辑
一切都将在这里启动!🚀 你即将编写第一个真正的事件监听器,看到代码响应按钮点击非常令人满足。
想象一下:某处有玩家点击那个“开始”按钮,你的代码必须准备就绪。我们不知道他们什么时候点击——可能立刻,也可能喝杯咖啡后——但一旦点击,游戏立即开始。
当用户点击 `start`,我们需要选择一个引用,设置用户界面,跟踪当前单词和计时。以下是你需要添加的 JavaScript我们稍后会讲解这段脚本。
```javascript
// 在 script.js 的末尾
document.getElementById('start').addEventListener('click', () => {
// 获取一个引用
const quoteIndex = Math.floor(Math.random() * quotes.length);
const quote = quotes[quoteIndex];
// 将引用放入一个单词数组中
words = quote.split(' ');
// 重置单词索引用于跟踪
wordIndex = 0;
// 用户界面更新
// 创建一个 span 元素数组,以便我们可以设置类
const spanWords = words.map(function(word) { return `<span>${word} </span>`});
// 转换成字符串并设置为引用显示的 innerHTML
quoteElement.innerHTML = spanWords.join('');
// 高亮显示第一个单词
quoteElement.childNodes[0].className = 'highlight';
// 清除任何先前的消息
messageElement.innerText = '';
// 设置文本框
// 清空文本框
typedValueElement.value = '';
// 设置焦点
typedValueElement.focus();
// 设置事件处理程序
// 启动计时器
startTime = new Date().getTime();
});
```
**我们将代码分成以下逻辑部分:**
**📊 单词跟踪设置:**
- **随机选择**一个引用,使用 `Math.floor()``Math.random()` 实现多样性
- **拆分**引用成单词数组,使用 `split(' ')`
- **重置**`wordIndex` 为 0因为玩家从第一个单词开始
- **准备**游戏状态,迎接新一轮
**🎨 界面设置与显示:**
- **创建**一组 `<span>` 元素,分别包裹每个单词用于单独样式控制
- **合并**所有 span 元素成字符串,以高效更新 DOM
- **高亮**第一个单词,添加 `highlight` CSS 类
- **清除**之前的游戏消息,提供干净界面
**⌨️ 文本框准备:**
- **清空**输入框现有内容
- **聚焦**输入框,让玩家立刻开始打字
- **为新游戏准备**输入区域
**⏱️ 定时器初始化:**
- **捕获**当前时间戳,使用 `new Date().getTime()`
- **启用**准确计算输入速度和完成时间
- **开始**游戏计时和性能追踪
### 添加输入逻辑
这里是游戏的核心部分!别担心,看起来多,但我们会逐步讲解,结束后你会发现逻辑非常清晰。
我们正在构建的是非常智能的逻辑:每次输入字母时,代码都会检查输入内容,给予反馈,并决定下一步操作。这与 1970 年代 WordStar 这类早期文字处理器实时反馈打字员很相似。
```javascript
// 在 script.js 的末尾
typedValueElement.addEventListener('input', () => {
// 获取当前单词
const currentWord = words[wordIndex];
// 获取当前值
const typedValue = typedValueElement.value;
if (typedValue === currentWord && wordIndex === words.length - 1) {
// 句子结束
// 显示成功
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) {
// 单词结束
// 为新单词清除 typedValueElement
typedValueElement.value = '';
// 移动到下一个单词
wordIndex++;
// 重置 quote 中所有元素的类名
for (const wordElement of quoteElement.childNodes) {
wordElement.className = '';
}
// 突出显示新单词
quoteElement.childNodes[wordIndex].className = 'highlight';
} else if (currentWord.startsWith(typedValue)) {
// 当前正确
// 突出显示下一个单词
typedValueElement.className = '';
} else {
// 错误状态
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 类,给予即时视觉反馈
- **帮助**玩家快速识别并纠正错误
## 测试你的应用
看看你完成了什么!🎉 你刚用事件驱动编程从零构建了一个真正可用的打字游戏。好好感受这份成就——这可不容易!
接下来是测试环节!游戏能否按预期工作?我们是否遗漏了什么?没关系,如果刚开始有问题很正常。即使是资深开发者也经常遇到代码错误。这是开发流程的一部分!
点击 `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 模态样式方案
- **考虑**禁用和启用表单控件时的无障碍化处理
## 课后测验
[课后测验](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)的信息,思考你在哪些场景会使用它们。
## 作业
[创建一个新的键盘游戏](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免责声明**
本文件使用人工智能翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们力求准确,但请注意,自动翻译可能存在错误或不准确之处。原始语言的文件应被视为权威来源。对于重要信息,建议采用专业人工翻译。我们不对因使用本翻译而产生的任何误解或错误解释承担责任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save