aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/learn
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:43:23 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:43:23 -0500
commit218934fa2ed1c702a6d3923d2aa2cc6b43c48684 (patch)
treea9ef8ac1e1b8fe4207b6d64d3841bfb8990b6fd0 /files/zh-tw/learn
parent074785cea106179cb3305637055ab0a009ca74f2 (diff)
downloadtranslated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.gz
translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.bz2
translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.zip
initial commit
Diffstat (limited to 'files/zh-tw/learn')
-rw-r--r--files/zh-tw/learn/accessibility/index.html75
-rw-r--r--files/zh-tw/learn/accessibility/mobile/index.html302
-rw-r--r--files/zh-tw/learn/accessibility/wai-aria_basics/index.html421
-rw-r--r--files/zh-tw/learn/accessibility/what_is_accessibility/index.html201
-rw-r--r--files/zh-tw/learn/common_questions/index.html135
-rw-r--r--files/zh-tw/learn/common_questions/what_is_a_web_server/index.html116
-rw-r--r--files/zh-tw/learn/css/css_layout/index.html71
-rw-r--r--files/zh-tw/learn/css/first_steps/getting_started/index.html265
-rw-r--r--files/zh-tw/learn/css/first_steps/how_css_works/index.html156
-rw-r--r--files/zh-tw/learn/css/first_steps/index.html59
-rw-r--r--files/zh-tw/learn/css/first_steps/what_is_css/index.html131
-rw-r--r--files/zh-tw/learn/css/index.html72
-rw-r--r--files/zh-tw/learn/css/styling_text/index.html40
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html273
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html117
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html101
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html232
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/index.html59
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html73
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html440
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html116
-rw-r--r--files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html108
-rw-r--r--files/zh-tw/learn/how_to_contribute/index.html81
-rw-r--r--files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html315
-rw-r--r--files/zh-tw/learn/html/forms/index.html359
-rw-r--r--files/zh-tw/learn/html/howto/index.html150
-rw-r--r--files/zh-tw/learn/html/index.html61
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html456
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html326
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html283
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/getting_started/index.html626
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html953
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/index.html61
-rw-r--r--files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html261
-rw-r--r--files/zh-tw/learn/html/multimedia_and_embedding/html中的圖片/index.html502
-rw-r--r--files/zh-tw/learn/html/multimedia_and_embedding/index.html53
-rw-r--r--files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html339
-rw-r--r--files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html104
-rw-r--r--files/zh-tw/learn/html/multimedia_and_embedding/其他_嵌入_技術/index.html386
-rw-r--r--files/zh-tw/learn/html/tables/index.html34
-rw-r--r--files/zh-tw/learn/html/tables/基礎/index.html568
-rw-r--r--files/zh-tw/learn/index.html238
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html246
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/conditionals/index.html789
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/functions/index.html396
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html135
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/index.html52
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/looping_code/index.html928
-rw-r--r--files/zh-tw/learn/javascript/building_blocks/return_values/index.html172
-rw-r--r--files/zh-tw/learn/javascript/client-side_web_apis/index.html39
-rw-r--r--files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html314
-rw-r--r--files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html706
-rw-r--r--files/zh-tw/learn/javascript/first_steps/arrays/index.html571
-rw-r--r--files/zh-tw/learn/javascript/first_steps/index.html71
-rw-r--r--files/zh-tw/learn/javascript/first_steps/math/index.html426
-rw-r--r--files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html149
-rw-r--r--files/zh-tw/learn/javascript/first_steps/strings/index.html352
-rw-r--r--files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html714
-rw-r--r--files/zh-tw/learn/javascript/first_steps/variables/index.html344
-rw-r--r--files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html425
-rw-r--r--files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html253
-rw-r--r--files/zh-tw/learn/javascript/howto/index.html294
-rw-r--r--files/zh-tw/learn/javascript/index.html71
-rw-r--r--files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html184
-rw-r--r--files/zh-tw/learn/javascript/objects/basics/index.html243
-rw-r--r--files/zh-tw/learn/javascript/objects/index.html42
-rw-r--r--files/zh-tw/learn/javascript/objects/inheritance/index.html210
-rw-r--r--files/zh-tw/learn/javascript/objects/json/index.html325
-rw-r--r--files/zh-tw/learn/javascript/objects/object-oriented_js/index.html277
-rw-r--r--files/zh-tw/learn/javascript/objects/object_building_practice/index.html283
-rw-r--r--files/zh-tw/learn/javascript/objects/object_prototypes/index.html236
-rw-r--r--files/zh-tw/learn/performance/index.html124
-rw-r--r--files/zh-tw/learn/performance/多媒體/index.html130
-rw-r--r--files/zh-tw/learn/server-side/django/admin_site/index.html354
-rw-r--r--files/zh-tw/learn/server-side/django/authentication/index.html698
-rw-r--r--files/zh-tw/learn/server-side/django/deployment/index.html675
-rw-r--r--files/zh-tw/learn/server-side/django/development_environment/index.html429
-rw-r--r--files/zh-tw/learn/server-side/django/django_assessment_blog/index.html316
-rw-r--r--files/zh-tw/learn/server-side/django/forms/index.html661
-rw-r--r--files/zh-tw/learn/server-side/django/generic_views/index.html612
-rw-r--r--files/zh-tw/learn/server-side/django/home_page/index.html383
-rw-r--r--files/zh-tw/learn/server-side/django/index.html115
-rw-r--r--files/zh-tw/learn/server-side/django/introduction/index.html306
-rw-r--r--files/zh-tw/learn/server-side/django/models/index.html475
-rw-r--r--files/zh-tw/learn/server-side/django/sessions/index.html185
-rw-r--r--files/zh-tw/learn/server-side/django/skeleton_website/index.html388
-rw-r--r--files/zh-tw/learn/server-side/django/testing/index.html907
-rw-r--r--files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html92
-rw-r--r--files/zh-tw/learn/server-side/django/web_application_security/index.html180
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/deployment/index.html521
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html385
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html89
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html85
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html112
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html72
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html91
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html71
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html60
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html137
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html123
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html133
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html87
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html71
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html149
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html155
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html214
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html150
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html294
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html167
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/forms/index.html274
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/index.html73
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/introduction/index.html522
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html792
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/routes/index.html646
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html506
-rw-r--r--files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html91
-rw-r--r--files/zh-tw/learn/server-side/first_steps/index.html41
-rw-r--r--files/zh-tw/learn/server-side/first_steps/介紹/index.html225
-rw-r--r--files/zh-tw/learn/server-side/index.html59
-rw-r--r--files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html130
-rw-r--r--files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html387
-rw-r--r--files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html614
-rw-r--r--files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html372
-rw-r--r--files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html33
-rw-r--r--files/zh-tw/learn/tools_and_testing/index.html31
125 files changed, 33958 insertions, 0 deletions
diff --git a/files/zh-tw/learn/accessibility/index.html b/files/zh-tw/learn/accessibility/index.html
new file mode 100644
index 0000000000..9ded955a1e
--- /dev/null
+++ b/files/zh-tw/learn/accessibility/index.html
@@ -0,0 +1,75 @@
+---
+title: 無障礙網頁
+slug: Learn/Accessibility
+tags:
+ - ARIA
+ - Accessibility
+ - Articles
+ - Beginner
+ - CSS
+ - CodingScripting
+ - HTML
+ - JavaScript
+ - Landing
+ - Learn
+ - Module
+ - NeedsTranslation
+ - TopicStub
+translation_of: Learn/Accessibility
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">如果要當 web 開發者,學會 HTML、CSS、JavaScript 是很重要的。不過除此之外,你還要學得更多:你需要<strong>負責任地</strong>運用這些技術,才能讓所有讀者都能使用你的網頁。要達成這點,本模塊將展示一般最佳實做(在 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/en-US/docs/Learn/JavaScript">JavaScript</a> 有示範)、<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing">跨瀏覽器測試</a>、還有其他啟動的要點。</p>
+
+<h2 id="概觀">概觀</h2>
+
+<p>When someone describes a site as "accessible," they mean that any user can use all its features and content, regardless of how the user accesses the web — even and especially users with physical or mental impairments.</p>
+
+<ul>
+ <li>Sites should be accessible to keyboard, mouse, and touch screen users, and any other way users access the web, including screen readers and voice assistants like Alexa and Google Home.</li>
+ <li>Applications should be understandable and usable by people regardless of auditory, visual, physical, or cognitive abilities.</li>
+ <li>Sites should also not cause harm: web features like motion can cause migraines or epileptic seizures.</li>
+</ul>
+
+<p><strong>By default, HTML is accessible, if used correctly.</strong> Web accessibility involves ensuring that content remains accessible, regardless of who and how the web is accessed.</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>要理解本模塊的概念,最少理解 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 是個好主意。如果在學習相關技術時學習會更好。</p>
+
+<div class="note">
+<p><strong>注</strong>:如果使用的設備無法讓你建立自己的文件,可以試著在 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a> 這種程式撰寫網站,執行大多數範例。</p>
+</div>
+
+<h2 id="教學">教學</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/What_is_accessibility">何謂無障礙網頁?</a></dt>
+ <dd>這篇文章針對何謂無障礙網頁,起了一個好開頭。這模塊包含了要考慮哪些族群以及理由、不同族群會用什麼工具和 Web 互動、還有怎麼把無障礙網頁導入 Web 開發工作流程。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/HTML">HTML:無障礙網頁的好開始</a></dt>
+ <dd>只要確保在任何時候,正確的 HTML 元素都用於正確的目的,就能消除各種網頁的障礙。這篇文章詳述 HTML 如何確保網頁無障礙。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/CSS_and_JavaScript">充分實踐 CSS 與 JavaScript 的無障礙</a></dt>
+ <dd>如果 CSS 與 JavaScript 使用得當,將可以為無障礙網頁提供助力……反過來的話,就會嚴重影響無障礙體驗。這篇文章詳述如何在內容複雜的情況下,確保能充分實踐 CSS 與 JavaScript 的無障礙。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA 基礎</a></dt>
+ <dd>從之前的文章來看,有時製作要涉及到非語意的 HTML 還有動態 JavaScript 更新技術……等,會令複雜的 UI 控制變得很困難。WAI-ARIA 正是為了解決此一問題而生。它對瀏覽器和輔助技術添加進一步的語意,讓用戶能知道發生了什麼事。我們將介紹如何在基本層面使用此技術,以提昇無障礙。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/Multimedia">無障礙多媒體</a></dt>
+ <dd>會導致無障礙網頁出問題的另一個根源是多媒體:影片、聲音、圖片等內容,需要有合適的文字替代,以便輔助技術和它的用戶能夠理解。我們將在這篇文章中闡明作法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/Mobile">行動無障礙網頁</a></dt>
+ <dd>隨著行動設備訪問漸受歡迎、還有像是 iOS 與 Android 這般熱門平台,已經具備完善的輔助工具,考慮到如何在這些平台上實踐無障礙網頁,就變得十分重要。這篇文章將討論行動裝置特有的無障礙網頁相關議題。</dd>
+</dl>
+
+<h2 id="評估">評估</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility/Accessibility_troubleshooting">無障礙網頁偵錯</a></dt>
+ <dd>要評估本模塊,我們會提出一些簡單的網站,你需要偵測有哪些無障礙的問題並修復之。</dd>
+</dl>
+
+<h2 id="參見">參見</h2>
+
+<ul>
+ <li><a href="https://egghead.io/courses/start-building-accessible-web-applications-today">Start Building Accessible Web Applications Today</a>:Marcy Sutton 所作的一套優秀教學影片。</li>
+ <li><a href="https://dequeuniversity.com/resources/">Deque University resources</a>:包含程式碼範例、螢幕閱讀器參考、或是其他有用的資源。</li>
+ <li><a href="http://webaim.org/resources/">WebAIM resources</a>:有教學、便覽、工具……等。</li>
+ <li><a href="https://www.w3.org/WAI/ER/tools/">Web Accessibility Evaluation Tools List</a> - includes a list of web accessibility evaluation tools.</li>
+</ul>
diff --git a/files/zh-tw/learn/accessibility/mobile/index.html b/files/zh-tw/learn/accessibility/mobile/index.html
new file mode 100644
index 0000000000..eb04f93fd4
--- /dev/null
+++ b/files/zh-tw/learn/accessibility/mobile/index.html
@@ -0,0 +1,302 @@
+---
+title: Mobile accessibility
+slug: Learn/Accessibility/Mobile
+translation_of: Learn/Accessibility/Mobile
+---
+<div>
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div>
+
+<p class="summary">With web access on mobile devices being so popular, and popular platforms such as iOS and Android having fully fledged accessibility tools, it is important to consider the accessibility of your web content on these platforms. This article looks at mobile-specific accessibility considerations.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a basic understanding of HTML, CSS, and JavaScript, and an understanding of the <a href="/en-US/docs/Learn/Accessibility">previous articles in the course</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand what problems exist with accessibility on mobile devices, and how to overcome them.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="行動裝置上的無障礙">行動裝置上的無障礙</h2>
+
+<p>The state of accessibility — and support for web standards in general — is good in modern mobile devices. Long gone are the days when mobile devices ran completely different web technologies to desktop browsers, forcing developers to use browser sniffing and serve them completely separate sites (although quite a few companies still detect usage of mobile devices and serve them a separate mobile domain).</p>
+
+<p>目前,行動裝置通常可以處理“全脂(full fat)”網站,主要平台甚至還內置了屏幕閱讀器,使視障人士能夠成功使用它們。 現代手機行動瀏覽器也傾向於對<a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA</a>有很好的支持。</p>
+
+<p>To make a website accessible and usable on mobile, you just need to follow general good web design and accessibility best practices.</p>
+
+<p>There are some exceptions that need special consideration for mobile; the main ones are:</p>
+
+<ul>
+ <li>Control mechanisms — Make sure interface controls such as buttons are accessible on mobiles (i.e., mainly touchscreen), as well as desktops/laptops (mainly mouse/keyboard).</li>
+ <li>User input — Make user input requirements as painless as possible on mobile (e.g., in forms, keep typing to a minimum).</li>
+ <li>Responsive design — Make sure layouts work on mobile, conserve image download sizes, and think about provision of images for high-resolution screens.</li>
+</ul>
+
+<h2 id="Summary_of_screenreader_testing_on_Android_and_iOS">Summary of screenreader testing on Android and iOS</h2>
+
+<p>The most common mobile platforms have fully functional screenreaders. These function in much the same way as desktop screenreaders, except they are largely operated using touch gestures rather than key combinations.</p>
+
+<p>Let's look at the main two: TalkBack on Android and VoiceOver on iOS.</p>
+
+<h3 id="Android_TalkBack">Android TalkBack</h3>
+
+<p>The TalkBack screenreader is built into the Android operating system.</p>
+
+<p>To turn it on, select <em>Settings &gt; Accessibility &gt; TalkBack</em>, and then press the slider switch to turn it on. Follow any additional on-screen prompts that you are presented with.</p>
+
+<p><strong>Note:</strong> Older versions of TalkBack are turned on in <a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">slightly different ways</a>.</p>
+
+<p>When TalkBack is turned on, your Android device's basic controls will be a bit different. For example:</p>
+
+<ol>
+ <li>Single-tapping an app will select it, and the device will read out what the app is.</li>
+ <li>Swiping left and right will move between apps, or buttons/controls if you are in a control bar. The device will read out each option.</li>
+ <li>Double-tapping anywhere will open the app/select the option.</li>
+ <li>You can also "explore by touch" — hold your finger down on the screen and drag it around, and your device will read out the different apps/items you move across.</li>
+</ol>
+
+<p>If you want to turn TalkBack off:</p>
+
+<ol>
+ <li>Navigate to your <em>Settings</em> app using the above gestures.</li>
+ <li>Navigate to <em>Accessibility &gt; TalkBack</em>.</li>
+ <li>Navigate to the slider switch and activate it to turn it off.</li>
+</ol>
+
+<p><strong>Note:</strong> You can get to your homescreen at any time by swiping up and left in a smooth motion. If you have more than one homescreen, you can move between them by swiping two fingers left and right.</p>
+
+<p>For a more complete list of TalkBack gestures, see <a href="https://support.google.com/accessibility/android/answer/6151827">Use TalkBack gestures</a>.</p>
+
+<h4 id="Unlocking_the_phone">Unlocking the phone</h4>
+
+<p>When TalkBack is turned on, unlocking the phone is a bit different.</p>
+
+<p>You can do a two-finger swipe up from the bottom of the lock screen. If you've set a passcode or pattern for unlocking your device, you will then be taken to the relevant entry screen to enter it.</p>
+
+<p>You can also explore by touch to find the <em>Unlock</em> button at the bottom middle of the screen, and then double-tap.</p>
+
+<h4 id="Global_and_local_menus">Global and local menus</h4>
+
+<p>TalkBack allows you to access global and local context menus, wherever you have navigated to on the device. The former provides global options relating to the device as a whole, and the latter provides options relating just to the current app/screen you are in.</p>
+
+<p>To get to these menus:</p>
+
+<ol>
+ <li>Access the global menu by quickly swiping down, and then right.</li>
+ <li>Access the local menu by quickly swiping up, and then right.</li>
+ <li>Swipe left and right to cycle between the different options.</li>
+ <li>Once you've selected the option you want, double-click to choose that option.</li>
+</ol>
+
+<p>For details on all the options available under the global and local context menus, see <a href="https://support.google.com/accessibility/android/answer/6007066">Use global and local context menus</a>.</p>
+
+<h4 id="Browsing_web_pages">Browsing web pages</h4>
+
+<p>You can use the local context menu while in a web browser to find options to navigate web pages using just the headings, form controls, or links, or navigate line by line, etc.</p>
+
+<p>For example, with TalkBack turned on:</p>
+
+<ol>
+ <li>Open your web browser.</li>
+ <li>Activate the URL bar.</li>
+ <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL:
+ <ul>
+ <li>Select the URL bar by swiping left/right till you get to it, and then double-tapping.</li>
+ <li>Hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to type it. Repeat for each character.</li>
+ <li>Once you've finished, find the Enter key and press it.</li>
+ </ul>
+ </li>
+ <li>Swipe left and right to move between different items on the page.</li>
+ <li>Swipe up and right with a smooth motion to enter the local content menu.</li>
+ <li>Swipe right until you find the "Headings and Landmarks" option.</li>
+ <li>Double-tap to select it. Now you'll be able to swipe left and right to move between headings and ARIA landmarks.</li>
+ <li>To go back to the default mode, enter the local context menu again by swiping up and right, select "Default", and then double-tap to activate.</li>
+</ol>
+
+<p><strong>Note:</strong> See <a href="https://support.google.com/accessibility/android/answer/6283677?hl=en&amp;ref_topic=3529932">Get started on Android with TalkBack</a> for more complete documentation.</p>
+
+<h3 id="iOS_VoiceOver">iOS VoiceOver</h3>
+
+<p>A mobile version of VoiceOver is built into the iOS operating system.</p>
+
+<p>To turn it on, go to Your <em>Settings</em> app and select <em>General &gt; Accessibility &gt; VoiceOver</em>. Press the <em>VoiceOver</em> slider to enable it (you'll also see a number of other options related to VoiceOver on this page).</p>
+
+<p>Once VoiceOver is enabled, the iOS's basic control gestures will be a bit different:</p>
+
+<ol>
+ <li>A single tap will cause the item you tap on to be selected; your device will speak the item you've tapped on.</li>
+ <li>You can also navigate the items on the screen by swiping left and right to move between them, or by sliding your finger around on the screen to move between different items (when you find the item you want, you can remove your finger to select it).</li>
+ <li>To activate the selected item (e.g., open a selected app), double-tap anywhere on the screen.</li>
+ <li>Swipe with three fingers to scroll through a page.</li>
+ <li>Tap with two fingers to perform a context-relevant action — for example, taking a photo while in the camera app.</li>
+</ol>
+
+<p>To turn it off again, navigate back to <em>Settings &gt; General &gt; Accessibility &gt; VoiceOver</em> using the above gestures, and toggle the <em>VoiceOver</em> slider back to off.</p>
+
+<h4 id="Unlock_phone">Unlock phone</h4>
+
+<p>To unlock the phone, you need to press the home button (or swipe) as normal. If you have a passcode set, you can select each number by swiping/sliding (as explained above) and then double-tapping to enter each number when you've found the right one.</p>
+
+<h4 id="Using_the_Rotor">Using the Rotor</h4>
+
+<p>When VoiceOver is turned on, you have a navigation feature called the Rotor available to you, which allows you to quickly choose from a number of common useful options. To use it:</p>
+
+<ol>
+ <li>Twist two fingers around on the screen like you are turning a dial. Each option will be read aloud as you twist further around. You can go back and forth to cycle through the options.</li>
+ <li>Once you've found the option you want:
+ <ul>
+ <li>Release your fingers to select it.</li>
+ <li>If it is an option you can iterate the value of (such as Volume or Speaking Rate), you can do a swipe up or down to increase or decrease the value of the selected item.</li>
+ </ul>
+ </li>
+</ol>
+
+<p>The options available under the Rotor are context-sensitive — they will differ depending on what app or view you are in (see below for an example).</p>
+
+<h4 id="Browsing_web_pages_2">Browsing web pages</h4>
+
+<p>Let's have a go at web browsing with VoiceOver:</p>
+
+<ol>
+ <li>Open your web browser.</li>
+ <li>Activate the URL bar.</li>
+ <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL:
+ <ul>
+ <li>Select the URL bar by swiping left/right until you get to it, and then double-tapping.</li>
+ <li>For each character, hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to select it. Double-tap to type it.</li>
+ <li>Once you've finished, find the Enter key and press it.</li>
+ </ul>
+ </li>
+ <li>Swipe left and right to move between items on the page. You can double-tap an item to select it (e.g., follow a link).</li>
+ <li>By default, the selected Rotor option will be Speaking Rate; you can currently swipe up and down to increase or decrease the speaking rate.</li>
+ <li>Now turn two fingers around the screen like a dial to show the rotor and move between its options. Here are a few examples of the options available:
+ <ul>
+ <li><em>Speaking Rate</em>: Change the speaking rate.</li>
+ <li><em>Containers</em>: Move between different semantic containers on the page.</li>
+ <li><em>Headings</em>: Move between headings on the page.</li>
+ <li><em>Links</em>: Move between links on the page.</li>
+ <li><em>Form Controls</em>: Move between form controls on the page.</li>
+ <li><em>Language</em>: Move between different translations, if they are available.</li>
+ </ul>
+ </li>
+ <li>Select <em>Headings</em>. Now you'll be able to swipe up and down to move between headings on the page.</li>
+</ol>
+
+<p><strong>Note:</strong> For a more complete reference covering the VoiceOver gestures available and other hints on accessibility testing on iOS, see <a href="https://developer.apple.com/library/content/technotes/TestingAccessibilityOfiOSApps/TestAccessibilityonYourDevicewithVoiceOver/TestAccessibilityonYourDevicewithVoiceOver.html#//apple_ref/doc/uid/TP40012619-CH3">Test Accessibility on Your Device with VoiceOver</a>.</p>
+
+<h2 id="Control_mechanisms">Control mechanisms</h2>
+
+<p>In our CSS and JavaScript accessibility article, we looked at the idea of events that are specific to a certain type of control mechanism (see <a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#mouse-specific_events">Mouse-specific events</a>). To recap, these cause accessibility issues because other control mechanisms can't activate the associated functionality.</p>
+
+<p>As an example, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick">click</a> event is good in terms of accessibility — an associated event handler can be invoked by clicking the element the handler is set on, tabbing to it and pressing Enter/Return, or tapping it on a touchscreen device. Try our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-button-example.html">simple-button-example.html</a> example (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-button-example.html">see it running live</a>) to see what we mean.</p>
+
+<p>Alternatively, mouse-specific events such as <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmousedown">mousedown</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmouseup">mouseup</a> create problems — their event handlers cannot be invoked using non-mouse controls.</p>
+
+<p>If you try to control our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-box-drag.html">simple-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-box-drag.html">see example live</a>) example with keyboard or touch, you'll see the problem. This occurs because we are using code such as the following:</p>
+
+<pre>div.onmousedown = function() {
+ initialBoxX = div.offsetLeft;
+ initialBoxY = div.offsetTop;
+ movePanel();
+}
+
+document.onmouseup = stopMove;</pre>
+
+<p>To enable other forms of control, you need to use different, yet equivalent events — for example, touch events work on touchscreen devices:</p>
+
+<pre>div.ontouchstart = function(e) {
+ initialBoxX = div.offsetLeft;
+ initialBoxY = div.offsetTop;
+ positionHandler(e);
+ movePanel();
+}
+
+panel.ontouchend = stopMove;</pre>
+
+<p>We've provided a simple example that shows how to use the mouse and touch events together — see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/multi-control-box-drag.html">multi-control-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/multi-control-box-drag.html">see the example live</a> also).</p>
+
+<p><strong>Note:</strong> You can also see fully functional examples showing how to implement different control mechanisms at <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/Control_mechanisms">Implementing game control mechanisms</a>.</p>
+
+<h2 id="響應式設計">響應式設計</h2>
+
+<p><a href="https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Responsive">Responsive design</a> is the practice of making your layouts and other features of your apps dynamically change depending on factors such as screen size and resolution, so they are usable and accessible to users of different device types.</p>
+
+<p>In particular, the most common problems that need to be addressed for mobile are:</p>
+
+<ul>
+ <li>Suitability of layouts for mobile devices. A multi-column layout won't work as well on a narrow screen, for example, and the text size may need to be increased so it is legible. Such issues can be solved by creating a responsive layout using technologies such as <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries">media queries</a>, <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, and <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a>.</li>
+ <li>Conserving image sizes downloaded. In general, small screen devices won't need images that are as large as their desktop counterparts, and they are more likely to be on slow network connections. Therefore, it is wise to serve smaller images to narrow screen devices as appropriate. You can handle this using <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive image techniques</a>.</li>
+ <li>Thinking about high resolutions. Many mobile devices have high-resolution screens, and therefore need higher-resolution images so that the display can continue to look crisp and sharp. Again, you can serve images as appropriate using responsive image techniques. In addition, many image requirements can be fulfilled using the SVG vector images format, which is well-supported across browsers today. SVG has a small file size and will stay sharp regardless of whatever size is being displayed  (see <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the web</a> for more details).</li>
+</ul>
+
+<p><strong>Note:</strong> We won't provide a full discussion of responsive design techniques here, as they are covered in other places around MDN (see above links).</p>
+
+<h3 id="Specific_mobile_considerations">Specific mobile considerations</h3>
+
+<p>There are other important issues to consider when making sites more accessible on mobile. We have listed a couple here, but we will add more when we think of them.</p>
+
+<h4 id="Not_disabling_zoom">Not disabling zoom</h4>
+
+<p>Using <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, it is possible to disable zoom. Alwasy ensure resizing is enabled, and set the width to the device's width in the {{htmlelement("head")}}:</p>
+
+<pre><code>&lt;meta name="viewport" content="width=device-width; user-scalable=yes"&gt;</code></pre>
+
+<p>You should never set <code>user-scalable=no</code> if at all possible — many people rely on zoom to be able to see the content of your website, so taking this functionality away is a really bad idea. There are certain situations where zooming might break the UI; in such cases, if you feel that you absolutely need to disable zoom, you should provide some other kind of equivalent, such as a control for increasing the text size in a way that doesn't break your UI.</p>
+
+<h4 id="Keeping_menus_accessible">Keeping menus accessible</h4>
+
+<p>Because the screen is so much narrower on mobile devices, it is very common to use media queries and other technologies to make the navigation menu shrink down to a tiny icon at the top of the display — which can be pressed to reveal the menu only if it's needed — when the site is viewed on mobile. This is commonly represented by a "three horizontal lines" icon, and the design pattern is consequently known as a "hamburger menu".</p>
+
+<p>When implementing such a menu, you need to make sure that the control to reveal it is accessible by appropriate control mechanisms (normally touch for mobile), as discussed in {{anch("Control mechanisms")}} above, and that the rest of the page is moved out of the way or hidden in some way while the menu is being accessed, to avoid confusion with navigating it.</p>
+
+<p>Click here for a <a href="http://fritz-weisshart.de/meg_men/">good hamburger menu example</a>.</p>
+
+<h2 id="User_input">User input</h2>
+
+<p>On mobile devices, inputting data tends to be more annoying for users than the equivalent experience on desktop computers. It is more convenient to type text into form inputs using a desktop or laptop keyboard than a touchscreen virtual keyboard or a tiny mobile physical keyboard.</p>
+
+<p>For this reason, it is worth trying to minimize the amount of typing needed. As an example, instead of getting users to fill out their job title each time using a regular text input, you could instead offer a {{htmlelement("select")}} menu containing the most common options (which also helps with consistency in data entry), and offer an "Other" option that displays a text field to type any outliers into. You can see a simple example of this idea in action in <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/common-job-types.html">common-job-types.html</a> (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/common-job-types.html">common jobs example live</a>).</p>
+
+<p>It is also worth considering the use of HTML5 form input types such as date on mobile platforms as they handle them well — both Android and iOS, for example, display usable widgets that fit well with the device experience. See <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/html5-form-examples.html">html5-form-examples.html</a> for some examples (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/html5-form-examples.html">HTML5 form examples live</a>) — try loading these and manipulating them on mobile devices. For example:</p>
+
+<ul>
+ <li>Types <code>number</code>, <code>tel</code>, and <code>email</code> display suitable virtual keyboards for entering numbers/telephone numbers.</li>
+ <li>Types <code>time</code> and <code>date</code> display suitable pickers for selecting times and dates.</li>
+</ul>
+
+<p>If you want to provide a different solution for desktops, you could always serve different markup to your mobile devices using feature detection. See <a href="http://diveinto.html5doctor.com/detect.html#input-types">input types</a> for raw information on detecting different input types, and also check out our <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">feature detection article</a> for much more information.</p>
+
+<h2 id="總結">總結</h2>
+
+<p>In this article we have provided you with some details about common mobile accessibility-specific issues and how to overcome them. We also took you through usage of the most common screenreaders to aid you in accessibility testing.</p>
+
+<h2 id="延伸閱讀">延伸閱讀</h2>
+
+<ul>
+ <li><a href="https://www.smashingmagazine.com/guidelines-for-mobile-web-development/">Guidelines For Mobile Web Development</a> — A list of articles in <em>Smashing Magazine</em> covering different techniques for mobile web design.</li>
+ <li><a href="http://www.creativebloq.com/javascript/make-your-site-work-touch-devices-51411644">Make your site work on touch devices</a> — Useful article about using touch events to get interactions working on mobile devices.</li>
+</ul>
+
+<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div>
+
+<div>
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">What is accessibility?</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/Multimedia">Accessible multimedia</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/Mobile">Mobile accessibility</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/Accessibility_troubleshooting">Accessibility troubleshooting</a></li>
+</ul>
+</div>
+</div>
diff --git a/files/zh-tw/learn/accessibility/wai-aria_basics/index.html b/files/zh-tw/learn/accessibility/wai-aria_basics/index.html
new file mode 100644
index 0000000000..926505aa85
--- /dev/null
+++ b/files/zh-tw/learn/accessibility/wai-aria_basics/index.html
@@ -0,0 +1,421 @@
+---
+title: WAI-ARIA基礎
+slug: Learn/Accessibility/WAI-ARIA_basics
+translation_of: Learn/Accessibility/WAI-ARIA_basics
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}</div>
+
+<p class="summary">接續之前的文章,有時在涉及非語意HTML與動態 JavaScript更新的內容製作複雜的UI控制措施將是個難題。WAI-ARIA即是一個能藉由添加進一步的語意幫助處理這種問題的技術 ,讓瀏覽器與輔助科技可以辨識及用以讓使用者知道發生甚麼事情。這裡我們將展示如何以基本水準的運用來增進無障礙使用。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決條件:</th>
+ <td>基本電腦技能、基本瞭解HTML, CSS與JavaScript、瞭解本課程先前文章。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>能熟悉WAI-ARIA,以及在必要時如何用於提供有用的附加語意強化無障礙。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="甚麼是WAI-ARIA">甚麼是WAI-ARIA?</h2>
+
+<p>開始瞭解甚麼是WAI-ARIA,以及它可為我們做些甚麼。</p>
+
+<h3 id="一個全新問題集"><strong>一個全新問題集</strong></h3>
+
+<p>當網站應用程式開始更複雜與動態,新的無障礙特性與問題集就開始出現。</p>
+
+<p>例如,HTML5 導入許多語意的元素來定義一般頁面的特性({{htmlelement("nav")}}, {{htmlelement("footer")}}等) 在沒有這些可用之前,開發者僅簡單使用{{htmlelement("div")}}搭配IDs或classes,如&lt;div class="nav"&gt;,但這些是有問題的,因為沒有很簡單的方法可程式化地容易找到特定的頁面特性如主要導覽功能。</p>
+
+<p>起初的解決方案是在頁面的頂端添加一個或更多隱藏的連結去連結到導覽功能(或其他任何的功能),例如:</p>
+
+<pre class="brush: html">&lt;a href="#hidden" class="hidden"&gt;Skip to navigation&lt;/a&gt;</pre>
+
+<p>但這仍然不是非常精確,並且僅能使用於螢幕報讀器從頁面頂端閱讀下來的時候。</p>
+
+<p>如同另一個例子,應用程式開始具有複雜的控制措施如日期選取器提供選擇日期,內容滑塊提供選取內容值等。HTML5提供特定的輸入型態來呈現這些控制措施:</p>
+
+<pre class="brush: html">&lt;input type="date"&gt;
+&lt;input type="range"&gt;</pre>
+
+<p>這些在跨瀏覽器之間沒有全面性支援,而且也非常困難去為他們指定樣式,而使他們與網站設計整合時不是很好用。因此,開發者時常依賴JavaScript資源庫來產生這些一系列內嵌的控制措施 {{htmlelement("div")}}或具有classnames的表格元素,透過CSS指定樣式與使用JavaScript控制。</p>
+
+<p>這個的問題是視覺上可以運作,但螢幕報讀器則一點也無法理解它們是甚麼,以及它們的使用者僅被告知他們可以看到一堆沒有語意的元素來描述它們的含意。</p>
+
+<h3 id="進入WAI-ARIA">進入WAI-ARIA</h3>
+
+<p><a href="https://www.w3.org/TR/wai-aria-1.1/">WAI-ARIA</a> 是一個由W3C編撰的規格,定義一套額外的HTML屬性能用於元素上提供額外的語意及改善可及性,當元素缺乏這些條件時可適用。本規格定義三個主要的特點:</p>
+
+<ul>
+ <li><strong>Roles</strong> — 這些角色用以定義元素是甚麼或做甚麼事。在這些當中許多被稱為地標角色,大部分重複了HTML5結構化元素的語意值如<code>role="navigation"</code> ({{htmlelement("nav")}}) or <code>role="complementary"</code> ({{htmlelement("aside")}}), 但也有其他描述不同的頁面結構者,如<code>role="banner"</code>, <code>role="search"</code>, <code>role="tabgroup"</code>, <code>role="tab"</code>等常見於使用者介面中。</li>
+ <li><strong>Properties</strong> — 這些用以定義元素的屬性,可用來賦予元素額外的意義或語意。舉例,<code>aria-required="true"</code>指定一個表單輸入必須填寫才有效,而<code>aria-labelledby="label"</code>讓你可以在一個元素上置放一個ID,當該頁面上任何內容設定標籤後而引用它,頁面包含多個元素而不可能使用<code>&lt;label for="input"&gt;</code>。舉例,你可使用<code>aria-labelledby</code>指定一個鍵盤鍵描述包含在一個{{htmlelement("div")}}之中是多個表格儲存格的標籤,或者你可使用它做為圖片alt文字的替代方案 — 指定頁面上現有的資訊做為圖片的alt文字,而非將它重複放在<code>alt</code>屬性之內. 範例可參考<a href="/en-US/docs/Learn/Accessibility/HTML?document_saved=true#Text_alternatives">Text alternatives</a>。</li>
+ <li><strong>States</strong> — 定義目前元素狀態的特殊屬性,例如 <code>aria-disabled="true"</code>,是對螢幕報讀器指定表單輸入目前是停用的狀態。狀態不同於屬性,在於屬性在應用程序整個生命週期中不會改變,而狀態通常會透過 JavaScript程式化改變。</li>
+</ul>
+
+<p>有關WAI-ARIA屬性的重要觀點是他們不會影響網頁的任何內容,除了透過瀏覽器無障礙API揭露資訊之外(螢幕報讀器即從中獲得資訊)。儘管WAI-ARIA屬性對CSS選擇元素很有用,但不會影響網頁結構、DOM等。</p>
+
+<div class="note">
+<p><strong>注意:</strong>你可以在WAI-ARIA規格中找到所有ARIA的角色及其用法的很有用清單,請參見 <a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">Definition of Roles</a>連結以獲得更進一步的資訊。</p>
+
+<p>本規格也涵括所有屬性與狀態的清單,請參見 <a href="https://www.w3.org/TR/wai-aria-1.1/#state_prop_def">Definitions of States and Properties (all aria-* attributes)</a>連結以獲得更進一步的資訊。</p>
+</div>
+
+<h3 id="哪裡支援WAI-ARIA?">哪裡支援WAI-ARIA?</h3>
+
+<p>這不是一個容易回答的問題。要難找到一個決定性的資源來陳述何者是支援WAI-ARIA的特點以及在何處,因為:</p>
+
+<ol>
+ <li>在WAI-ARIA規格中有很多特點。</li>
+ <li>要考量作業系統、瀏覽器與螢幕報讀器的許多組合。</li>
+</ol>
+
+<p>最後一點是關鍵—首先要使用螢幕報讀器,你的作業系統必須執行具有必要的無障礙API的瀏覽器去揭露螢幕報讀器必須去完成工作的資訊。大部分主流的作業系統有1個或2個瀏覽器可供螢幕報讀器使用。Paciello Group一則最近的文章提供這些數據—請參見 <a href="https://www.paciellogroup.com/blog/2014/10/rough-guide-browsers-operating-systems-and-screen-reader-support-updated/">Rough Guide: browsers, operating systems and screen reader support updated</a>。</p>
+
+<p>接著,你必須擔心瀏覽器是否支援ARIA特徵並透過其API揭露,同時螢幕報讀器是否辨識該資訊並以可用的方式向使用者呈現的問題。</p>
+
+<ol>
+ <li>瀏覽器支援一般相當好—在撰文當下, <a href="http://caniuse.com/#feat=wai-aria">caniuse.com</a>表示全球瀏覽器對WAI-ARIA的支援率大約為88%。</li>
+ <li>螢幕報讀器對ARIA特徵的支援沒有相當於此水平,但大部分主流的螢幕報讀器是有達到此水平。你可查閱Powermapper的 <a href="http://www.powermapper.com/tests/screen-readers/aria/">WAI-ARIA Screen reader compatibility</a>這篇文章了解支援的水平。</li>
+</ol>
+
+<p>在本文中,我們未試圖涵蓋每一個WAI-ARIA特徵及其確切的支援細節。相反地,我們將涵蓋最關鍵的WAI-ARIA特徵讓你知道;如果我們沒有提到任何支援細節,你可認定該特徵得到很好的支援。我們會明確地提到這個例外情況。</p>
+
+<div class="note">
+<p><strong>注意</strong>:某些JavaScript儲存庫支援WAI-ARIA,亦即當他們產生UI特徵如複雜的表單控制措施,他們添加ARIA屬性來增進這些特徵的無障礙。如果你在尋找第三方的JavaScript解決方案來快速的開發UI,你應該謹慎地考量其UI插件的無障礙作為你決定使用的重要因素。jQuery UI(參見<a href="https://jqueryui.com/about/#deep-accessibility-support">About jQuery UI: Deep accessibility support</a>)、 <a href="https://www.sencha.com/products/extjs/">ExtJS</a>與 <a href="https://dojotoolkit.org/reference-guide/1.10/dijit/a11y/statement.html">Dojo/Dijit</a>是良好範例。</p>
+</div>
+
+<h3 id="何時應該使用WAI-ARIA"><strong>何時應該使用WAI-ARIA?</strong></h3>
+
+<p>我們討論了促使WAI-ARIA早期建立的一些問題,但基本上WAI-ARIA在4個主要領域很有用:</p>
+
+<ol>
+ <li><strong>路標/地標:</strong>ARIA的角色屬性值可作為地標,不是複製HTML5元素的語意(如{{htmlelement("nav")}}),就是超越HTML5語意而對不同的功能區域提供路標,如搜尋、頁籤群組、頁籤、清單框等。</li>
+ <li><strong>動態內容更新:</strong>螢幕報讀器往往難以報讀不斷改變的內容;當某個內容區域更新時,我們可以使用aria-live通知螢幕報讀器的使用者,例如透過 <a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>或<a href="/en-US/docs/Web/API/Document_Object_Model">DOM APIs</a>。</li>
+ <li><strong>增強鍵盤無障礙</strong>:內建的HTML元素具有原生的鍵盤無障礙;當其他元素伴隨使用JavaScript模擬相似的互動時,鍵盤無障礙操作與螢幕報讀器報讀會遭遇問題。如果這是不可避免的,WAI-ARIA提供讓其他元素獲得焦點的一種方法(使用 <code>tabindex</code>)。</li>
+ <li><strong>非語意控制措施的無障礙</strong>:當一系列巢狀的<code>&lt;div&gt;</code>搭配CSS/JavaScript用於創建一個複雜的UI特徵,或者一個透過JavaScript大幅增強/改變的原生控制措施,無障礙會遭遇到困難—如果沒有語意或其他線索,螢幕報讀器使用者將發覺難以理解該特徵的作用。在這種情況下,ARIA可以幫助提供缺失的部分使用如按鈕、清單框或頁籤群組等角色組合,以及aria-required 或aria-posinset等屬性對功能性提供進一步的線索。</li>
+</ol>
+
+<p>記住一件事 — <strong>僅在必需時才使用WAI-ARIA! </strong>理想情況下,你應該總是使用<a>原生HTML特徵</a>提供螢幕報讀器所需要的語意來告訴其使用者接下來將發生甚麼事情。有時候這是不可能的情形,不是因為你受限於控制該程式碼,就是因為你創建一些複雜而無法用簡易的HTML元素來開發。在這種情況下,WAI-ARIA可作為有價值的無障礙增強工作。</p>
+
+<p>再說一次,只有需要的時候才使用它!</p>
+
+<div class="note">
+<p><strong>注意</strong>: 請確保有各類實際的使用者來測試你的網站 — 非身障者、使用螢幕報讀器者、使用鍵盤導覽者等。他們將比你更能了解它運作的效果。</p>
+</div>
+
+<h2 id="實作WAI-ARIA開發">實作WAI-ARIA開發</h2>
+
+<p>在下一個章節我們將更仔細地看看這4個領域,並附帶實際的範例。在繼續之前,你應該將備妥螢幕報讀器測試設置,以便在過程中你可以測試這些範例。</p>
+
+<p>更多資訊請參見<a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">螢幕報讀器測試</a>章節。</p>
+
+<h3 id="路標地標"><strong>路標/地標</strong></h3>
+
+<p>WAI-ARIA添加<a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">角色屬性</a>給瀏覽器,讓你可以在必要時添加額外的語意值到你網站上的元素。這第一個主要的領域在為螢幕報讀器提供資訊方面非常有用,讓螢幕報讀器的使用者可以找到常見的頁面元素。我們來看個範例 — <a href="https://github.com/mdn/learning-area/tree/master/accessibility/aria/website-no-roles">網站-無-角色</a>範例(<a href="http://mdn.github.io/learning-area/accessibility/aria/website-no-roles/">看實際頁面</a>)有以下的結構:</p>
+
+<pre class="brush: html">&lt;header&gt;
+ &lt;h1&gt;...&lt;/h1&gt;
+ &lt;nav&gt;
+ &lt;ul&gt;...&lt;/ul&gt;
+ &lt;form&gt;
+ &lt;!-- search form --&gt;
+ &lt;/form&gt;
+ &lt;/nav&gt;
+&lt;/header&gt;
+
+&lt;main&gt;
+ &lt;article&gt;...&lt;/article&gt;
+ &lt;aside&gt;...&lt;/aside&gt;
+&lt;/main&gt;
+
+&lt;footer&gt;...&lt;/footer&gt;</pre>
+
+<p>若你嘗試在現代瀏覽器中使用螢幕報讀器來測試此範例,你將可以獲得一些有用的資訊。例如,VoiceOver給你以下的資訊:</p>
+
+<ul>
+ <li>在 <code>&lt;header&gt;</code> 元素上— "橫幅,2個項目"(含有一個標題與 <code>&lt;nav&gt;</code>)。</li>
+ <li>在 <code>&lt;nav&gt;</code> 元素上—"導航列 2個項目" (含有一個清單與一個表單)。</li>
+ <li>在 <code>&lt;main&gt;</code> 元素上—"主要內容 2個項目" (含有一則文章與一個附帶內容)。</li>
+ <li>在<code>&lt;aside&gt;</code> 元素上—"補充 2個項目" (含有一個標題與一個清單)。</li>
+ <li>在搜尋表單輸入—"搜尋查詢,插入文字開始處"。</li>
+ <li>在<code>&lt;footer&gt;</code> 元素上—"頁尾1個項目"。</li>
+</ul>
+
+<p>如果你到VoiceOver地標選單(使用VoiceOver主鍵+ U,然後使用游標鍵循環整個選單選項),你會看到大部分元素被列的很好,因此可以很快地訪問他們。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14420/landmarks-list.png" style="display: block; margin: 0 auto;"></p>
+
+<p>然而,這裡我們可以做得更好,搜尋表單是一個人們想要找到的很重要的地標,但是它並沒有列在地標選項之中或者被視為顯著的地標,除了在實際輸入而被召喚作為搜尋輸入之外(<code>&lt;input type="search"&gt;</code>)。另外,有些舊的瀏覽器(大部分是指IE8)無法辨識HTML5元素的語意。</p>
+
+<p>讓我們使用一些ARIA特徵來改善它。首先,我們將添加一些角色屬性到我們的HTML結構。你可以試著複製我們原始的檔案(參見<a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/website-no-roles/index.html">index.html</a>與<a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/website-no-roles/style.css">style.css</a>),或者瀏覽我們的<a href="https://github.com/mdn/learning-area/tree/master/accessibility/aria/website-aria-roles">網站-aria-角色</a>範例(<a href="http://mdn.github.io/learning-area/accessibility/aria/website-aria-roles/">看實際頁面</a>),其結構如下:</p>
+
+<pre class="brush: html">&lt;header&gt;
+ &lt;h1&gt;...&lt;/h1&gt;
+ &lt;nav role="navigation"&gt;
+ &lt;ul&gt;...&lt;/ul&gt;
+ &lt;form role="search"&gt;
+ &lt;!-- search form --&gt;
+ &lt;/form&gt;
+ &lt;/nav&gt;
+&lt;/header&gt;
+
+&lt;main&gt;
+ &lt;article role="article"&gt;...&lt;/article&gt;
+ &lt;aside role="complementary"&gt;...&lt;/aside&gt;
+&lt;/main&gt;
+
+&lt;footer&gt;...&lt;/footer&gt;</pre>
+
+<p>在本範例中我們也將給你一個額外的特徵—{{htmlelement("input")}} 元素賦予 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-label">aria-label</a></code>屬性,藉由給予描述性的標籤讓螢幕報讀器可以報讀出來,即使我們沒有包含{{htmlelement("label")}}元素。像這種情況就非常有用—搜尋表單是一個非常常見、容易辨識的特徵,而添加視覺的標籤可能破壞頁面的設計。</p>
+
+<pre class="brush: html">&lt;input type="search" name="q" placeholder="Search query" aria-label="Search through site content"&gt;</pre>
+
+<p>現在如果我們使用VoiceOver來看這個範例,我們可以獲得一些改善:</p>
+
+<ul>
+ <li>召喚搜尋表單當作獨立的項目,無論是在瀏覽頁面,或在地標選項之中。</li>
+ <li>當表單輸入凸顯時,將報讀出包含在<code>aria-label</code>屬性的標籤文字。</li>
+</ul>
+
+<p>除此之外,該網站對舊瀏覽器如IE8的使用者更可能無障礙;為了這個目的,包含ARIA角色是值得的。如果為了某些原因,你的網站僅使用 <code>&lt;div&gt;</code>建置,那麼肯定你應該包含ARIA角色來提供這些非常需要的語意!</p>
+
+<p>當ARIA超越從HTML5所能獲得的語意時,搜尋表單的改進語意已經顯示實現的可能性。你將會在下面看到更多關於這些語意與ARIA屬性的能力,尤其在{{anch("Accessibility of non-semantic controls")}}章節。現在,我們先來看看ARIA如何幫助動態內容更新。</p>
+
+<h3 id="動態內容更新">動態內容更新</h3>
+
+<p>從文本內容到附著於圖片的替代文字,其內容載入至DOM中可方便螢幕報讀器使用。因此,大部分使用文字內容的傳統靜態網站能輕易讓視覺障礙者無障礙使用。</p>
+
+<p>問題在於現代網頁應用程式通常不只是靜態的文字—他們傾向有很多動態更新的內容,例如透過像<a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>, <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a>, 或<a href="/en-US/docs/Web/API/Document_Object_Model">DOM APIs</a>等機制更新的內容而不必重新載入全部的頁面。這些有時稱為即時區塊。</p>
+
+<p>我們來看一個簡單的範例—請看 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-no-live.html">aria-no-live.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/aria/aria-no-live.html">看實際頁面</a>)。本範例中我們有簡單的隨機引言框:</p>
+
+<pre class="brush: html">&lt;section&gt;
+ &lt;h1&gt;Random quote&lt;/h1&gt;
+ &lt;blockquote&gt;
+ &lt;p&gt;&lt;/p&gt;
+ &lt;/blockquote&gt;
+&lt;/section&gt;</pre>
+
+<p>我們的JavaScript透過含有一系列的隨機引言與其作者的 <code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> <code>載入一個</code>JSON檔案。一旦這些完成,我們就開始 <code><a href="/en-US/docs/Web/API/WindowTimers/setInterval">setInterval()</a></code> 迴圈每10秒載入新的隨機引言到引言框之中。</p>
+
+<pre class="brush: js">var intervalID = window.setInterval(showQuote, 10000);</pre>
+
+<p>這個運作正常,但對無障礙不是很好—此內容更新無法被螢幕報讀器所偵測,所以他們的使用者不知道發生甚麼事情。這是一個相當平凡的例子,但只要想像一下如果你正在創建一個有著大量不斷更新內容的複雜UI,如聊天室、一個策略型的遊戲UI、或者一個即時更新的購物車顯示窗—則將不可能以任何有效的方式使用該應用程式而沒有某種提醒使用者該更新內容的方法。</p>
+
+<p>很幸運地WAI-ARIA提供一項有用的機制來提供這些警告—即<code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-live">aria-live</a></code> 屬性。將此屬性用在元素上可讓螢幕報讀器讀出更新的內容。報讀內容的緊急性決定於以下屬性值:</p>
+
+<ul>
+ <li><code>off:</code> 預設值,更新不應該通知。</li>
+ <li><code>polite</code>: 更新應該只在使用者空閒時才通知。</li>
+ <li><code>assertive</code>: 更新應盡快通知使用者。</li>
+ <li><code>rude</code>: 更新應立即通知,即使打斷使用者。</li>
+</ul>
+
+<p>一般而言, <code>assertive</code> 設置足以讓你的更新內容在他們出現時依序地讀出,因此如果同時有多個事件改變,你將獲得所有的更新。只有對非常高優先順序的更新使用  <code>rude</code> 才能覆蓋其他所有的更新。</p>
+
+<p>我們希望你複製 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-no-live.html">aria-no-live.html</a> 與 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/quotes.json">quotes.json</a>,並更新 <code>&lt;section&gt;</code> 標籤如下所示:</p>
+
+<pre class="brush: html">&lt;section aria-live="assertive"&gt;</pre>
+
+<p>這將使螢幕報讀器在內容更新時讀出更新的內容。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 如果你嘗試從 <code>XMLHttpRequest</code> 執行 <code>file://</code> URL<code>,</code>大部分的瀏覽器會拋出安全異常,例如你直接上傳該檔案到瀏覽器(透過雙擊滑鼠鍵等)。為了這項可以執行,你需要將檔案上傳到一個網站伺服器如<a href="/en-US/docs/Learn/Common_questions/Using_Github_pages"> GitHub</a>,或本機網站伺服器如 <a href="http://www.pythonforbeginners.com/modules-in-python/how-to-use-simplehttpserver/">Python's SimpleHTTPServer</a>。</p>
+</div>
+
+<p>這裡有一項額外的考量—只有文字更新才讀出。如果我們也總是讀出標題,那將很好,以讓使用者記住讀出的內容。為做到這樣,我們可以添加 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-atomic">aria-atomic</a></code> 屬性到這個部分,再次更新您的 <code>&lt;section&gt;</code> 標籤如下所示:</p>
+
+<pre class="brush: html">&lt;section aria-live="assertive" aria-atomic="true"&gt;</pre>
+
+<p><code>aria-atomic="true"</code>屬性告訴螢幕報讀器以一個原子單位方式讀出完整的元素內容,而不僅只讀出更新的部分。</p>
+
+<div class="note">
+<p><strong>注意</strong>:你可以查看完成的範例 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-live.html">aria-live.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/aria/aria-live.html">看實際頁面</a>)。</p>
+</div>
+
+<div class="note">
+<p><strong>注意</strong>: <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-relevant">aria-relevant</a></code> 屬性在即時區塊更新時對於控制讀出甚麼內容也相當有用,例如你可以僅獲得讀出新增或移除的內容。</p>
+</div>
+
+<h3 id="增強鍵盤無障礙"><strong>增強鍵盤無障礙</strong></h3>
+
+<p>如同在本模組其他章節所討論, HTML關於無障礙的關鍵優勢之一是內建鍵盤無障礙特徵如按鈕、表單控制措施及連結。一般而言,你可以使用tab鍵在控制措施之間移動,輸入(Enter)/返回(Return)鍵用來選擇或觸發控制措施,以及偶爾需要其他的控制措施(例如上下游標在 <code>&lt;select&gt;</code> 框中的選項間移動)。</p>
+
+<p>然而,有時你最終必須撰寫不是使用非語意的元素如按鈕(或其他控制的型態),或者使用可獲焦點的控制措施用作非正確目的程式碼。你可能嘗試修正一些繼承來的不好的程式碼,或者你可能創建需要某些種類的複雜插件。</p>
+
+<p>讓非焦點的程式碼可獲得焦點,WAI-ARIA使用一些新值擴展 <code>tabindex</code> 屬性:</p>
+
+<ul>
+ <li><code>tabindex="0"</code> —如上述,此值允許正常不被tab遊走到的元素變得可以tab遊走,這是<code>tabindex</code>最有用的值。</li>
+ <li><code>tabindex="-1"</code> — 此允許正常不被tab遊走到的元素,可以程式化地獲得焦點,如透過JavaScript或作為連結的對象。</li>
+</ul>
+
+<p>我們更詳細討論這一點並在我們的HTML無障礙文章中展示典型的實作—請參見 <a href="/en-US/docs/Learn/Accessibility/HTML#Building_keyboard_accessibility_back_in">Building keyboard accessibility back in</a>.</p>
+
+<h3 id="非語意控制措施的無障礙">非語意控制措施的無障礙</h3>
+
+<p>本部份接續前一章節—當一系列巢狀的 <code>&lt;div&gt;</code>搭配CSS/JavaScript用於創建一個複雜的UI特徵,或者一個透過JavaScript大幅增強/改變的原生控制措施,不僅鍵盤無障礙會遭遇到困難,而且如果沒有語意或其他線索,螢幕報讀器使用者也會發覺難以理解該特徵的作用。在這種情況下,ARIA可以幫助提供缺失的語意。</p>
+
+<h4 id="表單驗證與錯誤警告">表單驗證與錯誤警告</h4>
+
+<p>首先,讓我們再看一次在我們的CSS與JavaScript無障礙文章中第一次看的表單範例(請閱讀 <a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#Keeping_it_unobtrusive">Keeping it unobtrusive</a>完整回顧)。在本章節文末我們展示當你試著送出表單而驗證錯誤時,出現我們包含一些在錯誤訊息框的ARIA屬性。</p>
+
+<pre class="brush: html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>div</span> <span class="attr-name token">class</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>errors<span class="punctuation token">"</span></span> <span class="attr-name token">role</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>alert<span class="punctuation token">"</span></span> <span class="attr-name token">aria-relevant</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>all<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span>
+ <span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>ul</span><span class="punctuation token">&gt;</span></span>
+ <span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>ul</span><span class="punctuation token">&gt;</span></span>
+<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>div</span><span class="punctuation token">&gt;</span></span></code></pre>
+
+<ul>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#alert">role="alert"</a></code> 自動地將其應用的該元素轉換為即時區塊,以利讀出它的改變;它也將語意地辨識其為警告訊息(重要時間/內容脈絡敏感資訊),而呈現以更好、更無障礙的方式向使用者傳遞警告(模態對話框如 <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 具有許多無障礙的問題;請參見WebAIM的 <a href="http://webaim.org/techniques/javascript/other#popups">Popup Windows</a>)。</li>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-relevant">aria-relevant</a></code> 的all值指示螢幕報讀器當它任何改變時讀出錯誤清單的內容—例如當錯誤新增或移除時。這個很有用因為使用者會想知道留著的錯誤是甚麼,而不只有知道清單中甚麼是已經新增或移除。</li>
+</ul>
+
+<p>我們可進一步使用我們的ARIA,並提供更多的驗證協助。如何指出區塊是否需要在第一個位置,以及年齡的範圍應該多少?</p>
+
+<ol>
+ <li>在此,複製我們的 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/form-validation.html">form-validation.html</a> 與 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/validation.js">validation.js</a> 檔案,並將他們儲存在本機目錄。</li>
+ <li>在文字編輯器開啟他們並且看一下該程式碼如何運作。</li>
+ <li>首先,在開始的 <code>&lt;form&gt;</code> 標籤之上增加一個段落,如下所示,並且用星號標記兩個表單的 <code>&lt;label&gt;</code>。這是一般我們對有視力的使用者標記必要區塊的方法。
+ <pre class="brush: html">&lt;p&gt;Fields marked with an asterisk (*) are required.&lt;/p&gt;</pre>
+ </li>
+ <li>這讓視覺有意義,但這對螢幕報讀器使用者不能輕易理解。很幸運地,WAI-ARIA提供 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-required">aria-required</a></code> 屬性以提示螢幕報讀器應告訴使用者需要填寫的表單輸入欄位。更新<code>&lt;input&gt;</code> 元素如下:
+ <pre class="brush: html">&lt;input type="text" name="name" id="name" aria-required="true"&gt;
+
+&lt;input type="number" name="age" id="age" aria-required="true"&gt;</pre>
+ </li>
+ <li>如果你現在儲存本範例並使用螢幕報讀器測試,你應該聽到這個內容 "Enter your name star, required, edit text"。</li>
+ <li>如果我們給予螢幕報讀器使用者與視覺的使用者有關年齡的值應該是甚麼的概念,這樣也將會很有用。這個或許常以提示或在表單輸入區內預設文本的方式呈現。WAI-ARIA用包含 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-valuemin">aria-valuemin</a></code> 與 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-valuemax">aria-valuemax</a></code> 屬性來指定最小與最大值,但這些目前未受到很好的支持;比較受支持的特徵是 HTML5 <code>placeholder</code> 屬性,它在沒有輸入值的時間將含有的訊息顯示在輸入框,並能由許多螢幕報讀器讀出。更新你的數值輸入如下所示:
+ <pre class="brush: html">&lt;input type="number" name="age" id="age" placeholder="Enter 1 to 150" aria-required="true"&gt;</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>注意</strong>:你可以查看完成的範例 <a href="http://mdn.github.io/learning-area/accessibility/aria/form-validation-updated.html">form-validation-updated.html</a>。</p>
+</div>
+
+<p>除了傳統的 {{htmlelement("label")}} 元素之外,WAI-ARIA也能賦予一些進階的表單標籤技術。我們已經談論過使用 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-label">aria-label</a></code> 屬性在我們不希望標籤讓有視覺的使用者看見的地方來提供標籤(參見上述 {{anch("Signposts/Landmarks")}} 章節。如果你想要指定一個非<code>&lt;label&gt;</code> 元素當作標籤或具有相同標籤多重的表單輸入標籤,這裡有使用其他屬性如 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby">aria-labelledby</a></code> 的其他標籤技術,如果你想要其他的訊息與表單輸入關聯並且報讀出來,使用 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-describedby">aria-describedby</a></code>。更多細節請參見 <a href="http://webaim.org/techniques/forms/advanced">WebAIM's Advanced Form Labeling article</a><span class="subtitle"> 。</span></p>
+
+<p>還有許多其他有用的屬性與狀態,用來指出表單元素的狀態。例如,<span class="subtitle"> <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-disabled">aria-disabled</a>="true"</code> </span>可用於指出表單區域是處於停用的狀態。許多瀏覽器只會跳過停用的表單區塊,並且甚至不會被螢幕報讀器讀出,但在某些情況下,他們可被感知,所以最好包含此屬性讓螢幕報讀器知道停用的輸入事實上即是停用的狀態。</p>
+
+<p>如果輸入的停用狀態可能產生改變,也最好在發生時指出,以及其結果為何。例如,在我們的<span class="subtitle"> <a href="http://mdn.github.io/learning-area/accessibility/aria/form-validation-checkbox-disabled.html">form-validation-checkbox-disabled.html</a> </span>展示中,當核取框被核取時,可以讓另一個表單輸入允許輸入更進一步的資訊。我們已經設置一個隱藏的即時區塊:</p>
+
+<pre class="brush: html">&lt;p class="hidden-alert" aria-live="assertive"&gt;&lt;/p&gt;</pre>
+
+<p>這是使用絕對位置從視窗中隱藏。當核取/未核取時,我們更新在隱藏的即時區塊中的文字,告訴螢幕報讀器使用者選取這個核取框時結果會是甚麼,以及更新 <code>aria-disabled</code> 的狀態,連同一些視覺的指示:</p>
+
+<pre class="brush: js">function toggleMusician(bool) {
+ var instruItem = formItems[formItems.length-1];
+ if(bool) {
+ instruItem.input.disabled = false;
+ instruItem.label.style.color = '#000';
+ instruItem.input.setAttribute('aria-disabled', 'false');
+ hiddenAlert.textContent = 'Instruments played field now enabled; use it to tell us what you play.';
+ } else {
+ instruItem.input.disabled = true;
+ instruItem.label.style.color = '#999';
+ instruItem.input.setAttribute('aria-disabled', 'true');
+ instruItem.input.removeAttribute('aria-label');
+ hiddenAlert.textContent = 'Instruments played field now disabled.';
+ }
+}</pre>
+
+<h4 id="描述非語意按鈕為按鈕">描述非語意按鈕為按鈕</h4>
+
+<p>本課程我們已經談過幾次按鈕、連結或表單元素(參見HTML無障礙文章的 <a href="/en-US/docs/Learn/Accessibility/HTML#UI_controls">UI controls</a> ,以及前述{{anch("Enhancing keyboard accessibility")}}的原生無障礙(以及在使用其他元素偽造背後的無障礙議題)。基本上,使用 <code>tabindex</code> 與一些 JavaScript,在很多情況下,你可以在沒有太多困難下增加鍵盤無障礙支援功能。</p>
+
+<p>但螢幕報讀器的情況如何呢?他們仍然無法將這些元素視為按鈕。如果我們用螢幕報讀器測試我們的 <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a> 範例,我們偽造的按鈕將會用句子如 "Click me!, group"讀出,很顯然地令人困惑。</p>
+
+<p>我們可以使用WAI-ARIA角色來修正它。請複製 <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a>在本機,並且對每個按鈕<code>&lt;div&gt;</code>增加  <code><a href="https://www.w3.org/TR/wai-aria-1.1/#button">role="button"</a></code> ,範例如下:</p>
+
+<pre>&lt;div data-message="This is from the first button" tabindex="0" role="button"&gt;Click me!&lt;/div&gt;</pre>
+
+<p>現在當你使用螢幕報讀器測試它時,按鈕將會用句子如"Click me!, button" 讀出—這樣好多了。</p>
+
+<div class="note">
+<p>注意:記住最好盡可能使用正確的語意元素,如果你希望創建一個按鈕,並且可使用 {{htmlelement("button")}} 元素,就應該使用 {{htmlelement("button")}} 元素!</p>
+</div>
+
+<h4 id="透過複雜的插件引導使用者">透過複雜的插件引導使用者</h4>
+
+<p>除了標準HTML可用外,還有一堆其他<a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">角色</a>可以辨識非語意的元素結構作為一般的使用者介面特徵,例如 <code><a href="https://www.w3.org/TR/wai-aria-1.1/#combobox">combobox</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#slider">slider</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tabpanel">tabpanel</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tree">tree</a></code>。你可在 <a href="https://dequeuniversity.com/library/">Deque university code library</a>中找到很多有用的範例,可給你這些控制措施如何做到無障礙的想法。</p>
+
+<p>我們來看看我們自己的範例,我們回到我們簡單的絕對位置頁籤的介面(參見在我們的CSS與JavaScript無障礙文章中的 <a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#Hiding_things">Hiding things</a> ),你可以找到 <a href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/info-box.html">頁籤資訊框範例</a>(看<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box.html">原始碼</a>).</p>
+
+<p>本範例以鍵盤無障礙而言運作正常—你可以開心地在不同的頁籤間跳位,並且選擇他們顯示該頁籤的內容,也相當地容易操作—你可以滾動內容並使用標題來導覽,即使你看不到螢幕上正發生的事情。然而內容是甚麼並非很明顯—螢幕報讀器目前以連結的清單報讀內容,以及有三個標題的內容。這樣無法給你了解內容之間的關係。最好給予使用者更多關於內容結構的線索。</p>
+
+<p>為改善這些,我們創建新的範例版本為 <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-tabbed-info-box.html">aria-tabbed-info-box.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/aria/aria-tabbed-info-box.html">看實際頁面</a>),我們已經更新頁籤介面的結構如下:</p>
+
+<pre class="brush: html">&lt;ul role="tablist"&gt;
+  &lt;li class="active" role="tab" aria-selected="true" aria-setsize="3" aria-posinset="1" tabindex="0"&gt;Tab 1&lt;/li&gt;
+  &lt;li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="2" tabindex="0"&gt;Tab 2&lt;/li&gt;
+  &lt;li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="3" tabindex="0"&gt;Tab 3&lt;/li&gt;
+&lt;/ul&gt;
+&lt;div class="panels"&gt;
+ &lt;article class="active-panel" role="tabpanel" aria-hidden="false"&gt;
+ ...
+ &lt;/article&gt;
+ &lt;article role="tabpanel" aria-hidden="true"&gt;
+ ...
+ &lt;/article&gt;
+ &lt;article role="tabpanel" aria-hidden="true"&gt;
+ ...
+ &lt;/article&gt;
+&lt;/div&gt;</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 這裡最引人注目的是我們移除在原來範例中的連結,並且只使用清單項目作為頁籤—這樣做是因為對螢幕報讀器使用者比較少困擾(連結並非真正地帶妳到哪個地方;他們只是改變視窗),並且可讓組件大小/位置在組件特徵中有很好的運作—當這些是放在連結上的時候,瀏覽器將維持報讀"1 of 1",而非"1 of 3"、"2 of 3"等。</p>
+</div>
+
+<p>新的特徵如下:</p>
+
+<ul>
+ <li>新的角色— <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tablist">tablist</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tab">tab</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tabpanel">tabpanel</a></code> — 這些確認頁籤介面的重要區域—頁籤的容器、頁籤本身,以及相對應的頁籤控制盤。</li>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-selected">aria-selected</a></code> — 定義目前被選取的是哪一個頁籤。當不同的頁籤被使用者選取時,本屬性在不同頁籤的值透過JavaScript更新。</li>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-hidden">aria-hidden</a></code> — 隱藏元素不讓螢幕報讀器讀出來。當不同的頁籤被使用者選取時,本屬性在不同頁籤的值透過JavaScript更新。</li>
+ <li><code>tabindex="0"</code> — 由於我們已經移除連結,我們需要給予清單項目本屬性,提供鍵盤焦點。</li>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-setsize">aria-setsize</a></code> — T本屬性允許你向螢幕報讀器指定某元素是一系列中的部分,以及該系列有多少項目。</li>
+ <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-posinset">aria-posinset</a></code> — 本屬性允許你指定某個元素在一系列中的位置,伴隨 <code>aria-setsize,</code>提供螢幕報讀器有足夠資訊來告訴你目前的位置在"1 of 3"項目等。在許多情況下,瀏覽器應該可從元素層級結構推測這項資訊,但它肯定有助於提供更多的線索。</li>
+</ul>
+
+<p>在我們的測試中,這些新的結構確實提供整體的改善。頁籤現在被認定為頁籤(如螢幕報讀器讀出"索引標籤"),被選取的頁籤以”已選取”指出並讀出頁籤的名稱,螢幕報讀器也告訴你目前所在的頁籤數目。此外,因為設置 <code>aria-hidden</code> (只有非隱藏的頁籤才設定<code>aria-hidden="false"</code> ),非隱藏的頁籤是唯一你可以向下導覽的內容,意即所選取的內容很容易找到。</p>
+
+<div class="note">
+<p>注意:如果有任何你很明確地不希望螢幕報讀器讀出的內容,你可賦予它們 <code>aria-hidden="true"</code> 屬性。</p>
+</div>
+
+<h2 id="總結">總結</h2>
+
+<p>本文並未涵蓋所有WAI-ARIA的內容,但應該給予你足夠的資訊來了解如何使用它,以及了解一些你會遇到而需要它的最常見型態。</p>
+
+<h2 id="相關參考資訊">相關參考資訊</h2>
+
+<ul>
+ <li><a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">Definition of Roles</a> — ARIA角色參考資訊。</li>
+ <li><a href="https://www.w3.org/TR/wai-aria-1.1/#state_prop_def">Definitions of States and Properties (all aria-* attributes)</a> — 屬性與狀態參考資訊。</li>
+ <li><a href="https://dequeuniversity.com/library/">Deque university code library</a> — 實用的範例資源庫,展示使用WAI-ARIA特徵讓複雜的UI控制措施無障礙</li>
+ <li><a href="http://w3c.github.io/aria-practices/">WAI-ARIA Authoring Practices</a> — 由W3C發佈之非常詳細的設計模型,解釋如何使用WAI-ARIA特徵實作不同類型的複雜UI控制措施無障礙</li>
+ <li><a href="https://www.w3.org/TR/html-aria/">ARIA in HTML</a> — W3C標準針對每一個HTML特徵定義由瀏覽器設置隱含特徵的無障礙(ARIA)語意,以及如果需要額外的語意,你可以設置的WAI-ARIA特徵。</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}</p>
+
+<p> </p>
+
+<h2 id="本模組章節">本模組章節</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">何謂無障礙網頁?</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/HTML">HTML: 無障礙網頁的好開始</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript">充分實踐CSS與JavaScript的無障礙</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA基礎</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/Multimedia">無障礙多媒體</a></li>
+ <li><a href="/en-US/docs/Learn/Accessibility/Mobile">行動無障礙網頁</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/Accessibility_troubleshooting">無障礙問題排除</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/accessibility/what_is_accessibility/index.html b/files/zh-tw/learn/accessibility/what_is_accessibility/index.html
new file mode 100644
index 0000000000..35e520c814
--- /dev/null
+++ b/files/zh-tw/learn/accessibility/what_is_accessibility/index.html
@@ -0,0 +1,201 @@
+---
+title: 何謂無障礙網頁?
+slug: Learn/Accessibility/What_is_accessibility
+translation_of: Learn/Accessibility/What_is_accessibility
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</div>
+
+<p class="summary">這篇文章給「到底什麼是無障礙網頁」的模塊,開了個好起頭:以下將包括我們該考慮什麼樣的用戶以及理由、不同的人要在 web 用什麼工具互動、還有如何令無障礙網頁成為 web 開發的一部分。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決要求:</th>
+ <td>基本資訊能力、還有對 HTML 與 CSS 有基本的理解。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>熟悉無障礙網頁,包含它是什麼、還有它如何影響作為 web 開發者的你。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="到底什麼是無障礙網頁?">到底什麼是無障礙網頁?</h2>
+
+<p>無障礙是盡可能令更多人,使用你網站的實做:一般來說,我們會認為這屬於身心障礙者的範疇,但它其實會涵蓋其他群體:像是使用行動設備、或者網速很慢的人。</p>
+
+<p>也可以把無障礙想成:所有人,不論他們的能力或環境如何,都要同等看待、並給予同等機會。就如同我們不能把坐在輪椅的人,排除在某棟物理大樓之外:目前的公共建築,通常都會有電梯或輪椅坡道;我們也不能排除視障或手機用戶,使用我們的網站。儘管我們生而不同,但我們都是人,因此,我們都擁有相同的人權。</p>
+
+<p>無障礙是好事,但也是某些國家法律的一部分,也能開啟一些關係到你的服務或產品的市場。</p>
+
+<p>無障礙與其所需之最佳實做將使大家受益:</p>
+
+<ul>
+ <li>提昇無障礙的語意 HTML 能增進 SEO,令網站更容易被找到、也更易於銷售。</li>
+ <li>關注無障礙網頁會展現優良的倫理道德、以增進你的公共形象。</li>
+ <li>無障礙網頁的一些作法也能令網站易於給其他族群使用,像是手機用戶、低網速……等等。事實上,任何人都能從此類改進中獲益。</li>
+ <li>我們還要提提某些地區的法律規定嗎?</li>
+</ul>
+
+<h2 id="你在鎖定什麼樣的障礙者?">你在鎖定什麼樣的障礙者?</h2>
+
+<p>身心障礙者和非身心障礙者一樣多元,他們的障別也是如此。重點是,不要光用自己使用電腦和 web 的角度去思考這件事:<em>你並不是無障礙網頁的用戶</em>。下文將解釋應當考慮的障別,還有他們訪問 web 內容的特殊工具(通常稱作 <strong>assistive technologies</strong>、<strong>AT</strong>、<strong>輔助工具</strong>、<strong>輔具</strong>)。</p>
+
+<div class="note">
+<p><strong>註</strong>:世界衛生組織的<a href="http://www.who.int/mediacentre/factsheets/fs352/zh/">殘疾與健康</a>指出「超過10億人,約佔世界人口的15%,患有某種形式的殘疾。」、且「1.1億至1.9億成年人有很嚴重的功能性障礙。」。</p>
+</div>
+
+<h3 id="視覺障礙">視覺障礙</h3>
+
+<p>視覺障礙包括盲人、低度視覺、色盲……等等。這類的用戶會使用擴視器(screen magnifier,可能是物理擴視機、或是軟體的縮放功能:當代多數瀏覽器和作業系統都有這種功能),也有些人會用螢幕閱讀器(screen reader,朗讀數位文字的軟體):</p>
+
+<ul>
+ <li>有些是商業軟體,例如 <a class="external external-icon" href="http://www.freedomscientific.com/Products/Blindness/JAWS">JAWS</a>(Windows)和 <a class="external external-icon" href="http://www.gwmicro.com/window-eyes/">Window Eyes</a>(Windows)。</li>
+ <li>也有些是自由軟體,例如 <a class="external external-icon" href="http://www.nvaccess.org/">NVDA</a>(Windows)、<a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a>(Chrome、Windows、Mac OS X)、<a class="external external-icon" href="https://wiki.gnome.org/Projects/Orca">Orca</a>(Linux)</li>
+ <li>還有些是系統內建,例如 <a class="external external-icon" href="http://www.apple.com/accessibility/osx/voiceover/">VoiceOver</a>(Mac OS X 與 iOS)、<a class="external external-icon" href="https://support.microsoft.com/en-us/help/22798/windows-10-narrator-get-started">Narrator</a>(Microsoft Windows)、<a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a>(Chrome OS)、<a class="external external-icon" href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a>(Android)。</li>
+</ul>
+
+<p>熟悉螢幕閱讀器是個好主意;你得設定好螢幕閱讀器、還要會使用它,以理解其工作原理。請參見<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">cross browser testing screen readers guide</a>以深入理解。以下影片提供了簡單的體驗。</p>
+
+<p>{{EmbedYouTube("IK97XMibEws")}}</p>
+
+<p>在統計方面,世界衛生組織表明:「全球視力受損人數約2.53億:3600萬人患有盲症,2.17億人有中度至重度視力損害。」(請參見<a href="http://www.who.int/mediacentre/factsheets/fs282/zh">視力損害和盲症</a>)。如果網站編寫不正確,你的網站就會失去如此龐大的和重要的用戶群:這大約是全美國的總人口數。</p>
+
+<h3 id="聽覺障礙">聽覺障礙</h3>
+
+<p>聽覺障礙者、或聾人,是指聽力低落、或毫無聽力的群體。聽覺障礙者通常會用輔具(請參見<a href="https://www.nidcd.nih.gov/health/assistive-devices-people-hearing-voice-speech-or-language-disorders">Assistive Devices for People with Hearing, Voice, Speech, or Language Disorders</a>),但沒有給電腦/web使用的專門輔具。</p>
+
+<p>不過,請記得有專門技術,會針對有聲內容,提供閱讀的替代文字。有簡單的文本記錄(text transcript)、也有能在影片出現的追蹤文字(text track),例如字幕。接下來將有文章深入探討。</p>
+
+<p>聽覺障礙者也是龐大的人口,世界衛生組織在<a href="http://www.who.int/mediacentre/factsheets/fs300/zh">耳聾和聽力損失</a>指出:「全球有3.6億人患有殘疾性聽力損失」。</p>
+
+<h3 id="行動障礙">行動障礙</h3>
+
+<p>有運動障礙的人,可能是純粹身體問題(例如: 肢體殘缺或癱瘓)或是四肢無力、失去控制等神經或遺傳疾病。他們可能難以使用滑鼠做出精確的手部動作,甚至可能只能使用<a href="http://pattersonmedical.com/app.aspx?cmd=getProductDetail&amp;key=070_921118261">頭指針(head pointer)</a>操作電腦。</p>
+
+<p>這些殘疾也可能是老化的結果,而不是受到創傷或疾病,或可能是硬體的限制——有些使用者可能沒有滑鼠。</p>
+
+<p>通常影響開發者開發網站的需求是要能使用鍵盤操作網頁——我們會在後續的文內討論使用鍵盤操作網頁。雖然這個需求有些麻煩,但這是一個很好的主意,請開發者嘗試看看。例如:你可以使用 Tab 鍵在表單中切換填寫項目嗎?你可以在我們的<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Using_native_keyboard_accessibility">跨瀏覽器測試中找到更多關於使用鍵盤控制網頁的相關資訊</a>。</p>
+
+<p>統計數據顯示,許多人有行動障礙。 美國疾病控制和預防中心的<a href="http://www.cdc.gov/nchs/fastats/disability.htm">殘疾統計數據(涵蓋範圍為非法人的18歲以上成人)</a>顯示,在美國,有身體機能障礙者佔成人人口的 15.1% 。</p>
+
+<h3 id="認知障礙">認知障礙</h3>
+
+<p>最後一類,可能是最廣泛出現的殘疾——認知障礙。認知障礙廣義可涵蓋從精神疾病到學習困難,包含<a href="https://www.nimh.nih.gov/health/topics/attention-deficit-hyperactivity-disorder-adhd/index.shtml">ADHD(注意缺陷多動障礙)</a>、<a href="https://www.nimh.nih.gov/health/topics/autism-spectrum-disorders-asd/index.shtml">自閉症</a>患者、<a href="https://www.nimh.nih.gov/health/topics/schizophrenia/index.shtml">思覺失調</a>以及許多其他相關疾病。這些與記憶、解決問題能力、理解能力與注意力等問題相關的疾病,都大大影響病患的日常生活。</p>
+
+<p>這些疾病會影響病患使用網站,而最常見的問題就是他們會在理解如何完成網頁操作、記憶以往完成網頁操作的過程、以及經歷各種不同的操作流程與不一致的佈局/導覽列/其他頁面功能時,增加許許多多的挫敗感。</p>
+
+<p>與其他網路無障礙問題不同,我們無法快速解決認知障礙引起的網路操作問題;<br>
+ 你唯一能做的就是設計網站時,盡可能符合邏輯性、一致性與可用性,例如:</p>
+
+<ul>
+ <li>頁面一致 - 導覽列、頁眉、頁腳和主要內容區塊在每一個頁面都位在相同的位置。</li>
+ <li><span class="short_text" id="result_box" lang="zh-TW"><span>網站內工具設計精良,易於使用。</span></span></li>
+ <li>多個階段的流程(例如註冊),被細分有邏輯性的步驟,並提醒使用者如何進行流程,以及他需要多長的時間才能完成流程。</li>
+ <li>工作流程是合乎邏輯的、簡單的,並且盡可能減少需要與網站互動的流程<br>
+ 例如:註冊和登入網站常常就是很複雜且不必要的。</li>
+ <li>適量呈現頁面資訊,盡量讓頁面呈現的資訊不要過多或過密。</li>
+ <li>適當的用語,頁面呈現的用語須標準或通俗易懂,不要充滿不必要的行話或俚語。</li>
+ <li>內容的重點處適時以某些方式(例如:使用螢光色標示)突顯出來。</li>
+ <li>使用者操作錯誤的地方也需要標示出來,並且提供相關訊息或解決方法,幫助使用者解決錯誤。</li>
+</ul>
+
+<p>上述這些並不是「無障礙技術」,但他們是很好的設計理念。他們會讓使用者受益良多,因此他們應該成為你開發網站的工作標準之一。</p>
+
+<p>康乃爾大學 <a href="http://www.disabilitystatistics.org/StatusReports/2014-PDF/2014-StatusReport_US.pdf">2014 年的殘疾報告</a>顯示,2014 年美國 21 歲至 64 歲的人中,有 4.5% 的人有認知障礙。</p>
+
+<div class="note">
+<p><strong>注:</strong>WebAIM 的<a href="http://webaim.org/articles/cognitive/">認知頁面</a>提供了更多資訊,值得一讀</p>
+</div>
+
+<h2 id="專案引入無障礙">專案引入無障礙</h2>
+
+<p>有一個很常見的迷思,就是在專案管理方面,無障礙屬於昂貴的「外加」成本。如果有以下情形的話,這個迷思<em>的確會</em>發生:</p>
+
+<ul>
+ <li>針對明顯有障礙的網站,想要「重寫」為無障礙網站。</li>
+ <li>在專案後期才想到無障礙網頁相關問題時。</li>
+</ul>
+
+<p>如果在專案初期就考慮到無障礙網頁,大多數無障礙內容的成本可以最小化。</p>
+
+<p>當在規劃專案時,將無障礙測試納入你的測試中,就像測試其他功能一樣(例如:移動裝置 UI 測試)。<br>
+ 及早測試、經常測試,理想情況是運行自動化測試以檢測缺少的功能(例如:圖片缺少<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Text_alternatives">替代文字</a>、不好的連結文字 - 請參見 <a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Element_relationships_and_context">Element relationships and context</a>),並做一些測試,為了讓殘疾人士能夠操作更複雜的網站功能。例如:</p>
+
+<ul>
+ <li>日期選擇器是否可以提供給螢幕閱讀器的人使用?</li>
+ <li>如果內容動態更新了,視障人士是否能馬上收到資訊?</li>
+ <li>使用鍵盤或觸控式介面的人能順利操作我的 UI 按鈕嗎?</li>
+</ul>
+
+<p>你應該記錄自己網站中有問題的地方,並努力讓這些地方變成無障礙或考慮解決方案 / 替代方案,並持續進行測試。文字內容(你可以在下一章看到更多資訊)要做到無障礙很簡單,但是如你想要在網站中放上更多絢麗的 3D 圖形,那應該要怎麼做呢?<br>
+ 你應該評估專案的預算,並考慮有什麼解決方案可以讓這些絢麗的 3D 圖形容易被存取。<br>
+ 例如:你可以支付高額的費用,讓那些多媒體內容轉錄成無障礙設備可存取的資訊,雖然昂貴,卻是可行的方案。</p>
+
+<p>雖然要實現 100% 無障礙網頁是一種難以達成的理想,世事難料,你總是會遇到一些不常見的問題,導致某個使用者難以使用網頁,但你還是應該盡可能做到無障礙網頁。如果你打算使用WebGL製作的炫麗的 3D 圓餅圖,可以撰寫替代的文字,來傳達圖表的資訊。或者你可以只使用表格來傳達資訊而不使用3D 圓餅圖,這樣每個人都可以一目了然表格傳達的資訊、網頁傳輸編碼更快、CPU使用率更低,並且更容易維護。</p>
+
+<p>但是如果你是一個有趣的 3D 藝術畫廊網站開發者,那麼期待這些藝術品能夠傳達給視障人士,就不太合理,因為圖畫這類的藝術品本身就是透過視覺作為傳達訊息的媒介。</p>
+
+<p>為了表明你對無障礙網頁的關心,請在你的網站上發佈無障礙網頁聲明,並詳細說明你為無障礙網頁做了哪些事情、採取了哪些步驟。如果有人抱怨你的網站存在無障礙問題,請他們回報給你們,並嘗試解決。</p>
+
+<div class="note">
+<p><strong>注</strong>:我們的 <a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Handling common accessibility problems article</a> 包含了應該進行詳細測試的無障礙網頁規範。</p>
+</div>
+
+<p>總而言之:</p>
+
+<ul>
+ <li>在專案初期就考量到無障礙網頁、還要測試得早而多。一如其他錯誤,無障礙網頁問題在越晚發現時,麻煩也越大。</li>
+ <li>謹記無障礙網頁,是對大家都有利的。例如說,精實的語意標記不只對螢幕閱讀有利,也利於快速載入與效能,從而對大家有利,尤其對行動設備、或是網速過慢的人。</li>
+ <li>再網站上標明支援無障礙網頁,並鼓勵身心障礙者參與。</li>
+</ul>
+
+<h2 id="無障礙網頁的指引與法律">無障礙網頁的指引與法律</h2>
+
+<p>有一些針對無障礙網頁的檢查清單和指引能夠用做測試,它們乍看之下可能令人眼花撩亂。我們建議你只要專注熟悉的基本領域、並理解指引裡面,與你最相關的高層次結構。</p>
+
+<ul>
+ <li>首先,W3C 針對無障礙網頁的一致性,發布了龐大而詳盡、並包含精確而不講明具體技術的準則文件。它們通常稱作 <a href="https://www.w3.org/WAI/intro/wcag.php">Web Content Accessibility Guidelines</a>(WCAG,無障礙網頁內容指引),無論從哪個角度來說,讀起來都不是普通的長。整個準則能分為以下四大類:它指定如何實做可感知、可操作、可理解、還有健壯(perceivable, operable, understandable, robust)的內容。要取得簡易指引並開始學習,可以去參閱 <a href="https://www.w3.org/WAI/WCAG20/glance/Overview.html">WCAG at a Glance</a>。你不需要學習 WCAG 的一切:只要了解主要的關注領域,並使用各種技術和工具來高亮任何不符 WCAG 標準的領域就型(參閱以下)。</li>
+ <li>你的國家或地區可能有特別立法,以管理這方面人口的需求:例如美國的 <a href="http://www.section508.gov/content/learn">Section 508 of the Rehabilitation Act</a>、德國的 <a href="https://www.einfach-fuer-alle.de/artikel/bitv_english/">Federal Ordinance on Barrier-Free Information Technology</a>、英國的 <a href="http://www.legislation.gov.uk/ukpga/2010/15/contents">Equality Act</a>、義大利的 <a href="http://www.agid.gov.it/agenda-digitale/pubblica-amministrazione/accessibilita">Accessibilità</a>、還有澳洲的 <a href="https://www.humanrights.gov.au/world-wide-web-access-disability-discrimination-act-advisory-notes-ver-41-2014">Disability Discrimination Act</a>……等等。<br>
+ (譯註:針對繁體中文,台灣有<a href="https://www.handicap-free.nat.gov.tw">基於《身心障礙者權益保障法》的無障礙網頁開發規範</a>、香港有<a href="https://www.ogcio.gov.hk/tc/community/web_mobileapp_accessibility/promulgating_resources/handbook/doc/Web_Accessibility_Handbook.pdf">基於《殘疾歧視條例》的無障礙設計指引</a>)</li>
+</ul>
+
+<p>因此,儘管 WCAG 有所指引,你的國家可能還是有管理無障礙網頁、或最少針對公眾無障礙服務(可能包含了網站、電視、物理空間……等等)的法案。最好先看看所處地區的法律管轄權。如果不好好檢查內容是否無障礙,當身心障礙者投訴時,你可能會面臨法律問題。</p>
+
+<p>聽起來很可怕,但只要在開發時,如上所述地把無障礙網頁議題當作高度優先就可以了。如果真的有疑問,請諮詢合格的專業律師。我們不是律師,所以不會提供更深入的意見。</p>
+
+<h2 id="無障礙網頁_API">無障礙網頁 API</h2>
+
+<p>瀏覽器使用特殊的<strong>accessibility API</strong>(由各自的作業系統底層提供)對輔助技術(AT)提供有用的信息:輔助技術傾向使用語義訊息,因此這種訊息不包含樣式化資訊、或是 JavaScript。這種資訊建構成一個稱為 <strong>accessibility tree</strong> 的訊息樹(tree of information)。</p>
+
+<p>不同的作業系統有不同的 accessibility API:</p>
+
+<ul>
+ <li>Windows: MSAA/IAccessible, UIAExpress, IAccessible2</li>
+ <li>Mac OS X: NSAccessibility</li>
+ <li>Linux: AT-SPI</li>
+ <li>Android: Accessibility framework</li>
+ <li>iOS: UIAccessibility</li>
+</ul>
+
+<p>如果由 web app 裡面,HTML 元素提供的原生語意訊息出問題了,你可以把它用做 <a href="https://www.w3.org/TR/wai-aria/">WAI-ARIA 規範</a>的補充:它會把語意訊息添加到 accessibility tree 以增進無障礙功能。你可以在 <a href="/zh-TW/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA 基礎</a>文章學習 WAI-ARIA。</p>
+
+<h2 id="結論">結論</h2>
+
+<p>本文應當使你對無障礙網頁有著概括性的認知、明白其重要性、並在知道如何在工作流程中安排它。你也該對知道如何實做無障礙網頁的細節有興趣。我們將在下個章節開始闡明為什麼 HTML 是無障礙網頁的好基礎。</p>
+
+<p>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</p>
+
+<h2 id="在本模塊">在本模塊</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/What_is_accessibility">What is accessibility?</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/Multimedia">Accessible multimedia</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/Mobile">Mobile accessibility</a></li>
+ <li><a href="/zh-TW/docs/Learn/Accessibility/Accessibility_troubleshooting">Accessibility troubleshooting</a></li>
+</ul>
diff --git a/files/zh-tw/learn/common_questions/index.html b/files/zh-tw/learn/common_questions/index.html
new file mode 100644
index 0000000000..4aafae4a32
--- /dev/null
+++ b/files/zh-tw/learn/common_questions/index.html
@@ -0,0 +1,135 @@
+---
+title: Common questions
+slug: Learn/Common_questions
+tags:
+ - CodingScripting
+ - Infrastructure
+ - Learn
+ - NeedsTranslation
+ - TopicStub
+ - Web
+ - WebMechanics
+translation_of: Learn/Common_questions
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">This section of the Learning Area is designed to provide answers to common questions that may come up, which are not necessarily part of the structured core learning pathways (e.g. the <a href="/en-US/docs/Learn/HTML">HTML</a> or <a href="/en-US/docs/Learn/CSS">CSS</a> learning articles.) These articles are designed to work on their own.</p>
+
+<h2 id="How_the_Web_works">How the Web works</h2>
+
+<p>This section covers web mechanics —questions relating to general knowledge of the Web ecosystem and how it works.</p>
+
+<dl>
+ <dt>
+ <h3 id="How_does_the_Internet_work"><a href="/en-US/docs/Learn/Common_questions/How_does_the_Internet_work">How does the Internet work?</a></h3>
+ </dt>
+ <dd>The <strong>Internet</strong> is the backbone of the Web, the technical infrastructure that makes the Web possible. At its most basic, the Internet is a large network of computers which communicate all together. This article discusses how it works, at a basic level.</dd>
+ <dt>
+ <h3 id="What_is_the_difference_between_webpage_website_web_server_and_search_engine"><a href="/en-US/docs/Learn/Common_questions/Pages_sites_servers_and_search_engines">What is the difference between webpage, website, web server, and search engine?</a></h3>
+ </dt>
+ <dd>In this article we describe various web-related concepts: webpages, websites, web servers, and search engines. These terms are often confused by newcomers to the Web, or are incorrectly used. Let's learn what they each mean!</dd>
+ <dt>
+ <h3 id="What_is_a_URL"><a href="/en-US/docs/Learn/Common_questions/What_is_a_URL">What is a URL?</a></h3>
+ </dt>
+ <dd>With {{Glossary("Hypertext")}} and {{Glossary("HTTP")}}, URL is one of the key concepts of the Web. It is the mechanism used by {{Glossary("Browser","browsers")}} to retrieve any published resource on the web.</dd>
+ <dt>
+ <h3 id="What_is_a_domain_name"><a href="/en-US/docs/Learn/Common_questions/What_is_a_domain_name">What is a domain name?</a></h3>
+ </dt>
+ <dd>Domain names are a key part of the Internet infrastructure. They provide a human-readable address for any web server available on the Internet.</dd>
+ <dt>
+ <h3 id="What_is_a_web_server"><a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">What is a web server?</a></h3>
+ </dt>
+ <dd>The term "Web server" can refer to the hardware or software that serves web sites to clients across the Web — or both of them working together. In this article we go over how web servers work, and why they're important.</dd>
+ <dt>
+ <h3 id="What_are_hyperlinks"><a href="/en-US/docs/Learn/Common_questions/What_are_hyperlinks">What are hyperlinks?</a></h3>
+ </dt>
+ <dd>In this article, we'll go over what hyperlinks are and why they matter.</dd>
+</dl>
+
+<h2 id="Tools_and_setup">Tools and setup</h2>
+
+<p>Questions related to the tools/software you can use to build websites.</p>
+
+<dl>
+ <dt>
+ <h3 id="How_much_does_it_cost_to_do_something_on_the_Web"><a href="/en-US/docs/Learn/Common_questions/How_much_does_it_cost">How much does it cost to do something on the Web?</a></h3>
+ </dt>
+ <dd>When you're launching a website, you may spend nothing or your costs may go through the roof. In this article we discuss how much everything costs and what you get for what you pay (or don't pay).</dd>
+ <dt>
+ <h3 id="What_software_do_I_need_to_build_a_website"><a href="/en-US/docs/Learn/Common_questions/What_software_do_I_need">What software do I need to build a website?</a></h3>
+ </dt>
+ <dd>In this article we explain which software components you need when you're editing, uploading, or viewing a website.</dd>
+ <dt>
+ <h3 id="What_text_editors_are_available"><a href="/en-US/docs/Learn/Common_questions/Available_text_editors">What text editors are available?</a></h3>
+ </dt>
+ <dd>In this article we highlight some things to think about when choosing and installing a text editor for web development.</dd>
+ <dt>
+ <h3 id="What_are_browser_developer_tools"><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools?</a></h3>
+ </dt>
+ <dd>Every browser features a set of devtools for debugging HTML, CSS, and other web code. This article explains how to use the basic functions of your browser's devtools.</dd>
+ <dt>
+ <h3 id="How_do_you_make_sure_your_website_works_properly"><a href="/en-US/docs/Learn/Common_questions/Checking_that_your_web_site_is_working_properly">How do you make sure your website works properly?</a></h3>
+ </dt>
+ <dd>So you've published your website online — very good! But are you sure it works properly? This article provides some basic troubleshooting steps.</dd>
+ <dt>
+ <h3 id="How_do_you_set_up_a_local_testing_server"><a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">How do you set up a local testing server?</a></h3>
+ </dt>
+ <dd>
+ <div>
+ <p>This article explains how to set up a simple local testing server on your machine, and the basics of how to use it.</p>
+ </div>
+ </dd>
+ <dt>
+ <h3 id="How_do_you_upload_files_to_a_web_server"><a href="/en-US/docs/Learn/Common_questions/Upload_files_to_a_web_server">How do you upload files to a web server?</a></h3>
+ </dt>
+ <dd>This article shows how to publish your site online with <a class="glossaryLink" href="https://developer.mozilla.org/en-US/docs/Glossary/FTP" title="FTP: FTP (File Transfer Protocol) is the standard network protocol for transferring files from one host to another over the Internet through TCP.">FTP</a> tools — one of the most common ways to get a website online so others can access it from their computers.</dd>
+ <dt>
+ <h3 id="How_do_I_use_GitHub_Pages"><a href="/en-US/docs/Learn/Common_questions/Using_GitHub_Pages">How do I use GitHub Pages?</a></h3>
+ </dt>
+ <dd>This article provides a basic guide to publishing content using GitHub's gh-pages feature.</dd>
+ <dt>
+ <h3 id="How_do_you_host_your_website_on_Google_App_Engine"><a href="/en-US/Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine">How do you host your website on Google App Engine?</a></h3>
+ </dt>
+ <dd>Looking for a place to host your website? Here's a step-by-step guide to hosting your website on Google App Engine.</dd>
+ <dt>
+ <h3 id="What_tools_are_available_to_debug_and_improve_website_performance"><a href="/en-US/docs/Tools/Performance">What tools are available to debug and improve website performance?</a></h3>
+ </dt>
+ <dd>This set of articles shows you how to use the Developer Tools in Firefox to debug and improve performance of your website, using the tools to check the memory usage, the JavaScript call tree, the amount of DOM nodes being rendered, and more.</dd>
+</dl>
+
+<h2 id="Design_and_accessibility">Design and accessibility</h2>
+
+<p>This section lists questions related to aesthetics, page structure, accessibility techniques, etc.</p>
+
+<dl>
+ <dt>
+ <h3 id="How_do_I_start_to_design_my_website"><a href="/en-US/docs/Learn/Common_questions/Thinking_before_coding">How do I start to design my website?</a></h3>
+ </dt>
+ <dd>This article covers the all-important first step of every project: define what you want to accomplish with it.</dd>
+ <dt>
+ <h3 id="What_do_common_web_layouts_contain"><a href="/en-US/docs/Learn/Common_questions/Common_web_layouts">What do common web layouts contain?</a></h3>
+ </dt>
+ <dd>When designing pages for your website, it's good to have an idea of the most common layouts. This article runs thorugh some typical web layouts, looking at the parts that make up each one.</dd>
+ <dt>
+ <h3 id="What_is_accessibility"><a href="/en-US/docs/Learn/Common_questions/What_is_accessibility">What is accessibility?</a></h3>
+ </dt>
+ <dd>This article introduces the basic concepts behind web accessibility.</dd>
+ <dt>
+ <h3 id="How_can_we_design_for_all_types_of_users"><a href="/en-US/docs/Learn/Common_questions/Design_for_all_types_of_users">How can we design for all types of users?</a></h3>
+ </dt>
+ <dd>This article provides basic techniques to help you design websites for any kind of user — quick accessibility wins, and other such things.</dd>
+ <dt>
+ <h3 id="What_HTML_features_promote_accessibility"><a href="/en-US/docs/Learn/Common_questions/HTML_features_for_accessibility">What HTML features promote accessibility?</a></h3>
+ </dt>
+ <dd>This article describes specific features of HTML that can be used to make a web page more accessible to people with different disabilities.</dd>
+</dl>
+
+<h2 id="HTML_CSS_and_JavaScript_questions">HTML, CSS and JavaScript questions</h2>
+
+<p>For common solutions to HTML/CSS/JavaScript problems, try the following articles:</p>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto">Use HTML to solve common problems</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/Howto">Use CSS to solve common problems</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Howto">Use JavaScript to solve common problems</a></li>
+</ul>
diff --git a/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html b/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html
new file mode 100644
index 0000000000..d8bb301ab1
--- /dev/null
+++ b/files/zh-tw/learn/common_questions/what_is_a_web_server/index.html
@@ -0,0 +1,116 @@
+---
+title: 何謂網路伺服器?
+slug: Learn/Common_questions/What_is_a_web_server
+translation_of: Learn/Common_questions/What_is_a_web_server
+---
+<div class="summary">
+<p><span class="seoSummary">本文章將講解網路伺服器是什麼、如何運作、還有他們的重要性。</span></p>
+</div>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">要求:</th>
+ <td>你要知道 <a href="/zh-TW/docs/Learn/How_the_Internet_works">Internet 是怎麼運作的</a>、並<a href="/zh-TW/docs/Learn/page_vs_site_vs_server_vs_search_engine">知道網頁、網站、網路伺服器的不同</a>。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>你將知道網路伺服器是什麼、並大致了解它的運作原理。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概要">概要</h2>
+
+<p>「網路伺服器」(web server)可以指軟體、也可以指硬體、還可以指它們共同運作的狀態。</p>
+
+<ol>
+ <li>以硬體來說,web server 是存放網路伺服器軟體、還有網站檔案(如 HTML 文件、圖片、CSS 樣式表、JavaScript 檔案)的電腦。它會連上網際網路(Internet)並能和其他連上網的設備做物理數據交換。</li>
+ <li>以軟體來說,web server 包含了一連串控制網路用戶如何訪問託管檔案──至少有 HTTP 伺服器──的檔案。HTTP 伺服器是其中一個部份,它理解 {{Glossary("URL","URLs")}}(網路地址)與 {{Glossary("HTTP")}}(瀏覽器用來觀察網頁的協議)。它能透過域名(domain name)訪問託管的網站(如 <code>mozilla.org</code>)、並將其內容遞送到終端用戶(end-user)的設備上。</li>
+</ol>
+
+<p>以最基本的層面來說,如果瀏覽器需要網路伺服器所託管的檔案,它就需要透過 HTTP 發送對該檔案的請求。如果請求已經傳送到正確的(硬體)網路伺服器,那 HTTP(軟體)伺服器就會接受請求、找出所請求的文件(假若不是接著回傳 <a href="/zh-TW/docs/Web/HTTP/Status/404">404</a> 頁面)、再透過 HTTP 回傳給瀏覽器。</p>
+
+<p><img alt="Basic representation of a client/server connection through HTTP" src="https://mdn.mozillademos.org/files/8659/web-server.svg" style="height: 200px; width: 600px;"></p>
+
+<p>要發布網站,你需要一個靜態或動態的網路伺服器。</p>
+
+<p><strong>靜態網路伺服器</strong>(static web server)、或是 stack,由(硬體的)電腦和(軟體的) HTTP 伺服器組成。之所以稱為「靜態」是因為伺服器只會給你的瀏覽器,傳送「事先寫好的」(as-is)檔案。</p>
+
+<p><strong>動態網路伺服器</strong>(dynamic web server)除了靜態網路伺服器以外、還附加了一些軟體:通常是應用伺服器(application server)與資料庫(database)之所以稱為「動態」是因為:應用伺服器會在託管檔案,透過 HTTP 伺服器傳送到瀏覽器之前更新之。</p>
+
+<p>例如說,要生成瀏覽器看到的最終網頁,應用伺服器會使用從資料庫讀取資料的 HTML 模板(HTML template)填補之。像 MDN 或維基百科(Wikipedia)這樣的網站也有上千個網頁:但它們全都不是「真的」HTML 文件,而是少數的 HTML 模板、還有龐大的資料庫。如此一來,要維護並傳送資料、都會變得很容易。</p>
+
+<h2 id="主動學習">主動學習</h2>
+
+<p><em>目前還沒有好用的內容。<a href="https://developer.mozilla.org/zh-TW/docs/MDN/Getting_started">請考慮貢獻一下</a>。</em></p>
+
+<h2 id="深入一點……">深入一點……</h2>
+
+<p>如同我們講過的:要取得網頁,瀏覽器會向伺服器發送一個在伺服器內,尋找某個檔案的請求。如果伺服器找到了檔案,就會讀取它、按需求處理、並回傳檔案。讓我們逐步檢視它們。</p>
+
+<h3 id="託管檔案">託管檔案</h3>
+
+<p>首先,網路伺服器要儲存網站檔案,也就是所有 HTML 文件、和附屬的 asset:asset 包含了圖片、CSS 樣式表、JavaScript 檔案、字型檔、還有影片。</p>
+
+<p>技術上來說,你可以把它們都放在自己的電腦裡面,但放在網路伺服器上面會方便許多,理由是伺服器:</p>
+
+<ul>
+ <li>永遠開機並運轉</li>
+ <li>永遠連上網際網路</li>
+ <li>永遠都有相同的 IP 地址(不是所有{{Glossary("ISP", "網際網路提供者")}}都給家庭用戶提供固定的 IP 地址)</li>
+ <li>由第三方提供者維護</li>
+</ul>
+
+<p>因此,找到優秀的託管提供者,是建立網站的重點之一。好好探索各大公司提供的服務、並選擇一個符合需求、預算也能負擔的方案(服務的價格從免費到上千美元都有)。你可以<a href="https://developer.mozilla.org/zh-TW/Learn/How_much_does_it_cost#Hosting">在這篇文章</a>找到更多資訊。</p>
+
+<p>一旦找到適合的網絡託管解決方案,你只要<a href="/zh-TW/docs/Learn/Upload_files_to_a_web_server">把文件上傳到網路伺服器</a>就行了。</p>
+
+<h3 id="透過_HTTP_溝通">透過 HTTP 溝通</h3>
+
+<p>接下來,網路伺服器會支援 {{Glossary("HTTP")}}(<strong>H</strong>yper<strong>t</strong>ext <strong>T</strong>ransfer <strong>P</strong>rotocol,超文本傳輸協議)。顧名思義,HTTP 會指定兩台電腦之間,該如何傳送超文本(例如 linked web document)。</p>
+
+<p>協議({{Glossary("Protocol")}})是一套兩台電腦間該如何溝通的規則。HTTP 是文本性、無狀態的協議。</p>
+
+<dl>
+ <dt>文本性(Textual)</dt>
+ <dd>所有指令都是純文字、人類也容易理解。</dd>
+ <dt>無狀態(Stateless)</dt>
+ <dd>無論伺服器還是瀏覽器,都不會記得他們上一次的溝通。像是伺服器,如果只依賴 HTTP 的話,它就不會記得你輸入的帳號密碼、或是在交易中採取了哪些步驟。要完成這樣的任務,你需要應用伺服器(我們將在其他文章中介紹這種技術)。</dd>
+</dl>
+
+<p>HTTP 提供了用戶端與伺服器端,該如何溝通的明確規則。我們將在之後的<a href="https://developer.mozilla.org/zh-TW/docs/Web/HTTP">技術文章</a>內講解 HTTP 本身。目前,我們會先聚焦在:</p>
+
+<ul>
+ <li>只有用戶端能發出 HTTP 請求,也只有伺服器能接受它。相對地,也只有伺服器能回應用戶端的 HTTP 請求。</li>
+ <li>如果透過 HTTP 請求檔案,用戶端必須提供檔案的 {{Glossary("URL")}}。</li>
+ <li>網路伺服器<strong>必須回應</strong>所有的 HTTP 請求,最起碼需要回應錯誤訊息。</li>
+</ul>
+
+<p><a href="https://developer.mozilla.org/zh-TW/404"><img alt="MDN 404 錯誤頁面範例" src="https://mdn.mozillademos.org/files/8661/mdn-404.jpg" style="float: right; height: 300px; width: 300px;"> </a>在網路伺服器裡面,HTTP 伺服器負責處理和回答傳入的請求。</p>
+
+<ol>
+ <li>HTTP 伺服器接收請求後,會先檢查請求的 URL 是否匹配現有文件。</li>
+ <li>如果匹配,網路伺服器會把檔案內容回傳給瀏覽器。不然,應用伺服器會建立需要的檔案。</li>
+ <li>如果都沒有用的話,網路伺服器會回傳錯誤訊息給瀏覽器,最常見的就是「404 Not Found」。(這個錯誤很常見,所以許多網頁設計師花了相當多的心力設計 <a href="http://www.404notfound.fr/" rel="external">404 錯誤頁面</a>。)</li>
+</ol>
+
+<h3 id="靜態與動態內容">靜態與動態內容</h3>
+
+<p>大略上來說,伺服器能儲存動態與靜態的內容。「靜態」是指「提供事先寫好的」。靜態網站設定上最簡單,所以我們建議選擇靜態內容,作為你的第一個網站。</p>
+
+<p>「動態」指的是伺服器處理內容、甚至從資料庫即時產生。這個解決方案提供了更多靈活性,但技術會變得難以駕馭、令網站明顯複雜許多。</p>
+
+<p>以你目前閱讀的頁面為例。在託管的伺服器裡面,有個應用伺服器會從資料庫取得內容、規範化、再把它塞進某些 HTML 模板裡面。這裡的應用伺服器,是以 Python 語言的 Django 框架為基礎,所組建的 <a href="/zh-TW/docs/MDN/Kuma">Kuma</a>。Mozilla 團隊基於 MDN 的特殊需求開發了 Kuma,不過也有很多相似、但使用其他技術的應用程式。</p>
+
+<p>從海量的應用伺服器裡面選一個推薦,是個大難題。有些應用程式會迎合特定的類別,如部落格、百科、電子商務。其他還有更通用的 {{Glossary("CMS")}}(content management systems,內容管理系統)。如果要建立動態網站,花點時間找個符合需求的工具。除非想學習伺服器端程式設計(也是個扣人心弦的領域!),否則不用建立屬於自己的應用伺服器。那樣只是在{{Interwiki("wikipedia", "重造輪子")}}。</p>
+
+<h2 id="下一步">下一步</h2>
+
+<p>熟悉了伺服器以後可以:</p>
+
+<ul>
+ <li>讀讀<a href="/zh-TW/docs/Learn/How_much_does_it_cost">how much it costs to do something on the web</a></li>
+ <li>了解<a href="/zh-TW/docs/Learn/What_software_do_I_need">various software you need to create a website</a></li>
+ <li>移駕到<a href="/zh-TW/docs/Learn/Upload_files_to_a_web_server">how to upload files on a web server</a>之類的實戰。</li>
+</ul>
diff --git a/files/zh-tw/learn/css/css_layout/index.html b/files/zh-tw/learn/css/css_layout/index.html
new file mode 100644
index 0000000000..385121536f
--- /dev/null
+++ b/files/zh-tw/learn/css/css_layout/index.html
@@ -0,0 +1,71 @@
+---
+title: CSS 排版
+slug: Learn/CSS/CSS_layout
+tags:
+ - CSS
+ - 佈局
+ - 多欄
+ - 彈性盒子
+ - 排版
+ - 新手
+ - 浮動
+ - 網格
+translation_of: Learn/CSS/CSS_layout
+---
+<div>{{draft}}</div>
+
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">基於我們已經看過了 CSS 基本原理:如何將文字賦予樣式、如何該便樣式或操作你的文字內容所處的 box 模型。現在是時候看看如何將你的 box 模型在視圖中放置於相對應的正確位置。我們已經涵蓋了必要的先備知識,接下來我們可以深入CSS 排版,看一些不同的顯示方式,如現代的排版方式——彈性盒子、CSS 網格及定位,當然還有一些舊式的技術你可能會想要理解。</p>
+
+<h2 id="先備知識">先備知識</h2>
+
+<p>開始這個單元之前,需要做如下準備:</p>
+
+<ol>
+ <li>對 HTML 有基本的認知,如  <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 簡介</a> 單元中所述。</li>
+ <li>熟悉 CSS 基本原理,如 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 簡介</a>中所述。</li>
+ <li>了解如何 <a href="/en-US/docs/Learn/CSS/Styling_boxes">樣式框</a>。</li>
+</ol>
+
+<div class="note">
+<p><strong>注</strong>: 如果你正在使用的電腦/平板/其他設備讓你無法建立自己的文件,你可以透過線上工具如 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a> 編輯並嘗試(大部分的)範例程式碼。</p>
+</div>
+
+<h2 id="指導">指導</h2>
+
+<p>這些文章旨在提供關於 CSS 中可用的技術以及基本排版工具和技術的指導。在課程的結尾有一個評估測驗——配置一個網頁的版面,這可以幫助你了解你對 CSS 排版方式的理解程度。</p>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">CSS 排版介紹</a></dt>
+ <dd>這篇文章將回顧一些之前單元中提過的 CSS 排版特性,像是不同的{{cssxref("display")}} 參數,藉由這個單元我們將介紹一些基本概念。</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">常規流</a></dt>
+ <dd>在我們做任何事之前,網頁上的元素會根據常規流自行排列。這篇文章解釋常規流的基礎知識,用來學習如何改變它。</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">彈性盒子</a></dt>
+ <dd><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_flexbox_to_lay_out_web_applications">彈性盒子</a>是一維空間的排版方式,用來讓項目以行或列的方式排列。項目會延展或限縮來符合較大或較小的空間。這篇文章會解釋基礎原理。</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">網格</a></dt>
+ <dd>CSS 網格排版是一個二維空間的網頁排版系統。它讓你將內容排入行與列中,且它有許多功能讓你在建立複雜的排版時變得簡單明瞭。這篇文章會告訴你全部。</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">浮動</a></dt>
+ <dd>最初是為了在文字區塊中浮動排列圖片,而後為了在網頁中建造多攔排版{{cssxref("float")}} 屬性成為了最常用的工具之一。這篇文章會解釋如何使用。</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">定位</a></dt>
+ <dd>定位准許將元素從正常的文檔流中脫離出來,讓他們表現不同,例如設置在另一個模塊的上方,或使模塊在瀏覽器視窗內部始終停留在相同的地方。這篇文章將解釋不同的{{cssxref("position")}} 值和如何使用它們。</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">多欄排版</a></dt>
+ <dd>多欄排版規格提供你將內容排進欄位的排版方式,像你可能在報紙上看到的那樣。這篇文章會解釋如何使用這個功能。</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">舊式排版方式</a></dt>
+ <dd>網格系統是另一個在 CSS 排版中非常常用的特性,在網格排版出現之前,它通常使用浮動或其他佈局來實現。想像你的佈局為一組列數(如 4, 6, 或 12),然後將你的內容放置在這些虛構的列中。在這篇文章中我們將隨著創建網格系統、看看使用網格框架提供現成的網格框架和體驗 CSS 網格來結束-一個新興的瀏覽器特性使得在 Web 實現網格設計變得大為容易等來探索這些基本的想法。</dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">支援舊版瀏覽器</a></dt>
+ <dd>
+ <p>在這個單元,我們建議你使用彈性盒子和網格作為主要的設計方式。但是有些造訪你網站的人會使用舊版瀏覽器,或者他使用的瀏覽器不支援你的設計方式。以下情形在網路上一定會發生——當新功能開發出來了,不同的瀏覽器會有不同的支援優先級。這篇文章會解釋如何使用現代網頁技術且不遺漏舊技術的使用者。</p>
+ </dd>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">基礎排版理解測驗</a></dt>
+ <dd>配置網頁版面,這是一個測試你對於不同排版方式理解程度的測驗。</dd>
+</dl>
+
+<h2 id="參見">參見 </h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">實際的定位排版範例</a></dt>
+ <dd>這篇文章會告訴你如何建立一些真實的範例來說明什麼樣的情況你可以使用定位排版。</dd>
+</dl>
+
+<p> </p>
diff --git a/files/zh-tw/learn/css/first_steps/getting_started/index.html b/files/zh-tw/learn/css/first_steps/getting_started/index.html
new file mode 100644
index 0000000000..aed101592c
--- /dev/null
+++ b/files/zh-tw/learn/css/first_steps/getting_started/index.html
@@ -0,0 +1,265 @@
+---
+title: CSS 入門
+slug: Learn/CSS/First_steps/Getting_started
+tags:
+ - CSS
+ - 元素
+ - 初學者
+ - 學習
+ - 狀態
+ - 範例
+ - 語法
+ - 課程
+ - 選擇器
+translation_of: Learn/CSS/First_steps/Getting_started
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</div>
+
+<p class="summary">在這個主題中,我們將 CSS 套用到一個簡單的 HTML 文件上,在過程中學習這個語言一些實際的東西。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基本的電腦概念、能夠<a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a>,基本<a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各種檔案打交道</a>的能力,以及 HTML 的基礎(由<a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 入門</a>學到)。</td>
+ </tr>
+ <tr>
+ <th scope="row">學習目標:</th>
+ <td>了解將 CSS 文件與 HTML 檔案連接的基本知識,並且能夠使用 CSS 對文字作簡單的格式變化。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="由某個_HTML_開始">由某個 HTML 開始</h2>
+
+<p>我們的起點是一個 HTML 文件。如果您想要在自己的電腦上操作,可以把下面的程式碼複製下來。在您電腦上的目錄中,用 <code>index.html</code> 為檔名儲存</p>
+
+<p>。</p>
+
+<pre class="brush: html notranslate">&lt;!doctype html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Getting started with CSS&lt;/title&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+
+ &lt;h1&gt;I am a level one heading&lt;/h1&gt;
+
+ &lt;p&gt;This is a paragraph of text. In the text is a &lt;span&gt;span element&lt;/span&gt;
+and also a &lt;a href="http://example.com"&gt;link&lt;/a&gt;.&lt;/p&gt;
+
+ &lt;p&gt;This is the second paragraph. It contains an &lt;em&gt;emphasized&lt;/em&gt; element.&lt;/p&gt;
+
+ &lt;ul&gt;
+ &lt;li&gt;Item one&lt;/li&gt;
+ &lt;li&gt;Item two&lt;/li&gt;
+ &lt;li&gt;Item &lt;em&gt;three&lt;/em&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+
+&lt;/body&gt;
+
+&lt;/html&gt;</pre>
+
+<div class="blockIndicator note">
+<p><strong>注意:</strong>如果您用來閱讀這篇文章的環境沒辦法簡單地建立檔案,也別擔心。底下會提供線上程式編輯器讓你就在這個頁面中撰寫範例程式。</p>
+</div>
+
+<h2 id="為我們的文件加入CSS">為我們的文件加入CSS</h2>
+
+<p>首先,告訴HTML文件我們有些CSS規則要加入是第一個步驟。你可能會碰到三種不同的方式可以將CSS檔案應用進HTML文件之中,不過我們現在先將焦點放在最常見且最實用的方式:將CSS從文件的前頭連接進去。</p>
+
+<p>先建立一個檔案,將它存在與你HTML文件同一個目錄之中並命名為<code>styles.css</code> 。<code>.css</code> 外掛會辨識它為一個CSS檔案。</p>
+
+<p>To link <code>styles.css</code> to <code>index.html</code> add the following line somewhere inside the {{htmlelement("head")}} of the HTML document:</p>
+
+<pre class="brush: html notranslate">&lt;link rel="stylesheet" href="styles.css"&gt;</pre>
+
+<p>This {{htmlelement("link")}} element tells the browser that we have a stylesheet, using the <code>rel</code> attribute, and the location of that stylesheet as the value of the <code>href</code> attribute. You can test that the CSS works by adding a rule to <code>styles.css</code>. Using your code editor add the following to your CSS file:</p>
+
+<pre class="brush: css notranslate">h1 {
+ color: red;
+}</pre>
+
+<p>Save your HTML and CSS files and reload the page in a web browser. The level one heading at the top of the document should now be red. If that happens, congratulations — you have successfully applied some CSS to an HTML document. If that doesn't happen, carefully check that you've typed everything correctly.</p>
+
+<p>You can continue to work in <code>styles.css</code> locally, or you can use our interactive editor below to continue with this tutorial. The interactive editor acts as if the CSS in the first panel is linked to the HTML document, just as we have with our document above.</p>
+
+<h2 id="Styling_HTML_elements">Styling HTML elements</h2>
+
+<p>By making our heading red we have already demonstrated that we can target and style an HTML element. We do this by targeting an <em>element selector</em> — this is a selector that directly matches an HTML element name. To target all paragraphs in the document you would use the selector <code>p</code>. To turn all paragraphs green you would use:</p>
+
+<pre class="brush: css notranslate">p {
+ color: green;
+}</pre>
+
+<p>You can target multiple selectors at once, by separating the selectors with a comma. If I want all paragraphs and all list items to be green my rule looks like this:</p>
+
+<pre class="brush: css notranslate">p, li {
+ color: green;
+}</pre>
+
+<p>Try this out in the interactive editor below (edit the code boxes), or in your local CSS document.</p>
+
+<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started1.html", '100%', 900)}} </p>
+
+<h2 id="Changing_the_default_behavior_of_elements">Changing the default behavior of elements</h2>
+
+<p>When we look at a well-marked up HTML document, even something as simple as our example, we can see how the browser is making the HTML readable by adding some default styling. Headings are large and bold and our list has bullets. This happens because browsers have internal stylesheets containing default styles, which they apply to all pages by default; without them all of the text would run together in a clump and we would have to style everything from scratch. All modern browsers display HTML content by default in pretty much the same way.</p>
+
+<p>However, you will often want something other than the choice the browser has made. This can be done by simply choosing the HTML element that you want to change, and using a CSS rule to change the way it looks.  A good example is our <code>&lt;ul&gt;</code>, an unordered list. It has list bullets, and if I decide I don't want those bullets I can remove them like so:</p>
+
+<pre class="brush: css notranslate">li {
+ list-style-type: none;
+}</pre>
+
+<p>Try adding this to your CSS now.</p>
+
+<p>The <code>list-style-type</code> property is a good property to look at on MDN to see which values are supported. Take a look at the page for <code><a href="/en-US/docs/Web/CSS/list-style-type">list-style-type</a></code> and you will find an interactive example at the top of the page to try some different values in, then all allowable values are detailed further down the page.</p>
+
+<p>Looking at that page you will discover that in addition to removing the list bullets you can change them — try changing them to square bullets by using a value of <code>square</code>.</p>
+
+<h2 id="Adding_a_class">Adding a class</h2>
+
+<p>So far we have styled elements based on their HTML element names. This works as long as you want all of the elements of that type in your document to look the same. Most of the time that isn't the case and so you will need to find a way to select a subset of the elements without changing the others. The most common way to do this is to add a class to your HTML element and target that class.</p>
+
+<p>In your HTML document, add a <a href="/en-US/docs/Web/HTML/Global_attributes/class">class attribute</a> to the second list item. Your list will now look like this:</p>
+
+<pre class="brush: html; highlight[3] notranslate">&lt;ul&gt;
+ &lt;li&gt;Item one&lt;/li&gt;
+ &lt;li class="special"&gt;Item two&lt;/li&gt;
+ &lt;li&gt;Item &lt;em&gt;three&lt;/em&gt;&lt;/li&gt;
+&lt;/ul&gt;</pre>
+
+<p>In your CSS you can target the class of <code>special</code> by creating a selector that starts with a full stop character. Add the following to your CSS file:</p>
+
+<pre class="brush: css notranslate">.special {
+ color: orange;
+ font-weight: bold;
+}</pre>
+
+<p>Save and refresh to see what the result is.</p>
+
+<p>You can apply the class of <code>special</code> to any element on your page that you want to have the same look as this list item. For example, you might want the <code>&lt;span&gt;</code> in the paragraph to also be orange and bold. Try adding a <code>class</code> of <code>special</code> to it, then reload your page and see what happens.</p>
+
+<p>Sometimes you will see rules with a selector that lists the HTML element selector along with the class:</p>
+
+<pre class="brush: css notranslate">li.special {
+ color: orange;
+ font-weight: bold;
+}</pre>
+
+<p>This syntax means "target any <code>li</code> element that has a class of special". If you were to do this then you would no longer be able to apply the class to a <code>&lt;span&gt;</code> or another element by simply adding the class to it; you would have to add that element to the list of selectors:</p>
+
+<pre class="brush: css notranslate">li.special,
+span.special {
+ color: orange;
+ font-weight: bold;
+}</pre>
+
+<p>As you can imagine, some classes might be applied to many elements and you don't want to have to keep editing your CSS every time something new needs to take on that style. Therefore it is sometimes best to bypass the element and simply refer to the class, unless you know that you want to create some special rules for one element alone, and perhaps want to make sure they are not applied to other things.</p>
+
+<h2 id="Styling_things_based_on_their_location_in_a_document">Styling things based on their location in a document</h2>
+
+<p>There are times when you will want something to look different based on where it is in the document. There are a number of selectors that can help you here, but for now we will look at just a couple. In our document are two <code>&lt;em&gt;</code> elements — one inside a paragraph and the other inside a list item. To select only an <code>&lt;em&gt;</code> that is nested inside an <code>&lt;li&gt;</code> element I can use a selector called the <strong>descendant combinator</strong>, which simply takes the form of a space between two other selectors.</p>
+
+<p>Add the following rule to your stylesheet.</p>
+
+<pre class="brush: css notranslate">li em {
+ color: rebeccapurple;
+}</pre>
+
+<p>This selector will select any <code>&lt;em&gt;</code> element that is inside (a descendant of) an <code>&lt;li&gt;</code>. So in your example document, you should find that the <code>&lt;em&gt;</code> in the third list item is now purple, but the one inside the paragraph is unchanged.</p>
+
+<p>Something else you might like to try is styling a paragraph when it comes directly after a heading at the same hierarchy level in the HTML. To do so place a <code>+</code>  (an <strong>adjacent sibling combinator</strong>) between the selectors.</p>
+
+<p>Try adding this rule to your stylesheet as well:</p>
+
+<pre class="brush: css notranslate">h1 + p {
+ font-size: 200%;
+}</pre>
+
+<p>The live example below includes the two rules above. Try adding a rule to make a span red, if it is inside a paragraph. You will know if you have it right as the span in the first paragraph will be red, but the one in the first list item will not change color.</p>
+
+<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started2.html", '100%', 1100)}}</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: As you can see, CSS gives us several ways to target elements, and we've only scratched the surface so far! We will be taking a proper look at all of these selectors and many more in our <a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">Selectors</a> articles later on in the course.</p>
+</div>
+
+<h2 id="Styling_things_based_on_state">Styling things based on state</h2>
+
+<p>The final type of styling we shall take a look at in this tutorial is the ability to style things based on their state. A straightforward example of this is when styling links. When we style a link we need to target the <code><a href="/en-US/docs/Web/HTML/Element/a">&lt;a&gt;</a></code> (anchor) element. This has different states depending on whether it is unvisited, visited, being hovered over, focused via the keyboard, or in the process of being clicked (activated). You can use CSS to target these different states — the CSS below styles unvisited links pink and visited links green.</p>
+
+<pre class="brush: css notranslate">a:link {
+ color: pink;
+}
+
+a:visited {
+ color: green;
+}</pre>
+
+<p>You can change the way the link looks when the user hovers over it, for example removing the underline, which is achieved by in the next rule:</p>
+
+<pre class="brush: css notranslate">a:hover {
+ text-decoration: none;
+}</pre>
+
+<p>In the live example below, you can play with different values for the various states of a link. I have added the rules above to it, and now realise that the pink color is quite light and hard to read — why not change that to a better color? Can you make the links bold?</p>
+
+<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started3.html", '100%', 900)}} </p>
+
+<p>We have removed the underline on our link on hover. You could remove the underline from all states of a link. It is worth remembering however that in a real site, you want to ensure that visitors know that a link is a link. Leaving the underline in place, can be an important clue for people to realize that some text inside a paragraph can be clicked on — this is the behavior they are used to. As with everything in CSS, there is the potential to make the document less accessible with your changes — we will aim to highlight potential pitfalls in appropriate places.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: you will often see mention of <a href="/en-US/docs/Learn/Accessibility">accessibility</a> in these lessons and across MDN. When we talk about accessibility we are referring to the requirement for our webpages to be understandable and usable by everyone.</p>
+
+<p>Your visitor may well be on a computer with a mouse or trackpad, or a phone with a touchscreen. Or they might be using a screenreader, which reads out the content of the document, or they may need to use much larger text, or be navigating the site using the keyboard only.</p>
+
+<p>A plain HTML document is generally accessible to everyone — as you start to style that document it is important that you don't make it less accessible.</p>
+</div>
+
+<h2 id="Combining_selectors_and_combinators">Combining selectors and combinators</h2>
+
+<p>It is worth noting that you can combine multiple selectors and combinators together. For example:</p>
+
+<pre class="brush: css notranslate">/* selects any &lt;span&gt; that is inside a &lt;p&gt;, which is inside an &lt;article&gt; */
+article p span { ... }
+
+/* selects any &lt;p&gt; that comes directly after a &lt;ul&gt;, which comes directly after an &lt;h1&gt; */
+h1 + ul + p { ... }</pre>
+
+<p>You can combine multiple types together, too. Try adding the following into your code:</p>
+
+<pre class="brush: css notranslate">body h1 + p .special {
+ color: yellow;
+ background-color: black;
+ padding: 5px;
+}</pre>
+
+<p>This will style any element with a class of <code>special</code>, which is inside a <code>&lt;p&gt;</code>, which comes just after an <code>&lt;h1&gt;</code>, which is inside a <code>&lt;body&gt;</code>. Phew!</p>
+
+<p>In the original HTML we provided, the only element styled is <code>&lt;span class="special"&gt;</code>.</p>
+
+<p>Don't worry if this seems complicated at the moment — you'll soon start to get the hang of it as you write more CSS.</p>
+
+<h2 id="Wrapping_up">Wrapping up</h2>
+
+<p>In this tutorial, we have taken a look at a number of ways in which you can style a document using CSS. We will be developing this knowledge as we move through the rest of the lessons. However you now already know enough to style text, apply CSS based on different ways of targeting elements in the document, and look up properties and values in the MDN documentation.</p>
+
+<p>In the next lesson we will be taking a look at how CSS is structured.</p>
+
+<p>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ol>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">What is CSS?</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">Getting started with CSS</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">How CSS is structured</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">How CSS works</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Using your new knowledge</a></li>
+</ol>
diff --git a/files/zh-tw/learn/css/first_steps/how_css_works/index.html b/files/zh-tw/learn/css/first_steps/how_css_works/index.html
new file mode 100644
index 0000000000..eebac03f5c
--- /dev/null
+++ b/files/zh-tw/learn/css/first_steps/how_css_works/index.html
@@ -0,0 +1,156 @@
+---
+title: How CSS works
+slug: Learn/CSS/First_steps/How_CSS_works
+translation_of: Learn/CSS/First_steps/How_CSS_works
+---
+<p>{{LearnSidebar}}<br>
+ {{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p>
+
+<p class="summary">我們已經學會基本 CSS 的用途與用法了,這堂課我們就來看看瀏覽器是如何將 CSS 和 HTML 變化成網頁的吧。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">需求:</th>
+ <td>基本電腦操作、<a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">已安裝基本的軟體</a>、 <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">檔案處理的基本知識</a>、HTML 基礎 (請參閱 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 入門</a>)。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解瀏覽器如何解析 CSS 和 HTML ,以及當瀏覽器遇到不認識的 CSS 時會發生什麼事。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="CSS_實際上是怎麼運作的?">CSS 實際上是怎麼運作的?</h2>
+
+<p>每當瀏覽器要顯示一份文件時,它得先為文件內容穿上樣式,這會歷經許多程序,我們已經列在下方了。記得喔,這只是非常簡化的版本,不同的瀏覽器會有自己的做法,不過原則上就是這樣。</p>
+
+<ol>
+ <li>瀏覽器載入 HTML (比如從網路上接收(receive))。</li>
+ <li>它將 {{Glossary("HTML")}} 轉換成 {{Glossary("DOM")}} (Document Object Model,文件物件模型),這東西是文件在電腦記憶體中的表示形式,詳情我們下個小節再說。</li>
+ <li>瀏覽器蒐集所有 HTML 文件連到的資源,像是嵌入網頁的圖片和影片等等,當然,裡面也包含 CSS!JavaScript 也是其中的一種資源,在此步驟的稍後就會處理,但我們先不要把事情弄得這麼複雜,這邊暫且不講。</li>
+ <li>瀏覽器解析 (parse) CSS,先按照選擇器的類型(如元素、類別、ID 等等),將規則放入相對應的「桶子(buckets)」裡。接著再依找到的選擇器,推算哪些規則應該要套用在哪些 DOM 節點上,並將樣式附著上去,最後產生的東西叫做轉譯樹(render tree)。</li>
+ <li>當規則都套用完畢後,開始按照網頁結構布局(layout)轉譯樹。</li>
+ <li>網頁被呈現在螢幕上,這個步驟稱為繪製(painting)。</li>
+</ol>
+
+<p>下面是此流程的示意圖。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/11781/rendering.svg" style="height: auto; max-width: 635px; width: 100%;"></p>
+
+<h2 id="關於_DOM">關於 DOM</h2>
+
+<p>DOM 有著一個樹狀結構,每個標記語言中的元素、屬性,以及文字片段都會是這個樹狀結構裡的{{Glossary("Node/DOM","節點")}}。每個節點與其他節點間的關係都有定義:若節點有子節點(child),則自己是他們的父節點(parent);若子節點為複數,則這些子節點稱彼此為兄弟/姊妹節點(sibling)。</p>
+
+<p>了解 DOM 對於設計、除錯以及維護 CSS 有相當大的助益,因為 DOM 正是 CSS 與文件內容的交會之處。當你要利用瀏覽器的開發者工具(DevTools)來查看元素套用的規則時,你就會見到它們。</p>
+
+<h2 id="一個活生生的_DOM_例子">一個活生生的 DOM 例子</h2>
+
+<p>我們就別絮絮叨叨了,直接看個簡單的例子,來瞭解 HTML 片段是如何轉換成 DOM 的吧。</p>
+
+<p>以下列 HTML 原始碼為例:</p>
+
+<pre class="brush: html">&lt;p&gt;
+ Let's use:
+ &lt;span&gt;Cascading&lt;/span&gt;
+ &lt;span&gt;Style&lt;/span&gt;
+ &lt;span&gt;Sheets&lt;/span&gt;
+&lt;/p&gt;
+</pre>
+
+<p>在 DOM 中,<code>&lt;p&gt;</code> 元素對應到的節點是一個父節點,它的子節點有一個純文字節點以及三個 <code>&lt;span&gt;</code> 元素節點,而 <code>SPAN</code> 節點也是有著純文字子節點的父節點:</p>
+
+<pre>P
+├─ "Let's use:"
+├─ SPAN
+| └─ "Cascading"
+├─ SPAN
+| └─ "Style"
+└─ SPAN
+ └─ "Sheets"
+</pre>
+
+<p>這就是瀏覽器如何解析上段的 HTML 片段的 — 它轉譯了以上的 DOM 樹,並產生了以下的輸出:</p>
+
+<p>{{EmbedLiveSample('一個活生生的_DOM_例子', '100%', 55)}}</p>
+
+<div class="hidden">
+<pre class="brush: css">p {margin:0;}</pre>
+</div>
+
+<h2 id="將_CSS_套用至_DOM">將 CSS 套用至 DOM</h2>
+
+<p>讓我們在上例中加入一些 CSS 來增添樣式。同樣地,HTML 如下:</p>
+
+<pre class="brush: html">&lt;p&gt;
+ Let's use:
+ &lt;span&gt;Cascading&lt;/span&gt;
+ &lt;span&gt;Style&lt;/span&gt;
+ &lt;span&gt;Sheets&lt;/span&gt;
+&lt;/p&gt;</pre>
+
+<p>假設我們把以下 CSS 套用上去:</p>
+
+<pre class="brush: css">span {
+ border: 1px solid black;
+ background-color: lime;
+}</pre>
+
+<p>瀏覽器會先解析 HTML 並產生 DOM 樹,然後再解析 CSS。因為這個 CSS 中只有使用 <code>span</code> 選擇器,所以瀏覽器可以很快地完成分類!接著它會將這個規則套用到每一個 <code>&lt;span&gt;</code> 上,並在螢幕上繪製出最終的畫面。</p>
+
+<p>現在輸出變成這樣:</p>
+
+<p>{{EmbedLiveSample('將_CSS_套用至_DOM', '100%', 55)}}</p>
+
+<p>在下個主題裡的<a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">為 CSS 除錯</a>中我們將會使用瀏覽器的 DevTools 來為 CSS 除錯,屆時我們將會學到更多瀏覽器解析 CSS 的方法。</p>
+
+<h2 id="瀏覽器遇到不認識的_CSS_時會發生什麼事?">瀏覽器遇到不認識的 CSS 時會發生什麼事?</h2>
+
+<p><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS#Browser_support">在先前的課程中</a>,我們曾提過瀏覽器並不會一次實作全部的新 CSS。此外,很多人都不是使用最新版的瀏覽器。要知道 CSS 是與時俱進的,會超出瀏覽器可辨認的範圍是很正常的事,所以啦,你可能會很好奇,當瀏覽器遇到它看不懂的 CSS 選擇器或宣告時會發生什麼事呢?</p>
+
+<p>答案就是裝作沒看到,繼續往下解析其它的CSS!</p>
+
+<p>如果瀏覽器在解析規則時,遇到它不認識的屬性或值,它會忽略它,並繼續解析下一個宣告。因此當它這麼做的時候,如果不是你拼錯字了,那就是那個屬性或值太新奇了,所以你的瀏覽器還沒有支援它。</p>
+
+<p>同樣地,如果瀏覽器遇到一個它不認識的選擇器時,它會忽略整條規則,並繼續解析其他規則。</p>
+
+<p>下面的例子使用英式英語來拼寫 color (也就是 colour),進而導致該屬性失效,因為現在瀏覽器看不懂它了。也因此下面的段落無法以藍字顯示,不過其他的 CSS 還是成功地套用上去了,只有無效的會被忽略掉。</p>
+
+<div id="Skipping_example">
+<pre class="brush: html">&lt;p&gt; I want this text to be large, bold and blue.&lt;/p&gt;</pre>
+
+<pre class="brush: css">p {
+ font-weight: bold;
+ colour: blue; /* incorrect spelling of the color property */
+ font-size: 200%;
+}</pre>
+</div>
+
+<p>{{EmbedLiveSample('Skipping_example', '100%', 200)}}</p>
+
+<p>這樣做有個很大的好處,就是你可以放心地利用新 CSS 做出很炫炮的效果,而不用擔心瀏覽器不支援時會出錯 — 反正差別只在於那個新特性有或沒有而已。再加上 CSS 層疊 (cascade) 的天性,只要你提供兩條具有相同具體程度(specificity)的規則,就能讓不支援的瀏覽器套用另一條規則。</p>
+
+<p>這在想要使用某個剛推出的值,但它還未普及時非常有用。舉個例子,一些老舊的瀏覽器不支援以 <code>calc()</code> 來當作值,所以當我想要用它來決定寬的時候,可能會先寫一個備用的寬(以像素為單位的值),然後再寫一個值為 <code>calc</code><code>(100% - 50px)</code> 的寬。這樣一來,老舊的瀏覽器會使用像素版本 ,並忽略 <code>calc()</code> 版本,因為它們看不懂這個;而新的瀏覽器則會先解析像素版本,然後再將 <code>calc()</code> 版本覆寫上去,因為它比較晚出現。</p>
+
+<pre class="brush: css">.box {
+ width: 500px;
+ width: calc(100% - 50px);
+}</pre>
+
+<p>我們在之後的課程中還會學到更多支援不同瀏覽器的方法。</p>
+
+<h2 id="最後">最後</h2>
+
+<p>你已經快完成這個主題了,但是還差臨門一腳,在下篇文章裡,你將會<a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">利用你學到的新知識</a>來重新美化一個範例,並在過程中重溫你所學到的 CSS 技巧。</p>
+
+<p>{{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p>
+
+<h2 id="在這個主題中">在這個主題中</h2>
+
+<ol>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 是什麼?</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 入門</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 是如何組織的</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 是如何運作的</a></li>
+ <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">利用你學到的新知識</a></li>
+</ol>
diff --git a/files/zh-tw/learn/css/first_steps/index.html b/files/zh-tw/learn/css/first_steps/index.html
new file mode 100644
index 0000000000..ee9dc82a1d
--- /dev/null
+++ b/files/zh-tw/learn/css/first_steps/index.html
@@ -0,0 +1,59 @@
+---
+title: 初探 CSS
+slug: Learn/CSS/First_steps
+tags:
+ - CSS
+ - 入門
+ - 單元
+ - 學習
+ - 新手
+ - 新手教學
+translation_of: Learn/CSS/First_steps
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">CSS(階層式樣式表)被用來設定網頁的樣式及佈局。舉例來說,改變字體、顏色、尺寸以及擺放您的內容、拆分為多欄,或是添加動畫效果和其它裝飾的特性。這個單元提供一個平緩的學習路徑,透過介紹 CSS 的工作原理、語法的樣式,以及如何在 HTML 中添加樣式設定。</p>
+
+<h3 class="summary" id="想要成為網頁前端開發員?">想要成為網頁前端開發員?</h3>
+
+<p class="summary">我們整理了一門課程,包含了您實現目標所需要的所有基本知識。</p>
+
+<p><a class="cta primary" href="/docs/Learn/Front-end_web_developer">開始</a></p>
+
+<h2 id="先備知識">先備知識</h2>
+
+<p>開始這個單元之前,您應該具備:</p>
+
+<ol>
+ <li>基本熟悉電腦的操作,以及網路的使用(即:在網路查資料,看看內容)。</li>
+ <li>設定好一個基本的工作環境(參考<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a>單元),並知道如何建立以及管檔案(參考<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Dealing_with_files">檔案的管理</a>單元)。</li>
+ <li>對 HTML 有基本的認識,像是 <a href="/zh-tw/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a>單元裡所提到的。 </li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>如果您使用的電腦/平板/或其它裝置上,無法建立您所需要的檔案。您可以在像是 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://glitch.com/">Glitch</a> 的線上程式編輯平台上嘗試(絕大部分的)範例程式。</p>
+</div>
+
+<h2 id="導覽">導覽</h2>
+
+<p>這個單元包含以下的主題,會帶你瀏覽所有 CSS 的基本理論,並提供您一些測試技巧的機會:</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps/What_is_CSS">CSS 是什麼?</a></dt>
+ <dd><strong>{{Glossary("CSS")}}</strong> (階層式樣式表)讓您能夠建立好看的網頁,但是它骨子是是怎麼運作的?這個主題用一個簡單的語法範例來解釋 CSS 是什麼,並涵蓋有關這個語言的一些關鍵術語。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps/Getting_started">CSS 入門</a></dt>
+ <dd>這個主題中,我們將把 CSS 套用到一個簡單的 HTML 文件上,逐步學習有關這個語言的一些實用知識。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 的結構</a></dt>
+ <dd>現在您對 CSS 是什麼以及基本使用方法有了一些概念,是時候去更深入看看這個語言的結構了。我們在這裡討論了許多的觀念;如果之後您對任何概念感到模糊,可以到這裡來回顧。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps/How_CSS_works">CSS 的運作方式</a></dt>
+ <dd>我們已經學到了什麼是 CSS 以及如何寫一個簡單樣式表的基礎概念。我們會在這堂課裡看看瀏覽器是如何依據 CSS 和 HTML 的內容轉化為網頁的呈現。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps/Using_your_new_knowledge">使用您的新知識</a></dt>
+ <dd>透過你在前面堂課所學到的東西,你應該會發現您可以對簡單的文字內套用 CSS 設定,加入您想要的樣式。這個主題給您一個機會來做這件事。</dd>
+</dl>
+
+<h2 id="參見">參見</h2>
+
+<dl>
+ <dt><a href="https://teach.mozilla.org/activities/intermediate-web-lit/">Intermediate Web Literacy 1: Intro to CSS</a></dt>
+ <dd>一個很好的 Mozilla 基礎課程,探討及測試許多 CSS 技巧。了解關於在網頁上設定 HTML 元素樣式、 CSS 選擇器、屬性、數值。</dd>
+</dl>
diff --git a/files/zh-tw/learn/css/first_steps/what_is_css/index.html b/files/zh-tw/learn/css/first_steps/what_is_css/index.html
new file mode 100644
index 0000000000..3eb04bcbe1
--- /dev/null
+++ b/files/zh-tw/learn/css/first_steps/what_is_css/index.html
@@ -0,0 +1,131 @@
+---
+title: CSS 是什麼?
+slug: Learn/CSS/First_steps/What_is_CSS
+tags:
+ - CSS
+ - CSS 入門
+ - 初學者
+ - 單元
+ - 學習
+ - 技術指引
+ - 語法
+translation_of: Learn/CSS/First_steps/What_is_CSS
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}</div>
+
+<p class="summary"><strong>{{Glossary("CSS")}}</strong> (階層式樣式表)可以讓您建立出好看的網頁,但是它背後是怎麼運作的?在這個主題裡,藉由簡單的語法範例來說明 CSS 是什麼,以及含蓋這個語言的一些關鍵項目。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基本的電腦概念、能夠<a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a>,基本<a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各種檔案打交道</a>的能力,以及 HTML 的基礎(由<a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 入門</a>學到)。</td>
+ </tr>
+ <tr>
+ <th scope="row">學習目標:</th>
+ <td>學到 CSS 是什麼。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>在 <a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 入門</a>單元中,我們含蓋了什麼是 HTML 以及它是如何被用來標記文件。這些文件能夠被瀏覽器讀取,標題的文字會看起來比一般段落更大,段落之間會換行並帶有間隔。連結會帶有顏色及底線,讓它與其它一般的文字有區別。您所看到的這些是瀏覽器的預設樣式,用來確保當作者沒有指定任何樣式的狀況下,仍有一些非常基本的樣式被套用上,好讓內容基本上能夠被閱讀(如下圖所示)。</p>
+
+<p><img alt="The default styles used by a browser" src="https://mdn.mozillademos.org/files/16493/html-example.png" style="border: 1px solid #cccccc; height: 594px; width: 1385px;"></p>
+
+<p>然而,如果所有的網站都長這個樣子,網路世界將是個很無趣的地方。您能使用 CSS 對 HTML 元件的樣子作更多控制,將這些標記以任何您喜歡的設計作調整。</p>
+
+<p>看看下面的影片,了解更多關於瀏覽器預設樣式(可開 CC 字幕並自動翻譯為中文)。</p>
+
+<p>{{EmbedYouTube("spK_S0HfzFw")}}</p>
+
+<h2 id="CSS_是作什麼用的?">CSS 是作什麼用的?</h2>
+
+<p>如同我們前面所提到的, CSS 是一種用來指定文件該用什麼方式呈現的語言,可以定義它們的樣式、布局…等。</p>
+
+<p><strong>文件</strong>通常指的是使用標記語言的文字檔案,{{Glossary("HTML")}} 是其中最常見的,但是您也可能遇到其它例如 {{Glossary("SVG")}} 或 {{Glossary("XML")}} 的標記語言。</p>
+
+<p>所謂的<strong>呈現</strong>文件,指的是將文件轉換為你的讀者可用的形式。像是 {{Glossary("Mozilla Firefox","Firefox")}} 、 {{Glossary("Google Chrome","Chrome")}} 或 {{Glossary("Microsoft Edge","Edge")}} 這類的{{Glossary("browser","瀏灠器")}},是設計來將文件視覺化,再呈現電腦螢幕、投影機上或是由列表機列印出來。</p>
+
+<div class="blockIndicator note">
+<p><strong>注意:</strong>瀏覽器有時候被稱為 {{Glossary("User agent","user agent")}}(用戶終端),它基本上泛指電腦裡安裝的應用軟體。雖然並不是唯一,當我們在討論 CSS 的時候,用戶終端主要指的是瀏覽器。至於其它的用戶終端,有些能夠將 HTML 和 CSS 轉換為 PDF 再列印出來。</p>
+</div>
+
+<p>CSS 可以用在很基本文字樣式上頭,像是改變標題和連結的<a href="/zh-TW/docs/Web/CSS/color_value">顏色</a>及<a href="/zh-TW/docs/Web/CSS/font-size">尺寸</a>。它可以用在建立布局,像是<a href="/zh-TW/docs/Web/CSS/Layout_cookbook/Column_layouts">將原本單欄的文字內容加入布局</a>,劃分出主要的內容以及包含相關資訊的側邊欄。它甚至可以用在建立<a href="/zh-TW/docs/Web/CSS/CSS_Animations">動畫</a>效果。點進上面的連結,看看相關的例子。</p>
+
+<h2 id="CSS_語法">CSS 語法</h2>
+
+<p>CSS 是一種基於規則的語言,您對網頁裡特定或一群元素指定一系列的規則。舉例來說:「我要讓頁面裡的主標題,以紅色且大號的字體呈現」。</p>
+
+<p>下面這段語法是為了實現上面的需求,用簡單 CSS 規則示範:</p>
+
+<pre class="brush: css notranslate">h1 {
+ color: red;
+ font-size: 5em;
+}</pre>
+
+<p>樣式規則以一個{{Glossary("CSS Selector", "選擇器")}}開始。它<em>選擇</em>了您預計改變樣式的 HTML 元素。在這個例子中,我們要調整的是第一級的標題元素({{htmlelement("h1")}})。</p>
+
+<p>接著我們跟著一組花括號 <code>{ }</code>,裡面是一到多個<strong>聲明</strong>,它的形式是一對一對<strong>屬性名稱</strong>和<strong>屬性內容</strong>的組合。每一對聲明會將我們選中元素的屬性,付予我們所想要設定的內容(或數值)。</p>
+
+<p>在冒號(:)前面的是屬性的名稱,後面的是屬性內容(值)。CSS 的{{Glossary("property/CSS","屬性")}}依照其類型可以使用的值而有所不同。在我們的例子中,有個 <code>color</code> 屬性,它可以設定各種<a href="/zh-TW/docs/Learn/CSS/Building_blocks/Values_and_units#Color">顏色值</a>。而 <code>font-size</code> 屬性則可以採用不同<a href="/zh-TW/docs/Learn/CSS/Building_blocks/Values_and_units#Numbers_lengths_and_percentages">尺寸單位</a>的值。</p>
+
+<p>一個 CSS 樣式表包含了許多這樣子的規則,一個接著一個。</p>
+
+<pre class="brush: css notranslate">h1 {
+ color: red;
+ font-size: 5em;
+}
+
+p {
+ color: black;
+}</pre>
+
+<p>你將會發些有些值很容易學會,而另一些則需要查資料確認。MDN 上有各個屬性的獨立頁面讓您能查到屬性及其可使用的值,在你忘記了或是想知道其它可能用法的時候提供一個快速的路徑。</p>
+
+<div class="blockIndicator note">
+<p><strong>注意:</strong> 您可以在 MDN 的 <a href="/zh-TW/docs/Web/CSS/Reference">CSS 參考資源</a>找到所有的 CSS 屬性(以及其它 CSS 特性)頁面的連結。 另外,當您需要得到某個 CSS 特性的更多資訊,應該去習慣使用「mdn <em>特性名稱</em>」的方式在您喜歡搜尋引擊上搜尋。舉例來說,嘗試以「mdn color」和「mdn font-size」作關鍵字搜尋!</p>
+</div>
+
+<h2 id="CSS_的各個主題(單元)">CSS 的各個主題(單元)</h2>
+
+<p>由於 CSS 有太多的項目可以進行設定,因此將這個語言依不同主題切分出單元。您將會在探索 MDN 的時候看到這些單元,並發現許多文章是圍繞著特定單元所組織的。舉例來說,您可以在 MDN 關於<a href="/zh-TW/docs/Web/CSS/CSS_Backgrounds_and_Borders">背景與邊框</a>的單元裡,看到它的目的,以及其包含了哪些不同的屬性及特性。 您也將在文末發現到相關 <em>CSS 規範</em>的連結。</p>
+
+<p>在這裡不用太煩惱 CSS 的架構,可以讓尋找資訊變得簡單一些。例如說,當你知道某個屬性可能用在其它類似的東西上,因此它們可能被放在同一個規範(單元)裡。</p>
+
+<p>舉個特別的例子,讓我們回到背景與邊框的單元中,您可能會認為在邏輯上 <code><a href="/zh-TW/docs/Web/CSS/background-color">background-color</a></code> 和 <code><a href="/zh-TW/docs/Web/CSS/border-color">border-color</a></code> 會在同一個單元裡被定義。所以您猜對了。</p>
+
+<h3 id="CSS_規範">CSS 規範</h3>
+
+<p>所有網路標準技術(HTML、CSS、JavaScript…等)都被定義在稱為定義(specifications 或簡稱 specs)巨型文件中,由像是 {{glossary("W3C")}}、{{glossary("WHATWG")}}、{{glossary("ECMA")}} 或 {{glossary("Khronos")}} 之類的標準組織所發布,並且很精確地定義這些技術的行為方式。</p>
+
+<p>CSS 並沒有什麼不同,它由 W3C 一個被稱為 <a href="https://www.w3.org/Style/CSS/">CSS 工作組</a>的團體所發展。這個團體是由對 CSS 感興趣的瀏覽器供應商和其它公司的代表所組成。還有其它被稱為<em>邀請專家</em>的人,與其它的成員組織無關,可以獨立的發聲。</p>
+
+<p>新的 CSS 特性被 CSS 工作組所發展、定義。有時候是因為特定瀏覽器對某個功能有興趣,而有時候是因為網站設計師與開發人員的要求,還有一些時候是工作組本身定義的需求。CSS 正不斷發展,新的可用特性正在出現。然而,每個人很努力達到的 CSS 重要方針,是不要往會破壞舊網站的方向進行改變。一個在 2000 年建立的網站,使用了當時能用的 CSS 特性,應該到今天仍能夠在瀏覽器上使用。</p>
+
+<p>作為一個 CSS 新手,你會發現 CSS 的規範不勝枚舉,它們是用來給開發用戶端程式的開發者實作功能所使用,而不是讓網站開發人員閱讀來了解 CSS。許多經驗的豐富的開發者,寧願看 MDN 上的文件或其它指引。然而,知道規範的存在還是有價值的,可以了解它們與您正使用的 CSS 之間的關係,瀏覽器支援(如下)以及相關定義。</p>
+
+<h2 id="瀏覽器支援">瀏覽器支援</h2>
+
+<p>被定義好的 CSS 特性,只有被一個或更多瀏覽器實作出來之後,才會在我們開發網頁上面有所幫助。這意味著已經編寫了程式,可以將 CSS 檔案裡的設定轉換為輸出在畫面上的結果。我們將在 <a href="/zh-TW/docs/Learn/CSS/First_steps/How_CSS_works">CSS 工作原理</a>中詳細介紹這個過程。一個(新)特性被所有瀏覽器同時實作出來是不常見的,通常會缺了幾個,CSS 某些部分您可以在某些瀏覽器上使用,然而在其它瀏覽器人則沒有作用。基於這個原因,確認特性被實作的狀況是有用的。在每個 MDN 的資源頁面上,您可以看到感興趣的屬性現在的狀態,因此您可以確定能不能把它使用在網站上。</p>
+
+<p>以下是 CSS <code><a href="/zh-TW/docs/Web/CSS/font-family">font-family</a></code> 屬性的支援狀態表。</p>
+
+<p>{{Compat("css.properties.font-family")}}</p>
+
+<h2 id="下一步…">下一步…</h2>
+
+<p>現在您已經知卜 CSS 是什麼,接著移動到 <a href="/zh-TW/docs/Learn/CSS/First_steps/Getting_started">CSS 入門</a>單元,您可以在這裡開始寫一些 CSS。</p>
+
+<p>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}</p>
+
+<h2 id="在這個單元中">在這個單元中</h2>
+
+<ol>
+ <li><a href="/zh-TW/docs/Learn/CSS/First_steps/What_is_CSS">CSS 是什麼?</a></li>
+ <li><a href="/zh-TW/docs/Learn/CSS/First_steps/Getting_started">CSS 入門</a></li>
+ <li><a href="/zh-TW/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 的結構</a></li>
+ <li><a href="/zh-TW/docs/Learn/CSS/First_steps/How_CSS_works">CSS 工作原理</a></li>
+ <li><a href="/zh-TW/docs/Learn/CSS/First_steps/Using_your_new_knowledge">使用您的新知識</a></li>
+</ol>
diff --git a/files/zh-tw/learn/css/index.html b/files/zh-tw/learn/css/index.html
new file mode 100644
index 0000000000..eedd54f655
--- /dev/null
+++ b/files/zh-tw/learn/css/index.html
@@ -0,0 +1,72 @@
+---
+title: CSS(樣式表)
+slug: Learn/CSS
+tags:
+ - CSS
+ - 入門
+ - 初學者
+ - 撰寫程式
+ - 樣式
+ - 風格
+translation_of: Learn/CSS
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary"><span class="st">階層式</span><span class="notranslate">樣式表</span>({{glossary("CSS")}})是學習完 {{glossary("HTML")}} 之後,您應該學習的第一項技術。HTML 用於定義內容的架構與語意,CSS 則是用來設定樣式與佈局方式。舉例來說,您可以使用 CSS 來改變內容的字體、顏色、字型大小、間距、拆分成多欄,或是加入動畫和其他裝飾性質的特性。</p>
+
+<h3 class="summary" id="想要成為_Web_前端開發人員?">想要成為 Web 前端開發人員?</h3>
+
+<p>我們整理了一門課程,包含了你實現目標需要的所有基礎知識。</p>
+
+<p><a class="cta primary" href="/docs/Learn/Front-end_web_developer">開始</a></p>
+
+<h2 id="先備知識">先備知識</h2>
+
+<p>在嘗試 CSS 之前,您應該先了解基本的 HTML 知識。我們建議先閱讀 <a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a>單元。在這個單元你會學習到關於:</p>
+
+<ul>
+ <li>CSS,由 <a href="/zh-TW/docs/Learn/CSS/First_steps">CSS 介紹</a>單元開始</li>
+ <li>更進階 <a href="/zh-TW/docs/Learn/HTML#模組">HTML 模組</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 以及它如何在網頁加上動態的功能</li>
+</ul>
+
+<p>在您了解最基礎的 HTML 運作思維後,我們推薦您同時學習 HTML 與 CSS,使兩者之間互相搭配。因為 HTML 搭配上 CSS 會變得無比有趣,兩者是密不可分的,您無法在不理解 HTML 的情況下獨立學習 CSS。</p>
+
+<p>在開始這個主題之前,您應該要有電腦的基礎使用概念以及使用網頁的經驗(單純地瀏覽、查看內容)。您應該要有一個已經設定的好的基本工作環境,如同<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a>所敘述的,知道怎麼建立與管理檔案,如同<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Dealing_with_files">處理檔案</a>提到的內容。這兩者都是 <a href="/zh-TW/docs/Learn/Getting_started_with_the_web">Web 入門</a>裡初學者單元中一部分。</p>
+
+<p>建議您在開始課程前先閱讀 <a href="/zh-TW/docs/Learn/Getting_started_with_the_web">Web 入門</a>,不過並非絕對必要,儘量那裡有許多詳細的介紹,大部分 CSS 概念在我們的 CSS 入門單元中也會含蓋到。</p>
+
+<h2 id="單元">單元</h2>
+
+<p>這個主題按建議的學習順序包含以下的單元。強烈建議您從第一項開始。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/CSS/First_steps">CSS 入門</a></dt>
+ <dd>CSS(<span class="st">階層式</span>樣式表)用來設定網頁的樣式及佈局,例如:改變文字的字體、顏色、大小及間距以及拆分為多欄,或是增加動畫或裝飾性的效果。這個單元提供一個溫和的路徑,讓您逐漸熟悉 CSS 的基礎概念,包含它的運作方式,語法是什麼樣子,以及如何開始在 HTML 裡添加樣式。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/Building_blocks">CSS 的組成</a></dt>
+ <dd>這個單元接續在 <a href="/zh_TW/docs/Learn/CSS/First_steps">CSS 入門</a>之後,現在已經熟悉了這門語言的語法,並有了一些基本的使用經驗,是時候再深入一些。這個單元關注於疊加(cascade)和繼承(inheritance)規則、所有可用的選擇器類型、單位、尺寸、背景與邊框的樣式、除錯,以及其它更多的。</dd>
+ <dd>這裡的目的是在進入更進階的主題,像是<a href="/zh_TW/docs/Learn/CSS/Styling_text">文字樣式</a>及 <a href="/zh_TW/docs/Learn/CSS/CSS_layout">CSS 佈局</a>之前,給您一個足以寫出合格 CSS 的工具包並幫助您了解所有的基礎理論。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/Styling_text">裝飾文字</a></dt>
+ <dd>在含蓋了 CSS 語言基本的部分之後,下一個帶給您的 CSS 主題會專注於文字樣式的裝飾上,您將最常用 CSS 作的事情之一。在這裡,我們文字樣式的基礎,包括設定字體、粗細、斜體、行距與字距、陰影與其它的文字效果。整個單元圍繞於在您的頁面上套用選擇的字體,以及對清單和連結進行樣式調整。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS/CSS_layout">CSS 的布局</a></dt>
+ <dd>到了這邊,我們已經看過了 CSS 的基礎知識,如何裝飾文字,如何裝飾並控制您內容所在的區。現在是時候來看看如合將您的這些區塊擺放到正確的位置,並能依不同的可視空間進行調整。我們已經含蓋了必須的先備知識,所以我們現在可以深入到 CSS 的布局,看看不同的顯示設定,像是新的佈局工具 flexbox 、 CSS grid 和定位(position)以及一些您可能仍想要了解的早期技術。</dd>
+</dl>
+
+<h2 id="解決常見的_CSS_問題">解決常見的 CSS 問題</h2>
+
+<p><a href="/zh-TW/docs/Learn/CSS/Howto">使用 CSS 解決常見的問題</a>裡提供了許多單元的連結,其內容說明如何使用 CSS 解決在建立網頁時常見的問題。</p>
+
+<p>在一開始,您主要將顏色套用到 HTML 元素或是背景;改變元素的大小、形狀和位置,然後添加、定義元素的邊框。當您對 CSS 的基礎知識有深刻的理解,就沒有太多作不到的事情。學習 CSS 其中一項最棒的事情,是當你了解了基本原理,通常您就能很好的抓到「什麼能作」、「什麼作不到」的感覺,既使是在您還不確切的知道要怎麼實現它的狀況下。</p>
+
+<h2 id="怪異的_CSS">怪異的 CSS</h2>
+
+<p>CSS 與您將遇到程式語言或設計工具在運作上有點不太一樣。為什麼要用這種方式運作?在下面影片中, Miriam Suzanne 解釋為什麼 CSS 是這樣運作,以及為什麼會這樣子發展。(可以利用字幕翻譯功能,將 CC 字幕轉為中文)</p>
+
+<p>{{EmbedYouTube("aHUtMbJw8iA")}}</p>
+
+<h2 id="相關資源">相關資源</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Web/CSS">MDN 中的 CSS 資源</a></dt>
+ <dd>在 MDN 網站裡,CSS 文件的主要入口,您將可以在這裡找到所有 CSS 語言的所有特性,以及它們詳細的參考資訊。想要知道一個屬性可以套用的所有設定嗎?這是一個不錯的地方。</dd>
+</dl>
diff --git a/files/zh-tw/learn/css/styling_text/index.html b/files/zh-tw/learn/css/styling_text/index.html
new file mode 100644
index 0000000000..2d5368fdfe
--- /dev/null
+++ b/files/zh-tw/learn/css/styling_text/index.html
@@ -0,0 +1,40 @@
+---
+title: 文字樣式
+slug: Learn/CSS/Styling_text
+translation_of: Learn/CSS/Styling_text
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">託了 CSS 語言基礎的福,下一個讓你專攻的 CSS 主題是文字樣式——最常會在 CSS 使用的部分。讓我們來看看文字樣式的基礎知識,包含設定字形、粗細、斜體、行距與字距、陰影以及更多文字功能。我們會套用客製化字形、設定清單樣式和連結樣式到你的網頁來完成這個單元。</p>
+
+<h2 id="先備知識">先備知識</h2>
+
+<p>在開始這個單元之前,你應該先熟悉基礎的 HTML,如 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a> 這個單元所討論的,並且要對 CSS 的基礎感到輕鬆,如 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 介紹</a> 討論的。</p>
+
+<div class="note">
+<p><strong>Note</strong>: If you are working on a computer/tablet/other device where you don't have the ability to create your own files, you could try out (most of) the code examples in an online coding program such as <a href="http://jsbin.com/">JSBin</a>,<a href="https://codepen.io/"> CodePen</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p>
+</div>
+
+<h2 id="指南">指南</h2>
+
+<p>這個單元包含以下的文章會教導你?設定 HTML 文字內容樣式的全部要領。</p>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">基本的字形及文字樣式</a></dt>
+ <dd>In this article we go through all the basics of text/font styling in detail, including setting font weight, family and style, font shorthand, text alignment and other effects, and line and letter spacing.</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">清單樣式</a></dt>
+ <dd>Lists behave like any other text for the most part, but there are some CSS properties specific to lists that you need to know about, and some best practices to consider. This article explains all.</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">連結樣式</a></dt>
+ <dd>When styling links, it is important to understand how to make use of pseudo-classes to style link states effectively, and how to style links for use in common varied interface features such as navigation menus and tabs. We'll look at all these topics in this article.</dd>
+ <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">網頁字形</a></dt>
+ <dd>Here we will explore web fonts in detail — these allow you to download custom fonts along with your web page, to allow for more varied, custom text styling.</dd>
+</dl>
+
+<h2 id="Assessments">Assessments</h2>
+
+<p>The following assessments will test your understanding of the text styling techniques covered in the guides above.</p>
+
+<dl>
+ <dt><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Typesetting a community school homepage</a></dt>
+ <dd>In this assessment we'll test your understanding of styling text by getting you to style the text for a community school's homepage.</dd>
+</dl>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html
new file mode 100644
index 0000000000..f51f584cf8
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/css_basics/index.html
@@ -0,0 +1,273 @@
+---
+title: CSS 基本
+slug: Learn/Getting_started_with_the_web/CSS_basics
+translation_of: Learn/Getting_started_with_the_web/CSS_basics
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p><strong>階層樣式表</strong> (Cascading Stylesheets;CSS) 可用以塑造網站的特殊風格。例如這段文字要用一般的黑色,或是改用紅色標明重點?某段重要內容應該置於畫面的何處?想用什麼背景圖片及顏色裝飾你的網站?〈<a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a>〉帶你入門。</p>
+</div>
+
+<h2 id="CSS到底是什麼">CSS到底是什麼?</h2>
+
+<p>跟 HTML 一樣,CSS 既非標準程式語言,也不是標記語言, 而是一種風格頁面語言(<em>style sheet language</em>):它能讓你在 HTML 文件中的元素(element)上套用不同的頁面樣式(style)。例如, 當想要將 HTML 頁面上所有段落元素(paragraph elements)裡的文字<strong>全部</strong>轉換成紅色,你會在CSS裡寫:</p>
+
+<pre class="brush: css notranslate" dir="rtl">p {
+ color: red;
+}</pre>
+
+<p>試看看在你的編輯器上建立新的檔案 <code>style.css</code> 並貼上這三行 CSS 程式碼,並存到你的<code>styles</code> 目錄。</p>
+
+<p>但我們還需要把 CSS 套用在 HTML 文件上。否則 CSS 的樣式效果,不會在瀏覽器的 HTML 檔案顯示。(如果你還未跟上我們的專案,請閱讀 <a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a> 和 <a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a> 以找出你需要什麼)</p>
+
+<ol>
+ <li>打開 <code>index.html</code> 文件,然後將下面一行貼到 head,也就是 <code>&lt;head&gt;</code> 和 <code>&lt;/head&gt;</code> 標籤之間。
+
+ <pre class="brush: html notranslate">&lt;link href="styles/style.css" rel="stylesheet" type="text/css"&gt;</pre>
+ </li>
+ <li>存檔 <code>index.html</code> 並且在瀏覽器載入。你應該可以看到下面的頁面。</li>
+</ol>
+
+<p><img alt="A mozilla logo and some paragraphs. The paragraph text has been styled red by our css." src="https://mdn.mozillademos.org/files/9435/website-screenshot-styled.png" style="display: block; height: 832px; margin: 0px auto; width: 711px;">如果你的段落文字現在變成紅色, 恭喜, 你已經成功撰寫你的第一份 CSS!</p>
+
+<h3 id="解析_CSS_ruleset">解析 CSS ruleset</h3>
+
+<p>讓我們深入解析下列的 CSS:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9461/css-declaration-small.png" style="display: block; height: 480px; margin: 0px auto; width: 850px;"></p>
+
+<p>整個架構我們稱為規則集<strong> (rule set),或是簡稱為規則 (rule) </strong>也可以。(也注意名字裡面的單獨部分)</p>
+
+<dl>
+ <dt>選擇器(Selector)</dt>
+ <dd>在這個規則的最前頭為 HTML 的元素名。它將決定你 HTML 裡什麼元素將被你接下來的設定影響(在這個範例中,就是 段落元素 <code>p</code>)。若要改變欲影響的元素,只要更改選擇器就行了。</dd>
+ <dt>宣告(Declaration)</dt>
+ <dd>單一個規則,例如 <code>color: red;</code> 指定了這個元素的呈現樣貌。</dd>
+ <dt>屬性 (Properties)</dt>
+ <dd>修改屬性是改變你HTML元素的一種方法 . (在這範例中, <code>color</code> 是段落(<code>p</code>)元素的一種屬性.) 在CSS中, 你可以選擇哪些屬性用來影響 rule.</dd>
+ <dt>屬性值 (Property value)</dt>
+ <dd><strong>屬性值 </strong> 就是位於屬性右邊,在冒號(<code>:</code>)之後,從眾多的可能樣式選出一個給予屬性(範例中就是從眾多的 <code>color</code> 樣式中選出 <code>red</code>)</dd>
+</dl>
+
+<p>注意語法其他重要的部分:</p>
+
+<ul>
+ <li>每一個規則當中,除了選擇器名稱以外,其他都必須被大括號(<code>{}</code>)給包住.</li>
+ <li>在每一個宣告裡面,屬性跟屬性值之間必須用冒號(<code>:</code>) 做區分。</li>
+ <li>在每一個規則裡面可以包含有許多宣告,但不同的宣告之間必須使用分號 (<code>;</code>) 來區分。</li>
+</ul>
+
+<p>下面是一個簡單的CSS規則範例。注意每個宣告都是以冒號(<code>:</code>)來指定屬性值,並且宣告之間都是以分號做區分 (<code>;</code>) 。</p>
+
+<pre class="brush: css notranslate">p {
+ color: red;
+ width: 500px;
+ border: 1px solid black;
+}</pre>
+
+<h3 id="選擇多個元素">選擇多個元素</h3>
+
+<p>你可以選擇數種元素(elements)並同時用在同一個 rule set 上。可以用逗號(,)包含數個選擇器,如:</p>
+
+<pre class="brush: css notranslate">p,li,h1 {
+ color: red;
+}</pre>
+
+<h3 id="選擇器的不同類型">選擇器的不同類型</h3>
+
+<p>選擇器有很多種類。到目前為止,我們只看到了<strong>元素選擇器(element selector)</strong>,它選取了指定 HTML 檔案下的所有選定元素。不過,我們還有更多選擇器。以下有一些常見類型:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">選擇器名</th>
+ <th scope="col">選取/控制什麼</th>
+ <th scope="col">範例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>元素選擇器,有時也稱作標籤或類型選擇器(Element selector、tag or type selector)</td>
+ <td>指定所有 HTML 元素中的特定元素</td>
+ <td><code>p</code><br>
+ 選取 <code>&lt;p&gt;</code></td>
+ </tr>
+ <tr>
+ <td>ID 選擇器(ID selector)</td>
+ <td>指定頁面上的特定 ID 元素(單一 HTML 頁面中,每個 ID 只能綁定一個元素)</td>
+ <td><code>#my-id</code><br>
+ 控制 <code>&lt;p id="my-id"&gt;</code> 或 <code>&lt;a id="my-id"&gt;</code></td>
+ </tr>
+ <tr>
+ <td>Class 選擇器(Class selector)</td>
+ <td>指定頁面上的特定 class 元素(單一 HTML 頁面中,class 屬性可以被多個元素使用)</td>
+ <td><code>.my-class</code><br>
+ 控制 <code>&lt;p class="my-class"&gt;</code> 與 <code>&lt;a class="my-class"&gt;</code></td>
+ </tr>
+ <tr>
+ <td>屬性選擇器(Attribute selector)</td>
+ <td>指定頁面上的特定屬性元素</td>
+ <td><code>img[src]</code><br>
+ 控制 <code>&lt;img src="myimage.png"&gt;</code> 但不控制 <code>&lt;img&gt;</code></td>
+ </tr>
+ <tr>
+ <td>虛擬 class 選擇器(Pseudo-class selector)</td>
+ <td>在特定的情況下,指定頁面的元素,例如懸停時。</td>
+ <td>
+ <p><code>a:hover</code><br>
+ 控制 <code>&lt;a&gt;</code>, 但只有在滑鼠游標停留在連結上時.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>還有很多值得探索的選擇器,你可以在我們的選擇器導引章節 <a href="/zh-TW/docs/Web/Guide/CSS/Getting_started/Selectors">Selectors guide</a> 看到更多介紹。</p>
+
+<h2 id="文字與字體">文字與字體</h2>
+
+<p>現在我們已經瀏覽過一些CCS的基礎,接下來我們開始增加更多的規則和資訊到我們的style.css檔案,讓我們範例中的字型和文字看起來更好.</p>
+
+<ol>
+ <li>第一步, 我們回到 <a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">output from Google Fonts</a> 找到你存的字體。 加上 <code>&lt;link ... &gt;</code> 這個元素在你的 <code>index.html</code>文件裡的head中(在 <code>&lt;head&gt;</code> 跟 <code>&lt;/head&gt;</code> 任何位置中)。<br>
+ 這一段code將頁面連結到樣式表,將Open Sans字體系列與網頁一起下載,並讓你在HTML元素上使用自己的樣式表進行設置。 它看起來會像:
+ <pre class="brush: html notranslate">&lt;link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'&gt;</pre>
+ </li>
+ <li>下一步, 刪除<code>style.css文件中</code>其他現有的字體。這是個很好的嘗試, 但紅色字體看起來真的有點醜。</li>
+ <li>把下面這行加在這個地方, 取代 placeholder line with the actual <code>font-family</code> line you got from Google 字體. (<code>font-family</code> 是指你想在文件中使用的字體.)<br>
+ 這規則<br>
+ 此規則首先為頁面設置整體的基本字體和字型(因 <code>&lt;html&gt;</code> 是整個頁面的父元素, 頁面中所有的元素會繼承同樣的字體和字型):
+ <pre class="brush: css notranslate">html {
+ font-size: 10px; /* px means 'pixels': the base font size is now 10 pixels high */
+ font-family: placeholder: this should be the rest of the output you got from Google fonts
+}</pre>
+
+ <div class="note">
+ <p><strong>Note</strong>: 我已增加了對於 "px" 的說明在上面. 任何在 CSS document 中 <code>/*</code>  <code>*/</code> 內的文字是 <strong>CSS 說明</strong>, 瀏覽器在編譯時會忽略掉. 這是一個可以用來說明你做了什麼的幫助訊息.</p>
+ </div>
+ </li>
+ <li>現在我們將會在HTML body中為包含文字的元素設置字體大小,<code>&lt;h1&gt;</code>,<code>&lt;li&gt;</code>,<code>&lt;p&gt;</code>。我們也設置標題居中,並在正文內容上設置一些行高和間距,使其更具可讀性</li>
+ <li>
+ <pre class="brush: css notranslate">h1 {
+ font-size: 60px;
+ text-align: center;
+}
+
+p, li {
+  font-size: 16px;
+  line-height: 2;
+  letter-spacing: 1px;
+}</pre>
+ </li>
+</ol>
+
+<p>你可以依自己喜好修改 <code>px</code> 的值。你目前的工作成果可能如下圖所示:</p>
+
+<p><img alt="a mozilla logo and some paragraphs. a sans-serif font has been set, the font sizes, line height and letter spacing are adjusted, and the main page heading has been centered" src="https://mdn.mozillademos.org/files/9447/website-screenshot-font-small.png" style="display: block; height: 1020px; margin: 0px auto; width: 921px;"></p>
+
+<h2 id="CSS:和塊(box)密不可分">CSS:和塊(box)密不可分</h2>
+
+<p>當你在編寫 CSS,設定尺寸、顏色及位置時,你會發現它有著如同箱子(塊,box)的概念。多數在網頁上的 HTML 元素就像是箱子一般相互堆疊而成。</p>
+
+<p><img alt="a big stack of boxes or crates sat on top of one another" src="https://mdn.mozillademos.org/files/9441/boxes.jpg" style="display: block; height: 463px; margin: 0px auto; width: 640px;"></p>
+
+<p>CSS佈局主要基於「box 模型」。在頁面空間的每個 box 都有下列屬性:</p>
+
+<ul>
+ <li><code>padding:</code>內容周圍的空格(例如,段落文字周圍)</li>
+ <li><code>border:</code> 位於矩形內容外部的實線</li>
+ <li><code>margin:</code> 元素外部的空間</li>
+</ul>
+
+<p><img alt="three boxes sat inside one another. From outside to in they are labelled margin, border and padding" src="https://mdn.mozillademos.org/files/9443/box-model.png" style="display: block; height: 450px; margin: 0px auto; width: 574px;"></p>
+
+<p>在本節中,我們還使用:</p>
+
+<ul>
+ <li><code>width:</code>(元素的寬度)</li>
+ <li><code>background-color:</code>元素內容和矩形內容後面的顏色</li>
+ <li><code>color:</code> 元素內容的顏色(通常是文字)</li>
+ <li><code>text-shadow:</code>在元素內的文字上設置陰影</li>
+ <li><code>display:</code> 設置元素的顯示模式(後面會詳細介紹)</li>
+</ul>
+
+<p>所以,讓我們開始對我們的頁面添加更多 CSS!繼續將這些新規則添加到<code>style.css</code>頁面底部,不需要害怕多方嘗試去改值設定來了解結果。</p>
+
+<h3 id="改變頁面顏色">改變頁面顏色</h3>
+
+<pre class="brush: css notranslate">html {
+ background-color: #00539F;
+}</pre>
+
+<p>這條規則將會套用到整個頁面的背景顏色。根據你在<a href="/en-US/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like#Theme_color">規劃網站時選擇的顏色</a>修改其中的顏色代碼。</p>
+
+<h3 id="設定_body_的風格(styling)">設定 body 的風格(styling)</h3>
+
+<pre class="brush: css notranslate">body {
+ width: 600px;
+ margin: 0 auto;
+ background-color: #FF9500;
+ padding: 0 20px 20px 20px;
+ border: 5px solid black;
+}</pre>
+
+<p>接下來修改 <code>body</code> 元素。以下依序介紹一些常見的宣告:</p>
+
+<ul>
+ <li><code>width: 600px;</code> — 將 body 寬度固定為 600 像素</li>
+ <li><code>margin: 0 auto;</code> — When you set two values on a property like <code>margin</code> or <code>padding</code>, the first value affects the element's top <strong>and</strong> bottom side (make it <code>0</code> in this case), and the second value the left <strong>and</strong> right side (here, <code>auto</code> is a special value that divides the available horizontal space evenly between left and right). You can also use one, three, or four values, as documented <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/margin#Values">here</a>.</li>
+ <li><code>background-color: #FF9500;</code> — as before, this sets the element's background color. I used a sort of reddish orange for the body as opposed to dark blue for the <code>html</code> element. Go ahead and experiment. Feel free to use <code>white</code> or whatever you like.</li>
+ <li><code>padding: 0 20px 20px 20px;</code> — we have four values set on the padding, to make a bit of space around our content. This time we are setting no padding on the top of the body, and 20 pixels on the left, bottom and right. The values set top, right, bottom, left, in that order.</li>
+ <li><code>border: 5px solid black;</code> — this simply sets a 5 pixel wide solid black border on all sides of the body.</li>
+</ul>
+
+<h3 id="設定我們主要頁面標題的位置(Positioning)和風格(styling)">設定我們主要頁面標題的位置(Positioning)和風格(styling)</h3>
+
+<pre class="brush: css notranslate">h1 {
+ margin: 0;
+ padding: 20px 0;
+ color: #00539F;
+ text-shadow: 3px 3px 1px black;
+}</pre>
+
+<p>You may have noticed there's a horrible gap at the top of the body. That happens because browsers apply some <strong>default styling</strong> to the {{htmlelement("h1")}} element (among others), even when you haven't applied any CSS at all! That might sound like a bad idea, but we want even an unstyled webpage to have basic readability. To get rid of the gap we overrode the default styling by setting <code>margin: 0;</code>.</p>
+
+<p>Next up, we've set the heading's top and bottom padding to 20 pixels, and made the heading text the same color as the html background color.</p>
+
+<p>One rather interesting property we've used here is <code>text-shadow</code>, which applies a text shadow to the text content of the element. Its four values are as follows:</p>
+
+<ul>
+ <li>The first pixel value sets the <strong>horizontal offset</strong> of the shadow from the text — how far it moves across: a negative value should move it to the left.</li>
+ <li>The second pixel value sets the <strong>vertical offset</strong> of the shadow from the text — how far it moves down, in this example; a negative value should move it up.</li>
+ <li>The third pixel value sets the <strong>blur radius</strong> of the shadow — a bigger value will mean a more blurry shadow.</li>
+ <li>The fourth value sets the base colour of the shadow.</li>
+</ul>
+
+<p>Again, try experimenting with different values to see what you can come up with.</p>
+
+<h3 id="把圖像置中">把圖像置中</h3>
+
+<pre class="brush: css notranslate">img {
+ display: block;
+ margin: 0 auto;
+}</pre>
+
+<p>Finally, we'll center the image to make it look better. We could use the <code>margin: 0 auto</code> trick again as we did earlier for the body, but we also need to do something else. The body element is <strong>block level</strong>, meaning it takes up space on the page and can have margin and other spacing values applied to it. Images, on the other hand, are <strong>inline</strong> elements, meaning they can't. So to apply margins to the image, we have to give the image block-level behavior using <code>display: block;</code>.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Don't worry if you don't yet understand <code>display: block;</code> and the block-level/inline distinction. You will as you study CSS in more depth. You can find out more about the different available display values at our <a href="/en-US/docs/Web/CSS/display">display reference page</a>.</p>
+</div>
+
+<h2 id="結論">結論</h2>
+
+<p>看完了以上的介紹並依照各個步驟實做,你應該能自己寫出這樣的網頁(如下, <a href="http://mdn.github.io/beginner-html-site-styled/" rel="noopener">view it here</a>):</p>
+
+<p><img alt="a mozilla logo, centered, and a header and paragraphs. It now looks nicely styled, with a blue background for the whole page and orange background for the centered main content strip." src="https://mdn.mozillademos.org/files/9455/website-screenshot-final.png" style="display: block; height: 1084px; margin: 0px auto; width: 940px;"></p>
+
+<p>如果哪裡卡關了,你可以隨時造訪 Github 上的 <a href="https://github.com/mdn/beginner-html-site-styled/blob/gh-pages/styles/style.css" rel="noopener">finished example code</a> ,看看裡面的 code 和你寫的哪裡不同。</p>
+
+<p>這篇文章觸及的是非常基本的 CSS 介紹,若你有興趣想進一步了解,歡迎參考 <a href="https://developer.mozilla.org/en-US/Learn/CSS">CSS Learning topic</a>。</p>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</p>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html b/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html
new file mode 100644
index 0000000000..8411bdbe86
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/dealing_with_files/index.html
@@ -0,0 +1,117 @@
+---
+title: 與各式各樣檔案打交道
+slug: Learn/Getting_started_with_the_web/Dealing_with_files
+tags:
+ - HTML
+ - 初學者
+ - 指南
+ - 網站
+translation_of: Learn/Getting_started_with_the_web/Dealing_with_files
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p>一個網站會包含許多檔案: 文字內容、程式碼、樣式表、影音內容......等。每當你建立一個網站時,你需要將這些檔案在你的電腦上合理架構好。以確保它們能夠互相溝通,並讓內容正常顯示。然後你接著才能<a href="/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a>。本篇文章將探討你應該注意的一些議題,以便讓你能夠為你的網站設定好合理的檔案架構。</p>
+</div>
+
+<h2 id="你的網站在哪裡">你的網站在哪裡?</h2>
+
+<p>當你正在你自己的電腦上編輯你的網站時,你應該將所有相關的檔案放在同一個資料夾中,這反映到未來在伺服器上的檔案架構。這個資料夾可以放在任何地方,但你應該會放在一個容易找到的地方,對吧!像是你的桌面,你的家目錄,或是你硬碟的根目錄。</p>
+
+<ol>
+ <li>找到一個地方來存放你的網站專案。首先,建立一個新資料夾並命名為 <code>web-projects</code> (或類似名稱)。 這裡將存放你的各種網站專案.</li>
+ <li>在上述資料夾底下,建立另一個資料夾來存放你的第一個網站,請將這個資料夾命名為 <code>test-site</code> (或其他有創意的名稱).</li>
+</ol>
+
+<h2 id="留意大小寫與空格">留意大小寫與空格</h2>
+
+<p>你將注意到在本篇文章中,我們會要求你在命名檔案或是資料夾時,只使用小寫並且避免使用空格。這是因為:</p>
+
+<ol>
+ <li>許多的電腦尤其是網路伺服器,是大小寫區分的(case-sensitive)。所以假設你放了圖片在你的網站上而路徑是 <code>test-site/MyImage.jpg</code>,然後另一個檔案你想放在 <code>test-site/myimage.jpg</code>,這可能是無法運作的。</li>
+ <li>瀏覽器、伺服器、以及各種程式語言對於空格的處理並不是一致的。舉例來說,如果你在檔名中使用了空格,有些系統會將其視為兩個檔名,有些伺服器會將空格替換成 "%20" (這是空格在 URIs 中的表示法),並破壞了你的連結。我們建議使用底線(underscores)與破折號(dashes)來隔開單字。例如:<code>my-file.html</code> 或是 <code>my_file.html</code>.</li>
+</ol>
+
+<p>也因為這些原因,你應該盡量在命名資料夾與檔案時使用小寫並避免使用空格,這樣一來將能夠減少一些不必要的錯誤。</p>
+
+<h2 id="你的網站架構應該如何">你的網站架構應該如何?</h2>
+
+<p>下一步,我們要看看我們的測試網站應該具有什麼樣的架構。我們的網站專案最常見的東西就是一個HTML檔案與專門放圖片、樣式檔案、腳本檔案的資料夾們。讓我們來看看下面:</p>
+
+<ol>
+ <li><code><strong>index.html</strong></code>: 這個檔案會包含你的首頁內容,也就是別人一進到你的網站時所看到的文字與圖片。使用你的文字編輯器,建立一個新檔案命名為 <code>index.html</code> ,並將它存到 <code>test-site</code> 這個資料夾下。</li>
+ <li><strong><code>images</code> folder</strong>: 這個資料夾包含了所有網站會用到的圖片,建立一個新資料夾命名為 <code>images</code> ,並將它存到 <code>test-site</code> 這個資料夾下。</li>
+ <li><strong><code>styles</code> folder</strong>: 這個資料夾包含了能夠設計你的網站的CSS碼(例如:設定文字與背景顏色),建立一個資料夾命名為 <code>styles</code>,並將它存到 <code>test-site</code> 這個資料夾下。</li>
+ <li><strong><code>scripts</code> folder</strong>: 這個資料將包含能夠使網站具有互動性的JavaScript程式碼。(例如:按下按鈕後會載入資料)。建立一個資料夾命名<code> scripts</code> ,並將它存到 <code>test-site</code> 這個資料夾下。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 在Windows的電腦上,你可能在設定副檔名上會遇到一些困難。因為Windows預設會將已知的檔案類型名稱隱藏。一般來說你可以將這項設定關掉,只需要去檔案總管,選擇「資料夾選項」並取消選取「隱藏已知檔案類型的副檔名」,並點選 <strong>OK </strong>。有關不同版本的Windows的設定方法,請利用搜尋引擎搜尋。</p>
+</div>
+
+<h2 id="檔案路徑">檔案路徑</h2>
+
+<p>要讓一個檔案能夠與另一個檔案"溝通",你需要提供一個他們之間的相對檔案路徑以讓檔案能夠找到另一個檔案在哪裡。為了要展示,我們將插入一小段的HTML到我們的 <code>index.html</code> 檔案中,並且讓它顯示你在 <a href="/zh-TW/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like">"What will your website look like?" </a>這篇文章中所選的圖片。</p>
+
+<ol>
+ <li>複製你選的圖片並放到 <code>images</code> 資料夾中。</li>
+ <li>打開你的 <code>index.html</code>,並複製貼上下面這段code。先別擔心這些code代表什麼意思,我們會在後面的時候講解它們代表的意義。
+ <pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;My test page&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;img src="" alt="My test image"&gt;
+ &lt;/body&gt;
+&lt;/html&gt; </pre>
+ </li>
+ <li><code>&lt;img src="" alt="My test image"&gt;</code> 這行是一段將圖片插入到頁面中的 HTML code,我們必須告訴HTML圖片在哪。我們知道圖片在  <em>images</em> 資料夾中,而  <em>images</em> 資料夾就跟 <code>index.html </code>在同一目錄下。為了要在檔案系統結構中從 <code>index.html</code> 走到我們的圖片,我們需要將檔案路徑設為<code>images/your-image-filename</code>. 舉例來說,我們的圖片命名為 <code>firefox-icon.png,所以這裡的檔案路徑即為 </code><code>images/firefox-icon.png</code>.</li>
+ <li>將檔案路徑貼到你的 HTML code 中的<code> src=""</code> 的雙引號之間。</li>
+ <li>將你的 HTML 檔案存檔,並且滑鼠雙擊HTML檔案來打開它,你應該會看到一個新的網頁並展示著你的圖片!</li>
+</ol>
+
+<p><img alt="A screenshot of our basic website showing just the firefox logo - a flaming fox wrapping the world" src="https://mdn.mozillademos.org/files/9229/website-screenshot.png" style="display: block; height: 542px; margin: 0px auto; width: 690px;"></p>
+
+<p>一些有關路徑的規則:</p>
+
+<ul>
+ <li>要連結一個目標檔案到在同一個目錄下的HTML檔案,只需要檔案名稱就可以了。例如 <code>my-image.jpg</code>。</li>
+ <li>為了要參照到在子目錄下的檔案,在路徑前面加上該目錄的名稱,並接著加上一個斜線(/)。例如: <code>subdirectory/my-image.jpg</code>.</li>
+ <li>為了要連結到一個在 HTML file 的上層目錄的檔案,你需要使用兩個點點(..)。例如:index.html是在<code>test-site 這個目錄的一個子目錄下,而 my-image.png</code> 是在<code> test-site 這個目錄</code>下,HTML file 要參照 <code>my-image.png</code> 必須使用 <code>../my-image.png</code>。</li>
+ <li>你可以混和著使用以上的規則,例如 <code>../subdirectory/another-subdirectory/my-image.png</code>.</li>
+</ul>
+
+<p>至此,你已經知道目前需要知道的了。</p>
+
+<div class="note">
+<p><strong>Note</strong>: Windows的檔案系統會傾向使用反斜線(\),而非斜線(/)。例如 <code>C:\windows</code>. 這並沒有關係,即使你是在Windows上開發網站,你仍然應該在程式碼中使用斜線(/)。</p>
+</div>
+
+<h2 id="還有什麼需要被完成的">還有什麼需要被完成的?</h2>
+
+<p>目前先這樣吧。你的資料夾裡面現在應該長得像這樣:</p>
+
+<p><img alt="A file structure in mac os x finder, showing an images folder with an image in, empty scripts and styles folders, and an index.html file" src="https://mdn.mozillademos.org/files/9231/file-structure.png" style="display: block; height: 577px; margin: 0px auto; width: 929px;"></p>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html b/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html
new file mode 100644
index 0000000000..05ac9e4d7b
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/how_the_web_works/index.html
@@ -0,0 +1,101 @@
+---
+title: 網路如何運作
+slug: Learn/Getting_started_with_the_web/How_the_Web_works
+translation_of: Learn/Getting_started_with_the_web/How_the_Web_works
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p><em>〈網路如何運作〉將簡單介紹</em>,當你透過電腦或手機瀏覽器瀏覽網頁時,究竟發生什麼事。</p>
+</div>
+
+<p>短期來看,在撰寫網站程式碼時,這些理論並不是非懂不可,但在之後,了解這些背後原理,對你會很有幫助。</p>
+
+<h2 id="用戶與伺服器">用戶與伺服器</h2>
+
+<p>連接到網路的電腦稱為<strong>用戶端</strong>(client)與<strong>伺服器端</strong>(server)。彼此的連結原理如圖所示:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8973/Client-server.jpg" style="height: 123px; width: 336px;"></p>
+
+<ul>
+ <li>用戶端是網路用戶的典型上網設備(像是連到 Wi-Fi 的電腦、或是連到手機網路的手機),這些設備通常有能夠上網的軟體(通常是 Firefox 或 Chrome 之類的瀏覽器)。</li>
+ <li>伺服器端是放著網頁、網站、或者  app 的電腦。當用戶端設備要訪問網頁時,網頁的副本會從伺服器下載到用戶端,以便顯示在用戶的瀏覽器。</li>
+</ul>
+
+<h2 id="百寶箱的其他魔法">百寶箱的其他魔法</h2>
+
+<p>剛剛描述的用戶/伺服器端還不是一切,我們還要講述其他部份,才能說完整個故事。</p>
+
+<p>現在把網路想像成一條大道。大道的一端是用戶端,就像你家一樣;另一端則是伺服器,就像是你要去血拼的商店。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9749/road.jpg" style="display: block; height: 427px; margin: 0px auto; width: 640px;"></p>
+
+<p>除了用戶與伺服器之外,我們還需要和這些朋友們打招呼:</p>
+
+<ul>
+ <li><strong>網路連線</strong>:讓你可以在網路傳送與接收資料。基本上就像是家裡到商店一樣。</li>
+ <li><strong>TCP/IP</strong>:傳輸控制協定和網際網路協定(Transmission Control Protocol and Internet Protocol)是定義資料如何在網路通行的通訊協定。這就像是方便你去商店買東西的交通工具。在這裡本例中,這就像是車子、腳踏車、或其他你想得到的交通工具。</li>
+ <li><strong>DNS</strong>:網域名稱系統(Domain Name Servers)就像是網站的電話簿。當你在瀏覽器輸入網址時,瀏覽器會在取得網站前,先去看 DNS 以查到網站的真實地址。瀏覽器需要找到哪個伺服器在託管指定的網站、這樣才能把 HTTP 訊息傳送到對的地方(可以參考下文)。這就像你在去商店前會先翻開電話簿,才好去商店一般。</li>
+ <li><strong>HTTP</strong>超文本傳輸協定(Hypertext Transfer Protocol)是定義用戶端語言,和伺服器如何對話的應用{{Glossary("Protocol" , "協議")}}。可以想成你買東西時會用來溝通的語言。</li>
+ <li><strong>Component files</strong>:網站由許多不同的文件組成,如同商店內許多不同的商品。這些檔案分為以下類型:
+ <ul>
+ <li><strong>程式檔</strong>:網站主要是由 HTML、CSS、JavaScript 建立,雖然你知會看到其他工具或技術。</li>
+ <li><strong>Asset</strong>:這是構成網站其他內容的集體名稱,裡面可能包含圖像、音樂、影片、Word、PDF……之類的。</li>
+ </ul>
+ </li>
+</ul>
+
+<h2 id="所以我說到底發生了啥?">所以我說到底發生了啥?</h2>
+
+<p>當你在瀏覽器輸入網址時(你可以想像說自己要走去商店時):</p>
+
+<ol>
+ <li>瀏覽器會先去 DNS 伺服器尋找託管網站的伺服器,其真實位置所在(如同你去尋找商店的地址)</li>
+ <li>瀏覽器向伺服器傳送 HTTP 訊息,請求伺服器向用戶端傳送網站的複本(如同去商店下訂單)。在用戶端及伺服器的之間,請求訊息與其他資訊,會使用 TCP/IP 在網路連線之間傳送。</li>
+ <li>伺服器如果允許用戶端請求,伺服器就會傳送「200 OK」訊息,意味著「好,你可以閱覽這個網站,那我給你網站資料囉~」並開始對瀏覽器以一小串稱作「資料封包」的組合形式,傳送網站的檔案。這就像是商店給你商品,你接著把它們都帶回家一樣</li>
+ <li>瀏覽器把一小塊一小塊的東西,組合成完整的網站,並把它呈現起來--商品送到家門口後,閃亮亮的新貨在你眼前,超棒的啦!</li>
+</ol>
+
+<h2 id="講講_DNS">講講 DNS</h2>
+
+<p>真正的網址,並不是在瀏覽器的網址列上,輸入好記好讀的字串,就能找到你最愛的網站。它們其實是一串特殊的數字,看起來就像是這樣:63.245.215.20</p>
+
+<p>這叫做 {{Glossary("IP Address", "IP 地址")}},網路上它擁有獨一無二的位置。不過,記數字果然不簡單吧?這就是要發明域名伺服器的原因。他們會把你在瀏覽器輸入的網址(例如 mozilla.org)和網站的真實位置(IP)相匹配</p>
+
+<p>網站能直接透過其 IP 位置訪問之:在瀏覽器的網址列輸入 <code>63.245.215.20</code> 的話,可以走到 Mozilla 的網站。</p>
+
+<p><img alt="A domain name is just another form of an IP address" src="https://mdn.mozillademos.org/files/8405/dns-ip.png" style="height: 160px; width: 330px;"></p>
+
+<h2 id="再講講封包">再講講封包</h2>
+
+<p>稍早我們用了「封包」來描述從伺服器傳到用戶端的資料格式。這裡的「封包」是什麼意思呢?通常資料在網路傳送時,會傳送上千個小資料,這樣在同一時間和同一網站,才能有很多用戶下載內容。如果網站只傳送一個大傢伙過去,那在同一時間就只能有一個用戶能下載,網路會變得很慢、很無聊...</p>
+
+<h2 id="參見">參見</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/How_does_the_Internet_work">How the Internet works</a></li>
+ <li><a href="https://dev.opera.com/articles/http-basic-introduction/">HTTP — an Application-Level Protocol</a></li>
+ <li><a href="https://dev.opera.com/articles/http-lets-get-it-on/">HTTP: Let’s GET It On!</a></li>
+ <li><a href="https://dev.opera.com/articles/http-response-codes/">HTTP: Response Codes</a></li>
+</ul>
+
+<h2 id="製作群">製作群</h2>
+
+<p>街頭的照片:<a href="https://www.flickr.com/photos/kdigga/9110990882/in/photolist-cXrKFs-c1j6hQ-mKrPUT-oRTUK4-7jSQQq-eT7daG-cZEZrh-5xT9L6-bUnkip-9jAbvr-5hVkHn-pMfobT-dm8JuZ-gjwYYM-pREaSM-822JRW-5hhMf9-9RVQNn-bnDMSZ-pL2z3y-k7FRM4-pzd8Y7-822upY-8bFN4Y-kedD87-pzaATg-nrF8ft-5anP2x-mpVky9-ceKc9W-dG75mD-pY62sp-gZmXVZ-7vVJL9-h7r9AQ-gagPYh-jvo5aM-J32rC-ibP2zY-a4JBcH-ndxM5Y-iFHsde-dtJ15p-8nYRgp-93uCB1-o6N5Bh-nBPUny-dNJ66P-9XWmVP-efXhxJ">Street composing</a>、作者是<a href="https://www.flickr.com/photos/kdigga/">Kevin D</a>。</p>
+
+<p>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p>
+
+<h2 id="在模塊裡面">在模塊裡面</h2>
+
+<ul>
+ <li id="Installing_basic_software"><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li id="What_will_your_website_look_like"><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li id="Dealing_with_files"><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li id="HTML_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基礎</a></li>
+ <li id="CSS_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本</a></li>
+ <li id="JavaScript_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基礎</a></li>
+ <li id="Publishing_your_website"><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li id="How_the_web_works"><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網路如何做動</a></li>
+</ul>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html
new file mode 100644
index 0000000000..f59eb8eab7
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/html_basics/index.html
@@ -0,0 +1,232 @@
+---
+title: HTML 基礎
+slug: Learn/Getting_started_with_the_web/HTML_basics
+tags:
+ - HTML
+ - Web
+ - 學習
+ - 寫程式
+ - 新手
+translation_of: Learn/Getting_started_with_the_web/HTML_basics
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p>HTML(<strong>H</strong>ypertext <strong>M</strong>arkup <strong>L</strong>anguage),中文全名為「超文字標示語言」,是一種用來組織架構並呈現網頁內容的程式語言。網頁內容的組成,可能包含了段落、清單、圖片或表格...等。透過這篇文章,希望能幫助大家對 HTML 及其功能有基本的認識。</p>
+</div>
+
+<h2 id="HTML_到底是什麼?">HTML 到底是什麼?</h2>
+
+<p>HTML 是一種<em>標記語言(markup language)</em>,而非一般熟知的程式設計語言;它會告訴瀏覽器該如何呈現你的網頁──單純簡易或是極其複雜的頁面都沒問題。HTML 包含了一系列的<strong>元素({{Glossary("element", "elements")}})</strong>,而元素包含了<strong>標籤({{Glossary("tag", "tags")}})</strong>與<strong>內容(content)</strong>,我們用標籤來控制內容的呈現樣貌,例如字體大小、斜體粗體、在文字或圖片設置超連結等。舉例來說,請看看以下這個句子:</p>
+
+<pre>My cat is very grumpy</pre>
+
+<p>如果我們想讓這個句子自成一個段落,那麼可以在它前後分別加上段落標籤 ({{htmlelement("p")}}),它就變成一個段落元素了:</p>
+
+<pre class="brush: html">&lt;p&gt;My cat is very grumpy&lt;/p&gt;</pre>
+
+<h3 id="HTML_元素的組成">HTML 元素的組成</h3>
+
+<p>讓我們來仔細的觀察一下,內容、標籤和元素的關係:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9347/grumpy-cat-small.png" style="display: block; height: 255px; margin: 0px auto; width: 821px;"></p>
+
+<p>我們可以看到基本的架構:</p>
+
+<ol>
+ <li><strong>起始標籤 (The opening tag):</strong>先打角括弧,也就是大於、小於的符號「&lt; &gt;」,裡面再放入元素名稱,如上面的例子「&lt;p&gt;」。起始標籤代表這個元素從這裡開始。</li>
+ <li><strong>結束標籤 (The closing tag):</strong> 與起始標籤一樣,只是在元素名稱前面多了個<em>前置斜線</em>「/」。很容易理解地,內容的最後加上結束標籤,代表這個元素的尾端。在寫HTML時,很容易忘了最後的結束標籤,提醒大家要多注意唷!</li>
+ <li><strong>內容(The content):</strong> 這個元素的內容,以上面的例子來說,內容就是這句文字。</li>
+ <li><strong>元素(The element):</strong> 由起始標籤、結束標籤、內容所組成。</li>
+</ol>
+
+<p>元素還可以有「屬性(Attribute)」,請大家看看下面的例子:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p>
+
+<p>屬性能提供更多的資訊(當然,這個資訊是幫助我們更有效及方便編輯,不會呈現在網頁上),屬性包含了屬性名稱與值,你可以利用屬性設定這個元素的色彩、對齊方式、圖表的格線等等。</p>
+
+<p>屬性的組成包含:</p>
+
+<ol>
+ <li>在元素名稱和屬性之間有一個空格(如果有多個屬性,屬性之間也需要有空格)</li>
+ <li>屬性名稱後面接著等於符號「=」</li>
+ <li>屬性包在起始標籤裡面,如範例所示</li>
+</ol>
+
+<h3 id="巢狀元素">巢狀元素</h3>
+
+<p>元素裡面可以在放進元素,我們稱之為「<strong>巢狀元素(nesting element)</strong>」。例如這個句子:「我的貓有夠無敵臭臉」,若你想強調「有夠無敵」,我們就可以把「有夠無敵」這四個字自成一個顯示為粗體的元素 {{htmlelement("strong")}} :</p>
+
+<pre class="brush: html">&lt;p&gt;My cat is &lt;strong&gt;very&lt;/strong&gt; grumpy.&lt;/p&gt;</pre>
+
+<p>要注意的是,每個元素都有自己的起始和結束標籤,一層一層的包覆。所以最外層是&lt;p&gt;  ,接著&lt;strong&gt; ;先結束strong元素,所以先寫&lt;/strong&gt;,最外面才是 &lt;/p&gt;。</p>
+
+<pre class="example-bad brush: html">&lt;p&gt;My cat is &lt;strong&gt;very grumpy.&lt;/p&gt;&lt;/strong&gt;</pre>
+
+<p>如果元素的起始和結束標籤錯置(如上方),那麼瀏覽器只能自行判斷你想呈現的樣子,可能會完全不如預期!所以在做巢狀元素時要多注意唷!</p>
+
+<h3 id="空元素">空元素</h3>
+
+<p>有些元素沒有內容,我們稱為「<strong>空元素(empty elements)</strong>」。 以這個圖片元素 {{htmlelement("img")}} 為例:</p>
+
+<pre class="brush: html">&lt;img src="images/firefox-icon.png" alt="My test image"&gt;</pre>
+
+<p>它有兩個屬性,但是沒有結束標籤,也沒有裡面的內容。因為圖片元素是直接把圖檔嵌在 HTML 網頁上。</p>
+
+<h3 id="HTML_文件的架構">HTML 文件的架構</h3>
+
+<p>讓我們來看看一個完整的HTML頁面它所包含的要素(以下範例的程式碼出自這篇文章:<a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a>):</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;My test page&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;img src="images/firefox-icon.png" alt="My test image"&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>我們可以看到:</p>
+
+<ul>
+ <li><code>&lt;!DOCTYPE html&gt;</code> — 文件類型(doctype)。 在 HTML 發展初期(約莫 1991/2 的年代)文件類型是用來連結一些應遵守的規則,有點像自動校正的功能。然而,現在大家其實不太管文件類型,它就是個必須放在程式碼中的東西,現階段大家只需要知道這點就夠了。</li>
+ <li><code>&lt;html&gt;&lt;/html&gt;</code> — <code>&lt;html&gt;</code> 元素,又被視為根元素(root element),包含了所有顯示在這個頁面上的內容。</li>
+ <li><code>&lt;head&gt;&lt;/head&gt;</code> —  <code>&lt;head&gt;</code> 元素,裡面放的是你想涵括的重要資訊,但<strong>不會顯示於網頁瀏覽者眼前的</strong>。例如,顯示於搜尋結果的關鍵字、頁面說明<em>、</em>CSS、字元實體集...等。</li>
+ <li><code>&lt;body&gt;&lt;/body&gt;</code> —  <code>&lt;body&gt;</code> 元素,包含了<strong>所有會顯示於網頁瀏覽者眼前的內容。</strong> 無論是文字、圖片、影面、互動遊戲...等。</li>
+ <li><code>&lt;meta charset="utf-8"&gt;</code> — 這個元素指定了你的文件使用utf-8這種字元編碼, 建議大家都要使用這個元素,它會幫助你免去許多文字無法正確呈現的煩惱。</li>
+ <li><code>&lt;title&gt;&lt;/title&gt;</code> — 呈現於網頁瀏覽者眼前的網頁標題。</li>
+</ul>
+
+<h2 id="圖片">圖片</h2>
+
+<p>再讓我們複習一下圖片元素:</p>
+
+<pre class="brush: html">&lt;img src="images/firefox-icon.png" alt="My test image"&gt;</pre>
+
+<p>如同我們前面提到,圖片元素是直接把圖檔嵌在HTML網頁上,它是透過圖片來源(<code>src</code> ,source)這個屬性,提供了連到圖片檔案的路徑。</p>
+
+<p>我們也可以加上<code>alt</code> (alternative) 這個屬性。在網頁瀏覽者無法正確看到圖片時,你希望對他們呈現什麼樣的說明文字。這種狀況會發生通常是因為:</p>
+
+<ol>
+ <li>許多視能障礙的網頁瀏覽者,會使用「Screen Readers」這樣的工具,利用說明文字(alt text)來了解網頁要呈現的圖片內容。</li>
+ <li>就是有些東西出錯了。例如,你誤植了圖片來源的路徑,你可能就會看到類似以下的文字:</li>
+</ol>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9349/alt-text-example.png" style="display: block; height: 36px; margin: 0px auto; width: 108px;"></p>
+
+<p>說明文字應該要好好呈現這個圖片的內容,上面這個例子就很差。好的例子像是:「Firefox  Logo:有一隻狐狸繞著地球」</p>
+
+<div class="note">
+<p><strong>注意</strong>:你可以在 <a href="/zh-TW/docs/Web/Accessibility">MDN's Accessibility landing page</a> 查看無障礙頁面的資訊。</p>
+</div>
+
+<h2 id="標記文字">標記文字</h2>
+
+<p>這個段落將為大家介紹如何標記文字(讓這些文字如何呈現)。</p>
+
+<h3 id="文件標題_heading"><strong>文件標題</strong> (heading)</h3>
+
+<p>讓你呈現這些內容的主題,就像一本書有書名、章節名稱和副標題,一份HTML文件也有類似的概念。HTML最多可以有六層的heading, {{htmlelement("h1")}}–{{htmlelement("h6")}} ,雖然通常我們只使用3至4層:</p>
+
+<pre class="brush: html">&lt;h1&gt;My main title&lt;/h1&gt;
+&lt;h2&gt;My top level heading&lt;/h2&gt;
+&lt;h3&gt;My subheading&lt;/h3&gt;
+&lt;h4&gt;My sub-subheading&lt;/h4&gt;</pre>
+
+<p>請試試在 {{htmlelement("img")}} 上方,加上合適的heading。</p>
+
+<h3 id="段落_paragraph"><strong>段落 (paragraph)</strong></h3>
+
+<p>如上面介紹過的,{{htmlelement("p")}} elements 包含文字段落,在呈現一般文字時,這是我們最常用到的。</p>
+
+<pre class="brush: html">&lt;p&gt;This is a single paragraph&lt;/p&gt;</pre>
+
+<p><strong>請試試在這裡 <a href="/zh-TW/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like"><em>What should your website look like?</em></a><em> </em>的圖片(&lt;img&gt; element)下方,加上幾段文字。</strong></p>
+
+<h3 id="清單_list"><strong>清單 (list)</strong></h3>
+
+<p>清單至少會包含兩個元素,以下是最常見的清單類,無順序性與有順序性的:</p>
+
+<ol>
+ <li><strong>無順序性清單(Unordered lists)</strong> 代表這些項目的順序改變,不影響任何是,例如購物清單。項目會包含在  {{htmlelement("ul")}} 裡面。</li>
+ <li><strong>有順序性清單(Ordered lists)</strong>代表這些項目的順序是有意義的,例如食譜裡的製作步驟。項目會包含在 {{htmlelement("ol")}} 裡面。</li>
+</ol>
+
+<p>每個項目則分別放在{{htmlelement("li")}} (list item) element裡面。</p>
+
+<p>例如,我們想把以下這段文字變成清單:</p>
+
+<pre class="brush: html">&lt;p&gt;At Mozilla, we’re a global community of technologists, thinkers, and builders working together ... &lt;/p&gt;</pre>
+
+<p>寫法如下:</p>
+
+<pre class="brush: html">&lt;p&gt;At Mozilla, we’re a global community of&lt;/p&gt;
+
+&lt;ul&gt;
+ &lt;li&gt;technologists&lt;/li&gt;
+ &lt;li&gt;thinkers&lt;/li&gt;
+ &lt;li&gt;builders&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;working together ... &lt;/p&gt;</pre>
+
+<p><strong>請試試在練習網頁,加上一個清單。</strong></p>
+
+<h2 id="連結_link">連結 (link)</h2>
+
+<p>連結對於網頁來說是非常重要的。要加上連結,我們需要用到這個元素 — {{htmlelement("a")}} —  <em>a</em> 代表了「anchor」。要讓文字變成連結的步驟如下:</p>
+
+<ol>
+ <li>選擇一些文字,例如「Mozilla Manifesto」。</li>
+ <li>把他們包在這個&lt;a&gt; 元素裡:
+ <pre class="brush: html">&lt;a&gt;Mozilla Manifesto&lt;/a&gt;</pre>
+ </li>
+ <li>在&lt;a&gt; element 中加上href attribute這個屬性:
+ <pre class="brush: html">&lt;a href=""&gt;Mozilla Manifesto&lt;/a&gt;</pre>
+ </li>
+ <li>屬性質就是你要連結網址:
+ <pre class="brush: html">&lt;a href="https://www.mozilla.org/zh-TW/about/manifesto/"&gt;Mozilla Manifesto&lt;/a&gt;</pre>
+ </li>
+</ol>
+
+<p>網址的開頭使用<code>https://</code> 或 <code>http://</code> (網路文字傳送標準的不同)可能會給你不一樣的結果。因此,在寫連結時,請自己先點擊過,確認無誤。</p>
+
+<p><strong>請試試在練習網頁加上一個超連結。</strong></p>
+
+<div class="note">
+<p><code>href</code> 這個屬性名稱比較不直觀,不太好記,但它代表的是:<em><strong>h</strong>ypertext <strong>ref</strong>erence</em>的縮寫。</p>
+</div>
+
+<h2 id="sect1"></h2>
+
+<h2 id="結論">結論</h2>
+
+<p>看完了以上的介紹並依照各個步驟實做,你應該能自己寫出這樣的網頁(如下, <a href="http://mdn.github.io/beginner-html-site/">view it here</a>):<br>
+ <br>
+ <img alt="A web page screenshot showing a firefox logo, a heading saying mozilla is cool, and two paragraphs of filler text" src="https://mdn.mozillademos.org/files/9351/finished-test-page-small.png" style="display: block; height: 838px; margin: 0px auto; width: 716px;"></p>
+
+<p>如果哪裡卡關了,你可以隨時造訪Github上的 <a href="https://github.com/mdn/beginner-html-site/blob/gh-pages/index.html">finished example code</a> ,看看裡面的code和你寫的哪裡不同。</p>
+
+<p>這篇文章觸及的是非常基本的HTML介紹,若你有興趣想進一步了解,歡迎參考 <a href="/zh-TW/Learn/HTML">HTML Learning page</a>。</p>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</p>
+
+
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li id="Installing_basic_software"><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a></li>
+ <li id="What_will_your_website_look_like"><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li>
+ <li id="Dealing_with_files"><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li>
+ <li id="HTML_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li>
+ <li id="CSS_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li>
+ <li id="JavaScript_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li>
+ <li id="Publishing_your_website"><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li>
+ <li id="How_the_web_works"><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li>
+</ul>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/index.html b/files/zh-tw/learn/getting_started_with_the_web/index.html
new file mode 100644
index 0000000000..f2629247fc
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/index.html
@@ -0,0 +1,59 @@
+---
+title: Web 入門
+slug: Learn/Getting_started_with_the_web
+tags:
+ - Beginner
+ - CSS
+ - Design
+ - Guide
+ - HTML
+ - Index
+ - NeedsTranslation
+ - TopicStub
+ - publishing
+ - theory
+translation_of: Learn/Getting_started_with_the_web
+---
+<div>{{LearnSidebar}}</div>
+
+<div class="summary">
+<p><em>〈Web 入門〉</em>是一系列簡潔的文章,介紹網頁開發的實用範例。你將運用相關工具建構簡易網頁並發布自己的程式碼。</p>
+</div>
+
+<h2 id="替你的第一個網站說故事">替你的第一個網站說故事</h2>
+
+<p>建立個人網站需要很多功夫。如果你才剛開始接觸網頁設計,我們建議大家可以先從小地方著手。不是要你立刻就寫出跟「Facebook」一樣規模的網站,但自己架一個上線的網站一點都不難,現在就開始吧!</p>
+
+<p>只要依序看過以下的系列文章,你將初學者蛻變成會架設自己的第一個上線網頁,Let's go!</p>
+
+<h3 id="安裝基本軟體"><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></h3>
+
+<p>現有許多工具可建構網站。如果你剛起步,你可能不知從何選擇程式碼編輯器、框架、測試工具等等。我們將透過〈<a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a>〉逐步引領你安裝基本的網頁開發軟體。</p>
+
+<h3 id="你的網站看起來會是什麼樣子?"><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></h3>
+
+<p>在開始為自己的網站寫程式碼之前,你應該先規劃要呈現哪些資訊?要採用哪種字體與顏色?你可依照〈<a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a>〉所提供的簡易方法,照著來規劃網站的內容與設計。</p>
+
+<h3 id="與各式各樣檔案打交道"><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></h3>
+
+<p>一個網站包含許多檔案:文字內容、程式碼、樣式表、多媒體內容等等。當建立網站時,你需要將這些檔案組合成清晰的架構,並確保它們能彼此互動溝通。〈<a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a>〉將引領你安排合理的檔案架構,以及你應該注意的問題。</p>
+
+<h3 id="HTML_基本概念"><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a></h3>
+
+<p>超文字標籤語言 (Hypertext Markup Language;HTML) 可用以建構網頁內容,並賦予其含意和用途。例如某段內容要分為多個段落,或是用項目符號列成幾個重點?要在網頁插入圖片?這裡需要以資料表格整理嗎?如果這些沒有嚇到你,〈<a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a>〉將提供足夠的資訊。</p>
+
+<h3 id="CSS_基本概念"><a href="/zh-TW/docs/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a></h3>
+
+<p>串接樣式表 (Cascading Stylesheets;CSS) 可用以塑造網站的特殊風格。例如這段文字要用一般的黑色,或是改用紅色標明重點?某段重要內容應該置於畫面的何處?想用什麼背景圖片及顏色裝飾你的網站?〈<a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a>〉帶你入門。</p>
+
+<h3 id="JavaScript_基本概念"><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a></h3>
+
+<p>程式設計語言 JavaScript 可為你的網站增加互動功能,例如動畫、遊戲、按下按鈕的後續動作、將資料輸入表單、動態套用樣式的效果等等。〈<a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a>〉將帶你瞭解此一有趣的程式語言及其能耐,並讓你快速入門。</p>
+
+<h3 id="將你的網站發佈上線"><a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></h3>
+
+<p>在寫完程式碼並整理好檔案之後,接著就是將網站發佈上線,讓其他人可以瀏覽、欣賞內容。〈<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a>〉將帶領你以最輕鬆的方法發佈你的範例程式碼。</p>
+
+<h3 id="網站的運作方式"><a href="/zh-TW/docs/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a></h3>
+
+<p>在瀏覽喜愛的網站時,你可能未意識到瀏覽器正於背景中運作著許多複雜事情。〈<a href="/zh-TW/docs/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a>〉將簡略說明網頁瀏覽時所發生的大小事。</p>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html b/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html
new file mode 100644
index 0000000000..c9874db847
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/installing_basic_software/index.html
@@ -0,0 +1,73 @@
+---
+title: 安裝基本軟體
+slug: Learn/Getting_started_with_the_web/Installing_basic_software
+translation_of: Learn/Getting_started_with_the_web/Installing_basic_software
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p>在本文中,你會知道有哪些 Web 開發的簡易工具,以及正確的安裝方式。</p>
+</div>
+
+<h2 id="專家都用哪些工具?">專家都用哪些工具?</h2>
+
+<ul>
+ <li><strong>電腦</strong>,這東西對某些人來說再合理不過了,但可能有人用自己的手機,或在圖書館電腦上讀這篇文章。若要真正著手開發 Web,最好還是弄一台桌電或筆電(Windows、Mac、Linux 都行)。</li>
+
+ <li><strong>文字編輯器</strong>,用來寫程式碼。可以是文字編輯器(如 <a href="https://code.visualstudio.com/">Visual Studio Code</a>、<a href="https://notepad-plus-plus.org/">Notepad++</a>、<a href="https://www.sublimetext.com/">Sublime Text</a>、<a href="https://atom.io/">Atom</a>、<a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>、<a href="https://www.vim.org/">VIM</a>)、也可以是混合式編輯器(如 <a href="https://www.adobe.com/products/dreamweaver.html">Dreamweaver</a> 或 <a href="https://www.jetbrains.com/webstorm/">WebStorm</a>)。辦公室軟體的文件編輯器並不適合,因為它們依賴許多會干擾瀏覽器排版引擎的隱藏元素。</li>
+ <li><strong>Web 瀏覽器</strong>,可測試寫好的程式碼。目前最常用的瀏覽器有 <a href="https://www.mozilla.org/zh-TW/firefox/new/">Firefox</a>、<a href="https://www.google.com/chrome/browser/">Chrome</a>、<a href="http://www.opera.com/">Opera</a>、<a href="https://www.apple.com/safari/">Safari</a>、<a href="http://windows.microsoft.com/zh-tw/internet-explorer/download-ie">Internet Explorer</a> 與 <a href="https://www.microsoft.com/zh-tw/windows/microsoft-edge">Micrososft Edge</a>。你也可以測試自己網站在行動裝置上呈現的效果,若目標讀者分佈甚廣,你可能必須用舊版瀏覽器(如 IE 6–8)測試。</li>
+ <li><strong>圖像編輯器</strong>,如 <a href="http://www.gimp.org/">GIMP</a>、<a href="http://www.getpaint.net/">Paint.NET</a>、<a href="https://www.adobe.com/products/photoshop.html">Photoshop</a> 都可用來為自己的網站添增圖案。</li>
+
+ <li><strong>版本控制系統</strong>,可讓團隊用以協作某個專案、分享程式碼與外部檔案,更可避免編輯作業發生衝突、還可以管理伺服器的檔案。目前 <a href="http://git-scm.com/">Git</a> 是最常見的版本控制工具;<a href="https://github.com/">GitHub</a> 與 <a href="https://gitlab.com">GitLab</a> 則是最常用的程式碼分享服務。</li>
+ <li><strong>FTP 程式</strong>,可將網頁上傳至比較老的網路託管伺服器,以利使用者檢視──前述的 <a href="http://git-scm.com/">Git</a> 近年來漸漸取代了 FTP──可用的 (S)FTP 程式有 <a href="https://cyberduck.io/">Cyberduck</a>、<a href="http://fetchsoftworks.com/">Fetch</a>、<a href="https://filezilla-project.org/">FileZilla</a>。</li>
+ <li><strong>自動化系統,</strong>如 <a href="http://gruntjs.com/">Grunt</a> 或 <a href="http://gulpjs.com/">Gulp</a> 可自動執行重複性的作業,例如縮減程式碼並執行測試作業。</li>
+ <li>範本、函式庫、框架......等等,都能加速寫出一般功能。</li>
+ <li>及其他更多工具!</li>
+</ul>
+
+<h2 id="我實際需要、立刻需要哪些工具?">我實際需要、立刻需要哪些工具?</h2>
+
+<p>上面一長串看起來好像很嚇人,但其實剛接觸 Web 開發時,不需了解所有的東西。我們先幫你設定最低限度的必要工具:文字編輯器和幾款主流瀏覽器。</p>
+
+<h3 id="安裝文字編輯器">安裝文字編輯器</h3>
+
+<p>你的電腦裡很可能已經提供基本的文字編輯器了。Windows 本身就有 <a href="https://zh.wikipedia.org/wiki/記事本">記事本</a>;OS X 已提供 <a href="https://zh.wikipedia.org/wiki/文字編輯 (應用程式)">文字編輯</a>;Linux 各版本不太一樣:例如 Ubuntu 就有 <a href="https://zh.wikipedia.org/wiki/Gedit">gedit</a>。</p>
+
+<p>而針對 Web 開發,其實有著比 Notepad 或 TextEdit 好很多的工具。我們推薦使用 <a href="https://code.visualstudio.com/">Visual Studio Code</a>,因為這個自由編輯器有提供即時預覽、以及程式碼提示。</p>
+
+<h3 id="安裝常用瀏覽器">安裝常用瀏覽器</h3>
+
+<p>目前我們會安裝數款 Web 瀏覽器的桌面版,以利測試我們所寫的程式碼。先在下方找到自己所用的作業系統,再點擊你愛用的瀏覽器連結:</p>
+
+<ul>
+ <li>Linux:<a href="https://www.mozilla.org/zh-TW/firefox/new/">Firefox</a>、<a href="https://www.google.com/chrome/browser/">Chrome</a>、<a href="http://www.opera.com/">Opera</a>、<a href="https://brave.com">Brave</a>。</li>
+ <li>Windows:<a href="https://www.mozilla.org/zh-TW/firefox/new/">Firefox</a>、<a href="https://www.google.com/chrome/browser/">Chrome</a>、<a href="http://www.opera.com/">Opera</a>、<a href="http://windows.microsoft.com/zh-TW/internet-explorer/download-ie">Internet Explorer</a>、<a href="https://www.microsoft.com/en-us/windows/microsoft-edge">Micrososft Edge</a>、<a href="https://brave.com">Brave</a>。(Edge 是 Windows 10 的預設瀏覽器;如果你用的是 Windows 8 或之後版本,可以安裝 IE 10 或更高版本;否則應安裝其他瀏覽器替代)</li>
+ <li>macOS:<a href="https://www.mozilla.org/zh-TW/firefox/new/">Firefox</a>、<a href="https://www.google.com/chrome/browser/">Chrome</a>、<a href="http://www.opera.com/">Opera</a>、<a href="https://www.apple.com/safari/">Safari</a>、<a href="https://brave.com">Brave</a>。(Safari 是 iOS 與 OS X 的預設瀏覽器)</li>
+</ul>
+
+<p>在著手開發之前,應先安裝至少兩款瀏覽器以利後續測試。</p>
+
+<div class="blockIndicator note">
+<p>Internet Explorer 與當今的 web 不相容,可能會讓專案跑不動。</p>
+</div>
+
+<h3 id="安裝伺服器軟體">安裝伺服器軟體</h3>
+
+<p>有些例子需要使用伺服器軟體。你可以在 <a href="/zh-TW/docs/Learn/Common_questions/set_up_a_local_testing_server">How do you set up a local testing server?</a> 找到作法。</p>
+
+<p>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</p>
+
+<h2 id="於本模塊">於本模塊</h2>
+
+<ul>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a></li>
+</ul>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html b/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html
new file mode 100644
index 0000000000..e4c01763c9
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/javascript_basics/index.html
@@ -0,0 +1,440 @@
+---
+title: JavaScript 基礎
+slug: Learn/Getting_started_with_the_web/JavaScript_basics
+tags:
+ - JavaScript
+ - 初學
+ - 學習
+ - 寫程式
+ - 新手
+ - 網頁
+translation_of: Learn/Getting_started_with_the_web/JavaScript_basics
+---
+<div style="font-family: Microsoft jhenghei;">{{LearnSidebar}}</div>
+
+<div style="font-family: Microsoft jhenghei;">{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary" style="font-family: Microsoft jhenghei;">
+<p>JavaScript 是一個可以幫您在網站裡加入互動功能的程式語言(舉例來說,一個遊戲可能會在按鈕按下或資料被輸入表單內時回應、動態更改樣式、以及展示動畫等)。這篇文章會幫助您踏上學習這個令人興奮的語言的旅程,並展示她可以實現的所有可能。</p>
+</div>
+
+<h2 id="所以_JavaScript_到底是什麼?">所以 JavaScript 到底是什麼?</h2>
+
+<p>{{Glossary("JavaScript")}} 是一個成熟的動態程式語言,應用於 {{Glossary("HTML")}} 文件(document)上時,就可以為網頁提供動態的互動功能。JavaScript 是由 Mozilla project、Mozilla Foundation 和 Mozilla Corporation 的創辦人 Brendan Eich 所發明的。</p>
+
+<p>你可以用 JavaScript 實現許多事情。你可以先從簡單的特性開始,如跑馬燈、相簿、動態版型、回應按鈕點擊等。在你熟悉的這個程式語言以後,甚至可以製作遊戲、2D平面以及立體的圖像、資料庫系統等等的應用!</p>
+
+<p>JavaScript 本身非常的簡潔,卻也充滿彈性,開發者們已經以 JavaScript 核心為基礎為她撰寫了相當多的工具,讓各位可以感到事半功倍。這些工具包括:</p>
+
+<ul>
+ <li>內建在瀏覽器內的應用程式介面(Application Programming Interfaces,{{Glossary("API","APIs")}})提供了多樣化的功能,像是動態產生 HTML 以及設定 CSS 樣式、擷取以及處理從使用者的網路攝影機錄下的影像、製作立體圖形或是聲音樣本。</li>
+ <li>第三方 API 允許開發者將他們的網頁與其他如 Twitter 或 Facebook 提供的內容合併在一起。</li>
+ <li>第三方框架和函式庫允許您將這些元件套用在您的 HTML 文件內,讓您可以迅速地建立網頁或應用程式。</li>
+</ul>
+
+<h2 id="「Hello_world」範例程式">「Hello world」範例程式</h2>
+
+<p>前面所述的功能聽起來令人興奮,而她也的確符合這樣的期待— JavaScript 是眾多令人感到興奮的網路科技之一,您會因為選擇利用她來製作網頁而進入一個嶄新且充滿創意及力量的次元。</p>
+
+<p style="font-family: Microsoft jhenghei;">但無論如何,要讓 JavaScript 跟 HTML 和 CSS 合作無間的話,可能還要費一些功夫。現在您將會從一些細小的地方開始著手,接著一步步地往前進。首先,我們將會向您展示如何將一些基本的 JavaScript 給加入您的頁面中,並且打造一個<em>「hello world!」</em>的範例(<a href="https://zh.wikipedia.org/zh-tw/Hello_World">這同時也是許多程式語言的標準範例程式</a>)。</p>
+
+<div class="warning">
+<p><strong>注意</strong>:如果您還沒有學習過先前的課程,<a href="https://github.com/mdn/beginner-html-site-styled/archive/gh-pages.zip">請您下載這個範例程式碼</a>,並以此開始練習。</p>
+</div>
+
+<ol style="font-family: Microsoft jhenghei;">
+ <li>首先,進入您測試網頁的資料夾中,並建立一個名為 <code>main.js</code> 的檔案,再將她存放於 <code>scripts</code> 資料夾內。</li>
+ <li>接著,開啟 <code>index.html</code> 檔案,並在 <code>&lt;/body&gt;</code> 這個結束標籤之前的位置,使用一行新的空間來輸入以下的元素:
+ <pre class="brush: html">&lt;script src="scripts/main.js"&gt;&lt;/script&gt;</pre>
+ </li>
+ <li>我們做的事情,基本上跟新增一個 CSS 的 {{htmlelement("link")}} 元素是相同的概念 — 我們將 JavaScript 給導入這個頁面中,讓她來影響 HTML(以及 CSS、還有任何頁面上的東西)。</li>
+ <li>再來我們把以下的程式碼新增到 <code>main.js</code> 檔案內:
+ <pre class="brush: js">var myHeading = document.querySelector('h1');
+myHeading.textContent = 'Hello world!';</pre>
+ </li>
+ <li>現在請您將修改過的 HTML 和 JavaScript 給存檔,再用瀏覽器讀取 <code>index.html</code>。您應該會看到以下的內容:<img alt="" src="https://mdn.mozillademos.org/files/9543/hello-world.png" style="display: block; height: 236px; margin: 0px auto; width: 806px;"></li>
+</ol>
+
+<div class="note">
+<p><strong>備註</strong>:我們選擇將 {{htmlelement("script")}} 元素放在接近 HTML 檔案底部的原因,是因為瀏覽器是依照程式碼存在檔案中的順序來讀取 HTML 檔案的。如果 JavaScript 先被瀏覽器讀取了,那她應該要去影響她之後的 HTML 程式碼,但有時候卻行不通,因為她比應該產生改變的 HTML 還要早被讀取到。因此,把她放在接近檔案底部的位置,通常都會是一個不錯的策略。</p>
+</div>
+
+<h3 id="發生什麼事了?">發生什麼事了?</h3>
+
+<p>所以您的標題文字已經被 JavaScript 修改成「Hello world!」了。我們先使用了一個叫做 {{domxref("Document.querySelector", "querySelector()")}} 的函式來取得了我們標題參考(Reference),並且將她存在一個叫做 <code>myHeading</code> 的變數裡面。這跟我們在操作 CSS 時使用的選擇器是相似的。當您想要更動某個元素時,首先您要將她選取起來。</p>
+
+<p>之後,我們將變數 <code>myHeading</code> 中 {{domxref("Element.innerHTML", "innerHTML")}} 特性的值設為「Hello world!」。</p>
+
+<div class="note">
+<p><strong>備註</strong>:Both of the features you used above are parts of the <a href="/en-US/docs/Web/API/Document_Object_Model">Document Object Model (DOM) API</a>, which allows you to manipulate documents.</p>
+</div>
+
+<h2 id="語言基礎速成">語言基礎速成</h2>
+
+<p>接著我們來解釋一下 JavaScript 基本特性,以讓您更加地了解她是如何運作的。更好的事情是,這些特性基本上也存在於所有程式語言中。所以如果您可以充分理解這些基礎知識,您就可以撰寫程式來創造無限可能!</p>
+
+<div class="warning">
+<p>注意:在這篇文章中,請您試著將範例程式碼輸入到 JavaScript 主控台中,並觀察發生了什麼事。如果您想要了解更多 JavaScript 主控台的細節,請參閱 <a href="https://developer.mozilla.org/zh-TW/Learn/Discover_browser_developer_tools">Discover browser developer tools</a>。</p>
+</div>
+
+<h3 id="變數(Variables)">變數(Variables)</h3>
+
+<p>變數({{Glossary("Variable", "Variables")}})是可以用來儲存數值的容器。要宣告一個變數,首先要用關鍵字 <code>var</code> 來開頭,並在後面輸入您想要用來呼叫她的名字:</p>
+
+<pre class="brush: js">let myVariable;</pre>
+
+<div class="note" style="font-family: Microsoft jhenghei;">
+<p><strong>備註</strong>:在 JavaScript 檔案內的每行內容都需要在結尾加上分號,以標示出這行結束的位置。只有在需要於單行中隔開敘述句時,分號才是絕對需要的。然而,有些人相信在每一個敘述句結尾加上分號才是最佳實踐。這裡有其他何時要加或不加分號的規則——請參考 <a href="http://news.codecademy.com/your-guide-to-semicolons-in-javascript/">Your Guide to Semicolons in JavaScript</a> 以瞭解更多資訊。</p>
+</div>
+
+<div class="note">
+<p><strong>備註</strong>:基本上您可以幫變數取任何名字,不過還是有一些限制的(請參閱<a href="http://www.codelifter.com/main/tips/tip_020.shtml">這篇文章</a>以了解變數的命名規則)。假如不太確定,可以<a href="https://mothereff.in/js-variables">檢查變數名稱</a>來看看是否合法。</p>
+</div>
+
+<div class="note">
+<p><strong>備註</strong>:JavaScript 是會區分大小寫字母的——<code>myVariable</code> 就跟 <code>myvariable</code> 不相同。如果您的程式碼出現了一些問題,可以試著檢查一下字母的大小寫!</p>
+</div>
+
+<p>宣告了一個變數之後,您可以為她指定一個數值:</p>
+
+<pre class="brush: js">myVariable = 'Bob';</pre>
+
+<p>您可以呼叫這個變數的名字來取得這個值:</p>
+
+<pre class="brush: js">myVariable;</pre>
+
+<p>如果您有需要,您也可以在一行之內同時做完這兩件事情:</p>
+
+<pre class="brush: js">let myVariable = 'Bob';</pre>
+
+<p>當您把一個數值指定給一個變數之後,您也可以再次改變它:</p>
+
+<pre>let myVariable = 'Bob';
+myVariable = 'Steve';</pre>
+
+<p>請記得這些變數有著不同的<a href="/zh-TW/docs/Web/JavaScript/Data_structures">資料型態</a>:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="row">變數</th>
+ <th scope="col">說明</th>
+ <th scope="col">範例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th scope="row">{{Glossary("String")}}</th>
+ <td>字串,一段文字。如果要將字串指定給一個變數,您應該將內容用引號給框起來。</td>
+ <td><code>let myVariable = 'Bob';</code></td>
+ </tr>
+ <tr>
+ <th scope="row">{{Glossary("Number")}}</th>
+ <td>數值,一個數字。數字不被引號框起來。</td>
+ <td><code>let myVariable = 10;</code></td>
+ </tr>
+ <tr>
+ <th scope="row">{{Glossary("Boolean")}}</th>
+ <td>布林值,一個  True(真)/False(假)數值。<code>true</code>/<code>false</code> 是 JavaScript 內的特殊關鍵字,不需要用引號將她框住。</td>
+ <td><code>let myVariable = true;</code></td>
+ </tr>
+ <tr>
+ <th scope="row">{{Glossary("Array")}}</th>
+ <td>陣列,一個可以儲存多個數值在單一參考中的結構。</td>
+ <td>
+ <p><code>let myVariable = [1,'Bob','Steve',10];</code><br>
+ 可以用這個方式來呼叫陣列的每一個成員:<code>myVariable[0]、myVariable[1]</code> 等等。</p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">{{Glossary("Object")}}</th>
+ <td>物件。基本上,JavaScript 內的所有東西都可以視為一個物件,而且可以被存放在變數裡。請將這個概念記下來。</td>
+ <td><code>let myVariable = document.querySelector('h1');</code><br>
+ 這個項目之前的所有例子也都是物件。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>所以為什麼我們需要變數?這個嘛,我們寫程式時可以做的任何有趣的事情,都需要有變數的參與。如果數值不會更動,那您也無法做任何動態的事情,像是客製化一個歡迎訊息、或是變更相簿裡的圖片。</p>
+
+<h3 id="註解(Comments)">註解(Comments)</h3>
+
+<p>您可以在您的 JavaScript 程式碼中加入註解,就像您在撰寫 CSS 時做的事情一樣:</p>
+
+<pre class="brush: js">/*
+Everything in between is a comment.
+*/</pre>
+
+<p>如果您的註解只有一行,我們通常會簡單將註解放在兩個斜線的後方,像以下的範例:</p>
+
+<pre class="brush: js" style="font-size: 14px;">// This is a comment
+</pre>
+
+<h3 id="運算子(Operators)">運算子(Operators)</h3>
+
+<p>運算子( {{Glossary("operator")}})是一個數學符號,可以讓兩個數值(或是變數)交互作用以後產生結果。您可以從以下的表格中看到一些最簡單的運算子,並將範例輸入 JavaScript 主控台來測試看看。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="row">運算子</th>
+ <th scope="col">說明</th>
+ <th scope="col">符號</th>
+ <th scope="col">範例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th scope="row">相加/連接</th>
+ <td>用於將兩個數字相加,或是將兩個字串連接在一起。</td>
+ <td><code>+</code></td>
+ <td><code>6 + 9;<br>
+ 'Hello ' + 'world!';</code></td>
+ </tr>
+ <tr>
+ <th scope="row">
+ <p>減、乘、除</p>
+ </th>
+ <td>這些運算子就跟基礎數學計算中在做的事情相同。</td>
+ <td><code>-</code>, <code>*</code>, <code>/</code></td>
+ <td><code>9 - 3;<br>
+ 8 * 2; // 在 JavaScript 中,相乘運算子是個星號<br>
+ 9 / 3;</code></td>
+ </tr>
+ <tr>
+ <th scope="row">指定運算子</th>
+ <td>您已經見過她了:這可以將一個數值指定給一個變數。</td>
+ <td><code>=</code></td>
+ <td><code>var myVariable = 'Bob';</code></td>
+ </tr>
+ <tr>
+ <th scope="row">等價運算子</th>
+ <td>測試兩個數值是否相等,並且回傳一個 <code>true</code>/<code>false</code> 的結果。</td>
+ <td><code>===</code></td>
+ <td><code>var myVariable = 3;<br>
+ myVariable === 4;</code></td>
+ </tr>
+ <tr>
+ <th scope="row">否定、不相等</th>
+ <td>通常會跟相等運算子搭配使用,否定運算子在 JavaScript 中代表邏輯非(NOT)—她可以將 <code>true </code>轉換為 <code>false</code> ……等。</td>
+ <td><code>!</code>, <code>!==</code></td>
+ <td>
+ <p>第一個敘述句回傳的是 <code>true</code>,但我們使否定運算子,使得對照組的敘述句回傳了 <code>false</code>:</p>
+
+ <p><code>var myVariable = 3;<br>
+ !(myVariable === 3);</code></p>
+
+ <p>在這裏,我們測試了「<code>myVariable </code>是否不等於 3」的一個敘述。這個敘述回傳的是 <code>false</code>,因為她確實等於 3。</p>
+
+ <p><code><code>var myVariable = 3;</code><br>
+ myVariable !== 3;</code></p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>其實還有更多的運算子等的您去探索,但我們將在這裡先打住。您可以參照這篇<a href="/zh-TW/docs/Web/JavaScript/Reference/Operators">運算式與運算子</a>以取得完整的列表。</p>
+
+<div class="note">
+<p><strong>備註</strong>:混合使用多種資料型態的話,可能會在計算時產生一些奇怪的結果,所以您要謹慎地為變數選用正確的資料類型。舉個例子:在主控台中輸入  <code>"35" + "25"</code>。為什麼您沒有得到您所想要的結果?因為使用引號框住數字會將她轉換成字串,所以您其實是將兩個字串給連接起來,而不是將她們給相加。如果您輸入的是 <code>35 + 25</code>,您將會得到正確的結果。</p>
+</div>
+
+<h3 id="條件(Conditionals)">條件(Conditionals)</h3>
+
+<p>條件是種程式碼結構,可以讓您測試某個陳述式會不會回傳真值,並根據不同的結果執行不同程式碼。最常見的形式是 <code>if ... else</code> 。以下是一個範例:</p>
+
+<pre class="brush: js">let iceCream = 'chocolate';
+if (iceCream === 'chocolate') {
+ alert('Yay, I love chocolate ice cream!');
+} else {
+ alert('Awwww, but chocolate is my favorite...');
+}</pre>
+
+<p>在 <code>if ( ... )</code> 裡面的陳述式就是一個測試—這將會使用到等價運算子(如先前所描述的)來比較變數 <code>iceCream</code> 和字串 <code>chocolate</code> 兩者是否相等,如果在比較之後回傳了 <code>true</code>,接著就執行第一個區塊內的程式碼。如果不是,就略過第一個區塊的程式碼並轉而執行寫在執行在 <code>else 之後、</code>第二個區塊內的程式碼。</p>
+
+<h3 id="函式(Functions)">函式(Functions)</h3>
+
+<p>函式({{Glossary("Function", "Functions")}})是一種將需要重複使用的功能打包裝起來的方法,所以當要再次執行這些功能的時候,就可以呼叫這個函式來達成,而不是一再的重新撰寫程式碼。您在先前的篇幅中其實已經看過一些函式了,例如:</p>
+
+<ol>
+ <li>
+ <pre class="brush: js">let myVariable = document.querySelector('h1');</pre>
+ </li>
+ <li>
+ <pre class="brush: js">alert('hello!');</pre>
+ </li>
+</ol>
+
+<p>這些函式是瀏覽器為您內建的,您可以自由地使用。</p>
+
+<p>如果您看到某些很像是變數名稱的東西,但是後面帶有括號 — <code>()</code> — 的話,表示這可能是一個函式。函式通常會接收參數({{Glossary("Argument", "arguments")}})—這是一些可以讓她完成工作的必要資料。這些參數會被寫在括號裡面,如果有不只一個參數的話,彼此間要用逗號隔開。</p>
+
+<p>舉例來說,<code>alert()</code> 這個函式會在瀏覽器內視窗內產生一個彈出視窗,但是我們必須要傳給她一個字串當作參數,告訴這個函式,該把什麼東西放到這個彈出視窗裡。</p>
+
+<p>好消息是:您可以定義您自己的函式 — 底下的這個範例中,我們將會為您帶來一個簡單的函式,她會接收兩個數字當作參數,並將其相乘:</p>
+
+<pre class="brush: js">function multiply(num1,num2) {
+ let result = num1 * num2;
+ return result;
+}</pre>
+
+<p>您可以試著在主控台中執行上述的函式,然後再用不同的參數來測試這個函式幾次,例如:</p>
+
+<pre class="brush: js">multiply(4,7);
+multiply(20,20);
+multiply(0.5,3);</pre>
+
+<div class="note">
+<p><strong>備註</strong>:<a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/return"><code>return</code></a> 陳述式會要求瀏覽器將 <code>result </code>變數回傳,以利後續使用。這是必要的,不然在函式內定義的變數就只能在函式內使用。這個現象叫作變數的有效使用範圍({{Glossary("Scope", "scoping")}})(請參閱<a href="/zh-TW/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Variable_scope">這篇文章以了解變數的有效使用範圍</a>)</p>
+</div>
+
+<h3 id="事件(Events)">事件(Events)</h3>
+
+<p>如果要在網頁上創造真正的互動功能,您將會需要事件(Events) — 這是一種可以監聽瀏覽器發生了什麼事情的程式碼結構,接著她會允許您執行其他程式碼以回應這些事件。最明顯的事件就是 <a href="/zh-TW/docs/Web/Events/click">click event</a> 了,當瀏覽器裡的某個東西被滑鼠點選時,這個事件就會被觸發。如果要測試一下這個事件,請您把底下的程式碼輸入到主控台內,接著用滑鼠點選目前的網頁:</p>
+
+<pre class="brush: js">document.querySelector('html').onclick = function() {
+ alert('Ouch! Stop poking me!');
+}</pre>
+
+<p>有許多的方法可以把事件跟網頁元素結合在一起。在底下的程式碼中,我們先選擇了 HTML 元素,並把這個元素的 <code><a href="/zh-TW/docs/Web/API/GlobalEventHandlers.onclick">onclick</a></code> 處理器設定為一個匿名函式,裡面裝著在滑鼠點選事件發生時,要執行的程式碼:</p>
+
+<p>請特別注意到以下這段程式碼:</p>
+
+<pre class="brush: js">document.querySelector('html').onclick = function() {};</pre>
+
+<p>產生的結果將會與下面這段程式碼相同</p>
+
+<pre class="brush: js">var myHTML = document.querySelector('html');
+myHTML.onclick = function() {};</pre>
+
+<p>只是上面那段寫起來比較簡短罷了。</p>
+
+<h2 id="徹底加強我們的範例網頁">徹底加強我們的範例網頁</h2>
+
+<p>到目前為止,我們已經學會一些 JavaScript 的基礎知識了,接下來讓我們幫這個網頁新增一些很酷的特色,並給您一些靈感。</p>
+
+<h3 id="加入一個圖片變換器">加入一個圖片變換器</h3>
+
+<p>在這個小節中,我們將在這個網頁裡添加一個圖片,以及一些簡單的 JavaScript,當這個圖片被滑鼠點選的時候,就會在兩個圖片之間互相切換。</p>
+
+<ol>
+ <li>首先,先去找張您可以為您的網頁增添光彩的圖片。請盡量找一張尺寸跟第一張圖相同的圖片、或至少是張相似尺寸的圖片。</li>
+ <li>將圖片存放到 <code>images</code> 資料夾內。</li>
+ <li>編輯您的 <code>main.js</code> 檔案,並且將以下的 JavaScript 輸入到檔案內(如果您還有看見那段 hello world 的 JavaScript,請把她們給刪除):
+ <pre class="brush: js">var myImage = document.querySelector('img');
+
+myImage.onclick = function() {
+ let mySrc = myImage.getAttribute('src');
+ if(mySrc === 'images/firefox-icon.png') {
+ myImage.setAttribute ('src','images/firefox2.png');
+ } else {
+ myImage.setAttribute ('src','images/firefox-icon.png');
+ }
+}</pre>
+ </li>
+ <li>請將全部檔案儲存,並用瀏覽器開啟 <code>index.html</code>。現在請您點選圖片,她應該會切換成另外一張!</li>
+</ol>
+
+<p>在這裡,我們把一個圖片元素的參考存進了 <code>myImage</code> 變數裡。接著,我們把這個變數的 <code>onclick</code> 事件處理器設定為一個匿名函式。現在,每當這個圖片被點選一次:</p>
+
+<ol>
+ <li>我們會去取得圖片中 <code>src</code> 屬性的數值</li>
+ <li>我們用一個條件判斷式,來檢查 <code>src</code> 的數值是否跟原始圖片的位址相同:
+ <ol>
+ <li>如果兩者相同,那我們就把 <code>src</code> 的數值更改為第二個圖片的位址,也就是在  {{htmlelement("image")}} 元素裡強迫讀取另外一張圖片。</li>
+ <li>如果兩者不同(也就是圖片已經被切換過了),我們就把 <code>src</code> 的數值更改為原始圖片的位址,圖片就會被切換回原來那張。</li>
+ </ol>
+ </li>
+</ol>
+
+<h3 id="添加個客製化的歡迎訊息">添加個客製化的歡迎訊息</h3>
+
+<p>接著我們再來添加一些程式碼,在使用者瀏覽這個網頁的時候,將網頁標題改為客製化的歡迎訊息。這個歡迎訊息會一直保留著,直到使用者離開這個網頁為止。我們也會添加個切換使用者的選項,並且一併更改歡迎訊息。</p>
+
+<ol>
+ <li>編輯 <code>index.html</code> 檔案,並將下列程式碼置於 {{htmlelement("script")}} 元素之前:
+
+ <pre class="brush: html">&lt;button&gt;Change user&lt;/button&gt;</pre>
+ </li>
+ <li>編輯 <code>main.js</code> 檔案,並將下列程式碼一字不漏地置於檔案的最末端 — 這些程式碼將會取得新按鈕、標題的參考,並把它們存在變數裡:
+ <pre class="brush: js">var myButton = document.querySelector('button');
+var myHeading = document.querySelector('h1');</pre>
+ </li>
+ <li>現在,將以下的函式加進去以設定客製化的歡迎訊息 — 這些函式目前還不會產生作用,但我們等一下會用到她們:
+ <pre class="brush: js">function setUserName() {
+ let myName = prompt('Please enter your name.');
+ localStorage.setItem('name', myName);
+ myHeading.innerHTML = 'Mozilla is cool, ' + myName;
+}</pre>
+ 這個函式包含了一個會產生一個對話視窗的 <a href="/zh-TW/docs/Web/API/Window.prompt"><code>prompt()</code></a> 函式,有點像 <code>alert()</code>,只是 <code>prompt()</code> 會要求使用者輸入一些資料,並在使用者點選<code>確認</code>之後,將內容儲存在一個變數裡面。接著,我們呼叫一個名稱為 <code>localStorage</code> 的 API,這個 API 可以讓使用者先將一些資料儲存在瀏覽器裡面,之後有需要的話再取出來使用。我們使用 localStorage 的 <code>setItem()</code> 函式來建立並且把資料儲存到一個名稱為 <code>'name'</code> 的變數裡,再把包含者用者名字的 <code>myName</code> 的值指定給她。最後,我們將一個字串跟使用者的名字指定給標題的 <code>innerHTML</code> 特性:</li>
+ <li>接著,加入這個 <code>if ... else</code> 區塊 — 因為她會在程式一開始被讀取的時候就被啟用,我們稱她為初始化程式碼:
+ <pre class="brush: js">if(!localStorage.getItem('name')) {
+ setUserName();
+} else {
+ let storedName = localStorage.getItem('name');
+ myHeading.innerHTML = 'Mozilla is cool, ' + storedName;
+}</pre>
+ 這個區塊一開始使用了邏輯負運算子(邏輯非)來檢查 <code>name</code> 這個物件是否存在。如果沒有,那就執行 <code>setUserName()</code> 這個函式並且創造她。如果有了(例如:使用者已經在上一次造訪網頁時就設定過了),我們就使用 <code>getItem()</code> 函式來取得儲存的名字,並且將標題的 <code>innerHTML</code> 特性設定為一個字串加上使用者的名字,也就是我們在 <code>setUserName()</code> 函式裡做的事情。</li>
+ <li>最後,把以下的 <code>onclick</code> 事件處理器跟按鈕綁定,如此一來,每次點選按鈕時就會執行 <code>setUserName()</code>。這將允許使用者透過點選那個按鈕來重新設定一個新的名字:
+ <pre class="brush: js">myButton.onclick = function() {
+  setUserName();
+}
+</pre>
+ </li>
+</ol>
+
+<p>現在當您造訪這個網頁時,她會詢問您的名字,並且給您一個客製化過的歡迎訊息。在這之後,您也可以隨時透過點選那個按鈕來更改名字。順帶一提,因為這組客製化過的訊息是存在 localStorage 裡的,所以即使您將網頁關起來,她還是會保留著,所以當您下次開啟這個網頁時,這段客製化的訊息依然會出現!</p>
+
+<h3 id="用戶名稱是否為null">用戶名稱是否為null</h3>
+
+<p>當您運行範例並出現提示您輸入用戶名稱的對話框時,請嘗試按下<em>取消 </em>鈕。您會看到一個標題顯示著"Mozilla is cool, null"。這是因為當您取消提示時,該值將會被設為null。null在Javascript中的一個特殊值,基本上用來表示沒有任何值。</p>
+
+<p>再試試按下OK,但不輸入任何名字。您將會看到"Mozilla is cool,",該結果的原因非常簡單的可以理解。</p>
+
+<p>如果你想避免產生這些問題,您應該檢查使用者是否輸入了null或是空白的名字。試著透過修改<code>setUserName()</code>來應對這些問題,結果如下:</p>
+
+<pre>function setUserName() {
+ let myName = prompt('Please enter your name.');
+ if(!myName || myName === null) {
+ setUserName();
+ } else {
+ localStorage.setItem('name', myName);
+ myHeading.innerHTML = 'Mozilla is cool, ' + myName;
+ }
+}</pre>
+
+<p>用人類的語言來理解,如果<code>myName</code>沒有值或是它的值是<code>null</code>,再次從頭執行<code>setUserName()。</code>如果<code>myName</code>有值(如果上述條件是不為真).將值存入<code>localStorage</code>並將值設定給標頭檔的文件。</p>
+
+<h2 id="結語">結語</h2>
+
+<p>如果您已經照著這篇文章的所有步驟做完了,您應該會看到以下的畫面(或者您也可以<a href="https://mdn.github.io/beginner-html-site-scripted/">瀏覽我們製作的版本</a>):</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9539/website-screen-scripted.png" style="display: block; height: 995px; margin: 0px auto; width: 800px;"></p>
+
+<p>如果在過程中遇到了任何問題,您也可以隨時把您的成品與我們 <a href="https://github.com/mdn/beginner-html-site-scripted/blob/gh-pages/scripts/main.js">放在 Github 上的範例 </a>相互對照。</p>
+
+<p>在此,我們只稍稍體驗了 JavaScript 的一些皮毛。如果您非常享受這段學習的過程,並想要繼續深究,請您繼續瀏覽我們製作的 <a href="/zh-TW/docs/Web/JavaScript/Guide">JavaScript 指南</a>。</p>
+
+<h2 id="See_also">See also</h2>
+
+<dl>
+ <dt><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript">JavaScript — Dynamic client-side scripting</a></dt>
+ <dd>Our JavaScript learning topic — dive into JavaScript in much more detail.</dd>
+ <dt><a href="https://learnjavascript.online/">Learn JavaScript</a></dt>
+ <dd>An excellent resource for aspiring web developers — Learn JavaScript in an interactive environment, with short lessons and interactive tests, guided by automated assessment. The first 40 lessons are free, and the complete course is available for a small one-time payment.</dd>
+</dl>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li id="Installing_basic_software"><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a></li>
+ <li id="What_will_your_website_look_like"><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li>
+ <li id="Dealing_with_files"><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li>
+ <li id="HTML_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li>
+ <li id="CSS_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li>
+ <li id="JavaScript_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li>
+ <li id="Publishing_your_website"><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li>
+ <li id="How_the_web_works"><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li>
+</ul>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html b/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html
new file mode 100644
index 0000000000..355291387a
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/publishing_your_website/index.html
@@ -0,0 +1,116 @@
+---
+title: 將你的網站發佈上線
+slug: Learn/Getting_started_with_the_web/Publishing_your_website
+translation_of: Learn/Getting_started_with_the_web/Publishing_your_website
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p>當你完成你的網頁程式碼後,你需要把它放到網路上,這樣人們才可以搜尋得到。這個章節將介紹如何快速的把你的程式碼放到網路上。</p>
+</div>
+
+<h2 id="有哪些選項?">有哪些選項?</h2>
+
+<p>發佈網站並不是一個幾句話就能說得完的課題,主要是因為有太多方法能夠發佈網站。在這個章節中,我們不會介紹所有可能的方法,但是我們會簡單講解三個概念,並從初學者的角度分別說明它們的優缺點,然後一步一步帶你用一個你現階段有辦法完成的方法發佈網站。</p>
+
+<h3 id="取得主機(hosting)和網域名稱(domain_name)">取得主機(hosting)和網域名稱(domain name)</h3>
+
+<p>如果想要完全掌控你發佈的網站,那你可能需要花錢買:</p>
+
+<ul>
+ <li>主機:跟主機租借商(hosting company)的<a href="/zh-TW/docs/Learn/Common_questions/What_is_a_web_server">網路伺服器</a>(web server)租一個放置檔案的空間。你把你建置的網頁檔案放到這個空間中,然後想要連結到網頁的人就能透過網頁伺服器連結到你的網站。</li>
+ <li><a href="/zh-TW/Learn/Understanding_domain_names">網域名稱</a>(domain name):人們可以透過這個獨特的網址來尋找你的網站,像是 <code>http://www.mozilla.org</code> 或 <code>http://www.bbc.co.uk</code>。你需要向<strong>網域名稱註冊商(domain registrar)</strong>租借網域名稱。</li>
+</ul>
+
+<p>許多專業的網站是用這個方法發佈的。</p>
+
+<p>除此之外,你還會需要一個 {{Glossary("FTP", "File Transfer Protocol (FTP)")}} 程式(點選<a href="/zh-TW/Learn/How_much_does_it_cost#Software">How much does it cost: software</a> 來取得更多資訊),這樣才能真正的把你建置的網頁檔案傳達給伺服器。FTP 程式很廣泛,但一般來說,你可以用你公司提供的資訊,像是使用者名稱、密碼以及host name來登入你的網頁伺服器,它就會以兩個視窗的形式分別顯示你電腦裡的檔案和你網頁伺服器上的檔案,然後你就可以移動你的檔案。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9469/ftp.jpg" style="display: block; height: 487px; margin: 0px auto; width: 800px;"></p>
+
+<h4 id="租借主機和網域的方法">租借主機和網域的方法</h4>
+
+<ul>
+ <li>在這裡我們不介紹特定的主機租借商(hosting companies)或網域名稱註冊商(domain name registrars),你只要搜尋「web hosting」與「domain names」就能找到。所有的註冊商都會提供方法,讓你檢查你想要的網域名稱可否使用、或有沒有被註冊過。</li>
+ <li>你的 {{Glossary("ISP", "網路供應商")}} 可能會提供有限制的主機,這可以讓你發佈一些比較簡易的網站,雖然會有些限制,但嘗試使用它來發佈你的第一個網站也是很不錯的 — 聯絡並詢問他們!</li>
+ <li>有些公司提供免費的服務,像是 <a href="https://neocities.org/">Neocities</a>、<a href="https://www.blogger.com">Blogger</a>和 <a href="https://wordpress.com/">WordPress</a>,但是我要強調,你付出多少得到多少,不過使用它們來發佈你的第一個網站何嘗不是一個理想的方法? 而且免費的服務大部分不需要FTP程序來上傳檔案,你只需要用它們提供的介面來移動檔案。</li>
+ <li>有些公司同時提供主機(hosting)和網域(domains)的服務。</li>
+</ul>
+
+<h3 id="使用線上工具,像是_GitHub_或_Google_App_Engine">使用線上工具,像是 GitHub 或 Google App Engine</h3>
+
+<p>使用工具來發佈網站:</p>
+
+<ul>
+ <li><a href="https://github.com/">GitHub</a> 可以交流程式的平台,它提供你一個空間來存放程式碼,這個空間是基於 <a href="http://git-scm.com/">Git</a> 的<strong>版本控制系統,</strong>你能夠透過系統共同編輯平台上的程式專案,而這個系統是開放資源,也就是說全世界的人都可以找到你的 GitHub code,包括使用它、從中學習並將它改得更好。GitHub 提供一個非常實用的工具— <a href="https://pages.github.com/">GitHub Pages</a>,它能讓你發佈網站。</li>
+ <li><a href="https://cloud.google.com/appengine/" title="App Engine - Build Scalable Web &amp; Mobile Backends in Any Language | Google Cloud Platform">Google App Engine</a> 是一個強大的平台,不管是要從頭建置 multi-tiered web 程式還是託管靜態網站,它都能讓你在 Google 的基礎下建置和運行應用程式。點選 <a href="/zh-TW/docs/Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine">How do you host your website on Google App Engine?</a> 以獲得更多資訊。</li>
+</ul>
+
+<p>這類工具和託管不同,通常他們都是免費的,不過功能當然也會受限。</p>
+
+<h3 id="透過如_Thimble_這樣的網路_IDE">透過如 Thimble 這樣的網路 IDE</h3>
+
+<p>有些 web app 會模擬網站的開發環境,讓你能執行 HTML, CSS, JavaScript,顯示程式碼執行結果、並渲染至網站上--一切都在瀏覽器的一個頁籤內完成。通常這些工具用起來都簡單、學起來簡單、基本功能還是免費的。他們用獨一無二的網址,替你保管渲染好的頁面。不過,基本功能基本上很受限,而且 app 通常都不提供如圖像這種 asset 的託管。</p>
+
+<p>試試以下網站,看看你能想到什麼點子:</p>
+
+<ul>
+ <li><a href="https://jsfiddle.net/">JSFiddle</a></li>
+ <li><a href="https://thimble.mozilla.org">Thimble</a></li>
+ <li><a href="http://jsbin.com/">JS Bin</a></li>
+ <li><a href="https://codepen.io/">CodePen</a></li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9471/jsbin-screen.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></p>
+
+<h2 id="透過_GitHub_發布">透過 GitHub 發布</h2>
+
+<p>來看看把網站用 Github Pages 發佈多簡單。</p>
+
+<ol>
+ <li>首先註冊 <a href="https://github.com/">GitHub</a> 並驗證電子郵件。</li>
+ <li>接著針對要上傳的檔案<a href="https://github.com/new">建立一個 repository</a>。</li>
+ <li>在頁面的 <em>Repository name</em> 標籤輸入 <em>username</em>.github.io,<em>username</em> 是指你的用戶名。例如我們的好朋友 bobsmith 就會輸入 <em>bobsmith.github.io</em>.<br>
+ 另外,請勾選 <em>Initialize this repository with a README</em> 後點選 <em>Create repository</em>。<img alt="" src="https://mdn.mozillademos.org/files/9479/github-create-repo.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></li>
+ <li>之後,把網站內容拖曳到 repository 目錄,並勾選 <em>Commit changes</em>。
+ <div class="note">
+ <p><strong>注</strong>:請確定目錄內有 <em>index.html</em> 檔案。</p>
+ </div>
+ </li>
+ <li>
+ <p>現在讓瀏覽器連到 <em>username</em>.github.io 來看看你的網站。例如你的用戶名字是 <em>chrisdavidmills</em>,就連到 <a href="http://chrisdavidmills.github.io/">chrisdavidmills.github.io</a>。</p>
+
+ <div class="note">
+ <p><strong>注</strong>:讓網站上線需要一點時間。如果網站沒有馬上運行,稍等一段時間後再試一次。</p>
+ </div>
+ </li>
+</ol>
+
+<p>想多理解的話,請參考 <a href="https://help.github.com/categories/github-pages-basics/">GitHub Pages Help</a>.</p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/What_is_a_web_server">何謂網路伺服器</a></li>
+ <li><a href="/zh-TW/Learn/Understanding_domain_names">Understanding domain names</a></li>
+ <li><a href="/zh-TW/Learn/How_much_does_it_cost">How much does it cost to do something on the web?</a></li>
+ <li><a href="https://www.codecademy.com/learn/deploy-a-website">Deploy a Website</a>: A nice tutorial from Codecademy that goes a bit further and shows some additional techniques.</li>
+ <li><a href="http://alignedleft.com/resources/cheap-web-hosting">Cheap or Free Static Website Hosting</a> by Scott Murray has some useful ideas on available services.</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</p>
+
+<h2 id="在本模組內">在本模組內</h2>
+
+<ul>
+ <li id="Installing_basic_software"><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li id="What_will_your_website_look_like"><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li id="Dealing_with_files"><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li id="HTML_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基礎</a></li>
+ <li id="CSS_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本</a></li>
+ <li id="JavaScript_basics"><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基礎</a></li>
+ <li id="Publishing_your_website"><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li id="How_the_web_works"><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網路的運作方式</a></li>
+</ul>
diff --git a/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html b/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html
new file mode 100644
index 0000000000..cb753a09d2
--- /dev/null
+++ b/files/zh-tw/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html
@@ -0,0 +1,108 @@
+---
+title: 你的網站看起來會是什麼樣子?
+slug: Learn/Getting_started_with_the_web/What_will_your_website_look_like
+translation_of: Learn/Getting_started_with_the_web/What_will_your_website_look_like
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</div>
+
+<div class="summary">
+<p><em>你的網站看起來會是什麼樣子?</em>會說明你該為網站做的規劃與設計,決定自己的「網站該提供哪些資訊?」、「該使用哪些字型與色彩?」,以及「網站又該達到哪些目的?」</p>
+</div>
+
+<h2 id="首要:規劃">首要:規劃</h2>
+
+<p>做任何事之前都需要一些想法。你的網站要達到哪種目的?任何 1 個網站均具備基本作用,但首先你應該保持簡單。我們要先寫出包含了標題、圖像,以及數段文字的簡單網頁。</p>
+
+<p>開始之前,請你先回答下列問題:</p>
+
+<ol>
+ <li><strong>你網站的主題為何?</strong>你喜歡貓貓狗狗?想寫城市遊記?或你愛打電動呢?</li>
+ <li><strong>你對某個主題所提供的資訊到哪種程度?</strong>寫個標題加上幾段文字,或是在網頁上加個圖片。</li>
+ <li>簡單的問:<strong>你網站的外觀為何?</strong>背景顏色?哪種字型比較合適?一般字型?卡通化的字型?又粗又大的字體?還是要纖細淡化的文字呢?</li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>複雜專案就需要更詳細的建構指南,包含所用的顏色、字型、物件之間的留白空間、適合的書寫風格,等等。這些要素有時會統整為設計指南或品牌手冊,你可參閱〈<a href="https://www.mozilla.org/en-US/styleguide/products/firefox-os/">Firefox OS Guidelines</a>〉進一步了解。</p>
+</div>
+
+<h2 id="從頭設計">從頭設計</h2>
+
+<p>接著就是拿紙筆,概略畫出你理想的網站外觀。對自己的第一個簡易網頁,不需考量太多要素或畫得太仔細,應該先養成這個勾勒草圖的習慣。不是要你變成梵谷或畢卡索,但對你以後絕對有幫助!</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9239/website-drawing-scan.png" style="display: block; height: 460px; margin: 0px auto; width: 640px;"></p>
+
+<div class="note">
+<p><strong>注意:</strong>即便是實際的複雜網站,設計團隊也都會先在紙上勾勒草圖,再接著透過圖檔編輯器或 Web 技術弄出數位版的草稿。</p>
+
+<p>Web 團隊往往編制了圖像設計師與{{Glossary("UX", "使用者經驗")}} (User Experience;UX) 設計師各 1 名。圖像設計師當然是負責整合網站的視覺效果;較屬抽象角色的 UX 設計師則要確定使用者與網站的互動方式。</p>
+</div>
+
+<h2 id="選擇網頁風格">選擇網頁風格</h2>
+
+<p>現在開始組合你想在網頁上呈現的內容。</p>
+
+<h3 id="文字">文字</h3>
+
+<p>你應該已經準備好了一些文章並分好段落。</p>
+
+<h3 id="主題色彩">主題色彩</h3>
+
+<p>可透過<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Colors/Color_picker_tool">選色工具</a>找到你喜歡的顏色。當你點擊其中一種顏色,就會看到如下圖「<code>#660066</code>」的 6 位數字,此即代表該顏色的十六進位 (Hexadecimal) 色碼。請另外找個地方記錄此色碼。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8975/Screenshot%20from%202014-11-03%2017:40:49.png" style="height: 262px; width: 448px;"></p>
+
+<h3 id="圖片">圖片</h3>
+
+<p>可透過 <a href="https://www.google.com/imghp?gws_rd=ssl">Google 的圖片搜尋</a>找到適合的圖片。</p>
+
+<ol>
+ <li>找到你想要的圖片時,點選該圖片。</li>
+ <li>按下「查看圖片」按鈕。</li>
+ <li>接著在圖片上點擊滑鼠右鍵 (Mac 則是 Ctrl + click),選擇「將圖片另存新檔...」,將圖片儲存到你熟悉的位置。或是可複製瀏覽器網址列中的網址,以待往後使用。</li>
+</ol>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8985/Screenshot%20from%202014-11-04%2015:09:21.png" style="height: 293px; width: 420px;"></p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8989/Screenshot%20from%202014-11-04%2015:20:48.png" style="height: 292px; width: 340px;"></p>
+
+<div class="note">
+<p><strong>注意:</strong>在網路上可找到的大多數圖片,包含 Google 圖片服務在內,都已註冊了著作權。為了避免自己可能違反著作權法,你可以透過 Google 的授權篩選功能。只要點擊「<strong>搜尋工具</strong>」再找到「<strong>使用權限</strong>」即可:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8981/Screenshot%20from%202014-11-04%2014:27:45.png" style="height: 195px; width: 587px;"></p>
+</div>
+
+<h3 id="字型">字型</h3>
+
+<p>選用自己喜歡的字型:</p>
+
+<ol>
+ <li>到 <a href="http://www.google.com/fonts">Google Fonts</a> 上捲動清單,直找到你喜歡的字型。你也可以使用左邊的控制功能先行篩選。</li>
+ <li>點擊你想要的字型旁邊「Add to collection」按鈕。</li>
+ <li>點擊頁面底端的「使用 (Use)」按鈕。</li>
+ <li>進入下一頁,捲動到區塊 3 與區塊 4,將 Google 顯示的程式碼複製到你的文字編輯器中,儲存以待稍後利用。</li>
+</ol>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13871/font1.png" style="height: 359px; width: 600px;"></p>
+
+<p> </p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13873/font2.png" style="height: 608px; width: 600px;"></p>
+
+<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/how_to_contribute/index.html b/files/zh-tw/learn/how_to_contribute/index.html
new file mode 100644
index 0000000000..f8a864b98d
--- /dev/null
+++ b/files/zh-tw/learn/how_to_contribute/index.html
@@ -0,0 +1,81 @@
+---
+title: 如何建設 MDN 學習專區
+slug: Learn/How_to_contribute
+tags:
+ - Documentation
+ - 初學者
+ - 貢獻
+translation_of: Learn/How_to_contribute
+---
+<div>{{LearnSidebar}}</div>
+
+<p>無論你是初來乍到、抑或尋至深處無怨尤、都應該是對貢獻 MDN 學習專區起了興趣吧。那很棒!</p>
+
+<p><span class="seoSummary">在這裡,你會看到該如何改進 MDN 學習專區的內容。視你的時間多寡、以及你是<a href="/zh-TW/Learn/How_to_contribute#我是初學者">初學者</a>、<a href="/zh-TW/Learn/How_to_contribute#我是網路開發者">網路開發者</a>、<a href="/zh-TW/Learn/How_to_contribute#我是教師">教師</a>而定,有一些你可以完成的事情。</span></p>
+
+<div class="note">
+<p><strong>注意</strong>:你可以在<a href="/zh-TW/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">如何撰寫幫助別人理解 Web 的文章</a>裡面找到指引如何撰寫學習專區的新文章。</p>
+</div>
+
+<h2 id="找到特定的任務">找到特定的任務</h2>
+
+<p><strong>貢獻者們使用 <a href="https://trello.com/b/LDggrYSV">Trello board</a> 來組織工作事務。你可以透過這個方法,找出某個專案的工作。要加入的話,只要 <a href="https://trello.com/signup">建立一個 Trello 的帳號</a>、然後去 ping Chris Mills 叫他給你撰寫 board 的權限。</strong></p>
+
+<p>Contributing is a great way to have some fun while learning new stuff. If you ever feel lost or have questions, don't hesitate to reach us on <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">our mailing list</a> or <a href="/en-US/docs/MDN/Community#Get_into_IRC">IRC channel</a> (see at the bottom of this page for details). <a href="/en-US/profiles/chrisdavidmills">Chris Mills</a> is the topic driver for the Learning Area — you could also try pinging him directly.</p>
+
+<p>接下來的章節,會提供一些在你所能下的常見點子。</p>
+
+<h2 id="我是初學者">我是初學者</h2>
+
+<p>真棒!初學者在學習專區的創建與給予回饋,不但重要還很寶貴。身為目標閱聽者的你能在文章方面,提供令你成為團內重要成員的獨特觀點。如果你透過這些文章學習卻碰上問題、或是在某些地方稿不清楚,你可以自己去改它、或告訴我們以便我們修正之。</p>
+
+<p>我們建議你可以透過以下方法貢獻:</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/MDN/Contribute/Howto/Tag">給我們的文章添加標籤</a>(約五分鐘)</dt>
+ <dd>給 MDN 的文章添加標籤,是向 MDN 貢獻的最簡單方法。我們有很多功能會透過標籤助以呈現內文資訊,所以幫忙標籤的建設相當寶貴。從沒有任何標籤的<a href="/zh-TW/docs/MDN/Doc_status/Glossary#No_tags">術語表</a>以及<a href="/zh-TW/docs/MDN/Doc_status/Learn#No_tags">學習專區</a>開始吧。</dd>
+ <dt><a href="/zh-TW/docs/Glossary">閱讀並評價術語表</a>(約五分鐘)</dt>
+ <dd>我們需要身為初學者的眼光,來檢視我們的內容。如果你發現某個術語難以理解,就表示該術語需要改進。你可以作任何認為有需要的更動。如果你不認為自己有修改該術語的技能,至少請透過<a href="/zh-TW/docs/MDN/Community#Join_our_mailing_lists">我們的郵件清單</a>告訴我們。</dd>
+ <dt><a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">撰寫新的術語</a>(約二十分鐘)</dt>
+ <dd>這是最有效的新技能學習法。選一個你想理解的概念去研究。接著,撰寫這個術語。和別人解釋,是「固著」你腦內知識的好方法。既幫自己理解所知、也幫了其他人。利人利己,大家都贏!</dd>
+ <dt><a href="/zh-TW/Learn/Index">閱讀並評價術語表學習專區的文章</a>(約兩小時)</dt>
+ <dd>和閱讀術語表差不多,但因為文章會更長了些,所以要花更多時間。</dd>
+</dl>
+
+<h2 id="我是網路開發者">我是網路開發者</h2>
+
+<p>好極了!我們需要你的技能,來確保我們教給初學者的內容正確無誤。因為這裡的宗旨是理解網路,請確保解釋儘可能簡單,但不致毫無用處。比起過度精確,可以理解才是最重要的。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Glossary">閱讀並評價術語表</a>(約五分鐘)</dt>
+ <dd>我們需要你確認文章的內容是正確又不過於艱澀難懂的。請你變更任何你認為有必要改善的地方。如果你想要在做變更之前討論一下內容,歡迎透過 <a href="/zh-TW/docs/MDN/Community#Join_our_mailing_lists">our mailing list</a> 或 <a href="/zh-TW/docs/MDN/Community#Get_into_IRC">IRC channel</a>通知我們。</dd>
+ <dt><a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">撰寫新的術語</a>(約二十分鐘)</dt>
+ <dd>闡明術語是一個簡單又精確的學習方式,初學者還會感激你。我們有<a href="/zh-TW/docs/Glossary#Contribute">很多尚未定義的用詞</a>需要你的協助,挑一個你擅長的吧。</dd>
+ <dt><a href="/zh-TW/Learn/Index">閱讀並評價術語表學習專區的文章</a>(約兩小時)</dt>
+ <dd>這跟評價數語表一樣(如上述),只是這些文章的篇幅更常,需要花更多的時間。</dd>
+ <dt><a href="/zh-TW/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">撰寫新的學習專區文章</a> (<em>約四小時或更多</em>)</dt>
+ <dd>MDN缺少簡單易懂的網頁技術相關文章(例如<a href="/zh-TW/docs/Learn/CSS">HTML</a>, <a href="/zh-TW/docs/Learn/CSS">CSS</a>, <a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a>)。我們也有較舊的文章需要重新審視並修正,請你將技能發揮到極致,讓初學者也能使用網頁技術。</dd>
+ <dt><a href="/zh-TW/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">提供練習題、範例或是互動式的教學工具。</a>(<em>? 小時</em>)</dt>
+ <dd>我們所有的文章都需要 "active learning" 的素材在內,因為讓人們學習的最好途徑就是讓他們自己實作。這些素材會是練習題或互動式的內容,能協助使用者將文章內詳述的概念實際運用。有很多方式能夠製作 "active learning" 的內容,像是使用 <a href="http://jsfiddle.net" rel="external">JSFiddle</a> 或相似的工具提供範例程式碼,或使用<a href="https://thimble.mozilla.org/" rel="external">Thimble</a>提供互動式的內容。 好好發揮你得創造力吧!</dd>
+</dl>
+
+<h2 id="我是教師">我是教師</h2>
+
+<p>MDN 有著精良的技術史,但我們對教導新人觀念的最佳方法,缺乏深入了解。針對這方面,我們需要借重做為教師或導師身份的你。你能幫我們確保給讀者們的內容,有著良好而實用的教育路徑(educational track)。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Glossary">閱讀並評價術語表</a>(約十五分鐘)</dt>
+ <dd>Check out a glossary entry and feel free to make any changes you think are necessary. If you want to discuss the content before editing, ping us on <a href="/zh-TW/docs/MDN/Community#Join_our_mailing_lists">our mailing list</a> or <a href="/zh-TW/docs/MDN/Community#Get_into_IRC">IRC channel</a>.</dd>
+ <dt><a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">撰寫新的術語</a>(約一小時)</dt>
+ <dd>Clear, simple definitions of terms and basic overviews of concepts in the glossary are critical in meeting beginners' needs. Your experience as an educator can help create excellent glossary entries; we have <a href="/zh-TW/docs/Glossary#Contribute">many undefined terms</a> which need your attention. Pick one and go for it.</dd>
+ <dt><a href="/en-US/docs/tag/needsSchema">添加實例或圖表至文章</a> (<em>約一小時</em>)</dt>
+ <dd>As you might know, illustrations are an invaluable part of any learning content. This is something we often lack on MDN and your skills can make a difference in that area. Check out the <a href="/zh-TW/docs/tag/needsSchema">articles that lack illustrative content</a> and pick one you'd like to create graphics for.</dd>
+ <dt><a href="/en-US/Learn/Index">閱讀並審核教學文章</a> (約兩小時)</dt>
+ <dd>This is similar to reviewing glossary entries (see above), but it requires more time since the articles are typically quite a bit longer.</dd>
+ <dt><a href="/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">撰寫新的教學文章</a> (<em>約四小時</em>)</dt>
+ <dd>We need simple, straightforward articles about the Web ecosystem and other functional topics around it. Since these learning articles need to be educational rather than trying to literally cover everything there is to know, your experience in knowing what to cover and how will be a great asset.</dd>
+ <dt><a href="/en-US/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">建立練習題,測驗或是互動式的學習工具</a>(<em>? 小時</em>)</dt>
+ <dd>All our learning articles require "active learning" materials. Such materials are exercises or interactive content which help a user learn to use and expand upon the concepts detailed in an article.  There are lots of things you can do here, from creating quizzes to building fully hackable interactive content with <a href="https://thimble.mozilla.org/" rel="external">Thimble</a>. Unleash your creativity!</dd>
+ <dt><a href="/en-US/docs/MDN/Contribute/Howto/Create_learning_pathways">建立學習途徑</a> (<em>? 小時</em>)</dt>
+ <dd>In order to provide progressive and comprehensible tutorials, we need to shape our content into pathways. It's a way to gather existing content and figure out what is missing to create a learning article to write.</dd>
+</dl>
diff --git a/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html b/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html
new file mode 100644
index 0000000000..b403666795
--- /dev/null
+++ b/files/zh-tw/learn/html/forms/how_to_structure_an_html_form/index.html
@@ -0,0 +1,315 @@
+---
+title: 如何建構 HTML 表單
+slug: Learn/HTML/Forms/How_to_structure_an_HTML_form
+translation_of: Learn/Forms/How_to_structure_a_web_form
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Forms/Your_first_form", "Learn/Forms/Basic_native_form_controls", "Learn/Forms")}}</div>
+
+<p class="summary">有了基礎後,我們就能探討表單元素,所提供的結構與文意之詳細資訊;還有各表單部份的相異之處。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決條件:</th>
+ <td>對電腦還有 <a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML</a> 有基本理解。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>理解如何構建 HTML 表單並給予無障礙的語意化。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>表單表單的彈性化令其成為 <a href="/zh-TW/docs/Learn/HTML" title="/zh-TW/docs/HTML">HTML</a> 最複雜的結構之一。你能使用專用的表單元素和屬性,來構建任何類型的基本表單。使用正確的 HTML 表單結構能讓確保表單可用、且<a href="/zh-TW/docs/Learn/Accessibility">無障礙</a>。</p>
+
+<h2 id="&lt;form>_元素">&lt;form&gt; 元素</h2>
+
+<p>{{HTMLElement("form")}} 元素會形式上的定義表單和決定行為屬性。每次建立 HTML 表單時,都必須使用 form 元素;並將所有內容嵌進去。大多數的輔助技術與瀏覽器套件,都能抓到 {{HTMLElement("form")}} 元素,並實做特殊的 hook,使其更易於使用。</p>
+
+<p>我們之前就講過這件事了。</p>
+
+<div class="warning"><strong>注意:</strong>絕對不能在表單裡面再嵌入表單。這會讓表單行為變得難以理解,所以是一個壞主意。</div>
+
+<p>你可以從表單外面控制 {{HTMLElement("form")}} 。這麼做的話,除非使用 <a href="/zh-TW/docs/Web/HTML/Attributes/form"><code>form</code></a> 將其與表單關聯,否則該操作預設上和任何表單無關。引入此功能是為了可以在即使該操作未嵌在表單中,其依舊能顯式地將操作與表單綁定。</p>
+
+<p>接下來就開始探討表單裡面可能會嵌入什麼吧。</p>
+
+<h2 id="&lt;fieldset>_and_&lt;legend>_元素">&lt;fieldset&gt; and &lt;legend&gt; 元素</h2>
+
+<p>{{HTMLElement("fieldset")}} 元素能方便地建立用途相近、樣式及語意化都很方便的小部件組(groups of widgets)。你可以透過添加 {{HTMLElement("legend")}} 來給 {{HTMLElement("fieldset")}} 的內部開頭添加標籤。{{HTMLElement("legend")}} 的文字內容能描述 {{HTMLElement("legend")}} 目的。</p>
+
+<p>多數輔助科技會在 {{HTMLElement("legend")}} 元素被 {{HTMLElement("fieldset")}} 包住時偵測並使用它。比如說 <a href="http://www.freedomscientific.com/products/software/jaws/" rel="external" title="http://www.freedomscientific.com/products/fs/jaws-product-page.asp">Jaws</a> 與 <a href="http://www.nvda-project.org/" rel="external" title="http://www.nvda-project.org/">NVDA</a> 之類的螢幕報讀器就會在讀到每個控件的標籤前,讀出 legend 的內容。</p>
+
+<p>下面就有一個示例:</p>
+
+<pre class="brush:html; notranslate">&lt;form&gt;
+ &lt;fieldset&gt;
+ &lt;legend&gt;Fruit juice size&lt;/legend&gt;
+ &lt;p&gt;
+ &lt;input type="radio" name="size" id="size_1" value="small"&gt;
+ &lt;label for="size_1"&gt;Small&lt;/label&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;input type="radio" name="size" id="size_2" value="medium"&gt;
+ &lt;label for="size_2"&gt;Medium&lt;/label&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;input type="radio" name="size" id="size_3" value="large"&gt;
+ &lt;label for="size_3"&gt;Large&lt;/label&gt;
+ &lt;/p&gt;
+ &lt;/fieldset&gt;
+&lt;/form&gt;</pre>
+
+<div class="note">
+<p><strong>註</strong>:你可以在<a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/fieldset-legend.html">fieldset-legend.html</a> 觀察範例(<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/fieldset-legend.html">或著觀察這個動態互動</a>)。</p>
+</div>
+
+<p>在閱讀表單時,螢幕報讀器會針對第一個小部件組,說出「Fruit juice size small」、接著針對第二個小部件組,說出「Fruit juice size medium」、第三個則是「Fruit juice size large」。</p>
+
+<p>這個示例的是最重要的用法之一:每次有一組 radio 按鈕時,就該在裡面放一個 {{HTMLElement("fieldset")}} 元素。{{HTMLElement("fieldset")}} 也能用在表單的其他地方。理想上,要是表單一長,就要把他放到其他頁面。但如果做不到這點,那將不同的相關部分,放在不同的 fieldsets 之中,也可以提高可用性。</p>
+
+<p>由於 {{HTMLElement("fieldset")}} 對輔助技術的影響,這個元素是建立無障礙表單的基石,但請注意不要濫用這個元素。可以的話,<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">聽聽螢幕報讀是怎麼講的</a>。如果踢起來怪怪的,那就試著改進表單。</p>
+
+<h2 id="&lt;label>_元素">&lt;label&gt; 元素</h2>
+
+<p>正如上篇文章中所見,{{HTMLElement("label")}} 元素是定義 HTML 表單控件的正式方法。如果要構建無障礙的表單,這是最重要的元素:正確實做後,螢幕閱讀器會說出表單元素標籤、以及相關說明,同時也對有視力的用戶很有用。以這個例子為例,我們在上一篇文章中看過:</p>
+
+<pre class="brush: html notranslate">&lt;label for="name"&gt;Name:&lt;/label&gt; &lt;input type="text" id="name" name="user_name"&gt;</pre>
+
+<p>在 <code>&lt;label&gt;</code> 元素透過 <code>for</code> 屬性與 <code>&lt;input&gt;</code> 元素的 <code>id</code> 屬性正確連結後,螢幕閱讀器就會讀出「Name, edit text」這樣的文字。</p>
+
+<p>還有另一種控制標籤與表單控件關聯的方法:那就是把表單控件嵌在 <code>&lt;label&gt;</code> 元素裡面,以便隱式關聯。</p>
+
+<pre class="brush: html notranslate">&lt;label for="name"&gt;
+ Name: &lt;input type="text" id="name" name="user_name"&gt;
+&lt;/label&gt;</pre>
+
+<p>但即使在這種情況下,最好還是設置 <code>for</code> 屬性,以確保所有輔具都能理解標籤和控件之間的關係。</p>
+
+<p>如果沒有標籤、或著說表單控件沒有被顯式或隱式關聯,螢幕閱讀器會讀出沒啥幫助的「Edit text blank」。</p>
+
+<h3 id="標籤也能點喔!">標籤也能點喔!</h3>
+
+<p>使用標籤的另一個好處,就是能在點選該標籤後,啟動相對應的小部件。這種功能在控制文字輸入的時候會很好用:用戶點選標籤時就可以 focus 到 input 那邊。這對 button 與 checkbox 尤其有用:因為點選的區域可能很小,因此使它盡可能簡單地啟用,會是很有用的。</p>
+
+<p>例如在下面的示例中,點選「I like cherry」標籤文字後會切換 <em>taste_cherry</em> checkbox 的點選狀態:</p>
+
+<pre class="brush:html; notranslate">&lt;form&gt;
+ &lt;p&gt;
+ &lt;input type="checkbox" id="taste_1" name="taste_cherry" value="cherry"&gt;
+ &lt;label for="taste_1"&gt;I like cherry&lt;/label&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;input type="checkbox" id="taste_2" name="taste_banana" value="banana"&gt;
+ &lt;label for="taste_2"&gt;I like banana&lt;/label&gt;
+ &lt;/p&gt;
+&lt;/form&gt;</pre>
+
+<div class="note">
+<p><strong>註</strong>:你可以在 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/checkbox-label.html">checkbox-label.html</a> 觀察示例(<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/checkbox-label.html">這裡有展示版本!</a>)</p>
+</div>
+
+<h3 id="多個標籤">多個標籤</h3>
+
+<p>嚴格來說,一個小部件組能放很多個標籤,但由於部分輔助科技處理上會有問題,所以這也不是個好點子。如果有多個標籤,請試著把巢狀各個小部件,並在裡面只安插一個 {{htmlelement("label")}} 元素。</p>
+
+<p>來看看這個例子:</p>
+
+<pre class="brush: html notranslate">&lt;p&gt;Required fields are followed by &lt;abbr title="required"&gt;*&lt;/abbr&gt;.&lt;/p&gt;
+
+&lt;!-- So this: --&gt;
+&lt;div&gt;
+ &lt;label for="username"&gt;Name:&lt;/label&gt;
+ &lt;input id="username" type="text" name="username"&gt;
+ &lt;label for="username"&gt;&lt;abbr title="required" aria-label="required"&gt;*&lt;/abbr&gt;&lt;/label&gt;
+&lt;/div&gt;
+
+&lt;!-- would be better done like this: --&gt;
+&lt;div&gt;
+ &lt;label for="username"&gt;
+ &lt;span&gt;Name:&lt;/span&gt;
+ &lt;input id="username" type="text" name="username"&gt;
+ &lt;abbr title="required" aria-label="required"&gt;*&lt;/abbr&gt;
+ &lt;/label&gt;
+&lt;/div&gt;
+
+&lt;!-- But this is probably best: --&gt;
+&lt;div&gt;
+ &lt;label for="username"&gt;Name: &lt;abbr title="required" aria-label="required"&gt;*&lt;/abbr&gt;&lt;/label&gt;
+ &lt;input id="username" type="text" name="username"&gt;
+&lt;/div&gt;</pre>
+
+<p>{{EmbedLiveSample("Multiple_labels", 120, 120)}}</p>
+
+<p>The paragraph at the top states a rule for required elements. The rule must be included <em>before</em> it is used so that sighted users and users of assistive technologies such as screen readers can learn what it means before they encounter a required element. While this helps inform users what an asterisk means, it can not be relied upon. A screen reader will speak an asterisk as "<em>star</em>" when encountered. When hovered by a sighted mouse user, "<em>required</em>" should appear, which is achieved by use of the <code>title</code> attribute. Titles being read aloud depend on the screen reader's settings, so it is more reliable to also include the <code><a href="/zh-TW/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute">aria-label</a></code> attribute, which is always read by screen readers.</p>
+
+<p>The above variants increase in effectiveness as you go through them:</p>
+
+<ul>
+ <li>In the first example, the label is not read out at all with the input — you just get "edit text blank", plus the actual labels are read out separately. The multiple <code>&lt;label&gt;</code> elements confuse the screenreader.</li>
+ <li>In the second example, things are a bit clearer — the label read out along with the input is "name star name edit text required", and the labels are still read out separately. Things are still a bit confusing, but it's a bit better this time because the <code>&lt;input&gt;</code> has a label associated with it.</li>
+ <li>The third example is best — the actual label is read out all together, and the label read out with the input is "name required edit text".</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: You might get slightly different results, depending on your screenreader. This was tested in VoiceOver (and NVDA behaves similarly). We'd love to hear about your experiences too.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: You can find this example on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/required-labels.html">required-labels.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/required-labels.html">see it live also</a>). don't test the example with 2 or 3 of the versions uncommented — screenreaders will definitely get confused if you have multiple labels AND multiple inputs with the same ID!</p>
+</div>
+
+<h2 id="建立表單所常用的_HTML_結構">建立表單所常用的 HTML 結構</h2>
+
+<p>Beyond the structures specific to web forms, it's good to remember that form markup is just HTML. This means that you can use all the power of HTML to structure a web form.</p>
+
+<p>As you can see in the examples, it's common practice to wrap a label and its widget with a {{HTMLElement("li")}} element within a {{HTMLElement("ul")}} or {{HTMLElement("ol")}} list. {{HTMLElement("p")}} and {{HTMLElement("div")}} elements are also commonly used. Lists are recommended for structuring multiple checkboxes or radio buttons.</p>
+
+<p>In addition to the {{HTMLElement("fieldset")}} element, it's also common practice to use HTML titles (e.g. {{htmlelement("h1")}}, {{htmlelement("h2")}}) and sectioning (e.g. {{htmlelement("section")}}) to structure complex forms.</p>
+
+<p>Above all, it is up to you to find a comfortable coding style that results in accessible, usable forms. Each separate section of functionality should be contained in a separate {{htmlelement("section")}} element, with {{htmlelement("fieldset")}} elements to contain radio buttons.</p>
+
+<h3 id="主動學習:建立表單結構">主動學習:建立表單結構</h3>
+
+<p>Let's put these ideas into practice and build a slightly more involved form — a payment form. This form will contain a number of control types that you may not yet understand. Don't worry about this for now; you'll find out how they work in the next article (<a href="/zh-TW/docs/Learn/Forms/Basic_native_form_controls">Basic native form controls</a>). For now, read the descriptions carefully as you follow the below instructions, and start to form an appreciation of which wrapper elements we are using to structure the form, and why.</p>
+
+<ol>
+ <li>To start with, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">blank template file</a> and the <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.css">CSS for our payment form</a> in a new directory on your computer.</li>
+ <li>Apply the CSS to the HTML by adding the following line inside the HTML {{htmlelement("head")}}:
+ <pre class="brush: html notranslate">&lt;link href="payment-form.css" rel="stylesheet"&gt;</pre>
+ </li>
+ <li>Next, create your form by adding the outer {{htmlelement("form")}} element:
+ <pre class="brush: html notranslate">&lt;form&gt;
+
+&lt;/form&gt;</pre>
+ </li>
+ <li>Inside the <code>&lt;form&gt;</code> tags, add a heading and paragraph to inform users how required fields are marked:
+ <pre class="brush: html notranslate">&lt;h1&gt;Payment form&lt;/h1&gt;
+&lt;p&gt;Required fields are followed by &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;.&lt;/p&gt;</pre>
+ </li>
+ <li>Next we'll add a larger section of code into the form, below our previous entry. Here you'll see that we are wrapping the contact information fields inside a distinct {{htmlelement("section")}} element. Moreover, we have a set of two radio buttons, each of which we are putting inside its own list ({{htmlelement("li")}}) element. We also have two standard text {{htmlelement("input")}}s and their associated {{htmlelement("label")}} elements, each contained inside a {{htmlelement("p")}}, and a password input for entering a password. Add this code to your form:
+ <pre class="brush: html notranslate">&lt;section&gt;
+ &lt;h2&gt;Contact information&lt;/h2&gt;
+ &lt;fieldset&gt;
+ &lt;legend&gt;Title&lt;/legend&gt;
+ &lt;ul&gt;
+ &lt;li&gt;
+ &lt;label for="title_1"&gt;
+ &lt;input type="radio" id="title_1" name="title" value="K" &gt;
+ King
+ &lt;/label&gt;
+ &lt;/li&gt;
+ &lt;li&gt;
+ &lt;label for="title_2"&gt;
+ &lt;input type="radio" id="title_2" name="title" value="Q"&gt;
+ Queen
+ &lt;/label&gt;
+ &lt;/li&gt;
+ &lt;li&gt;
+ &lt;label for="title_3"&gt;
+ &lt;input type="radio" id="title_3" name="title" value="J"&gt;
+ Joker
+ &lt;/label&gt;
+ &lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;/fieldset&gt;
+ &lt;p&gt;
+ &lt;label for="name"&gt;
+ &lt;span&gt;Name: &lt;/span&gt;
+ &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;
+ &lt;/label&gt;
+ &lt;input type="text" id="name" name="username"&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;label for="mail"&gt;
+ &lt;span&gt;E-mail: &lt;/span&gt;
+ &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;
+ &lt;/label&gt;
+ &lt;input type="email" id="mail" name="usermail"&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;label for="pwd"&gt;
+ &lt;span&gt;Password: &lt;/span&gt;
+ &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;
+ &lt;/label&gt;
+ &lt;input type="password" id="pwd" name="password"&gt;
+ &lt;/p&gt;
+&lt;/section&gt;</pre>
+ </li>
+ <li>The second <code>&lt;section&gt;</code> of our form is the payment information. We have three distinct controls along with their labels, each contained inside a <code>&lt;p&gt;</code>. The first is a drop-down menu ({{htmlelement("select")}}) for selecting credit card type. The second is an <code>&lt;input&gt;</code> element of type <code>tel</code>, for entering a credit card number; while we could have used the <code>number</code> type, we don't want the number's spinner UI. The last one is an <code>&lt;input&gt;</code> element of type <code>date</code>, for entering the expiration date of the card; this one will come up with a date picker widget in supporting browsers, and fall back to a normal text input in non-supporting browsers. These newer input types are reintroduced in <a href="/zh-TW/docs/Learn/Forms/HTML5_input_types">The HTML5 input types</a>.<br>
+ <br>
+ Enter the following below the previous section:
+ <pre class="brush: html notranslate">&lt;section&gt;
+ &lt;h2&gt;Payment information&lt;/h2&gt;
+ &lt;p&gt;
+ &lt;label for="card"&gt;
+ &lt;span&gt;Card type:&lt;/span&gt;
+ &lt;/label&gt;
+ &lt;select id="card" name="usercard"&gt;
+ &lt;option value="visa"&gt;Visa&lt;/option&gt;
+ &lt;option value="mc"&gt;Mastercard&lt;/option&gt;
+ &lt;option value="amex"&gt;American Express&lt;/option&gt;
+ &lt;/select&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;label for="number"&gt;
+ &lt;span&gt;Card number:&lt;/span&gt;
+ &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;
+ &lt;/label&gt;
+ &lt;input type="tel" id="number" name="cardnumber"&gt;
+ &lt;/p&gt;
+ &lt;p&gt;
+ &lt;label for="date"&gt;
+ &lt;span&gt;Expiration date:&lt;/span&gt;
+ &lt;strong&gt;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&lt;/strong&gt;
+ &lt;em&gt;formatted as mm/dd/yyyy&lt;/em&gt;
+ &lt;/label&gt;
+ &lt;input type="date" id="date" name="expiration"&gt;
+ &lt;/p&gt;
+&lt;/section&gt;</pre>
+ </li>
+ <li>The last section we'll add is a lot simpler, containing only a {{htmlelement("button")}} of type <code>submit</code>, for submitting the form data. Add this to the bottom of your form now:
+ <pre class="brush: html notranslate">&lt;p&gt; &lt;button type="submit"&gt;Validate the payment&lt;/button&gt; &lt;/p&gt;</pre>
+ </li>
+</ol>
+
+<p>You can see the finished form in action below (also find it on GitHub — see our payment-form.html <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.html">source</a> and <a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/payment-form.html">running live</a>):</p>
+
+<p>{{EmbedLiveSample("A_payment_form","100%",620, "", "Learn/Forms/How_to_structure_a_web_form/Example")}}</p>
+
+<h2 id="結論">結論</h2>
+
+<p>你現在擁有了正確建構 HTML 表單的所有知識。接下來將介紹本章介紹的許多功能。在下一篇文章中,將詳細探討如何使用各種不同類型的表單小部件,來收集用戶的訊息。</p>
+
+<h2 id="參見">參見</h2>
+
+<ul>
+ <li><a href="http://www.alistapart.com/articles/sensibleforms/" rel="external" title="http://www.alistapart.com/articles/sensibleforms/">A List Apart: <em>Sensible Forms: A Form Usability Checklist</em></a></li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Forms/Your_first_form", "Learn/Forms/Basic_native_form_controls", "Learn/Forms")}}</p>
+
+<h2 id="在本模塊">在本模塊</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Forms/Your_first_form">Your first form</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/How_to_structure_a_web_form">How to structure a web form</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Basic_native_form_controls">Basic native form controls</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/HTML5_input_types">The HTML5 input types</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Other_form_controls">Other form controls</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Styling_web_forms">Styling web forms</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Advanced_form_styling">Advanced form styling</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/UI_pseudo-classes">UI pseudo-classes</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Form_validation">Client-side form validation</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Sending_and_retrieving_form_data">Sending form data</a></li>
+</ul>
+
+<h3 id="Advanced_Topics">Advanced Topics</h3>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Forms/How_to_build_custom_form_controls">How to build custom form controls</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li>
+ <li><a href="/zh-TW/docs/Learn/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/forms/index.html b/files/zh-tw/learn/html/forms/index.html
new file mode 100644
index 0000000000..589880794f
--- /dev/null
+++ b/files/zh-tw/learn/html/forms/index.html
@@ -0,0 +1,359 @@
+---
+title: 網站表單-與數據合作
+slug: Learn/HTML/Forms
+tags:
+ - Featured
+ - Forms
+ - Guide
+ - HTML
+ - NeedsTranslation
+ - TopicStub
+ - Web
+ - 待翻譯
+translation_of: Learn/Forms
+---
+<p><span class="seoSummary">這篇指南提供了一系列的文章,幫你掌握HTML表單的基本知識。對於與使用者互動,網站表單是一項十分有力的工具,最常使用於用戶數據蒐集,或控制使用者介面。但由於一些歷史與技術上的因素,並沒有顯著的方法發揮表單的潛力。</span>在下面的指引中,我們將介紹網站表單所有基本面向,包括標記他們的HTML結構、設定控制器樣式、驗證數據及將數距提送至伺服器</p>
+
+<h2 id="參考文章列表">參考文章列表</h2>
+
+<ol>
+ <li><a href="/zh-TW/docs/HTML/Forms/My_first_HTML_form">我的第一個HTML表單</a></li>
+ <li><a href="/zh-TW/docs/HTML/Forms/How_to_structure_an_HTML_form"><span>如何構建 HTML 表單</span></a></li>
+ <li><a href="/zh-TW/docs/HTML/Forms/The_native_form_widgets"><span>本機表單控件</span></a></li>
+ <li>CSS和HTML表單
+ <ol>
+ <li><a href="/zh-TW/docs/HTML/Forms/Styling_HTML_forms"><span>造型HTML表單</span></a></li>
+ <li><a href="/zh-TW/docs/Web/Guide/HTML/Forms/Advanced_styling_for_HTML_forms">HTML表單高級造型</a></li>
+ <li><a href="/zh-TW/docs/Property_compatibility_table_for_form_widgets">表單控件屬性兼容表</a></li>
+ </ol>
+ </li>
+ <li><a href="/zh-TW/docs/HTML/Forms/Sending_and_retrieving_form_data"><span>發送和檢索表單數據</span></a></li>
+ <li><a href="/zh-TW/docs/HTML/Forms/Data_form_validation">數據表單驗證</a></li>
+ <li><a href="/zh-TW/docs/HTML/Forms/How_to_build_custom_form_widgets">如何<span>創建自定義表單控件</span></a></li>
+ <li><a href="/zh-TW/docs/HTML/Forms/Sending_forms_through_JavaScript">通過JavaScript發送形式</a>
+ <ol>
+ <li><a href="/zh-TW/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects">使用FORMDATA 對象</a></li>
+ </ol>
+ </li>
+ <li><a href="/zh-TW/docs/HTML/Forms/HTML_forms_in_legacy_browsers">在傳統的瀏覽器的HTML表單</a></li>
+</ol>
+
+<h2 id="HTML_文件">HTML 文件</h2>
+
+<h3 id="HTML_元素">HTML 元素</h3>
+
+<table>
+ <thead>
+ <tr>
+ <th scope="col">HTML 元素</th>
+ <th scope="col">元素的 DOM interface</th>
+ <th scope="col">說明</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("button")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLButtonElement")}}</td>
+ <td style="vertical-align: top;">該<code>按鈕</code>元素表示一個可點擊的按鈕。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("datalist")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLDataListElement")}}</td>
+ <td style="vertical-align: top;">該<span style="font-family: courier new;">數據列表</span>元素包含了一組  {{ HTMLElement("option") }}  表示對其他表單元素的值可能的選擇要素。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("fieldset")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLFieldSetElement")}}</td>
+ <td style="vertical-align: top;">該<span style="font-family: courier new;">字段集</span>是用來在表單中的組數表單元素。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("form")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLFormElement")}}</td>
+ <td style="vertical-align: top;">的<code>形式</code>元素表示的文件的一部分,它包含使用戶能夠提交信息給web服務器的交互元件。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("input")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLInputElement")}}</td>
+ <td style="vertical-align: top;">該  <code>輸入</code>元素用於創建表格的交互式控制。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("keygen")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLKeygenElement")}}</td>
+ <td style="vertical-align: top;">所述<code>凱基</code>元素存在,以促進生成的密鑰材料,並提交了公開密鑰的作為HTML形式的一部分</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("label")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLLabelElement")}}</td>
+ <td style="vertical-align: top;">該<code>標籤</code>元素代表一個項目在用戶界面的標題</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("legend")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLLegendElement")}}</td>
+ <td style="vertical-align: top;">在<code>傳說</code>元素代表一個標題為其父 {{ HTMLElement("fieldset") }} 的內容。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("meter")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLMeterElement")}}</td>
+ <td style="vertical-align: top;">所述<code>米</code>元素表示一個已知的範圍內的任一標量值或分數值。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("optgroup")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLOptGroupElement")}}</td>
+ <td style="vertical-align: top;">在<code>OPTGROUP</code>元素創建一個 {{ HTMLElement("select") }}  元素中的一組選項。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("option")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLOptionElement")}}</td>
+ <td style="vertical-align: top;">在HTML <code><font>選項</font></code><font>元素用於創建表示 </font> {{ HTMLElement("select") }} <font>,一個 </font>{{ HTMLElement("optgroup") }} <font>或</font> {{ HTMLElement("datalist") }}<font> 元素中的項目的控制。<em> </em><code><em> </em></code></font></td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("output")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLOutputElement")}}</td>
+ <td style="vertical-align: top;">的<code>輸出</code>元素表示一個計算的結果。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("progress")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLProgressElement")}}</td>
+ <td style="vertical-align: top;">的<code>進展</code>元素用於查看任務的完成進度。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("select")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLSelectElement")}}</td>
+ <td style="vertical-align: top;">在<code>選擇</code>元素代表呈現一個選項菜單的控制。</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">{{HTMLElement("textarea")}}</td>
+ <td style="vertical-align: top;">{{domxref("HTMLTextAreaElement")}}</td>
+ <td style="vertical-align: top;">該<code>textarea的</code>元素代表多行純文本編輯控制。</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p><strong>注:</strong>所有的表單元素,因為所有的HTML元素,支持 {{domxref("HTMLElement")}} DOM接口。</p>
+</div>
+
+<h3 id="HTML_屬性">HTML 屬性</h3>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th>屬性</th>
+ <th>能使用該屬性的 HTML 元素</th>
+ <th>說明</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>accept</td>
+ <td>{{ HTMLElement("form") }}, {{ HTMLElement("input") }}</td>
+ <td>的類型列表服務器接受,通常是文件類型。</td>
+ </tr>
+ <tr>
+ <td style="white-space: nowrap;">accept-charset</td>
+ <td>{{ HTMLElement("form") }}</td>
+ <td>支持的字符集列表。</td>
+ </tr>
+ <tr>
+ <td>action</td>
+ <td>{{ HTMLElement("form") }}</td>
+ <td>一個程序處理通過表單提交的信息的URI。</td>
+ </tr>
+ <tr>
+ <td>autocomplete</td>
+ <td>{{ HTMLElement("form") }}, {{ HTMLElement("input") }}</td>
+ <td>指示是否在這個表單控件可以在默認情況下有其值由瀏覽器自動完成。</td>
+ </tr>
+ <tr>
+ <td>autofocus</td>
+ <td>{{ HTMLElement("button") }}、 {{ HTMLElement("input") }}、 {{ HTMLElement("keygen") }}、 {{ HTMLElement("select") }}、 {{ HTMLElement("textarea") }}</td>
+ <td>該元素應該在頁面加載後自動聚焦。</td>
+ </tr>
+ <tr>
+ <td>challenge</td>
+ <td>{{ HTMLElement("keygen") }}</td>
+ <td>即隨著公共密鑰提交的挑戰字符串。</td>
+ </tr>
+ <tr>
+ <td>checked</td>
+ <td>{{ HTMLElement("input") }}</td>
+ <td>指示是否應將元素在頁面加載檢查。</td>
+ </tr>
+ <tr>
+ <td>cols</td>
+ <td>{{ HTMLElement("textarea") }}</td>
+ <td>限定在一個textarea的列數。</td>
+ </tr>
+ <tr>
+ <td>data</td>
+ <td>{{ HTMLElement("object") }}</td>
+ <td>指定的資源的URL。</td>
+ </tr>
+ <tr>
+ <td>dirname</td>
+ <td>{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>disabled</td>
+ <td>{{ HTMLElement("button") }} 、{{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("optgroup") }} 、 {{ HTMLElement("option") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea")}}</td>
+ <td>表明用戶是否可以與元件進行交互。</td>
+ </tr>
+ <tr>
+ <td>enctype</td>
+ <td>{{ HTMLElement("form") }}</td>
+ <td>定義當表單數據的內容類型<code>的方法</code>是POST。</td>
+ </tr>
+ <tr>
+ <td>for</td>
+ <td>{{ HTMLElement("label") }}、 {{ HTMLElement("output") }}</td>
+ <td>描述了屬於這一種元素。</td>
+ </tr>
+ <tr>
+ <td>form</td>
+ <td>{{ HTMLElement("button") }} 、 {{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("label") }} 、 {{ HTMLElement("meter") }} 、 {{ HTMLElement("object") }} 、 {{ HTMLElement("output") }} 、 {{ HTMLElement("progress") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea")}}</td>
+ <td>表明是元件的所有者的形式。</td>
+ </tr>
+ <tr>
+ <td>high</td>
+ <td>{{ HTMLElement("meter") }}</td>
+ <td>表示下界的上限範圍。</td>
+ </tr>
+ <tr>
+ <td>keytype</td>
+ <td>{{ HTMLElement("keygen") }}</td>
+ <td>指定鍵所產生的類型。</td>
+ </tr>
+ <tr>
+ <td>list</td>
+ <td>{{ HTMLElement("input") }}</td>
+ <td>標識的預定義的選項的列表,以向用戶建議。</td>
+ </tr>
+ <tr>
+ <td>low</td>
+ <td>{{ HTMLElement("meter") }}</td>
+ <td>指示上限較低的範圍內。</td>
+ </tr>
+ <tr>
+ <td>max</td>
+ <td>{{ HTMLElement("input") }} 、 {{ HTMLElement("meter") }} 、 {{ HTMLElement("progress") }}</td>
+ <td>指示所允許的最大值。</td>
+ </tr>
+ <tr>
+ <td>maxlength</td>
+ <td>{{ HTMLElement("input") }} 、 {{ HTMLElement("textarea") }}</td>
+ <td>定義了在元件允許的字符的最大數目。</td>
+ </tr>
+ <tr>
+ <td>method</td>
+ <td>{{HTMLElement("form")}}</td>
+ <td>定義提交表單時使用的HTTP方法。可GET(默認)或POST。</td>
+ </tr>
+ <tr>
+ <td>min</td>
+ <td>{{ HTMLElement("input") }} 、 {{ HTMLElement("meter") }}</td>
+ <td>指示所允許的最小值。</td>
+ </tr>
+ <tr>
+ <td>multiple</td>
+ <td>{{ HTMLElement("input") }}、 {{ HTMLElement("select") }}</td>
+ <td>表示是否多個值所用的類型的輸入可以輸入<code>電子郵件</code>或<code>文件</code>。</td>
+ </tr>
+ <tr>
+ <td>name</td>
+ <td>{{ HTMLElement("button") }} 、 {{ HTMLElement("form") }} 、 {{ HTMLElement("fieldset") }} 、 {{ HTMLElement("input") }} 、 {{ HTMLElement("keygen") }} 、 {{ HTMLElement("output") }} 、 {{ HTMLElement("select") }} 、 {{ HTMLElement("textarea") }}</td>
+ <td>該元素的名稱。例如所使用的服務器,以確定在表單提交的字段。</td>
+ </tr>
+ <tr>
+ <td>novalidate</td>
+ <td>{{ HTMLElement("form") }}</td>
+ <td>此屬性表明,當提交表單應該無法通過驗證。</td>
+ </tr>
+ <tr>
+ <td>optimum</td>
+ <td>{{ HTMLElement("meter") }}</td>
+ <td>表示最佳數值。</td>
+ </tr>
+ <tr>
+ <td>pattern</td>
+ <td>{{ HTMLElement("input") }}</td>
+ <td>定義一個正則表達式元素的值將針對驗證。</td>
+ </tr>
+ <tr>
+ <td>placeholder</td>
+ <td>{{ HTMLElement("input") }}、 {{ HTMLElement("textarea") }}</td>
+ <td>提供一個提示什麼可以在字段中輸入的用戶。</td>
+ </tr>
+ <tr>
+ <td>readonly</td>
+ <td>{{ HTMLElement("input") }} 、 {{ HTMLElement("textarea") }}</td>
+ <td>指示該元素是否可以編輯或沒有。</td>
+ </tr>
+ <tr>
+ <td>required</td>
+ <td>{{ HTMLElement("input") }} 、 {{ HTMLElement("select") }}、 {{ HTMLElement("textarea") }}</td>
+ <td>指示此元素是否必填。</td>
+ </tr>
+ <tr>
+ <td>rows</td>
+ <td>{{ HTMLElement("textarea") }}</td>
+ <td>限定在一個textarea的行數。</td>
+ </tr>
+ <tr>
+ <td>selected</td>
+ <td>{{ HTMLElement("option") }}</td>
+ <td>定義了將在頁面加載所選的值。</td>
+ </tr>
+ <tr>
+ <td>size</td>
+ <td>{{ HTMLElement("input") }}、 {{ HTMLElement("select") }}</td>
+ <td>限定了元件的寬度(以像素為單位)。如果該元素的<code>類型</code>的屬性是<code>文本</code>或<code>密碼</code>那麼它的字符數。</td>
+ </tr>
+ <tr>
+ <td>src</td>
+ <td>{{ HTMLElement("img") }}</td>
+ <td>可嵌入內容的URL。</td>
+ </tr>
+ <tr>
+ <td>step</td>
+ <td>{{ HTMLElement("input") }}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>target</td>
+ <td>{{ HTMLElement("form") }}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>type</td>
+ <td>{{ HTMLElement("button") }} 、 {{ HTMLElement("input") }}</td>
+ <td>限定了元件的類型。</td>
+ </tr>
+ <tr>
+ <td>usemap</td>
+ <td>{{ HTMLElement("img") }}</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>value</td>
+ <td>{{ HTMLElement("button") }}、 {{ HTMLElement("option") }}、 {{ HTMLElement("input") }}、 {{ HTMLElement("meter") }}、 {{ HTMLElement("progress") }}</td>
+ <td>定義了將被顯示在頁面上的負載元件的默認值。</td>
+ </tr>
+ <tr>
+ <td>wrap</td>
+ <td>{{ HTMLElement("textarea") }}</td>
+ <td>指示文本是否應被包裹或沒有。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="規範性引用文件">規範性引用文件</h3>
+
+<ul>
+ <li><a href="http://www.w3.org/html/wg/drafts/html/master/forms.html#forms" lang="en" rel="external" title="http://www.w3.org/TR/html5/forms.html">W3C HTML 5.1規範(表格)</a></li>
+ <li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms" rel="external" title="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms">WHATWG HTML生活水平(表格)</a></li>
+</ul>
+
+<div id="gtx-trans" style="position: absolute; left: 562px; top: 71px;">
+<div class="gtx-trans-icon"></div>
+</div>
diff --git a/files/zh-tw/learn/html/howto/index.html b/files/zh-tw/learn/html/howto/index.html
new file mode 100644
index 0000000000..9a14c26039
--- /dev/null
+++ b/files/zh-tw/learn/html/howto/index.html
@@ -0,0 +1,150 @@
+---
+title: 使用HTML解決日常問題
+slug: Learn/HTML/Howto
+translation_of: Learn/HTML/Howto
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">以下連結會給出 HTML 常見待解問題的方法</p>
+
+<div class="column-container">
+<div class="column-half">
+<h3 id="基本結構">基本結構</h3>
+
+<p>HTML 文件的最基本結構應用。如果你是 HTML 新手,就先從這裡開始看。</p>
+
+<ul>
+ <li><a href="/zh-TW/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document">如何建立基本 HTML 文件</a></li>
+ <li><a href="/zh-TW/docs/Learn/HTML/Howto/Divide_a_webpage_into_logical_sections">如何有邏輯地分割網頁</a></li>
+ <li><a href="/zh-TW/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#The_basics_headings_and_paragraphs">如何建立良好的標題段落結構</a></li>
+</ul>
+
+<h3 id="基本文字語法">基本文字語法</h3>
+
+<p>HTML 專攻於為文件提供語義資訊,因此 HTML 可以提供使用者更精準的文件資訊傳達方式。</p>
+
+<ul>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">如何建立清單</a></li>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Emphasis_and_importance">如何強調文件的內容</a></li>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Emphasis_and_importance">如何表示出一段文字的重要性</a></li>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Representing_computer_code">如何顯示程式碼</a></li>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#Annotating_images_with_figures_and_figure_captions">如何為圖片加入註記</a></li>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Abbreviations">如何標示並註記縮寫</a></li>
+ <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Quotations">如何在網頁中加入引用</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Define_terms_with_HTML">如何加入詞語的定義</a></li>
+</ul>
+</div>
+
+<div class="column-half">
+<h3 id="超連結">超連結</h3>
+
+<p>{{Glossary("hyperlink", "超連結")}}把 HTML 導覽變得相當容易,它可以這麼用:</p>
+
+<ul>
+ <li><a href="/zh-TW/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">如何建立超連結</a></li>
+ <li><a href="/zh-TW/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Active_learning_creating_a_navigation_menu">How to create a table of contents with HTML</a></li>
+</ul>
+
+<h3 id="圖片與多媒體">圖片與多媒體</h3>
+
+<ul>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#How_do_we_put_an_image_on_a_webpage">How to add images to a webpage</a></li>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">How to add video content to a webpage</a></li>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">How to add audio content to a webpage</a></li>
+</ul>
+
+<h3 id="腳本與樣式">腳本與樣式</h3>
+
+<p>HTML 只建立文件的基礎架構,可以透過 {{glossary("CSS")}} 或腳本使內容呈現更具互動性。</p>
+
+<ul>
+ <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_to_apply_your_CSS_to_your_HTML">如何在網頁中使用 CSS</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Use_JavaScript_within_a_webpage">如何在網頁中使用 JavaScript</a></li>
+</ul>
+
+<h3 id="嵌入內容">嵌入內容</h3>
+
+<ul>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">How to embed a webpage within another webpage</a></li>
+ <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies#The_%3Cembed%3E_and_%3Cobject%3E_elements">How to add Flash content within a webpage</a></li>
+</ul>
+</div>
+</div>
+
+<h2 id="不常見或進階的問題">不常見或進階的問題</h2>
+
+<p>除了上述的基本功能外,HTML 還提供許多進階功能讓使用者解決較複雜的問題。這些文章可以幫助你處理一些較不常見的情況:</p>
+
+<div class="column-container">
+<div class="column-half">
+<h3 id="表單">表單</h3>
+
+<p>Forms are a complex HTML structure made to send data from a webpage to a web server. We encourage you to go over our <a href="/en-US/docs/Web/Guide/HTML/Forms">full dedicated guide</a>. Here is where you should start:</p>
+
+<ul>
+ <li><a href="/en-US/docs/Web/Guide/HTML/Forms/My_first_HTML_form">How to create a simple Web form</a></li>
+ <li><a href="/en-US/docs/Web/Guide/HTML/Forms/How_to_structure_an_HTML_form">How to structure a Web form</a></li>
+</ul>
+
+<h3 id="表格訊息">表格訊息</h3>
+
+<p>Some information, called tabular data, needs to be organized into tables with columns and rows. It's one of the most complex HTML structures, and mastering it is not easy:</p>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Create_a_data_spreadsheet">How to create a data spreadsheet</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Make_HTML_tables_accessible">How to make HTML tables accessible</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Optimize_HTML_table_rendering">How to optimize HTML table rendering</a></li>
+</ul>
+
+<h3 id="資料表示方式">資料表示方式</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTMLHowto/Represent_numeric_values_with_HTML">How to represent numeric values with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Use_data_attributes">How to use data attributes</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Associate_human_readable_content_with_arbitrary_computer_data_structures">How to associate human readable content with arbitrary computer data structures</a></li>
+</ul>
+
+<h3 id="互動性">互動性</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Create_collapsible_content_with_HTML">How to create collapsible content with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Add_context_menus_to_a_webpage">How to add context menus to a webpage</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Create_dialog_boxes_with_HTML">How to create dialog boxes with HTML</a></li>
+</ul>
+</div>
+
+<div class="column-half">
+<h3 id="進階文字語法">進階文字語法</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Take_control_of_HTML_line_breaking">How to take control of HTML line breaking</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Mark_text_insertion_and_deletion">How to mark changes (added and removed text)</a></li>
+</ul>
+
+<h3 id="進階圖片_多媒體">進階圖片 &amp; 多媒體</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">How to add responsive image to a webpage</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">How to add vector image to a webpage</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">How to add a hit map on top of an image</a></li>
+</ul>
+
+<h3 id="國際化">國際化</h3>
+
+<p>HTML is not monolingual. It provides tools to handle common internationalization issues.</p>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Add_multiple_languages_into_a_single_webpage">How to add multiple languages into a single webpage</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Handle_Japanese_ruby_characters">How to handle Japanese ruby characters</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Display_time_and_date_with_HTML">How to display time and date with HTML</a></li>
+</ul>
+
+<h3 id="效能">效能</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Howto/Author_fast-loading_HTML_pages">How to author fast-loading HTML pages</a></li>
+</ul>
+</div>
+</div>
+
+<p><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span> </p>
diff --git a/files/zh-tw/learn/html/index.html b/files/zh-tw/learn/html/index.html
new file mode 100644
index 0000000000..897bbcdd5e
--- /dev/null
+++ b/files/zh-tw/learn/html/index.html
@@ -0,0 +1,61 @@
+---
+title: 學習 HTML :指南與教學
+slug: Learn/HTML
+tags:
+ - Beginner
+ - Guide
+ - HTML
+ - Intro
+ - Learn
+ - NeedsTranslation
+ - Topic
+ - TopicStub
+ - 初心者
+ - 指南
+ - 超文本標記語言
+translation_of: Learn/HTML
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">為了建立網頁,你應該要先知道 {{Glossary('「HTML」')}} — 用來建造網站架構的科技。 HTML 是用來辨認網頁中的內容該如何被解讀,例如說被解讀為:一個段落(paragraph)、清單(list)、文件標題(heading)、連結(link)、圖片(images)、多媒體撥放器(multimedia player)、表單(form)或是任何一個可使用的「元素(elements)」,甚至是你自己定義的新元素。</p>
+
+<h2 id="學習途徑">學習途徑</h2>
+
+<p>理想上,你應該從學習 HTML 開始你的學習旅程。可以先從閱讀 <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML介紹(Introduction to HTML)</a> 開始。接下來你可以開始閱讀以下的進階主題:</p>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/CSS">CSS</a>, 和如何使用它來美化 HTML (例如改變文字大小和字形、加上邊框與陰影、用多欄位[columns]來排版你的頁面、增加動畫和視覺效果...)</li>
+ <li><a href="/en-US/docs/Learn/JavaScript">JavaScript</a>, 和如何使用它來為網頁增加互動性的功能 (例如將你的位置顯示在地圖上、點擊按鈕讓 UI 上的元素出現或消失、將用戶的一些資料存放在他們的電腦上... 等等)</li>
+</ul>
+
+<p>當你開始閱讀這主題時,你至少必須對使用電腦有基礎了解,以及會基本的上網 (諸如網頁瀏覽、了解網頁內容)。而你需要建立一個已安裝基本軟體 (詳細軟體請參閱<a href="/en-US/docs/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a>)的基礎工作環境,並且了解如何建立與管理檔案(詳細請參閱<a href="/en-US/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a>) — 這些都包含在新手 <a href="https://developer.mozilla.org/zh-TW/docs/Learn/Getting_started_with_the_web">Web 入門</a>的章節裡。</p>
+
+<p>建議你在開始學習 HTML 這個項目之前,可以先 <a href="/en-US/docs/Learn/Getting_started_with_the_web">從網際網路開始 </a>瞭解是如何運作的。儘管知道網路的運作不是必要的;大部分的項目都在 <a href="/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a> 的文章中 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a> 這個章節更詳盡地介紹 模組 (module), albeit。</p>
+
+<h2 id="模組">模組</h2>
+
+<p>這主題包含了以下幾個單元, 你可以根據以下順序來閱讀他們。強烈推薦從第一個單元開始讀起。</p>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML介紹</a></dt>
+ <dd>這個單元為你提供一個平台,讓你熟悉重要的概念和語法、思考如何將HTML應用於文本、如何創建超鏈接以及使用HTML來構建網頁。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding">嵌入多媒體</a></dt>
+ <dd>本單元探索如何在你的網頁中使用HTML置入多媒體,包括置入圖像的各種方法,以及如何嵌入影片,聲音檔或甚至其他網頁。</dd>
+ <dt><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Tables">表格</a></dt>
+ <dd><font><font>以一種易於理解、</font></font><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Glossary/Accessibility">無障礙的</a><font><font>方式</font><font>在網頁上顯示表格數據</font><font>可能是一個挑戰。</font><font>此單元涵蓋基本的表格標記以及更複雜的功能,例如實行標題和摘要。</font></font></dd>
+</dl>
+
+<h2 id="解決常見的_HTML_問題">解決常見的 HTML 問題</h2>
+
+<p><a href="/zh-TW/docs/Learn/HTML/Howto">利用HTML解決常見問題</a> 提供部分連結,這些內容解釋了在創建網頁時如何使用HTML解決常見的問題:標題,添加圖像或視頻,強調內容,創建基本表單等等。</p>
+
+<h2 id="或許你還想看......">或許你還想看......</h2>
+
+<div class="document-head" id="wiki-document-head">
+<dl>
+ <dt><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Forms">網站表單</a></dt>
+ <dd>這篇指南提供了一系列的文章,幫你掌握HTML表單的基本知識。對於與使用者互動,網站表單是一項十分有力的工具,最常使用於用戶數據蒐集,或控制使用者介面。但由於一些歷史與技術上的因素,並沒有顯著的方法發揮表單的潛力。在下面的指引中,我們將介紹網站表單所有基本面向,包括標記他們的HTML結構、設定控制器樣式、驗證數據及將數距提送至伺服器。</dd>
+ <dt><a href="/en-US/docs/Web/HTML">HTML</a></dt>
+ <dd>MDN的HTML參考文件的主要入口,包括詳細的元素和屬性參考-例如,如果您想知道元素具有哪些屬性或屬性具有什麼值,那麼這是一個很好的起點。</dd>
+</dl>
+</div>
diff --git a/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html b/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html
new file mode 100644
index 0000000000..3b5786613b
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/advanced_text_formatting/index.html
@@ -0,0 +1,456 @@
+---
+title: Advanced text formatting
+slug: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting
+tags:
+ - HTML
+translation_of: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">There are many other elements in HTML for formatting text, which we didn't get to in the <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a> article. The elements described in this article are less well-known, but still useful to know about (and this is still not a complete list by any means.) In here you'll learn about marking up quotations, description lists, computer code and other related text, subscript and superscript, contact information, and more.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic HTML familiarity, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>. HTML text formatting, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To learn how to use lesser-known HTML elements to mark up advanced semantic features.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="說明列表">說明列表</h2>
+
+<p>In HTML text fundamentals, we walked through how to <a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">mark up basic lists</a> in HTML, but we didn't mention the third type of list you'll occasionally come across — <strong>description lists</strong>. The purpose of these lists is to mark up a set of items and their associated descriptions, such as terms and definitions, or questions and answers. Let's look at an example of a set of terms and definitions:</p>
+
+<pre>soliloquy
+In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)
+monologue
+In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.
+aside
+In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information</pre>
+
+<p>Description lists use a different wrapper than the other list types — {{htmlelement("dl")}}; in addition each term is wrapped in a {{htmlelement("dt")}} (description term) element, and each description is wrapped in a {{htmlelement("dd")}} (description description) element. Let's finish marking up our example:</p>
+
+<pre class="brush: html">&lt;dl&gt;
+ &lt;dt&gt;soliloquy&lt;/dt&gt;
+ &lt;dd&gt;In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)&lt;/dd&gt;
+ &lt;dt&gt;monologue&lt;/dt&gt;
+ &lt;dd&gt;In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.&lt;/dd&gt;
+ &lt;dt&gt;aside&lt;/dt&gt;
+ &lt;dd&gt;In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.&lt;/dd&gt;
+&lt;/dl&gt;</pre>
+
+<p>The browser default styles will display description lists with the descriptions indented somewhat from the terms. MDN's styles follow this convention fairly closely, but also embolden the terms for extra definition.</p>
+
+<dl>
+ <dt>soliloquy</dt>
+ <dd>In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)</dd>
+ <dt>monologue</dt>
+ <dd>In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.</dd>
+ <dt>aside</dt>
+ <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of addtional background information.</dd>
+</dl>
+
+<p>Note that it is permitted to have a single term with multiple descriptions, for example:</p>
+
+<dl>
+ <dt>aside</dt>
+ <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.</dd>
+ <dd>In writing, a section of content that is related to the current topic, but doesn't fit directly into the main flow of content so is presented nearby (often in a box off to the side.)</dd>
+</dl>
+
+<h3 id="Active_learning_Marking_up_a_set_of_definitions">Active learning: Marking up a set of definitions</h3>
+
+<p>It's time to try your hand at description lists; add elements to the raw text in the <em>Input</em> field so that it appears as a description list in the <em>Output</em> field. You could try using your own terms and descriptions if you like.</p>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see the answer.</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Input&lt;/h2&gt;
+&lt;textarea id="code" class="input"&gt;Bacon
+The glue that binds the world together.
+Eggs
+The glue that binds the cake together.
+Coffee
+The drink that gets the world running in the morning.
+A light brown color.&lt;/textarea&gt;
+&lt;h2&gt;Output&lt;/h2&gt;
+&lt;div class="output"&gt;&lt;/div&gt;
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">body {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+.input, .output {
+ width: 90%;
+ height: 10em;
+ padding: 10px;
+ border: 1px solid #0095dd;
+ overflow: auto;
+}
+
+button {
+ padding: 10px 10px 10px 0;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var code = textarea.value;
+var output = document.querySelector(".output");
+var solution = document.getElementById("solution");
+
+function drawOutput() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener("click", function() {
+ textarea.value = code;
+ drawOutput();
+});
+
+solution.addEventListener("click", function() {
+textarea.value = '&lt;dl&gt;\n &lt;dt&gt;Bacon&lt;/dt&gt;\n &lt;dd&gt;The glue that binds the world together.&lt;/dd&gt;\n &lt;dt&gt;Eggs&lt;/dt&gt;\n &lt;dd&gt;The glue that binds the cake together.&lt;/dd&gt;\n &lt;dt&gt;Coffee&lt;/dt&gt;\n &lt;dd&gt;The drink that gets the world running in the morning.&lt;/dd&gt;\n &lt;dd&gt;A light brown color.&lt;/dd&gt;\n&lt;/dl&gt;';
+ drawOutput();
+});
+
+textarea.addEventListener("input", drawOutput);
+window.addEventListener("load", drawOutput);
+</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', 700, 500) }}</p>
+
+<h2 id="Quotations">Quotations</h2>
+
+<p>HTML also has features available for marking up quotations; which element you use depends on whether you are marking up a block or inline quotation.</p>
+
+<h3 id="Blockquotes">Blockquotes</h3>
+
+<p>If a section of block level content (be it a paragraph, multiple paragraphs, a list, etc.) is quoted from somewhere else, you should wrap it inside a {{htmlelement("blockquote")}} element to signify this, and include a URL pointing to the source of the quote inside a {{htmlattrxref("cite","blockquote")}} attribute. For example, the following markup is taken from the MDN <code>&lt;blockquote&gt;</code> element page:</p>
+
+<pre class="brush: html">&lt;p&gt;The &lt;strong&gt;HTML &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; Element&lt;/strong&gt; (or &lt;em&gt;HTML Block
+Quotation Element&lt;/em&gt;) indicates that the enclosed text is an extended quotation.&lt;/p&gt;</pre>
+
+<p>To turn this into a block quote, we would just do this:</p>
+
+<pre class="brush: html">&lt;blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"&gt;
+ &lt;p&gt;The &lt;strong&gt;HTML &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; Element&lt;/strong&gt; (or &lt;em&gt;HTML Block
+ Quotation Element&lt;/em&gt;) indicates that the enclosed text is an extended quotation.&lt;/p&gt;
+&lt;/blockquote&gt;</pre>
+
+<p>Browser default styling will render this as an indented paragraph, as an indicator that it is a quote; MDN does this, but also adds some extra styling:</p>
+
+<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote">
+<p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p>
+</blockquote>
+
+<h3 id="Inline_quotations">Inline quotations</h3>
+
+<p>Inline quotations work in exactly the same way, except that they use the {{htmlelement("q")}} element. For example, the below bit of markup contains a quotation from the MDN <code>&lt;q&gt;</code> page:</p>
+
+<pre class="brush: html">&lt;p&gt;The quote element — &lt;code&gt;&amp;lt;q&amp;gt;&lt;/code&gt; — is &lt;q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q"&gt;intended
+for short quotations that don't require paragraph breaks.&lt;/q&gt;&lt;/p&gt;</pre>
+
+<p>Browser default styling will render this as normal text put in quotes to indicate a quotation, like so:</p>
+
+<p>The quote element — <code>&lt;q&gt;</code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended for short quotations that don't require paragraph breaks.</q></p>
+
+<h3 id="Citations">Citations</h3>
+
+<p>The content of the {{htmlattrxref("cite","blockquote")}} attribute sounds useful, but unfortunately browsers, screenreaders, etc. don't really do much with it. There is no way to get the browser to display the contents of <code>cite</code>, without writing your own solution using JavaScript or CSS. If you want to make the source of the quotation available on the page, a better way to mark it up is put the {{htmlelement("cite")}} element next to the quote element. This is really meant to contain the name of the quote source — i.e. the name of the book, or name of the person that said the quote — but there is no reason why you couldn't link the text inside <code>&lt;cite&gt;</code> to the quote source in some way:</p>
+
+<pre class="brush: html">&lt;p&gt;According to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"&gt;
+&lt;cite&gt;MDN blockquote page&lt;/cite&gt;&lt;/a&gt;:
+&lt;/p&gt;
+
+&lt;blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"&gt;
+ &lt;p&gt;The &lt;strong&gt;HTML &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; Element&lt;/strong&gt; (or &lt;em&gt;HTML Block
+ Quotation Element&lt;/em&gt;) indicates that the enclosed text is an extended quotation.&lt;/p&gt;
+&lt;/blockquote&gt;
+
+&lt;p&gt;The quote element — &lt;code&gt;&amp;lt;q&amp;gt;&lt;/code&gt; — is &lt;q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q"&gt;intended
+for short quotations that don't require paragraph breaks.&lt;/q&gt; -- &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q"&gt;
+&lt;cite&gt;MDN q page&lt;/cite&gt;&lt;/a&gt;.&lt;/p&gt;</pre>
+
+<p>Citations are styled in italic font by default. You can see this code at work in our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/quotations.html">quotations.html</a> example.</p>
+
+<h3 id="Active_learning_Who_said_that">Active learning: Who said that?</h3>
+
+<p>Time for another active learning example! In this example we'd like you to:</p>
+
+<ol>
+ <li>Turn the middle paragraph into a blockquote, which includes a <code>cite</code> attribute.</li>
+ <li>Turn part of the third paragraph into an inline quote, which includes a <code>cite</code> attribute.</li>
+ <li>Include a <code>&lt;cite&gt;</code> element for each quote</li>
+</ol>
+
+<p>Search online to find appropriate quote sources.</p>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see the answer.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Input&lt;/h2&gt;
+&lt;textarea id="code" class="input"&gt;&lt;p&gt;Hello and welcome to my motivation page. As Confucius once said:&lt;/p&gt;
+
+&lt;p&gt;It does not matter how slowly you go as long as you do not stop.&lt;/p&gt;
+
+&lt;p&gt;I also love the concept of positive thinking, and The Need To Eliminate Negative Self Talk
+(as mentioned in Affirmations for Positive Thinking.)&lt;/p&gt;&lt;/textarea&gt;
+&lt;h2&gt;Output&lt;/h2&gt;
+&lt;div class="output"&gt;&lt;/div&gt;
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">body {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+.input, .output {
+ width: 90%;
+ height: 10em;
+ padding: 10px;
+ border: 1px solid #0095dd;
+ overflow: auto;
+}
+
+button {
+ padding: 10px 10px 10px 0;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var code = textarea.value;
+var output = document.querySelector(".output");
+var solution = document.getElementById("solution");
+
+function drawOutput() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener("click", function() {
+ textarea.value = code;
+ drawOutput();
+});
+
+solution.addEventListener("click", function() {
+textarea.value = '&lt;p&gt;Hello and welcome to my motivation page. As &lt;a href="http://www.brainyquote.com/quotes/authors/c/confucius.html"&gt;&lt;cite&gt;Confucius&lt;/cite&gt;&lt;/a&gt; once said:&lt;/p&gt;\n\n&lt;blockquote cite="http://www.brainyquote.com/quotes/authors/c/confucius.html"&gt;\n &lt;p&gt;It does not matter how slowly you go as long as you do not stop.&lt;/p&gt;\n&lt;/blockquote&gt;\n\n&lt;p&gt;I also love the concept of positive thinking, and &lt;q cite="http://www.affirmationsforpositivethinking.com/index.htm"&gt;The Need To Eliminate Negative Self Talk&lt;/q&gt; (as mentioned in &lt;a href="http://www.affirmationsforpositivethinking.com/index.htm"&gt;&lt;cite&gt;Affirmations for Positive Thinking&lt;/cite&gt;&lt;/a&gt;.)&lt;/p&gt;';
+ drawOutput();
+});
+
+textarea.addEventListener("input", drawOutput);
+window.addEventListener("load", drawOutput);
+</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', 700, 500) }}</p>
+
+<h2 id="Abbreviations">Abbreviations</h2>
+
+<p>Another fairly common element you'll meet when looking around the Web is {{htmlelement("abbr")}} — this is used to wrap around an abbreviation or acronym, and provide a full expansion of the term (included inside a {{htmlattrxref("title")}} attribute.) Let's look at a couple of examples:</p>
+
+<pre>&lt;p&gt;We use &lt;abbr title="Hypertext Markup Language"&gt;HTML&lt;/abbr&gt; to structure our web documents.&lt;/p&gt;
+
+&lt;p&gt;I think &lt;abbr title="Reverend"&gt;Rev.&lt;/abbr&gt; Green did it in the kitchen with the chainsaw.&lt;/p&gt;</pre>
+
+<p>These will come out looking something like this (the expansion will appear in a tooltip when the term is hovered over):</p>
+
+<p>We use <abbr title="Hypertext Markup Language">HTML</abbr> to structure our web documents.</p>
+
+<p>I think <abbr title="Reverend">Rev.</abbr> Green did it in the kitchen with the chainsaw.</p>
+
+<div class="note">
+<p><strong>Note</strong>: There is another element, {{htmlelement("acronym")}}, which basically does the same thing as <code>&lt;abbr&gt;</code>, and was intended specifically for acronyms rather than abbreviations. This however has fallen into disuse — it wasn't supported as well in browsers as well as <code>&lt;abbr&gt;</code>, and has such as similar function that it was felt pointless to have both. Just use <code>&lt;abbr&gt;</code> instead.</p>
+</div>
+
+<h3 id="Active_learning_marking_up_an_abbreviation">Active learning: marking up an abbreviation</h3>
+
+<p>For this simple active learning assignment, we'd like you to simply mark up an abbreviation. You can use our sample below, or replace it with one of your own. </p>
+
+<div class="hidden">
+<h6 id="Playable_code_3">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Input&lt;/h2&gt;
+&lt;textarea id="code" class="input"&gt;&lt;p&gt;NASA sure does some exciting work.&lt;/p&gt;&lt;/textarea&gt;
+&lt;h2&gt;Output&lt;/h2&gt;
+&lt;div class="output"&gt;&lt;/div&gt;
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">body {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+.input, .output {
+ width: 90%;
+ height: 5em;
+ padding: 10px;
+ border: 1px solid #0095dd;
+ overflow: auto;
+}
+
+button {
+ padding: 10px 10px 10px 0;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var code = textarea.value;
+var output = document.querySelector(".output");
+var solution = document.getElementById("solution");
+
+function drawOutput() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener("click", function() {
+ textarea.value = code;
+ drawOutput();
+});
+
+solution.addEventListener("click", function() {
+textarea.value = '&lt;p&gt;&lt;abbr title="National Aeronautics and Space Administration"&gt;NASA&lt;/abbr&gt; sure does some exciting work.&lt;/p&gt;';
+ drawOutput();
+});
+
+textarea.addEventListener("input", drawOutput);
+window.addEventListener("load", drawOutput);
+</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_3', 700, 350) }}</p>
+
+<h2 id="Marking_up_contact_details">Marking up contact details</h2>
+
+<p>HTML has an element for marking up contact details — {{htmlelement("address")}}. This simply wraps around your contact details, for example:</p>
+
+<pre class="brush: html">&lt;address&gt;
+ &lt;p&gt;Chris Mills, Manchester, The Grim North, UK&lt;/p&gt;
+&lt;/address&gt;</pre>
+
+<p>One thing to remember however is that the &lt;address&gt; element is meant for marking up the contact details of the person who wrote the HTML document, not <em>any</em> address. So the above would only be ok if Chris had written the document the markup appears on. Note that something like this would also be ok:</p>
+
+<pre class="brush: html">&lt;address&gt;
+ &lt;p&gt;Page written by &lt;a href="../authors/chris-mills/"&gt;Chris Mills&lt;/a&gt;.&lt;/p&gt;
+&lt;/address&gt;</pre>
+
+<h2 id="Superscript_and_subscript">Superscript and subscript</h2>
+
+<p>You will occasionally need to use superscript and subscript when marking up items like dates, chemical formulae, and mathematical equations so they have the correct meaning. The {{htmlelement("sup")}} and {{htmlelement("sub")}} elements handle this job. For example:</p>
+
+<pre class="brush: html">&lt;p&gt;My birthday is on the 25&lt;sup&gt;th&lt;/sup&gt; of May 2001.&lt;/p&gt;
+&lt;p&gt;Caffeine's chemical formula is C&lt;sub&gt;8&lt;/sub&gt;H&lt;sub&gt;10&lt;/sub&gt;N&lt;sub&gt;4&lt;/sub&gt;O&lt;sub&gt;2&lt;/sub&gt;.&lt;/p&gt;
+&lt;p&gt;If x&lt;sup&gt;2&lt;/sup&gt; is 9, x must equal 3 or -3.&lt;/p&gt;</pre>
+
+<p>The output of this code looks like so:</p>
+
+<p>My birthday is on the 25<sup>th</sup> of May 2001.</p>
+
+<p>Caffeine's chemical formula is C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p>
+
+<p>If x<sup>2</sup> is 9, x must equal 3 or -3.</p>
+
+<h2 id="Representing_computer_code">Representing computer code</h2>
+
+<p>There are a number of elements available for marking up computer code:</p>
+
+<ul>
+ <li>{{htmlelement("code")}}: For making up generic pieces of computer code.</li>
+ <li>{{htmlelement("pre")}}: For marking up blocks of fixed width text, in which the whitespace is retained (generally code blocks.)</li>
+ <li>{{htmlelement("var")}}: For specifically marking up variable names.</li>
+ <li>{{htmlelement("kbd")}}: For marking up keyboard (and other types of) input entered into the computer.</li>
+ <li>{{htmlelement("samp")}}: For marking up the output of a computer program.</li>
+</ul>
+
+<p>Let's look at a few examples. You should try having a play with these (try grabbing a copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/other-semantics.html">other-semantics.html</a> sample file):</p>
+
+<pre class="brush: html">&lt;pre&gt;&lt;code&gt;var para = document.querySelector('p');
+
+para.onclick = function() {
+ alert('Owww, stop poking me!');
+}&lt;/code&gt;&lt;/pre&gt;
+
+&lt;p&gt;You shouldn't use presentational elements like &lt;code&gt;&amp;lt;font&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;center&amp;gt;&lt;/code&gt;.&lt;/p&gt;
+
+&lt;p&gt;In the above JavaScript example, &lt;var&gt;para&lt;/var&gt; represents a paragraph element.&lt;/p&gt;
+
+
+&lt;p&gt;Select all the text with &lt;kbd&gt;Ctrl&lt;/kbd&gt;/&lt;kbd&gt;Cmd&lt;/kbd&gt; + &lt;kbd&gt;A&lt;/kbd&gt;.&lt;/p&gt;
+
+&lt;pre&gt;$ &lt;kbd&gt;ping mozilla.org&lt;/kbd&gt;
+&lt;samp&gt;PING mozilla.org (63.245.215.20): 56 data bytes
+64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms&lt;/samp&gt;&lt;/pre&gt;</pre>
+
+<p>The above code will look like so:</p>
+
+<p>{{ EmbedLiveSample('Representing_computer_code','100%',300) }}</p>
+
+<h2 id="Marking_up_times_and_dates">Marking up times and dates</h2>
+
+<p>HTML also provides the {{htmlelement("time")}} element for marking up times and dates in a machine-readable format. For example:</p>
+
+<pre class="brush: html">&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20<span class="pl-pds">"</span></span>&gt;20 January 2016&lt;/<span class="pl-ent">time</span>&gt;</pre>
+
+<p>Why is this useful? Well, there are many different ways that humans write down dates. The above date could be written as:</p>
+
+<ul>
+ <li>20 January 2016</li>
+ <li>20th January 2016</li>
+ <li>Jan 20 2016</li>
+ <li>20/06/16</li>
+ <li>06/20/16</li>
+ <li>The 20th of next month</li>
+ <li><span lang="fr">20e Janvier 2016</span></li>
+ <li><span lang="ja">2016年1月20日</span></li>
+ <li><span lang="ja">And so on</span></li>
+</ul>
+
+<p><span lang="ja">But these different forms cannot be easily recognised by the computers — what if you wanted to automatically grab the dates of all events in a page and insert them into a calendar? The </span>{{htmlelement("time")}} element allows you to attach a unambiguous, machine-readable time/date for this purpose.</p>
+
+<p>The basic example above just provides a simple machine readable date, but there are many other options that are possible, for example:</p>
+
+<pre class="brush: html">&lt;!-- Standard simple date --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20<span class="pl-pds">"</span></span>&gt;20 January 2016&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Just year and month --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01<span class="pl-pds">"</span></span>&gt;January 2016&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Just month and day --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>01-20<span class="pl-pds">"</span></span>&gt;20 January&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Just time, hours and minutes --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>19:30<span class="pl-pds">"</span></span>&gt;19:30&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- You can do seconds and milliseconds too! --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span></span>19:30:01.856<span class="pl-s"><span class="pl-pds">"</span></span>&gt;19:30:01.856&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Date and time --&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20T19:30<span class="pl-pds">"</span></span>&gt;7.30pm, 20 January 2016&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Date and time with timezone offset--&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20T19:30<span class="pl-pds">+01:00"</span></span>&gt;7.30pm, 20 January 2016 is 8.30pm in France&lt;/<span class="pl-ent">time</span>&gt;
+&lt;!-- Calling out a specific week number--&gt;
+&lt;<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-W04<span class="pl-pds">"</span></span>&gt;The fourth week of 2016&lt;/<span class="pl-ent">time</span>&gt;</pre>
+
+<h2 id="Summary">Summary</h2>
+
+<p>That marks the end of our study of HTML text semantics. Bear in mind that what you have seen during this course is not an exhaustive list of HTML text elements — we wanted to try to cover the essentials, and some of the more common ones you will see in the wild, or at least might find interesting. To find way more HTML elements, you can take a look at our <a href="/en-US/docs/Web/HTML/Element">HTML element reference</a> (the <a href="/en-US/docs/Web/HTML/Element#Inline_text_semantics">Inline text semantics</a> section would be a great place to start.) In the next article we will look at the HTML elements you'd use to structure the different parts of an HTML document.</p>
+
+<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</p>
diff --git a/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html b/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html
new file mode 100644
index 0000000000..059cfa427c
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/creating_hyperlinks/index.html
@@ -0,0 +1,326 @@
+---
+title: Creating hyperlinks
+slug: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks
+translation_of: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">超連結(Hyperlinks)真的超級重要 — 它造就了我們現今所熟知的網路。這篇文章將會介紹超連結的使用語法,並且探討建立它們的最佳實踐方法。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">需求:</th>
+ <td>我們在 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 入門</a> 中介紹過的 HTML 基礎,以及在 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 的文字基礎知識</a> 中介紹過的文字格式化技巧。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>學習如何有效地使用超連結,並利用它們來連結多個檔案。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是超連結?">什麼是超連結?</h2>
+
+<p>超連結可說是網路中最令人振奮的革新技術。當然啦,早在網路技術萌芽之初,它們就已經在那了,它們正是網路之所以被稱為「網路」的最大原因 — 它讓我們的文件能任意地與其他文件(或者資源)相互連結(或是連結文件中的特定部份),讓我們能透過一個簡單的網路位址來經營我們的網路應用(相較之下,本機應用(native apps)就必須要安裝在主機上才能使用)。幾乎所有的網路內容都能被轉換成一個連結,讓網路瀏覽器在這些連結被點擊或觸發之後,跳轉到該網路位址({{glossary("URL")}})上。</p>
+
+<div class="note">
+<p><strong>Note</strong>: URL 能夠指向 HTML 檔案、純文字檔案、圖片、文字文件、影音檔案等等可存在網路上的東西。如果網路瀏覽器不知道如何顯示或者處理該檔案的話,它會問你想要開啟這個檔案(將檔案交由本機應用來處理)還是要下載該檔案(意即你可以待會兒再處理)。</p>
+</div>
+
+<p>以 BBC 的主頁為例,裡面就包含了非常多的連結,各自連到不同新聞、網站的其它地方(導覽功能),或者登入/註冊頁面等等。</p>
+
+<p><img alt="frontpage of bbc.co.uk, showing many news items, and navigation menu functionality" src="https://mdn.mozillademos.org/files/17032/updated-bbc-website.png" style="display: block; height: 455px; margin: 0px auto; width: 700px;"></p>
+
+<h2 id="解析連結">解析連結</h2>
+
+<p>一個基本的連結由 {{htmlelement("a")}} 元素包裹一段文字而成(當然也不一定要是文字,見下方的{{anch("區塊級連結")}}),同時,你需要將網路位址填入 {{htmlattrxref("href", "a")}} 屬性中,這個屬性有時也被叫做<strong>超文字參考(Hypertext Reference)</strong>或<strong>目標(target)</strong>。</p>
+
+<pre class="brush: html">&lt;p&gt;I'm creating a link to
+&lt;a href="https://www.mozilla.org/en-US/"&gt;the Mozilla homepage&lt;/a&gt;.
+&lt;/p&gt;</pre>
+
+<p>這會產生以下結果:</p>
+
+<p>I'm creating a link to <a class="ignore-external" href="https://www.mozilla.org/en-US/">the Mozilla homepage</a>.</p>
+
+<h3 id="利用_title_屬性來添加額外資訊">利用 title 屬性來添加額外資訊</h3>
+
+<p>另外一個你可能會想在連結中附加的屬性是 <code>title</code>,它的目的是攜帶一個補充訊息到連結上,好比說目標網頁有什麼樣的資訊,或者是一些警告訊息,範例如下:</p>
+
+<pre class="brush: html">&lt;p&gt;I'm creating a link to
+&lt;a href="https://www.mozilla.org/en-US/"
+ title="The best place to find more information about Mozilla's
+ mission and how to contribute"&gt;the Mozilla homepage&lt;/a&gt;.
+&lt;/p&gt;</pre>
+
+<p>這將會產生以下結果(當游標移到連結上方時,標題會以提示的形式出現):</p>
+
+<p>I'm creating a link to <a class="ignore-external" href="https://www.mozilla.org/en-US/" title="The best place to find more information about Mozilla's mission and how to contribute">the Mozilla homepage</a>.</p>
+
+<div class="note">
+<p><strong>Note</strong>: 連結標題只有在游標停在連結上方時才會出現,也就是說那些只依賴鍵盤來瀏覽網頁的人將會很難看到這個訊息,因此,如果說標題資訊對網頁易用性(usability)有著重大影響的話,你應該把它放在大家都看得到的地方,比方說放在一般的文字元素裡。</p>
+</div>
+
+<h3 id="不要只用看的:建立你自己的範例連結">不要只用看的:建立你自己的範例連結</h3>
+
+<p>主動學習時間!我們想要你用自己的文字編輯器來撰寫一個 HTML 文件(你可以修改我們的<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">入門範本</a>,那應該就很夠用了)。</p>
+
+<ul>
+ <li>試著在 HTML 的主體(body)中,加入一個以上的段落或者其他你學過的內容元素。</li>
+ <li>將一些內容轉換成連結。</li>
+ <li>增加標題屬性到連結中。</li>
+</ul>
+
+<h3 id="區塊級連結Block-level_links">區塊級連結(Block-level links)</h3>
+
+<p>就像先前所提到的,你可以將任何內容轉換成連結,就算是<a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Block_versus_inline_elements">區塊級元素</a>也沒問題!如果你有一張圖片要轉換成連結,你可以把圖片元素放在 <code>&lt;a&gt;</code> 標籤裡,像這樣:</p>
+
+<pre class="brush: html">&lt;a href="https://www.mozilla.org/en-US/"&gt;
+ &lt;img src="mozilla-image.png" alt="mozilla logo that links to the mozilla homepage"&gt;
+&lt;/a&gt;</pre>
+
+<div class="note">
+<p><strong>Note</strong>: 在往後的教學中,你還會學到更多的圖片使用技法。</p>
+</div>
+
+<h2 id="快速理解_URL_和路徑">快速理解 URL 和路徑</h2>
+
+<p>在完全搞懂連結標的(link target)之前,你必須要先瞭解什麼是 URL 和檔案路徑,而這個小節就是要帶你來看這些東西。</p>
+
+<p>URL 全名為 Uniform Resource Locator (一致資源定位器,俗稱網址),是一條用來指出某樣東西在網路上的位址的字串。比如說 Mozilla 的英文主頁就是位在 <code>https://www.mozilla.org/en-US/</code>。</p>
+
+<p>URL 利用路徑來找到檔案,而路徑會指出你所感興趣的檔案位於檔案系統上的什麼地方。現在讓我們來看個簡單的目錄結構範例(請見我們的<a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/creating-hyperlinks">建立超連結</a>目錄)。</p>
+
+<p><img alt="A simple directory structure. The parent directory is called creating-hyperlinks and contains two files called index.html and contacts.html, and two directories called projects and pdfs, which contain an index.html and a project-brief.pdf file, respectively" src="https://mdn.mozillademos.org/files/12409/simple-directory.png" style="display: block; margin: 0 auto;"></p>
+
+<p><code>creating-hyperlinks</code> 是這個目錄結構的<strong>根目錄(root)</strong>,當你在本地端撰寫網站時,你會將整個網站都放在這樣的資料夾中。在我們的根目錄裡有 <code>index.html</code> 和 <code>contacts.html</code> 兩個檔案,在現實的情況中,<code>index.html</code> 會是我們的首頁或者登陸頁面(landing page,網站或它的某部份的進入點)。</p>
+
+<p>我們的根目錄中有兩個子目錄 — <code>pdfs</code> 和 <code>projects</code>,它們各自都有一個檔案在裡頭,分別是 <code>project-brief.pdf</code> 和 <code>index.html</code>。請記得,你可以很愉快地在一個專案中擁有兩個 <code>index.html</code>,只要它們處在檔案系統上的不同位址。很多網站都會這麼做,第二個 <code>index.html</code> 可能會拿來當作是與專案有關資訊的主登陸頁面。</p>
+
+<ul>
+ <li>
+ <p><strong>在相同目錄裡:</strong>如果你要連結的兩個檔案處在同一個的目錄下,你只需要寫指向的檔案名稱就行了。比方說,如果你想在 <code>index.html</code> (最上層的那個) 中加入一個通往 <code>contacts.html</code> 的超連結,你要用的 URL 就是 <code>contacts.html</code>:</p>
+
+ <pre class="brush: html">&lt;p&gt;Want to contact a specific staff member?
+Find details on our &lt;a href="contacts.html"&gt;contacts page&lt;/a&gt;.&lt;/p&gt;</pre>
+ </li>
+ <li>
+ <p><strong>往下到子目錄中</strong>:如果你想要在 <code>index.html</code> (還是最上層的那個) 中加入一個指向 <code>projects/index.html</code> 的超連結,在指出你要的檔案之前,你需要先往下進到 <code>projects</code> 目錄裡。要做到這件事,你可以先指出目錄名稱,然後加上一個 /,最後再加上檔案名稱。因此你要寫的 URL 會是 <code>projects/index.html</code>:</p>
+
+ <pre class="brush: html">&lt;p&gt;Visit my &lt;a href="projects/index.html"&gt;project homepage&lt;/a&gt;.&lt;/p&gt;</pre>
+ </li>
+ <li>
+ <p><strong>往上到父目錄中</strong>:如果你想要在 <code>projects/index.html</code> 中加入一個指向 <code>pdfs/project-brief.pdf</code> 的超連結,你需要先往上進到 <code>pdf</code> 目錄裡。而「往上移動一個目錄」可以用 <code>..</code> 來表示,因此你要寫的 URL 會是 <code>../pdfs/project-brief.pdf</code>:</p>
+
+ <pre class="brush: html">&lt;p&gt;A link to my &lt;a href="../pdfs/project-brief.pdf"&gt;project brief&lt;/a&gt;.&lt;/p&gt;</pre>
+ </li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: 你可以將多個這種語法組成一個較為複雜的 URL,例如:<code>../../../complex/path/to/my/file.html</code>。</p>
+</div>
+
+<h3 id="文件片段_Document_fragments">文件片段 (Document fragments)</h3>
+
+<p>並不是每次都只能連到文件的頂端,你也可以連到 HTML 文件中的某個部分,而這個部分叫做<strong>文件片段(document fragment)</strong>。要做到這件事,你得先為你要連的元素設定 {{htmlattrxref("id")}} 屬性,通常你可以把連結設在標題(heading)上,像是下面這樣:</p>
+
+<pre class="brush: html">&lt;h2 id="Mailing_address"&gt;Mailing address&lt;/h2&gt;</pre>
+
+<p>要連到特定的 <code>id</code>,你得在你的 URL 的後面加上一個 # 號,像這樣:</p>
+
+<pre class="brush: html">&lt;p&gt;Want to write us a letter? Use our &lt;a href="contacts.html#Mailing_address"&gt;mailing address&lt;/a&gt;.&lt;/p&gt;</pre>
+
+<p>你甚至可以利用文件片段來連到<em>同個文件的其他部分</em>:</p>
+
+<pre class="brush: html">&lt;p&gt;The &lt;a href="#Mailing_address"&gt;company mailing address&lt;/a&gt; can be found at the bottom of this page.&lt;/p&gt;</pre>
+
+<h3 id="絕對_URL_vs._相對_URL">絕對 URL vs. 相對 URL</h3>
+
+<p>你會在網路上看到兩個名詞,<strong>絕對 URL(absolute URL)</strong>和<strong>相對 URL(relative URL):</strong></p>
+
+<p><strong>絕對 URL</strong>:指向網路上的絕對位址,裡頭包含協定({{glossary("protocol")}})和網域名稱({{glossary("domain name")}})。舉個例子,假設一個 web server 的根目錄有一個 <code>projects</code> 目錄,裡面放著一個 <code>index.html</code>,該網站的網域為 <code>http://www.example.com</code>,則網頁可以透過網址 <code>http://www.example.com/projects/index.html</code> 來取得 (或寫成 <code>http://www.example.com/projects/</code> 也行,因為大多的 web server 都能在 URL 沒有明確指出時,自動找尋如 <code>index.html</code> 之類的登陸頁面)。</p>
+
+<p>絕對 URL 無論在什麼地方使用,它都會代表同一個位址。</p>
+
+<p><strong>相對 URL</strong>:指向一個檔案的相對位址,這跟我們在先前看到的非常類似。舉例來說,如果我們想要從 <code>http://www.example.com/projects/index.html</code> 連到同一目錄下的 PDF 檔,URL 就只要檔名就好 — 像是 <code>project-brief.pdf</code> — 不需要其它的資訊。如果那個 PDF 放在 <code>projects</code> 中叫做 <code>pdfs</code> 的子目錄裡,其相對連結就是 <code>pdfs/project-brief.pdf</code> (等效的絕對 URL 為 <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>)。</p>
+
+<p>相對 URL 指向的位址會受到檔案所在的真正位址影響 — 舉例來說,如果我們將 <code>index.html</code> 移出 <code>projects</code>,並放在網站的根目錄中 (也就是在最上層中),裡頭指向 <code>pdfs/project-brief.pdf</code> 的相對 URL 連結會指到 <code>http://www.example.com/pdfs/project-brief.pdf</code>,而非 <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>。</p>
+
+<p>當然,<code>project-brief.pdf</code> 和 <code>pdfs</code> 的位置不會因為你移動 <code>index.html</code> 就改變 — 這會使得你的連結指到錯誤的地方,你一定得非常小心!</p>
+
+<h2 id="連結的最佳實踐">連結的最佳實踐</h2>
+
+<p>撰寫連結時有幾個最佳實踐方法,現在讓我們來看看吧。</p>
+
+<ul>
+</ul>
+
+<h3 id="使用明確的字詞">使用明確的字詞</h3>
+
+<p>要在你的網頁上加入連結非常簡單,但這還不夠,我們必須確保連結能夠被所有讀者取用到,無論他們的背景或者使用的工具為何。比如說:</p>
+
+<ul>
+ <li>螢幕閱讀器的使用者會在頁面上的連結間跳來跳去,並且閱讀連結時不看上下文。</li>
+ <li>搜尋引擎使用連結上的文字來為目標建立索引,因此你可以將關鍵字包含在你的連結文字中,藉此有效地說明連結的對象。</li>
+ <li>以視覺進行閱讀的讀者對於內文往往匆匆一瞥,他們將注目在明顯的頁面特徵,像是連結,因此具有敘述性的連結文字將對他們有所助益。</li>
+</ul>
+
+<p>我們來看幾個例子:</p>
+
+<p><em><strong>好的</strong>連結文字:</em><a href="https://firefox.com">下載 Firefox</a></p>
+
+<pre class="brush: html">&lt;p&gt;&lt;a href="https://firefox.com/"&gt;
+ 下載 Firefox
+&lt;/a&gt;&lt;/p&gt;</pre>
+
+<p><em><strong>不好的</strong>連結文字:</em><a href="https://firefox.com/">點這裡</a>來下載 Firefox</p>
+
+<pre class="brush: html">&lt;p&gt;&lt;a href="https://firefox.com/"&gt;
+ 點這裡
+&lt;/a&gt;
+來下載 Firefox&lt;/p&gt;
+</pre>
+
+<p>其它小訣竅:</p>
+
+<ul>
+ <li>千萬別把 URL 當作連結文字 — URL 看起來醜斃了,更別提當螢幕閱讀器將它逐字唸出時會有多糟。</li>
+ <li>千萬別用「連結(link)」或「連至(link to)」— 那只是廢話罷了。螢幕閱讀器會直接告訴使用者哪邊有連結;而具有視力的讀者可以直接看出連結,因為連結通常使用不同的顏色,並且設有底線 (一般不會打破這項慣例,因為大家都已經習以為常了),所以也不用多提。</li>
+ <li>讓你的連結越短越好 — 太長的連結會使螢幕閱讀器的使用者蒙受其害,因為他們必須從頭聽到尾。</li>
+ <li>盡量讓連結的文字不一樣,太多重複的連結文字會帶給螢幕閱讀器的使用者麻煩,因為他們可能會從一個連結表中選擇連結,因此若有許多重複的「點這裡」會讓他們相當困惑。</li>
+</ul>
+
+<h3 id="盡可能使用相對連結">盡可能使用相對連結</h3>
+
+<p>經過之前的說明,你可能會覺得無論如何都應該採用絕對連結,畢竟它們不會像相對連結一樣,因為頁面被搬移而失效。然而,對於相同網站內的連結,你應該盡量使用相對連結 (連到別的網站的連結必須使用絕對連結),原因如下:</p>
+
+<ul>
+ <li>首先,由於相對 URL 通常比絕對 URL 來得短,因此使用它可以增進原始碼的可讀性。</li>
+ <li>第二,使用相對 URL 比較有效率。當你使用絕對 URL 時,瀏覽器會先查看 server 在域名系統({{glossary("DNS")}},詳情請見<a href="/en-US/docs/Learn/Getting_started_with_the_web/How_the_Web_works">網路是如何運作的</a>) 上的真實位址,並再從那個位址開始尋找請求的檔案;如果我們使用相對 URL,瀏覽器就可以直接從那個 server 開始搜尋。因此,如果你在可以使用相對 URL 時而去使用絕對 URL,就會迫使你的瀏覽器不斷地進行額外的工作,進而降低效能。</li>
+</ul>
+
+<h3 id="要連到非_HTML_的資源時請先聲明">要連到非 HTML 的資源時請先聲明</h3>
+
+<p>當連結連至一個需要下載的資源 (像是 PDF 或 Word 文件) 或是串流 (如影音串流) 或是其他有潛在未知影響的東西 (開啟彈出式視窗或者載入 Flash movie) 時,你應該要加上一些文字來預示,以下就是幾個非常惱人的情境:</p>
+
+<ul>
+ <li>假設你正處於低頻寬的連線,點擊連結之後,卻開始下載好幾 MB 的東西。</li>
+ <li>假設你沒有安裝 Flash player,點擊連結之後,卻進到一個需要 Flash 的頁面。</li>
+</ul>
+
+<p>讓我們來看一些可以改善這些情況的方法:</p>
+
+<pre class="brush: html">&lt;p&gt;&lt;a href="http://www.example.com/large-report.pdf"&gt;
+ 下載銷售報告(PDF, 10MB)
+&lt;/a&gt;&lt;/p&gt;
+
+&lt;p&gt;&lt;a href="http://www.example.com/video-stream/" target="_blank"&gt;
+ 觀看影片(將在新分頁開啟串流,HD 畫質)
+&lt;/a&gt;&lt;/p&gt;
+
+&lt;p&gt;&lt;a href="http://www.example.com/car-game"&gt;
+ 遊玩賽車遊戲(需要 Flash)
+&lt;/a&gt;&lt;/p&gt;</pre>
+
+<h3 id="當連結會觸發下載時,使用下載屬性">當連結會觸發下載時,使用下載屬性</h3>
+
+<p>當你連結一個需要下載的資源時,你可以使用 <code>download</code> 屬性來提供一個預設的儲存檔名。以下範例是最新版的 Windows 版 Firefox 的下載連結:</p>
+
+<pre class="brush: html">&lt;a href="https://download.mozilla.org/?product=firefox-latest-ssl&amp;os=win64&amp;lang=en-US"
+ download="firefox-latest-64bit-installer.exe"&gt;
+ 下載Windows上的最新版Firefox (64-bit) (English, US)
+&lt;/a&gt;</pre>
+
+<h2 id="不要只用看的:建立一個導覽選單">不要只用看的:建立一個導覽選單</h2>
+
+<p>在這次練習中,我們想要你利用導覽列來將許多網頁連結在一起,創造出一個具有多個頁面的網站。這是一個很常見的網站建造方式 — 每一個網頁都使用同樣的網頁結構,其中包含相同的導覽選單,這樣子一來,當連結被點擊時,會讓人以為還留在原地,但內容卻倏忽更迭。</p>
+
+<p>你需要先在一個目錄中建立下面這四個網頁的複本 (你可以在 <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-start">navigation-menu-start</a> 目錄下找到完整的清單):</p>
+
+<ul>
+ <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/index.html">index.html</a></li>
+ <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/projects.html">projects.html</a></li>
+ <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/pictures.html">pictures.html</a></li>
+ <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/social.html">social.html</a></li>
+</ul>
+
+<p>接著,你可以這麼做:</p>
+
+<ol>
+ <li>在指定的地方添加一個無序列表,裡面放著可以連到的網頁名稱。因為導覽選單其實就是一個連結的列表,所以這麼做在語義上沒什麼問題。</li>
+ <li>把每一個網頁名稱變成超連結。</li>
+ <li>把導覽選單複製到每一個頁面上。</li>
+ <li>把每個網頁中,連到自己的連結移除,因為這種連結毫無意義且令人困惑,此外,無連結的文字可以用來提示使用者的所在位置。</li>
+</ol>
+
+<p>完成後的範例應該會長這樣:</p>
+
+<p><img alt="An example of a simple HTML navigation menu, with home, pictures, projects, and social menu items" src="https://mdn.mozillademos.org/files/12411/navigation-example.png" style="display: block; margin: 0 auto;"></p>
+
+<div class="note">
+<p><strong>Note</strong>: 如果你卡住了,或者不確定有沒有做對,你可以到 <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-marked-up">navigation-menu-marked-up</a> 目錄來偷瞄答案。</p>
+</div>
+
+<h2 id="E-mail_連結">E-mail 連結</h2>
+
+<p>你可以建立一個連結或按鈕,使得它被點擊之後,開啟一個正在撰寫中的電子郵件訊息。這可以透過 {{HTMLElement("a")}} 元素和 <code>mailto:</code> URL scheme 來達成。</p>
+
+<p>多數情況 <code>mailto:</code> 會填入收信人的電子郵件地址。例如:</p>
+
+<pre class="brush: html">&lt;a href="mailto:nowhere@mozilla.org"&gt;Send email to nowhere&lt;/a&gt;
+</pre>
+
+<p>它的結果會像是這樣:<a href="mailto:nowhere@mozilla.org">Send email to nowhere</a>。</p>
+
+<p>事實上,電子郵件地址是選填的。如果你將它留空 (也就是說,你的 {{htmlattrxref("href", "a")}} 只寫了 "mailto:"),使用者的 mail client 會開啟一個寄信視窗,其中並沒有指定收信人,這在使用「分享」連結時非常有用,使用者可以自行決定要寄給誰。</p>
+
+<h3 id="指定細節">指定細節</h3>
+
+<p>除了電子郵件地址之外,你還可以提供其他資訊,事實上,任何標準的郵件標頭欄位都能被加到  <code>mailto</code> URL 中,常見的有主旨(subject)、副本(cc)以及主體(body) (這個雖然不是真的標頭欄位,但能讓你放一條簡短的訊息在新郵件的主體中)。每個欄位與它的值被定義成一組查詢項(query term)。</p>
+
+<p>下面是一個包含 cc、bcc(密件副本)、subject 和 body 的範例:</p>
+
+<pre class="brush: html">&lt;a href="mailto:nowhere@mozilla.org?cc=name2@rapidtables.com&amp;bcc=name3@rapidtables.com&amp;subject=The%20subject%20of%20the%20email&amp;body=The%20body%20of%20the%20email"&gt;
+ Send mail with cc, bcc, subject and body
+&lt;/a&gt;</pre>
+
+<div class="note">
+<p><strong>Note:</strong> 每一個欄位的值必須以 URL 編碼,也就是將空白及不可印字元(不可見的字元如縮排(tabs)、回車<span lang="en">(carriage return</span>)、換頁(page breaks)等等)轉換成<a href="http://en.wikipedia.org/wiki/Percent-encoding">百分號編碼</a>。也請注意這裡使用問號(<code>?</code>)來分隔主要 URL 和其他欄位;以 &amp; 來分隔 <code>mailto:</code> URL 中的不同的欄位,這是標準的 URL 查詢記號(query notation)。你可以閱讀 <a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data#The_GET_method">GET 方法</a>來得知有那些常用的查詢記號。</p>
+</div>
+
+<p>以下是 <code>mailto</code> URL 的其他例子:</p>
+
+<ul>
+ <li><a href="mailto:">mailto:</a></li>
+ <li><a href="mailto:nowhere@mozilla.org">mailto:nowhere@mozilla.org</a></li>
+ <li><a href="mailto:nowhere@mozilla.org,nobody@mozilla.org">mailto:nowhere@mozilla.org,nobody@mozilla.org</a></li>
+ <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org</a></li>
+ <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&amp;subject=This%20is%20the%20subject">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&amp;subject=This%20is%20the%20subject</a></li>
+</ul>
+
+<h2 id="小試身手!">小試身手!</h2>
+
+<p>你已經讀完這個章節囉,但你有掌握箇中的重點嗎?你可以在繼續閱讀後面的章節之前,先進行一些測驗 — 請前往<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Test_your_skills:_Links">小試身手:超連結。</a></p>
+
+<h2 id="總結">總結</h2>
+
+<p>總而言之,以上就是超連結的介紹了! 稍後你在後續的課程中學到如何位連結增添樣式時,還會再碰到它們。HTML 的下一章,我們將繼續討論文字語義(text semantics),並看一些進階/不常見的特性,相信你會獲益良多的 — 下一站是:進階文字格式化技巧!</p>
+
+<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</p>
+
+<h2 id="在本主題中的內容">在本主題中的內容</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html b/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html
new file mode 100644
index 0000000000..2a4a379123
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/document_and_website_structure/index.html
@@ -0,0 +1,283 @@
+---
+title: Document and website structure
+slug: Learn/HTML/Introduction_to_HTML/Document_and_website_structure
+translation_of: Learn/HTML/Introduction_to_HTML/Document_and_website_structure
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">{{glossary("HTML")}} 不僅能夠定義網頁的單獨部分(例如“段落”或“圖片”),還可以使用區塊級元素(例如“標題欄”、“導覽選單”、“主內容列”)來定義網站中的複合區域。本文將探討如何規劃基本的網站結構,並根據規劃的結構來編寫 HTML。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">預備知識:</th>
+ <td>Basic HTML familiarity, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>. HTML text formatting, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a>. How hyperlinks work, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">學習目標:</th>
+ <td>學習使用語義標籤來建立文本,建置簡單的網站結構。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="文本的基本組成">文本的基本組成</h2>
+
+<p>網頁有各式各樣的外觀,但是除了全螢幕影片、遊戲或藝術作品頁面外,都傾向於使用類似的標準元件:</p>
+
+<dl>
+ <dt>頁首:</dt>
+ <dd>通常橫跨於整個頁面頂部有一個大標題。這是網站的主要資訊,通常存在於所有網頁。</dd>
+ <dt>導覽列:</dt>
+ <dd>指向網站各個主要區段的超連結。通常用選單按鈕、連結或頁簽來表示。類似於頁首,導航列通常應在所有網頁之間保持一致,否則會讓用戶感到疑惑,甚至無所適從。許多web 設計人員認為導航列是頁首的一部分,而不是獨立的元件,但這並非絕對;還有人認為,兩者獨立可以提供更好的<a href="/en-US/docs/Learn/Accessibility">無障礙</a>訪問特性,因為螢幕可以更清晰地分辨二者。</dd>
+ <dt>主要內容:</dt>
+ <dd>中心的大部分區域是當前網頁大多數的獨有內容,例如影片、文章、地圖、新聞等。這些內容是網站的一部分,且會因頁面而異。</dd>
+ <dt>側邊攔:</dt>
+ <dd>一些外圍資訊、連結、引用、廣告等。通常與主內容相關(例如一個新聞頁面上,側邊欄可能包含作者資訊或相關文章連結)。</dd>
+ <dt>頁尾:</dt>
+ <dd>橫跨頁面底部的狹長區域。和頁首一樣,頁尾是放置共用資訊(比如版權聲明或聯繫方式)的,一般使用較小字體,且通常為次要內容。還可以通過提供快速訪問連結來進行{{Glossary("SEO")}} 。</dd>
+</dl>
+
+<p>一個“典型的網站”可能會這樣佈局:</p>
+
+<p><img alt="a simple website structure example featuring a main heading, navigation menu, main content, side bar, and footer." src="https://mdn.mozillademos.org/files/12417/sample-website.png" style="display: block; margin: 0 auto;"></p>
+
+<h2 id="用於構造內容的HTML">用於構造內容的HTML</h2>
+
+<p>上面顯示的簡單範例並不美觀,但對於說明典型的網站佈局範例來說是非常好的。 有些網站上有更多欄,有些則複雜得多,但是您知道了。 使用正確的CSS,您幾乎可以使用任何元素來包裹不同的部分,並使其看起來像您想要的樣子,但是如前所述,我們需要遵守語義並將正確的元素用於正確的運行。</p>
+
+<p>這是因為視覺效果並不能說明整個故事。 We use color and font size to draw sighted users' attention to the most useful parts of the content, like the navigation menu and related links, but what about visually impaired people for example, who might not find concepts like "pink" and "large font" very useful?</p>
+
+<div class="note">
+<p><strong>Note</strong>: Colorblind people represent around <a href="http://www.color-blindness.com/2006/04/28/colorblind-population/">4% of the world population</a> or, to put it another way, approximately 1 in every 12 men and 1 in every 200 women are colorblind. Blind and visually impaired people represent roughly 4-5% of the world population (in 2012 there were <a href="https://en.wikipedia.org/wiki/Visual_impairment">285 million such people in the world</a>, while the total population was <a href="https://en.wikipedia.org/wiki/World_human_population#/media/File:World_population_history.svg">around 7 billion</a>).</p>
+</div>
+
+<p>In your HTML code, you can mark up sections of content based on their <em>functionality</em> — you can use elements that represent the sections of content described above unambiguously, and assistive technologies like screenreaders can recognise those elements and help with tasks like "find the main navigation", or "find the main content." As we mentioned earlier in the course, there are a number of <a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Why_do_we_need_structure">consequences of not using the right element structure and semantics for the right job</a>.</p>
+
+<p>To implement such semantic mark up, HTML provides dedicated tags that you can use to represent such sections, for example:</p>
+
+<ul>
+ <li><strong>header: </strong>{{htmlelement("header")}}.</li>
+ <li><strong>navigation bar: </strong>{{htmlelement("nav")}}.</li>
+ <li><strong>main content: </strong>{{htmlelement("main")}}, with various content subsections represented by {{HTMLElement("article")}}, {{htmlelement("section")}}, and {{htmlelement("div")}} elements.</li>
+ <li><strong>sidebar: </strong>{{htmlelement("aside")}}; often placed inside {{htmlelement("main")}}.</li>
+ <li><strong>footer: </strong>{{htmlelement("footer")}}.</li>
+</ul>
+
+<h3 id="Active_learning_exploring_the_code_for_our_example">Active learning: exploring the code for our example</h3>
+
+<p>Our example seen above is represented by the following code (you can also <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/document_and_website_structure/index.html">find the example in our GitHub repository</a>). We'd like you to look at the example above, and then look over the listing below to see what parts make up what section of the visual.</p>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+
+ &lt;title&gt;My page title&lt;/title&gt;
+ &lt;link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Sonsie+One" rel="stylesheet" type="text/css"&gt;
+ &lt;link rel="stylesheet" href="style.css"&gt;
+
+ &lt;!-- the below three lines are a fix to get HTML5 semantic elements working in old versions of Internet Explorer--&gt;
+ &lt;!--[if lt IE 9]&gt;
+ &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"&gt;&lt;/script&gt;
+ &lt;![endif]--&gt;
+ &lt;/head&gt;
+
+ &lt;body&gt;
+ &lt;!-- Here is our main header that is used across all the pages of our website --&gt;
+
+ &lt;header&gt;
+ &lt;h1&gt;Header&lt;/h1&gt;
+ &lt;/header&gt;
+
+ &lt;nav&gt;
+ &lt;ul&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Home&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Our team&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Projects&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Contact&lt;/a&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+
+ &lt;!-- A Search form is another commmon non-linear way to navigate through a website. --&gt;
+
+ &lt;form&gt;
+ &lt;input type="search" name="q" placeholder="Search query"&gt;
+ &lt;input type="submit" value="Go!"&gt;
+ &lt;/form&gt;
+ &lt;/nav&gt;
+
+ &lt;!-- Here is our page's main content --&gt;
+ &lt;main&gt;
+
+ &lt;!-- It contains an article --&gt;
+ &lt;article&gt;
+ &lt;h2&gt;Article heading&lt;/h2&gt;
+
+ &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. Donec a diam lectus. Set sit amet ipsum mauris. Maecenas congue ligula as quam viverra nec consectetur ant hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.&lt;/p&gt;
+
+ &lt;h3&gt;Subsection&lt;/h3&gt;
+
+ &lt;p&gt;Donec ut librero sed accu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor.&lt;/p&gt;
+
+ &lt;p&gt;Pelientesque auctor nisi id magna consequat sagittis. Curabitur dapibus, enim sit amet elit pharetra tincidunt feugiat nist imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros.&lt;/p&gt;
+
+ &lt;h3&gt;Another subsection&lt;/h3&gt;
+
+ &lt;p&gt;Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum soclis natoque penatibus et manis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.&lt;/p&gt;
+
+ &lt;p&gt;Vivamus fermentum semper porta. Nunc diam velit, adipscing ut tristique vitae sagittis vel odio. Maecenas convallis ullamcorper ultricied. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, is fringille sem nunc vet mi.&lt;/p&gt;
+ &lt;/article&gt;
+
+ &lt;!-- the aside content can also be nested within the main content --&gt;
+ &lt;aside&gt;
+ &lt;h2&gt;Related&lt;/h2&gt;
+
+ &lt;ul&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Oh I do like to be beside the seaside&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Oh I do like to be beside the sea&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Although in the North of England&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;It never stops raining&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="#"&gt;Oh well...&lt;/a&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;/aside&gt;
+
+ &lt;/main&gt;
+
+ &lt;!-- And here is our main footer that is used across all the pages of our website --&gt;
+
+ &lt;footer&gt;
+ &lt;p&gt;©Copyright 2050 by nobody. All rights reversed.&lt;/p&gt;
+ &lt;/footer&gt;
+
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>Take some time to look over the code and understand it — the comments inside the code should also help you to understand it. We aren't asking you to do much else in this article, because the key to understanding document layout is writing a sound HTML structure, and then laying it out with CSS. We'll wait for this until you start to study CSS layout as part of the CSS topic.</p>
+
+<h2 id="HTML_layout_elements_in_more_detail">HTML layout elements in more detail</h2>
+
+<p>It's good to understand the overall meaning of all the HTML sectioning elements in detail — this is something you'll work on gradually as you start to get more experience with web development. You can find a lot of detail by reading our <a href="/en-US/docs/Web/HTML/Element">HTML element reference</a>. For now, these are the main definitions that you should try to understand:</p>
+
+<ul>
+ <li>{{HTMLElement('main')}} is for content <em>unique to this page. </em>Use <code>&lt;main&gt;</code> only <em>once </em>per page, and put it directly inside {{HTMLElement('body')}}. Ideally this shouldn't be nested within other elements.</li>
+ <li>{{HTMLElement('article')}} encloses a block of related content that makes sense on its own without the rest of the page (e.g., a single blog post).</li>
+ <li>{{HTMLElement('section')}} is similar to <code>&lt;article&gt;</code>, but it is more for grouping together a single part of the page that constitutes one single piece of functionality (e.g., a mini map, or a set of article headlines and summaries). It's considered best practice to begin each section with a <a href="/en-US/Learn/HTML/Howto/Set_up_a_proper_title_hierarchy">heading</a>; also note that you can break <code>&lt;article&gt;</code>s up into different <code>&lt;section&gt;</code>s, or <code>&lt;section&gt;</code>s up into different <code>&lt;article&gt;</code>s, depending on the context.</li>
+ <li>{{HTMLElement('aside')}} contains content that is not directly related to the main content but can provide additional information indirectly related to it (glossary entries, author biography, related links, etc.).</li>
+ <li>{{HTMLElement('header')}} represents a group of introductory content. If it is a child of {{HTMLElement('body')}} it defines the global header of a webpage, but if it's a child of an {{HTMLElement('article')}} or {{HTMLElement('section')}} it defines a specific header for that section (try not to confuse this with <a href="/en-US/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#Adding_a_title">titles and headings</a>).</li>
+ <li>{{HTMLElement('nav')}} contains the main navigation functionality for the page. Secondary links, etc., would not go in the navigation.</li>
+ <li>{{HTMLElement('footer')}} represents a group of end content for a page.</li>
+</ul>
+
+<h3 id="Non-semantic_wrappers">Non-semantic wrappers</h3>
+
+<p>Sometimes you'll come across a situation where you can't find an ideal semantic element to group some items together or wrap some content. Sometimes you might want to just group a set of elements together to affect them all as a single entity with some {{glossary("CSS")}} or {{glossary("JavaScript")}}. For cases like these, HTML provides the {{HTMLElement("div")}} and {{HTMLElement("span")}} elements. You should use these preferably with a suitable {{htmlattrxref('class')}} attribute, to provide some kind of label for them so they can be easily targeted.</p>
+
+<p>{{HTMLElement("span")}} is an inline non-semantic element, which you should only use if you can't think of a better semantic text element to wrap your content, or don't want to add any specific meaning. For example:</p>
+
+<pre class="brush: html notranslate">&lt;p&gt;The King walked drunkenly back to his room at 01:00, the beer doing nothing to aid
+him as he staggered through the door &lt;span class="editor-note"&gt;[Editor's note: At this point in the
+play, the lights should be down low]&lt;/span&gt;.&lt;/p&gt;</pre>
+
+<p>In this case, the editor's note is supposed to merely provide extra direction for the director of the play; it is not supposed to have extra semantic meaning. For sighted users, CSS would perhaps be used to distance the note slightly from the main text.</p>
+
+<p>{{HTMLElement("div")}} is a block level non-semantic element, which you should only use if you can't think of a better semantic block element to use, or don't want to add any specific meaning. For example, imagine a shopping cart widget that you could choose to pull up at any point during your time on an e-commerce site:</p>
+
+<pre class="brush: html notranslate">&lt;div class="shopping-cart"&gt;
+ &lt;h2&gt;Shopping cart&lt;/h2&gt;
+ &lt;ul&gt;
+ &lt;li&gt;
+ &lt;p&gt;&lt;a href=""&gt;&lt;strong&gt;Silver earrings&lt;/strong&gt;&lt;/a&gt;: $99.95.&lt;/p&gt;
+ &lt;img src="../products/3333-0985/thumb.png" alt="Silver earrings"&gt;
+ &lt;/li&gt;
+ &lt;li&gt;
+ ...
+ &lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;p&gt;Total cost: $237.89&lt;/p&gt;
+&lt;/div&gt;</pre>
+
+<p>This isn't really an <code>&lt;aside&gt;</code>, as it doesn't necessarily relate to the main content of the page (you want it viewable from anywhere). It doesn't even particularly warrant using a  <code>&lt;section&gt;</code>, as it isn't part of the main content of the page. So a <code>&lt;div&gt;</code> is fine in this case. We've included a heading as a signpost to aid screenreader users in finding it.</p>
+
+<div class="warning">
+<p><strong>Warning</strong>: Divs are so convenient to use that it's easy to use them too much. As they carry no semantic value, they just clutter your HTML code. Take care to use them only when there is no better semantic solution and try to reduce their usage to the minimum otherwise you'll have a hard time updating and maintaining your documents.</p>
+</div>
+
+<h3 id="Line_breaks_and_horizontal_rules">Line breaks and horizontal rules</h3>
+
+<p>Two elements that you'll use occasionally and will want to know about are {{htmlelement("br")}} and {{htmlelement("hr")}}:</p>
+
+<p><code>&lt;br&gt;</code> creates a line break in a paragraph; it is the only way to force a rigid structure in a situation where you want a series of fixed short lines, such as in a postal address or a poem. For example:</p>
+
+<div id="line-break-live-sample">
+<pre class="brush: html notranslate">&lt;p&gt;There once was a man named O'Dell&lt;br&gt;
+Who loved to write HTML&lt;br&gt;
+But his structure was bad, his semantics were sad&lt;br&gt;
+and his markup didn't read very well.&lt;/p&gt;</pre>
+</div>
+
+<p>Without the <code>&lt;br&gt;</code> elements, the paragraph would just be rendered in one long line (as we said earlier in the course, <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Whitespace_in_HTML">HTML ignores most whitespace</a>); with <code>&lt;br&gt;</code> elements in the code, the markup renders like this:</p>
+
+<p>{{EmbedLiveSample('line-break-live-sample', '100%', '125px', '', '', 'hide-codepen-jsfiddle')}}</p>
+
+<p><code>&lt;hr&gt;</code> elements create a horizontal rule in the document that denotes a thematic change in the text (such as a change in topic or scene). Visually it just looks like a horizontal line. As an example:</p>
+
+<div id="horizantal-rule-live-sample">
+<pre class="brush: html notranslate">&lt;p&gt;Ron was backed into a corner by the marauding netherbeasts. Scared, but determined to protect his friends, he raised his wand and prepared to do battle, hoping that his distress call had made it through.&lt;/p&gt;
+&lt;hr&gt;
+&lt;p&gt;Meanwhile, Harry was sitting at home, staring at his royalty statement and pondering when the next spin off series would come out, when an enchanted distress letter flew through his window and landed in his lap. He read it hazily and sighed; "better get back to work then", he mused.&lt;/p&gt;</pre>
+</div>
+
+<p>Would render like this:</p>
+
+<p>{{EmbedLiveSample('horizantal-rule-live-sample', '100%', '185px', '', '', 'hide-codepen-jsfiddle')}}</p>
+
+<h2 id="Planning_a_simple_website">Planning a simple website</h2>
+
+<p>Once you've planned out the structure of a simple webpage, the next logical step is to try to work out what content you want to put on a whole website, what pages you need, and how they should be arranged and link to one another for the best possible user experience. This is called {{glossary("Information architecture")}}. In a large, complex website, a lot of planning can go into this process, but for a simple website of a few pages, this can be fairly simple, and fun!</p>
+
+<ol>
+ <li>Bear in mind that you'll have a few elements common to most (if not all) pages — such as the navigation menu, and the footer content. If your site is for a business, for example, it's a good idea to have your contact information available in the footer on each page. Note down what you want to have common to every page.<img alt="the common features of the travel site to go on every page: title and logo, contact, copyright, terms and conditions, language chooser, accessibility policy" src="https://mdn.mozillademos.org/files/12423/common-features.png" style="border-style: solid; border-width: 1px; display: block; height: 375px; margin: 0px auto; width: 600px;"></li>
+ <li>Next, draw a rough sketch of what you might want the structure of each page to look like (it might look like our simple website above). Note what each block is going to be.<img alt="A simple diagram of a sample site structure, with a header, main content area, two optional sidebars, and footer" src="https://mdn.mozillademos.org/files/12429/site-structure.png" style="border-style: solid; border-width: 1px; display: block; height: 232px; margin: 0px auto; width: 600px;"></li>
+ <li>Now, brainstorm all the other (not common to every page) content you want to have on your website — write a big list down.<img alt="A long list of all the features that we could put on our travel site, from searching, to special offers and country-specific info" src="https://mdn.mozillademos.org/files/12425/feature-list.png" style="border-style: solid; border-width: 1px; display: block; height: 1066px; margin: 0px auto; width: 600px;"></li>
+ <li>Next, try to sort all these content items into groups, to give you an idea of what parts might live together on different pages. This is very similar to a technique called {{glossary("Card sorting")}}.<img alt="The items that should appear on a holiday site sorted into 5 categories: Search, Specials, Country-specific info, Search results, and Buy things" src="https://mdn.mozillademos.org/files/12421/card-sorting.png" style="border-style: solid; border-width: 1px; display: block; height: 579px; margin: 0px auto; width: 600px;"></li>
+ <li>Now try to sketch a rough sitemap — have a bubble for each page on your site, and draw lines to show the typical workflow between pages. The homepage will probably be in the center, and link to most if not all of the others; most of the pages in a small site should be available from the main navigation, although there are exceptions. You might also want to include notes about how things might be presented.<img alt="A map of the site showing the homepage, country page, search results, specials page, checkout, and buy page" src="https://mdn.mozillademos.org/files/12427/site-map.png" style="border-style: solid; border-width: 1px; display: block; height: 872px; margin: 0px auto; width: 600px;"></li>
+</ol>
+
+<h3 id="Active_learning_create_your_own_sitemap">Active learning: create your own sitemap</h3>
+
+<p>Try carrying out the above exercise for a website of your own creation. What would you like to make a site about?</p>
+
+<div class="note">
+<p><strong>Note</strong>: Save your work somewhere; you might need it later on.</p>
+</div>
+
+<h2 id="Test_your_skills!">Test your skills!</h2>
+
+<p>You've reached the end of this article, but can you remember the most important information? You can find a detailed assessment that tests these skills at the end of the module; see <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a>. We'd advise going through the next article in the series first and not just skipping to it though!</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>At this point you should have a better idea about how to structure a web page/site. In the last article of this module, we'll study how to debug HTML.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/Guide/HTML/Using_HTML_sections_and_outlines">Using HTML sections and outlines</a>: Advanced guide to HTML5 semantic elements and the HTML5 outline algorithm.</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html b/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html
new file mode 100644
index 0000000000..b68ccd2b73
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/getting_started/index.html
@@ -0,0 +1,626 @@
+---
+title: Getting started with HTML
+slug: Learn/HTML/Introduction_to_HTML/Getting_started
+translation_of: Learn/HTML/Introduction_to_HTML/Getting_started
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">本文將探討 HTML 最基本的部分。首先,我們將會定義元素(elements)、屬性(attributes)以及其它你可能聽過的重要名詞,然後講解該如何使用它們。我們也會告訴你典型的 HTML 頁面以及其中的元素是如何構成的,以及解釋其他重要的基礎語言特性。在此過程中,我們會撰寫一些 HTML 來引發你的興趣!</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">需求:</th>
+ <td>基礎電腦能力、已安裝<a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">需要的基本軟體</a>、並知道如何<a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">操作檔案</a>。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>對 HTML 產生初步認識、並練習如何撰寫 HTML 元素。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是_HTML">什麼是 HTML?</h2>
+
+<p>{{glossary("HTML")}} (Hypertext Markup Language) 並不是一種程式語言,而是用來告訴瀏覽器該如何呈現網頁的<strong>標記式語言(</strong><em><strong>markup language</strong></em><strong>)</strong>。它可以很複雜也可以很陽春,端看網頁開發者如何構思。HTML 由一系列的元素({{glossary("Element", "elements")}})組成,你將利用它們來圍住、包裹,或者說標記(<em>mark up</em>)網頁中的每個部分,使它們在外表或行為上呈現某種特定風貌。被標籤({{glossary("Tag", "tags")}})包住的內容會變成超連結,或者斜體字,以及諸如此類的功能,舉例來說,請看下列內容:  </p>
+
+<pre>My cat is very grumpy</pre>
+
+<p>如果我們想要讓這行字獨立出來,不讓它跟其他東西排在一起,我們可以用段落標籤( paragraph tag {{htmlelement("p")}})讓它自成段落:</p>
+
+<pre class="brush: html">&lt;p&gt;My cat is very grumpy&lt;/p&gt;
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>:<br>
+ HTML 中的元素是不區分大小寫的<em>。</em><br>
+ 例如 : 一個 {{htmlelement("title")}} 標籤可以寫成<code>&lt;title&gt;</code>, <code>&lt;TITLE&gt;</code>, <code>&lt;Title&gt;</code>, <code>&lt;TiTlE&gt;</code>,之類的形式,都沒有問題<em>。</em><br>
+ 通常來說,為了保持一致性(consistency)、可讀性(readability),以及其他可能的原因,最好還是以小寫來撰寫標籤<em>。</em></p>
+</div>
+
+<h2 id="分析_HTML_元素">分析 HTML 元素</h2>
+
+<p>讓我們更深入地探索段落中的元素:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/9347/grumpy-cat-small.png" style="display: block; height: 255px; margin: 0px auto; width: 821px;"></p>
+
+<p>元素中主要的內容有: </p>
+
+<ol>
+ <li><strong>起始標籤(opening tag):</strong>它包含了元素的名字(在這裡是 p),夾在一對 <strong>&lt;、&gt; (angle brackets)</strong>之間。它指明元素從何開始生效 — 在上例中則代表段落的開始。</li>
+ <li><strong>結束標籤(closing tag):</strong>結束標籤和起始標籤長得差不多,只不過它在名字前面還多加了一條斜線 (forward slash) 。它表示元素結束的地方 — 在上例中表示該段落的結束。忘記加上結束標籤是初學者常犯的錯誤,這將導致奇怪的結果。</li>
+ <li><strong>內容(content):</strong> 元素的內容。在上例中就是一段文字。</li>
+ <li><strong>元素(element):</strong> 以上三者加起來就是元素。</li>
+</ol>
+
+<h3 id="不要光是看_創造你的第一個_HTML_元素">不要光是看: 創造你的第一個 HTML 元素</h3>
+
+<p>編輯下面輸入區域中的文字,嘗試用 <code>&lt;em&gt;</code> 和 <code>&lt;/em&gt;</code> 標籤包裹住文字(把 <code>&lt;em&gt;</code> 放在文字前面來起始元素,把 <code>&lt;/em&gt;</code> 放在後面來結束元素) ,這會使得文字變成斜體字。你可以在下面的輸出區域看到更新後的變化。</p>
+
+<p>如果你不小心打錯了,你可以按下 <em>Reset</em> 鍵來重置。如果你卡關了,你可以點擊 <em>Show solution</em> 鍵來偷看答案。</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="min-height: 100px;width: 95%"&gt;
+ This is my text.
+&lt;/textarea&gt;
+
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">html {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;em&gt;This is my text.&lt;/em&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="巢狀元素Nesting_elements">巢狀元素(Nesting elements)</h3>
+
+<p>你可以把元素放進另一個元素裡面 — 這叫做<strong>巢套(nesting)</strong>。比如說,我們想要強調我們的貓咪<strong>非常</strong>兇,我們可以用{{htmlelement("strong")}}元素來包住 "very" 這個字,這樣就可以標註我們想要強調的字:</p>
+
+<pre class="brush: html">&lt;p&gt;My cat is &lt;strong&gt;very&lt;/strong&gt; grumpy.&lt;/p&gt;</pre>
+
+<p>你必須確保你的元素正確地巢套:在上述範例中,我們先用了 <code>p</code> 元素,然後才用 <code>strong</code> 元素,因此我們必須先關閉 <code>strong</code> 元素,再關閉 <code>p</code> 元素。下面是錯誤示範:</p>
+
+<pre class="example-bad brush: html">&lt;p&gt;My cat is &lt;strong&gt;very grumpy.&lt;/p&gt;&lt;/strong&gt;</pre>
+
+<p>這些元素必須要正確地開啟與關閉,它們與其他元素的內外關係要相當明確。如果它們像上例這樣交互重疊,你的網頁瀏覽器將無法解讀,只能盡可能地猜測你的意思,因此你很有可能會得到一個不如預期的結果。所以,別這樣做!!</p>
+
+<h3 id="區塊級元素_vs._行內元素Block_versus_inline_elements">區塊級元素 vs. 行內元素(Block versus inline elements)</h3>
+
+<p>在 HTML 中有兩種你應該要知道的重要元素類別 — 區塊級元素(block-level elements)和行內元素(inline elements)。</p>
+
+<ul>
+ <li>區塊級元素在頁面中組成一個可見區塊 — 它在頁面中單獨佔據一行,在它前後的內容都將以一個換行分隔。區塊級元素傾向於作為頁面上的結構化元素(structural elements),舉凡段落、列表、導航選單(navigation menus)、頁尾(footers)等等皆是。區塊級元素不會巢套在行內元素中,但有可能會巢套其他區塊級元素中。 </li>
+ <li>行內元素指的是放在區塊級元素之中的內容,這些元素只由文件內容的一小部分組成,而非由完整段落或群組式內容組成。一個行內元素不會在文件中產生新的一行,它們通常只會出現在一段文字中,舉例來說,{{htmlelement("a")}} 元素(超連結),或者強調元素如 {{htmlelement("em")}} 和 {{htmlelement("strong")}}。</li>
+</ul>
+
+<p>以下面這個例子來說:</p>
+
+<pre class="brush: html">&lt;em&gt;first&lt;/em&gt;&lt;em&gt;second&lt;/em&gt;&lt;em&gt;third&lt;/em&gt;
+
+&lt;p&gt;fourth&lt;/p&gt;&lt;p&gt;fifth&lt;/p&gt;&lt;p&gt;sixth&lt;/p&gt;
+</pre>
+
+<p>{{htmlelement("em")}} 是一個行內元素,所以你可以看到下面的例子中,前三個元素互相緊鄰在同一行,兩兩中間並無任何空白。另一方面,{{htmlelement("p")}} 是一個區塊級元素,所以每個元素都自成一行,並且上下都有一些空間。(這些空間是由於瀏覽器套用預設的<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS styling</a>到這些段落上的緣故)。</p>
+
+<p>{{ EmbedLiveSample('區塊級元素_vs._行內元素Block_versus_inline_elements', 700, 200, "", "") }}</p>
+
+<div class="note">
+<p><strong>Note</strong>: HTML5 重新定義了元素類別:請見 <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/section-index.html#element-content-categories">Element content categories</a>。新的定義比先前所定義的更為準確且少歧義性,因此它們也同時比 block 和 inline 還來得複雜,所以我們選擇在這裡繼續使用這個觀念。</p>
+</div>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 在本主題所使用的 block 與 inline 這兩個名詞,不應與 CSS 的 boxes 種類混淆。它們在預設時是很像的,但改變 CSS 的顯示型態(display type)並不會改變元素的類別,也不會影響該元素能包含或被包含的元素類別。HTML5 之所以會重新定義元素類別,部分也是基於此一原因。</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: 你可以查看 block element 與 inline element 分別有哪些元素 — 請見 <a href="/en-US/docs/Web/HTML/Block-level_elements">Block-l</a><a href="/en-US/docs/Web/HTML/Block-level_elements">evel elements</a> 和 <a href="/en-US/docs/Web/HTML/Inline_elements">Inline elements</a>。</p>
+</div>
+
+<h3 id="空元素Empty_elements">空元素(Empty elements)</h3>
+
+<p>不是所有元素都符合起始標籤、內容、結束標籤的格式。有些元素只有一個標籤,這些標籤通常用來在文件中插入/嵌入物件。例如 {{htmlelement("img")}} 元素便是用來在當前位置嵌入圖片檔:</p>
+
+<pre class="brush: html">&lt;img src="https://raw.githubusercontent.com/mdn/beginner-html-site/gh-pages/images/firefox-icon.png"&gt;</pre>
+
+<p>這將會產生下面的結果:</p>
+
+<p>{{ EmbedLiveSample('空元素Empty_elements', 700, 300, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<div class="note">
+<p><strong>Note</strong>: 空元素有時也被稱作 <em>void elements。</em></p>
+</div>
+
+<h2 id="屬性Attributes">屬性(Attributes)</h2>
+
+<p>你也可以在元素中加入屬性,像是:</p>
+
+<p><img alt='&amp;lt;p class="editor-note">My cat is very grumpy&amp;lt;/p>' src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p>
+
+<p>屬性有著關於元素的額外資訊,但你並不會想要顯示它們。在這個例子中 <code>class</code> 屬性讓你能夠賦予一個元素辨別名稱,稍後就能用這個名稱來指定元素的樣式及其他的東西。</p>
+
+<p>一個屬性應該要有:</p>
+
+<ol>
+ <li>一個空白,用來隔開屬性和元素名稱(或者前一個屬性,如果該元素已經有一個以上的屬性的話)。</li>
+ <li>屬性名稱以及一個接在其後的等號。</li>
+ <li>屬性值以及一對包著它的引號。</li>
+</ol>
+
+<h3 id="主動學習_在元素中加入屬性">主動學習: 在元素中加入屬性</h3>
+
+<p>我們再舉另外一個元素的例子 {{htmlelement("a")}} 代表 anchor (錨),而這個元素會讓被它包裹住的內容變成一個超連結。它可以和很多種屬性搭配,以下僅列出幾種:</p>
+
+<ul>
+ <li><strong><code>href</code></strong>: 這個屬性的值為你想要連到的網址,當連結被點擊時,瀏覽器就會導向到該網站。例如: <code>href="https://www.mozilla.org/"</code>。</li>
+ <li><strong><code>title</code></strong>: <code>title</code> 屬性用來附加有關連結的其他資訊,像是連結到的網站名稱。例如: <code>title="The Mozilla homepage"</code> 。當游標移動到連結上時,就會以提示的方式顯示。</li>
+ <li><strong><code>target</code></strong>: <code>target</code> 屬性用來指定要在哪裡打開網頁。例如: <code>target="_blank"</code> 會開啟新分頁。如果你想要在目前的分頁開啟網站,只要忽略這個屬性即可。</li>
+</ul>
+
+<p>請編輯下面輸入區的文字,使它變成一個通往你最喜歡的網站的連結。</p>
+
+<ol>
+ <li>首先,加入<code>&lt;a&gt;</code> 元素。</li>
+ <li>再來,加入 <code>href</code> 屬性以及 <code>title</code> 屬性。</li>
+ <li>最後,將 <code>target</code> 屬性設定為在新分頁中開啟。</li>
+</ol>
+
+<p>你將會在底下的輸出區域裡面即時地看到你改動產生的變化。當你完成後,你應該會看到一個連結;當你滑過時,連結將顯示 <code>title</code> 屬性的內容;當你點擊連結時,將會導向到 <code>href</code> 元素中的網址。切記,你需要以空白隔開元素名字以及每一個屬性。 </p>
+
+<p>如果你不小心打錯了,你可以按下<em> Reset </em>鍵重置。如果你卡關了,可以點擊<em> Show solution</em> 鍵來偷看答案。</p>
+
+<div class="hidden">
+<h6 id="Playable_code2">Playable code2</h6>
+
+<pre class="brush: html">&lt;h2&gt;Input&lt;/h2&gt;
+&lt;textarea id="code" class="input"&gt;&amp;lt;p&amp;gt;A link to my favourite website.&amp;lt;/p&amp;gt;&lt;/textarea&gt;
+&lt;h2&gt;Output&lt;/h2&gt;
+&lt;div class="output"&gt;&lt;/div&gt;
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">body {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+.input, .output {
+ width: 90%;
+ height: 2em;
+ padding: 10px;
+ border: 1px solid #0095dd;
+}
+
+button {
+ padding: 10px 10px 10px 0;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var code = textarea.value;
+var output = document.querySelector(".output");
+var solution = document.getElementById("solution");
+
+function drawOutput() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener("click", function() {
+ textarea.value = code;
+ drawOutput();
+});
+
+solution.addEventListener("click", function() {
+ textarea.value = '&lt;p&gt;A link to my &lt;a href="<code>https://www.mozilla.org/</code>" title="The Mozilla homepage" target="_blank"&gt;favourite website&lt;/a&gt;.&lt;/p&gt;';
+ drawOutput();
+});
+
+textarea.addEventListener("input", drawOutput);
+window.addEventListener("load", drawOutput);
+</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code2', 700, 300) }}</p>
+
+<h3 id="布林屬性Boolean_attributes">布林屬性(Boolean attributes)</h3>
+
+<p>你有時會看到一些沒有值的屬性,這完全是可行的。它們叫做布林屬性,他們只能附帶一個值,而這個值一般來說會和屬性的名字一樣。以 {{htmlattrxref("disabled", "input")}} 屬性來說,你可以把它指派為 input 元素的屬性,使得輸入文字的框框變得不能輸入文字。</p>
+
+<pre>&lt;input type="text" disabled="disabled"&gt;</pre>
+
+<p>你可以把它寫得更簡短(在下面的例子中,我們也寫出了沒有 disabled 屬性的 input 元素供你參考,讓你更了解兩者的差別):</p>
+
+<pre class="brush: html">&lt;input type="text" disabled&gt;
+
+&lt;input type="text"&gt;
+</pre>
+
+<p>結果 :</p>
+
+<p>{{ EmbedLiveSample('布林屬性Boolean_attributes' , 700, 100, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="忘記加屬性值的引號">忘記加屬性值的引號</h3>
+
+<p>當你看遍全世界的網頁,你就會發現各種千奇百怪的標記風格(markup style),包括沒加引號的屬性值。這在某些情況是被允許的,但在其他情況下則會使屬性結果不如預期。沿用我們之前的例子,我們先只用 <code>href</code> 屬性,如下:</p>
+
+<pre>&lt;a href=<code>https://www.mozilla.org/</code>&gt;favourite website&lt;/a&gt;</pre>
+
+<p>看起來沒甚麼問題,但是,一旦我們加上 <code>title</code> 屬性時,就會造成錯誤的結果: </p>
+
+<pre class="brush: html">&lt;a href=<code>https://www.mozilla.org/</code> title=The Mozilla homepage&gt;favourite website&lt;/a&gt;</pre>
+
+<p>此時瀏覽器會誤解你的標記,認為 <code>title</code> 屬性其實是三個屬性:一個值為 "The" 的標題屬性,以及兩個布林屬性 <code>Mozilla</code> 和 <code>homepage</code>。這絕對不是你想要的結果,而且會導致錯誤或者意想不到的行為。你可以看看下面的示範,把你的游標移到連結上,看看會出現什麼提示!</p>
+
+<p>{{ EmbedLiveSample('忘記加屬性值的引號', 700, 100) }}</p>
+
+<p>我們建議不管怎樣都要加屬性引號,避免這些錯誤,同時增加原始碼的可讀性。</p>
+
+<h3 id="要用單引號還是雙引號_Single_or_double_quotes">要用單引號還是雙引號? (Single or double quotes?)</h3>
+
+<p>在這個章節中,你會發現所有的屬性都是使用雙引號,而你可能會發現其他人的 HTML 中使用的是單引號。這純粹是個人風格,你可以依照你個人的喜好去使用它們。下面兩行的意思是相同的:</p>
+
+<pre class="brush: html">&lt;a href="http://www.example.com"&gt;A link to my example.&lt;/a&gt;
+
+&lt;a href='http://www.example.com'&gt;A link to my example.&lt;/a&gt;</pre>
+
+<p>但是,你應該確認你沒有混著使用它們。下面這行則會造成錯誤!</p>
+
+<pre class="brush: html">&lt;a href="http://www.example.com'&gt;A link to my example.&lt;/a&gt;</pre>
+
+<p>如果你在你的 HTML 中使用其中一種引號,你就可以包裹另外一種引號:</p>
+
+<pre class="brush: html">&lt;a href="http://www.example.com" title="Isn't this fun?"&gt;A link to my example.&lt;/a&gt;</pre>
+
+<p>不過,如果你想要包裹相同種類的引號,你就必須要用到 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#Entity_references_including_special_characters_in_HTML">HTML entities</a>。例如,以下範例是錯的:</p>
+
+<pre class="brush: html"> &lt;a href='http://www.example.com' title='Isn't this fun?'&gt;A link to my example.&lt;/a&gt; </pre>
+
+<p>你應該要這樣寫:</p>
+
+<pre class="brush: html">&lt;a href='http://www.example.com' title='Isn&amp;#39;t this fun?'&gt;A link to my example.&lt;/a&gt; </pre>
+
+<h2 id="解析_HTML_文檔">解析 HTML 文檔</h2>
+
+<p>以上講述了 HTML 中個別元素的基礎知識,但是單獨使用它們,並沒有多大用處。所以現在就讓我們來看看如何將這些元素組成一個 HTML 網頁吧:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;My test page&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;p&gt;This is my page&lt;/p&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>這裡有:</p>
+
+<ol>
+ <li><code>&lt;!DOCTYPE html&gt;</code>: 文件類型(doctype)。 在很久很久以前,當 HTML 還年輕的時候(約莫在西元 1991 年左右),文件類型是要作為一系列規範的連結,HTML 網頁必須要遵守這些規範才會被當作是好的 HTML,比如說具備自動錯誤檢查和其他有用的東西等。在那個時候,它們看起來像這樣:
+
+ <pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;</pre>
+ 不過,現在已經沒有人在乎它們了,它們只是個歷史痕跡,需要形式上地被引入,以確保一切正常。<code>&lt;!DOCTYPE html&gt;</code> 是字數最短的有效 doctype。你只需要知道這些就夠了。</li>
+ <li><code>&lt;html&gt;&lt;/html&gt;</code>: {{htmlelement("html")}} 元素。該元素包裹住頁面的所有內容,有時也被稱作根元素(root element)。</li>
+ <li><code>&lt;head&gt;&lt;/head&gt;</code>: {{htmlelement("head")}} 元素。這個元素放著你想含括的所有重要資訊,這些資訊不會呈現在網頁瀏覽者眼前。這些東西包括,顯示於搜尋結果的關鍵字、頁面說明、CSS 等等。你將會在這個系列的下個章節中學到更多有關這部分的知識。</li>
+ <li><code>&lt;meta charset="utf-8"&gt;</code>: 這個元素指定你的文件使用 UTF-8 為字元編碼,這種編碼含有這世上大部分語言的字元,理論上可以處理所有你想放文字內容,因此建議大家都要使用這種編碼,它能幫你免去許多煩惱。</li>
+ <li><code>&lt;title&gt;&lt;/title&gt;</code>: {{htmlelement("title")}} 元素。這是用來設定網頁名稱的,它會顯示在分頁標籤上,當你將該網頁加入書籤或加入最愛時,則是用來形容這個網站。</li>
+ <li><code>&lt;body&gt;&lt;/body&gt;</code>: {{htmlelement("body")}} 元素含括了<em>所有</em>你想要給網頁瀏覽者看到的內容,不管是文字、圖片、遊戲、可以播放的音樂或其他東西。</li>
+</ol>
+
+<h3 id="主動學習_在HTML文檔中加入一些特徵">主動學習: 在HTML文檔中加入一些特徵</h3>
+
+<p>如果你想試試看在你的電腦上寫一些 HTML,你可以: </p>
+
+<ol>
+ <li>複製上面的 HTML 範例。</li>
+ <li>在你的文字編輯器中建立一個新檔案。</li>
+ <li>將剛複製的 HTML 範例貼到新開的檔案裡。</li>
+ <li>將檔案儲存為 <code>index.html</code>。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 你也可以在這找到基本的 HTML 範本: <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">MDN Learning Area Github repo</a>。</p>
+</div>
+
+<p>接著你就可以用網頁瀏覽器開啟你的檔案,看看這些原始碼會被渲染(rendered)成什麼樣子,然後編輯原始碼並重新整理瀏覽器,再看看會變成怎樣。目前你的網頁會長這樣:</p>
+
+<p><img alt="A simple HTML page that says This is my page" src="https://mdn.mozillademos.org/files/12279/template-screenshot.png" style="display: block; height: 365px; margin: 0px auto; width: 595px;">在這個練習中,你可以在自己的電腦中撰寫原始碼,就像上面寫的一樣,或者你可以在底下的範例視窗中進行編輯(該視窗僅表示 {{htmlelement("body")}} 元素的內容) 我們希望你依照以下的步驟逐步前行:</p>
+
+<ul>
+ <li>在 {{htmlelement("body")}} 之後,加入這個文件的主要標題。這應該由一個 <code>&lt;h1&gt;</code> 以及一個 <code>&lt;/h1&gt;</code> 包著。</li>
+ <li>撰寫段落的內容,這些內容可以是一些你感興趣的事物。</li>
+ <li>讓其中重要的字詞以粗體顯示,讓它們更加搶眼,你可以用一個 <code>&lt;strong&gt;</code> 以及一個 <code>&lt;/strong&gt;</code> 包著它們來達成這件事情。</li>
+ <li>加入一個連結到你的文章段落中,像<a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Active_learning_Adding_attributes_to_an_element">前面所講過的那樣</a>。</li>
+ <li>在這段文字的下面加入一張圖片,<a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Empty_elements">像前面所說的那樣</a>。如果你可以使用不同的圖片(你電腦裡的或網路上的都可以),你就能獲得加分!!</li>
+</ul>
+
+<p>如果你不小心打錯了,你可以用<em> Reset</em> 鍵重置。如果你卡關了,可以點擊<em> Show solution</em> 鍵來偷看答案。</p>
+
+<div class="hidden">
+<h6 id="Playable_code3">Playable code3</h6>
+
+<pre class="brush: html">&lt;h2&gt;Input&lt;/h2&gt;
+&lt;textarea id="code" class="input"&gt;
+&amp;lt;p&amp;gt;This is my page&amp;lt;/p&amp;gt;&lt;/textarea&gt;
+&lt;h2&gt;Output&lt;/h2&gt;
+&lt;div class="output"&gt;&lt;/div&gt;
+&lt;div class="controls"&gt;
+  &lt;input id="reset" type="button" value="Reset" /&gt;
+ &lt;input id="solution" type="button" value="Show solution" /&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">body {
+ font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;
+}
+
+.input, .output {
+ width: 90%;
+ height: 10em;
+ padding: 10px;
+ border: 1px solid #0095dd;
+}
+
+img {
+ max-width: 100%;
+}
+
+.output {
+ overflow: auto;
+}
+
+button {
+ padding: 10px 10px 10px 0;
+}
+</pre>
+
+<pre class="brush: js">var textarea = document.getElementById("code");
+var reset = document.getElementById("reset");
+var code = textarea.value;
+var output = document.querySelector(".output");
+var solution = document.getElementById("solution");
+
+function drawOutput() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener("click", function() {
+ textarea.value = code;
+ drawOutput();
+});
+
+solution.addEventListener("click", function() {
+ textarea.value = '&lt;p&gt;I really enjoy &lt;strong&gt;playing the drums&lt;/strong&gt;. One of my favourite drummers is Neal Peart, who\
+ plays in the band &lt;a href="https://en.wikipedia.org/wiki/Rush_%28band%29" title="Rush Wikipedia article"&gt;Rush&lt;/a&gt;.\
+ My favourite Rush album is currently &lt;a href="http://www.deezer.com/album/942295"&gt;Moving Pictures&lt;/a&gt;.&lt;/p&gt;\
+&lt;img src="http://www.cygnus-x1.net/links/rush/images/albums/sectors/sector2-movingpictures-cover-s.jpg"&gt;';
+ drawOutput();
+});
+
+textarea.addEventListener("input", drawOutput);
+window.addEventListener("load", drawOutput);
+</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code3', 700, 600) }}</p>
+
+<h3 id="HTML中的空格Whitespace">HTML中的空格(Whitespace)</h3>
+
+<p>在上面的範例中,你可能會發現原始碼中有許多空格,其實這是完全不需要的,下面兩段原始碼會有相同的結果: </p>
+
+<pre class="brush: html">&lt;p&gt;Dogs are silly.&lt;/p&gt;
+
+&lt;p&gt;Dogs are
+ silly.&lt;/p&gt;</pre>
+
+<p>不管你用多少空格(whitespace,包括空白字元與換行字元),HTML 的語法分析器都只會留下一個空格。所以說,為什麼要用這麼多空格呢?答案是為了增加可讀性 — 適當的排版會讓人更明白你的原始碼,所以千萬不要把你的原始碼擠成一團,讓它們變得雜亂無章。在我們的 HTML 中,我們將每個巢狀的元素都以兩個空格縮排。原始碼的排版風格(如要用多少空格進行縮排),可依照個人喜好使用,但你的排版方式應該要一致。</p>
+
+<h2 id="實體參照Entity_references_引用_HTML_中的特殊字元">實體參照(Entity references): 引用 HTML 中的特殊字元</h2>
+
+<p>在 HTML 中, <code>&lt;</code> 、 <code>&gt;</code> 、 <code>"</code> 、 <code>'</code> 和 <code>&amp;</code> 是特殊字元,它們是 HTML 語法的一部份。那麼,要如何使用這些特殊字元呢?比方說,你如果想要用 <code>&amp;</code> (ampersand)或小於符號  <code>&lt;</code> (less than sign) 時,要如何避免它們被瀏覽器當成原始碼呢?</p>
+
+<p>這時候我們就需要用到字元參照(character references),它們是用來表示特殊字元的編碼,專門用在這種情形上。每個字元參照都是以 &amp; (ampersand) 起頭,以分號 ; (semi-colon) 做結。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">字元</th>
+ <th scope="col">相應的字元引用</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>&lt;</td>
+ <td>&amp;lt;</td>
+ </tr>
+ <tr>
+ <td>&gt;</td>
+ <td>&amp;gt;</td>
+ </tr>
+ <tr>
+ <td>"</td>
+ <td>&amp;quot;</td>
+ </tr>
+ <tr>
+ <td>'</td>
+ <td>&amp;apos;</td>
+ </tr>
+ <tr>
+ <td>&amp;</td>
+ <td>&amp;amp;</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>如果你英文不錯的話,應該不難發現字元參照其實就是這些字元的英文縮寫,也就是說,"&amp;lt;" 為 less than (小於);"&amp;gt;" 為 great than (大於);"&amp;quot;" 為 quotation (引號);"&amp;apos;" 為 apostrophe (單引號);"&amp;amp;" 為 ampersand (和號)。你可以透過下面的維基連結來查看 HTML 的字元實體參照。在下面的範例中,你可以看到兩段敘述網頁技術的段落:</p>
+
+<pre class="brush: html">&lt;p&gt;In HTML, you define a paragraph using the &lt;p&gt; element.&lt;/p&gt;
+
+&lt;p&gt;In HTML, you define a paragraph using the &amp;lt;p&amp;gt; element.&lt;/p&gt;</pre>
+
+<p>看到下面的輸出結果,你會發現第一個段落是錯誤的,因為瀏覽器認為第二個 <code>&lt;p&gt;</code> 是要開啟新段落。而第二個段落就沒問題,因為我們將 &lt; 及 &gt; 換成了字元參照。</p>
+
+<p>{{ EmbedLiveSample('實體參照Entity_references_引用_HTML_中的特殊字元', 700, 200, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<div class="note">
+<p><strong>Note</strong>: 你可以在維基百科中找到完整的 HTML 字元實體參照的對照表: <a class="external text" href="http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references" rel="nofollow">List of XML and HTML character entity references</a>。請記得只要你的 HTML 的<a href="Introduction_to_HTML/The_head_metadata_in_HTML#Specifying_your_document's_character_encoding">字元編碼設定為 UTF-8</a>,你就不需要使用其他字元的實體參照,因為現今的瀏覽器都能應付。</p>
+</div>
+
+<h2 id="HTML_註解">HTML 註解</h2>
+
+<p>HTML 就像大部分的程式語言,提供了一種能讓我們可以在原始碼中加入註解的方式 — 註解是會被瀏覽器忽略,並且不會被使用者看到的,它們存在的目的是要讓你得以在原始碼中說明你的原始碼是如何運作的、每段原始碼的作用等等。當你已經六個月沒有察看某個網頁的原始碼,而你完全想不起來你做了什麼的時候、或是當你把你的原始碼交給別人一同協作時,註解將會是你的好朋友!</p>
+
+<p>試著將你 HTML 檔案中的一部份內容變成註解,你需要將內容包裹在特殊的符號 <code>&lt;!--</code> 和 <code>--&gt;</code>之中,例如:</p>
+
+<pre class="brush: html">&lt;p&gt;I'm not inside a comment&lt;/p&gt;
+
+&lt;!-- &lt;p&gt;I am!&lt;/p&gt; --&gt;</pre>
+
+<p>如你所見,在下方的範例中,第一個段落出現在輸出結果中,但第二個段落並沒有出現。</p>
+
+<p>{{ EmbedLiveSample('HTML_註解', 700, 100) }}</p>
+
+<h2 id="總結">總結</h2>
+
+<p>恭喜你看完了這個章節,我們你能享受這個學習基礎 HTML 的旅程!目前,你應該已經了解 HTML 長什麼樣子、它最基本的運作方式,並且能夠寫出一些元素和屬性。基礎 HTML 大致上就到這裡結束,在單元接下來的章節中,我們將會更深入探討本章節學到的內容並介紹更多 HTML 的觀念。千萬別轉台!</p>
+
+<div class="note">
+<p><strong>Note</strong>: 目前,在你要開始學更多有關 HTML 的知識時,你可能也想要探索基礎的 <a href="/en-US/docs/Learn/CSS">CSS</a>(Cascading Style Sheets)。CSS 是一種用來為你的網頁增添花樣的語言,例如改變字型、顏色,或改變頁面的布局。你很快就會發現,同時使用 HTML 和 CSS 會帶來很棒的效果。</p>
+</div>
+
+<h2 id="另見"> 另見</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/HTML/Applying_color">Applying color to HTML elements using CSS</a></li>
+</ul>
+
+<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<h2 id="在本主題中的內容">在本主題中的內容</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html b/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html
new file mode 100644
index 0000000000..fc0e2eff89
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/html_text_fundamentals/index.html
@@ -0,0 +1,953 @@
+---
+title: 基本 HTML 文字
+slug: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals
+translation_of: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">HTML 的其中一件核心工作,就是給出文件的結構和含義(又稱{{glossary("semantics")}}),以便瀏覽器正確顯示。本文章旨在說明 {{glossary("HTML")}} 可透過增加標題、章節、強調、建立清單等,建立結構化的頁面。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">需求:</th>
+ <td>熟悉基本 HTML、在 <a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a> 有講解。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>學習如何標記一個具有文字的基礎頁面賦予它結構及含義— 包含段落, 標題, 列表, 強調文字, 以及引用句</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="基本:標題與段落">基本:標題與段落</h2>
+
+<p>多數結構化的文字由標題及段落構成,不論你是在閱讀故事,翻閱報紙,讀教科書,翻閱雜誌,等等。</p>
+
+<p><img alt="An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs." src="https://mdn.mozillademos.org/files/12371/newspaper_small.jpg" style="display: block; margin: 0px auto;" title="An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs."></p>
+
+<p>充滿結構性的文字內容讓閱讀經驗變得輕鬆且更加愉悅。</p>
+
+<p>在HTML裡,每個段落都被包在 {{htmlelement("p")}} 元素中,就像:</p>
+
+<pre class="brush: html">&lt;p&gt;I am a paragraph, oh yes I am.&lt;/p&gt;</pre>
+
+<p>而每個標題需要被包在標題元素中:</p>
+
+<pre class="brush: html">&lt;h1&gt;I am the title of the story.&lt;/h1&gt;</pre>
+
+<p>在HTML裡有六種標題元素:{{htmlelement("h1")}}, {{htmlelement("h2")}}, {{htmlelement("h3")}}, {{htmlelement("h4")}}, {{htmlelement("h5")}},跟 {{htmlelement("h6")}}. 每個元素分別代表著在文件中的不同層級; <code>&lt;h1&gt;</code> 代表主標題, <code>&lt;h2&gt;</code> 代表副標題, <code>&lt;h3&gt;</code> 代表更次級的副標題, 依此類推。</p>
+
+<h3 id="實作架構化階層">實作架構化階層</h3>
+
+<p>舉例來說,在一個故事裡,<code>&lt;h1&gt;</code> 將用來代表整個故事的標題,<code>&lt;h2&gt;</code> 則代表每個章節的標題,而<code>&lt;h3&gt;</code> 代表每個章節中的副標題,依此類推下去。</p>
+
+<pre class="brush: html">&lt;h1&gt;The Crushing Bore&lt;/h1&gt;
+
+&lt;p&gt;By Chris Mills&lt;/p&gt;
+
+&lt;h2&gt;Chapter 1: The dark night&lt;/h2&gt;
+
+&lt;p&gt;It was a dark night. Somewhere, an owl hooted. The rain lashed down on the ...&lt;/p&gt;
+
+&lt;h2&gt;Chapter 2: The eternal silence&lt;/h2&gt;
+
+&lt;p&gt;Our protagonist could not so much as a whisper out of the shadowy figure ...&lt;/p&gt;
+
+&lt;h3&gt;The specter speaks&lt;/h3&gt;
+
+&lt;p&gt;Several more hours had passed, when all of a sudden the specter sat bolt upright and exclaimed, "Please have mercy on my soul!"&lt;/p&gt;</pre>
+
+<p>只要層次結構有意義,要一個元件顯示什麼取決於你。當你在建立類似的文字結構時,只要記得以下幾點:</p>
+
+<ul>
+ <li>一個頁面最好只用一個 <code>&lt;h1&gt;</code> 元素:這是頂層標題,所有其他標題都位於層次結構的下方。</li>
+ <li>在使用標題元素的時候,要注意層級的順序。不要在&lt;h2&gt;前使用&lt;h3&gt;來標示副標題,這要很容易造成意外的結果。</li>
+ <li>每次使用標題元素時,雖有六個層級可使用,但應該以使用少於三個層級為目標,除非你真的覺得有必要用到三個以上。有過多層級的文件變得很笨重且很難導航文件架構。在這種情況下,可以考慮把文件內容劃分到多個頁面。</li>
+</ul>
+
+<h3 id="為何我們需要架構?">為何我們需要架構?</h3>
+
+<p>為了回答這個問題。我們先看看 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-start.html">text-start.html</a> 這個文章(鷹嘴豆泥食譜)的最前端。請先下載這個文件的副本到你的電腦,等一下練習時會用到。這個文件目前包含很多不同的內容,並沒有被標記出架構,唯一的排版只有換行而已。</p>
+
+<p><span style="font-size: 1rem; letter-spacing: -0.00278rem;">所以當你在瀏覽器中打開這份文件時,你將會看到這些文字看起來擠成一團!</span></p>
+
+<p><img alt="A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it." src="https://mdn.mozillademos.org/files/14827/Screen%20Shot%202017-03-29%20at%2009.20.35.png" style="display: block; height: 377px; margin: 0px auto; width: 600px;" title="A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it."></p>
+
+<p>這是因為文件內沒有元素去標示出文件的架構,所以瀏覽器不知道怎麼排版。此外:</p>
+
+<ul>
+ <li>使用者造訪一個網站時,時常只是快速的瀏覽內容以找尋他們正在找的相關內容,更常時候,使用者只有看一個頁面內的標題而已(來源:<a class="external external-icon" href="http://www.nngroup.com/articles/how-long-do-users-stay-on-web-pages/">spend a very short time on a web page</a>)。如果他們沒在短時間內找到實用的資訊,他們就會放棄這個頁面而去其他網頁尋找。</li>
+ <li>搜尋引擎會把標題作為重要關鍵字來排序搜尋結果。所以如果一個頁面沒有標題,就很難被搜尋引擎排在上方。換句話說,就是沒有達到搜尋引擎最佳化(Search Engine Optimization ({{glossary("SEO")}}))。</li>
+ <li>視力嚴重受損的使用者通常無法閱覽網頁,而透過螢幕閱讀器(<a href="http://en.wikipedia.org/wiki/Screen_reader" title="screen readers">screen reader</a>)聽頁面。螢幕閱讀器軟體提供使用者能夠更快速的取得頁面資訊。其中一個方式是透過朗誦出文件的架構,能讓使用者更快地獲得他們在尋找的資訊。所以假如一個頁面沒被恰當地標記架構,就會迫使使用者必須聆聽完整個頁面以取得尋找的資訊。</li>
+ <li>若要用{{glossary("CSS")}}裝飾頁面,或者讓瀏覽器透過{{glossary("JavaScript")}}做特效,也要用特別的元素來做標記。這樣CSS/JS才知道哪一部分是屬於他們的文件。</li>
+</ul>
+
+<p>以上原因說明為何我們要為內容標示出架構。</p>
+
+<h3 id="Active_learning_Giving_our_content_structure">Active learning: Giving our content structure</h3>
+
+<p>Let's jump straight in with a live example. In the example below, add elements to the raw text in the <em>Input</em> field so that it appears as a heading and two paragraphs in the <em>Output</em> field.</p>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. 如果你中途卡關,點擊<em>按鈕來查看答案</em>。</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 100px; width: 95%"&gt;My short story I am a policewoman and my name is Trish.
+
+My legs are made of cardboard and I am married to a fish.&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;h1&gt;My short story&lt;/h1&gt;\n&lt;p&gt;I am a policewoman and my name is Trish.&lt;/p&gt;\n&lt;p&gt;My legs are made of cardboard and I am married to a fish.&lt;/p&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Why_do_we_need_semantics">Why do we need semantics?</h3>
+
+<p>Semantics are relied on everywhere around us — we rely on previous experience to tell us what the function of an everyday object is; when we see something, we know what its function will be. So, for example, we expect a red traffic light to mean "stop", and a green traffic light to mean "go". Things can get tricky very quickly if the wrong semantics are applied (Do any countries use red to mean "go"? I hope not.)</p>
+
+<p>In a similar vein, we need to make sure we are using the correct elements, giving our content the correct meaning, function, or appearance. In this context the {{htmlelement("h1")}} element is also a semantic element, which gives the text it wraps around the role (or meaning) of "a top level heading on your page."</p>
+
+<pre class="brush: html">&lt;h1&gt;This is a top level heading&lt;/h1&gt;</pre>
+
+<p>By default, the browser will give it a large font size to make it look like a heading (although you could style it to look like anything you wanted using CSS). More importantly, its semantic value will be used in multiple ways, for example by search engines and screen readers (as mentioned above).</p>
+
+<p>On the other hand, you could make any element <em>look</em> like a top level heading. Consider the following:</p>
+
+<pre class="brush: html">&lt;span style="font-size: 32px; margin: 21px 0; display: block;"&gt;Is this a top level heading?&lt;/span&gt;</pre>
+
+<p>This is a {{htmlelement("span")}} element. It has no semantics. You use it to wrap content when you want to apply CSS to it (or do something to it with JavaScript) without giving it any extra meaning (you'll find out more about these later on in the course). We've applied some CSS to it to make it look like a top level heading, but since it has no semantic value, it will not get any of the extra benefits described above. It is a good idea to use the relevant HTML element for the job.</p>
+
+<h2 id="Lists">Lists</h2>
+
+<p>Now let's turn our attention to lists. Lists are everywhere in life — from your shopping list to the list of directions you subconsciously follow to get to your house every day, to the lists of instructions you are following in these tutorials! Lists are everywhere on the Web too, and we've got three different types to worry about.</p>
+
+<h3 id="Unordered">Unordered</h3>
+
+<p>Unordered lists are used to mark up lists of items for which the order of the items doesn't matter — let's take a shopping list as an example.</p>
+
+<pre>milk
+eggs
+bread
+hummus</pre>
+
+<p>Every unordered list starts off with a {{htmlelement("ul")}} element — this wraps around all the list items:</p>
+
+<pre class="brush: html">&lt;ul&gt;
+milk
+eggs
+bread
+hummus
+&lt;/ul&gt;</pre>
+
+<p>The last step is to wrap each list item in a {{htmlelement("li")}} (list item) element:</p>
+
+<pre class="brush: html">&lt;ul&gt;
+ &lt;li&gt;milk&lt;/li&gt;
+ &lt;li&gt;eggs&lt;/li&gt;
+ &lt;li&gt;bread&lt;/li&gt;
+ &lt;li&gt;hummus&lt;/li&gt;
+&lt;/ul&gt;</pre>
+
+<h4 id="Active_learning_Marking_up_an_unordered_list">Active learning: Marking up an unordered list</h4>
+
+<p>Try editing the live sample below to create your very own HTML unordered list.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 100px; width: 95%"&gt;milk
+eggs
+bread
+hummus&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;ul&gt;\n&lt;li&gt;milk&lt;/li&gt;\n&lt;li&gt;eggs&lt;/li&gt;\n&lt;li&gt;bread&lt;/li&gt;\n&lt;li&gt;hummus&lt;/li&gt;\n&lt;/ul&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Ordered">Ordered</h3>
+
+<p>Ordered lists are lists in which the order of the items <em>does</em> matter — let's take a set of directions as an example:</p>
+
+<pre>Drive to the end of the road
+Turn right
+Go straight across the first two roundabouts
+Turn left at the third roundabout
+The school is on your right, 300 meters up the road</pre>
+
+<p>The markup structure is the same as for unordered lists, except that you have to wrap the list items in an {{htmlelement("ol")}} element, rather than <code>&lt;ul&gt;</code>:</p>
+
+<pre class="brush: html">&lt;ol&gt;
+ &lt;li&gt;Drive to the end of the road&lt;/li&gt;
+ &lt;li&gt;Turn right&lt;/li&gt;
+ &lt;li&gt;Go straight across the first two roundabouts&lt;/li&gt;
+ &lt;li&gt;Turn left at the third roundabout&lt;/li&gt;
+ &lt;li&gt;The school is on your right, 300 meters up the road&lt;/li&gt;
+&lt;/ol&gt;</pre>
+
+<h4 id="Active_learning_Marking_up_an_ordered_list">Active learning: Marking up an ordered list</h4>
+
+<p>Try editing the live sample below to create your very own HTML ordered list.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_3">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 200px; width: 95%"&gt;Drive to the end of the road
+Turn right
+Go straight across the first two roundabouts
+Turn left at the third roundabout
+The school is on your right, 300 meters up the road&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;ol&gt;\n&lt;li&gt;Drive to the end of the road&lt;/li&gt;\n&lt;li&gt;Turn right&lt;/li&gt;\n&lt;li&gt;Go straight across the first two roundabouts&lt;/li&gt;\n&lt;li&gt;Turn left at the third roundabout&lt;/li&gt;\n&lt;li&gt;The school is on your right, 300 meters up the road&lt;/li&gt;\n&lt;/ol&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_3', 700, 500, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Active_learning_Marking_up_our_recipe_page">Active learning: Marking up our recipe page</h3>
+
+<p>So at this point in the article, you have all the information you need to mark up our recipe page example. You can choose to either save a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-start.html">text-start.html</a> starting file and do the work there, or do it in the editable example below. Doing it locally will probably be better, as then you'll get to save the work you are doing, whereas if you fill it in to the editable example, it will be lost the next time you open the page. Both have pros and cons.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_4">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 200px; width: 95%"&gt;Quick hummus recipe
+
+ This recipe makes quick, tasty hummus, with no messing. It has been adapted from a number of different recipes that I have read over the years.
+
+ Hummus is a delicious thick paste used heavily in Greek and Middle Eastern dishes. It is very tasty with salad, grilled meats and pitta breads.
+
+ Ingredients
+
+ 1 can (400g) of chick peas (garbanzo beans)
+ 175g of tahini
+ 6 sundried tomatoes
+ Half a red pepper
+ A pinch of cayenne pepper
+ 1 clove of garlic
+ A dash of olive oil
+
+ Instructions
+
+ Remove the skin from the garlic, and chop coarsely
+ Remove all the seeds and stalk from the pepper, and chop coarsely
+ Add all the ingredients into a food processor
+ Process all the ingredients into a paste
+ If you want a coarse "chunky" hummus, process it for a short time
+ If you want a smooth hummus, process it for a longer time
+
+ For a different flavour, you could try blending in a small measure of lemon and coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and feta cheese. Experiment and see what works for you.
+
+ Storage
+
+ Refrigerate the finished hummus in a sealed container. You should be able to use it for about a week after you've made it. If it starts to become fizzy, you should definitely discard it.
+
+ Hummus is suitable for freezing; you should thaw it and use it within a couple of months.&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;h1&gt;Quick hummus recipe&lt;/h1&gt;\n\n&lt;p&gt;This recipe makes quick, tasty hummus, with no messing. It has been adapted from a number of different recipes that I have read over the years.&lt;/p&gt;\n\n&lt;p&gt;Hummus is a delicious thick paste used heavily in Greek and Middle Eastern dishes. It is very tasty with salad, grilled meats and pitta breads.&lt;/p&gt;\n\n&lt;h2&gt;Ingredients&lt;/h2&gt;\n\n&lt;ul&gt;\n&lt;li&gt;1 can (400g) of chick peas (garbanzo beans)&lt;/li&gt;\n&lt;li&gt;175g of tahini&lt;/li&gt;\n&lt;li&gt;6 sundried tomatoes&lt;/li&gt;\n&lt;li&gt;Half a red pepper&lt;/li&gt;\n&lt;li&gt;A pinch of cayenne pepper&lt;/li&gt;\n&lt;li&gt;1 clove of garlic&lt;/li&gt;\n&lt;li&gt;A dash of olive oil&lt;/li&gt;\n&lt;/ul&gt;\n\n&lt;h2&gt;Instructions&lt;/h2&gt;\n\n&lt;ol&gt;\n&lt;li&gt;Remove the skin from the garlic, and chop coarsely.&lt;/li&gt;\n&lt;li&gt;Remove all the seeds and stalk from the pepper, and chop coarsely.&lt;/li&gt;\n&lt;li&gt;Add all the ingredients into a food processor.&lt;/li&gt;\n&lt;li&gt;Process all the ingredients into a paste.&lt;/li&gt;\n&lt;li&gt;If you want a coarse "chunky" hummus, process it for a short time.&lt;/li&gt;\n&lt;li&gt;If you want a smooth hummus, process it for a longer time.&lt;/li&gt;\n&lt;/ol&gt;\n\n&lt;p&gt;For a different flavour, you could try blending in a small measure of lemon and coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and feta cheese. Experiment and see what works for you.&lt;/p&gt;\n\n&lt;h2&gt;Storage&lt;/h2&gt;\n\n&lt;p&gt;Refrigerate the finished hummus in a sealed container. You should be able to use it for about a week after you\'ve made it. If it starts to become fizzy, you should definitely discard it.&lt;/p&gt;\n\n&lt;p&gt;Hummus is suitable for freezing; you should thaw it and use it within a couple of months.&lt;/p&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_4', 900, 500, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>If you get stuck, you can always press the <em>Show solution</em> button, or check out our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-complete.html">text-complete.html</a> example on our github repo.</p>
+
+<h3 id="Nesting_lists">Nesting lists</h3>
+
+<p>It is perfectly ok to nest one list inside another one. You might want to have some sub-bullets sitting below a top level bullet. Let's take the second list from our recipe example:</p>
+
+<pre class="brush: html">&lt;ol&gt;
+ &lt;li&gt;Remove the skin from the garlic, and chop coarsely.&lt;/li&gt;
+ &lt;li&gt;Remove all the seeds and stalk from the pepper, and chop coarsely.&lt;/li&gt;
+ &lt;li&gt;Add all the ingredients into a food processor.&lt;/li&gt;
+ &lt;li&gt;Process all the ingredients into a paste.&lt;/li&gt;
+ &lt;li&gt;If you want a coarse "chunky" hummus, process it for a short time.&lt;/li&gt;
+ &lt;li&gt;If you want a smooth hummus, process it for a longer time.&lt;/li&gt;
+&lt;/ol&gt;</pre>
+
+<p>Since the last two bullets are very closely related to the one before them (they read like sub-instructions or choices that fit below that bullet), it might make sense to nest them inside their own unordered list, and put that list inside the current fourth bullet. This would look like so:</p>
+
+<pre class="brush: html">&lt;ol&gt;
+ &lt;li&gt;Remove the skin from the garlic, and chop coarsely.&lt;/li&gt;
+ &lt;li&gt;Remove all the seeds and stalk from the pepper, and chop coarsely.&lt;/li&gt;
+ &lt;li&gt;Add all the ingredients into a food processor.&lt;/li&gt;
+ &lt;li&gt;Process all the ingredients into a paste.
+ &lt;ul&gt;
+ &lt;li&gt;If you want a coarse "chunky" hummus, process it for a short time.&lt;/li&gt;
+ &lt;li&gt;If you want a smooth hummus, process it for a longer time.&lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;/li&gt;
+&lt;/ol&gt;</pre>
+
+<p>Try going back to the previous active learning example and updating the second list like this.</p>
+
+<h2 id="Emphasis_and_importance">Emphasis and importance</h2>
+
+<p>In human language, we often emphasise certain words to alter the meaning of a sentence, and we often want to mark certain words as important or different in some way. HTML provides various semantic elements to allow us to mark up textual content with such effects, and in this section, we'll look at a few of the most common ones.</p>
+
+<h3 id="Emphasis">Emphasis</h3>
+
+<p>When we want to add emphasis in spoken language, we <em>stress</em> certain words, subtly altering the meaning of what we are saying. Similarly, in written language we tend to stress words by putting them in italics. For example, the following two sentences have different meanings.</p>
+
+<p>I am glad you weren't late.</p>
+
+<p>I am <em>glad</em> you weren't <em>late</em>.</p>
+
+<p>The first sentence sounds genuinely relieved that the person wasn't late. In contrast, the second one sounds sarcastic or passive-aggressive, expressing annoyance that the person arrived a bit late.</p>
+
+<p>In HTML we use the {{htmlelement("em")}} (emphasis) element to mark up such instances. As well as making the document more interesting to read, these are recognised by screen readers and spoken out in a different tone of voice. Browsers style this as italic by default, but you shouldn't use this tag purely to get italic styling. To do that, you'd use a {{htmlelement("span")}} element and some CSS, or perhaps an {{htmlelement("i")}} element (see below).</p>
+
+<pre class="brush: html">&lt;p&gt;I am &lt;em&gt;glad&lt;/em&gt; you weren't &lt;em&gt;late&lt;/em&gt;.&lt;/p&gt;</pre>
+
+<h3 id="Strong_importance">Strong importance</h3>
+
+<p>To emphasize important words, we tend to stress them in spoken language and <strong>bold</strong> them in written language. For example:</p>
+
+<p>這液體具有<strong>相當強的毒性</strong>。</p>
+
+<p>我相信你。<strong>千萬</strong>別遲到了!</p>
+
+<p>In HTML we use the {{htmlelement("strong")}} (strong importance) element to mark up such instances. As well as making the document more useful, again these are recognized by screen readers and spoken in a different tone of voice. Browsers style this as bold text by default, but you shouldn't use this tag purely to get bold styling. To do that, you'd use a {{htmlelement("span")}} element and some CSS, or perhaps a {{htmlelement("b")}} element (see below).</p>
+
+<pre class="brush: html">&lt;p&gt;This liquid is &lt;strong&gt;highly toxic&lt;/strong&gt;.&lt;/p&gt;
+
+&lt;p&gt;I am counting on you. &lt;strong&gt;Do not&lt;/strong&gt; be late!&lt;/p&gt;</pre>
+
+<p>You can nest strong and emphasis inside one another if desired:</p>
+
+<pre class="brush: html">&lt;p&gt;This liquid is &lt;strong&gt;highly toxic&lt;/strong&gt; —
+if you drink it, &lt;strong&gt;you may &lt;em&gt;die&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;</pre>
+
+<h3 id="Active_learning_Lets_be_important!">Active learning: Let's be important!</h3>
+
+<p>In this active learning section, we have provided an editable example. Inside it, we'd like you to try adding emphasis and strong importance to the words you think need them, just to have some practice.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_5">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 200px; width: 95%"&gt;&lt;h1&gt;Important notice&lt;/h1&gt;
+&lt;p&gt;On Sunday January 9th 2010, a gang of goths were
+ spotted stealing several garden gnomes from a
+ shopping center in downtown Milwaukee. They were
+ all wearing green jumpsuits and silly hats, and
+ seemed to be having a whale of a time. If anyone
+ has any information about this incident, please
+ contact the police now.&lt;/p&gt;&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;h1&gt;Important notice&lt;/h1&gt;\n&lt;p&gt;On &lt;strong&gt;Sunday January 9th 2010&lt;/strong&gt;, a gang of &lt;em&gt;goths&lt;/em&gt; were spotted stealing &lt;strong&gt;&lt;em&gt;several&lt;/em&gt; garden gnomes&lt;/strong&gt; from a shopping center in downtown &lt;strong&gt;Milwaukee&lt;/strong&gt;. They were all wearing &lt;em&gt;green jumpsuits&lt;/em&gt; and &lt;em&gt;silly hats&lt;/em&gt;, and seemed to be having a whale of a time. If anyone has &lt;strong&gt;any&lt;/strong&gt; information about this incident, please contact the police &lt;strong&gt;now&lt;/strong&gt;.&lt;/p&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_5', 700, 500, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Italic_bold_underline...">Italic, bold, underline...</h3>
+
+<p>The elements we've discussed so far have clearcut associated semantics. The situation with {{htmlelement("b")}}, {{htmlelement("i")}}, and {{htmlelement("u")}} is somewhat more complicated. They came about so people could write bold, italics, or underlined text in an era when CSS was still supported poorly or not at all. Elements like this, which only affect presentation and not semantics, are known as <strong>presentational elements</strong> and should no longer be used, because as we've seen before, semantics is so important to accessibility, SEO, etc.</p>
+
+<p>HTML5 redefined <code>&lt;b&gt;</code>, <code>&lt;i&gt;</code> and <code>&lt;u&gt;</code> with new, somewhat confusing, semantic roles.</p>
+
+<p>Here's the best rule of thumb: it's likely appropriate to use <code>&lt;b&gt;</code>, <code>&lt;i&gt;</code>, or <code>&lt;u&gt;</code> to convey a meaning traditionally conveyed with bold, italics, or underline, provided there is no more suitable element. However, it always remains critical to keep an accessibility mindset. The concept of italics isn't very helpful to people using screen readers, or to people using a writing system other than the Latin alphabet.</p>
+
+<ul>
+ <li>{{HTMLElement('i')}} is used to convey a meaning traditionally conveyed by italic: Foreign words, taxonomic designation, technical terms, a thought...</li>
+ <li>{{HTMLElement('b')}} is used to convey a meaning traditionally conveyed by bold: Key words, product names, lead sentence...</li>
+ <li>{{HTMLElement('u')}} is used to convey a meaning traditionally conveyed by underline: Proper name, misspelling...</li>
+</ul>
+
+<div class="note">
+<p>A kind warning about underline: <strong>People strongly associate underlining with hyperlinks.</strong> Therefore, on the Web, it's best to underline only links. Use the <code>&lt;u&gt;</code> element when it's semantically appropriate, but consider using CSS to change the default underline to something more appropriate on the Web. The example below illustrates how it can be done.</p>
+</div>
+
+<pre class="brush: html">&lt;!-- scientific names --&gt;
+&lt;p&gt;
+ The Ruby-throated Hummingbird (&lt;i&gt;Archilochus colubris&lt;/i&gt;)
+ is the most common hummingbird in Eastern North America.
+&lt;/p&gt;
+
+&lt;!-- foreign words --&gt;
+&lt;p&gt;
+ The menu was a sea of exotic words like &lt;i lang="uk-latn"&gt;vatrushka&lt;/i&gt;,
+ &lt;i lang="id"&gt;nasi goreng&lt;/i&gt; and &lt;i lang="fr"&gt;soupe à l'oignon&lt;/i&gt;.
+&lt;/p&gt;
+
+&lt;!-- a known misspelling --&gt;
+&lt;p&gt;
+ Someday I'll learn how to &lt;u style="text-decoration-line: underline; text-decoration-style: wavy;"&gt;spel&lt;/u&gt; better.
+&lt;/p&gt;
+
+&lt;!-- Highlight keywords in a set of instructions --&gt;
+&lt;ol&gt;
+ &lt;li&gt;
+ &lt;b&gt;Slice&lt;/b&gt; two pieces of bread off the loaf.
+ &lt;/li&gt;
+ &lt;li&gt;
+ &lt;b&gt;Insert&lt;/b&gt; a tomato slice and a leaf of
+ lettuce between the slices of bread.
+ &lt;/li&gt;
+&lt;/ol&gt;</pre>
+
+<h2 id="總結">總結</h2>
+
+<p>That's it for now! This article should have given you a good idea of how to start marking up text in HTML, and introduced you to some of the most important elements in this area. There are a lot more semantic elements to cover in this area, and we'll look at a lot more in our 'More Semantic Elements' article, later on in the course. In the next article, we'll be looking in detail at how to <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">create hyperlinks</a>, possibly the most important element on the Web.</p>
+
+<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/introduction_to_html/index.html b/files/zh-tw/learn/html/introduction_to_html/index.html
new file mode 100644
index 0000000000..47c9f80769
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/index.html
@@ -0,0 +1,61 @@
+---
+title: HTML介紹
+slug: Learn/HTML/Introduction_to_HTML
+translation_of: Learn/HTML/Introduction_to_HTML
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">本質上,{{glossary("HTML")}} 是一種非常簡單的語言,由元素所組成。元素可以賦予文字片段不同的意義 (比方說,將它們描述成段落、項目清單,或是表格的一部分)、將文件組織成不同的邏輯區段 (如標頭(header)、三行的內文,或是導覽目錄),以及在網頁中嵌入圖片或影片等內容。在這個主題中我們將介紹前面兩項,並介紹基本概念以及語法以讓你了解 HTML。</p>
+
+<h2 id="預備知識">預備知識</h2>
+
+<p>在開始閱讀之前,你並不需要具備任何 HTML 知識,你只要能夠操作電腦、瀏覽網頁並消化其中的內容即可。你需要<a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Installing_basic_software">建立一個基礎工作環境</a>,並且了解<a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Dealing_with_files">如何建立與管理檔案</a>──這些都屬於我們 <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web">Web 入門</a> 的一部分。</p>
+
+<div class="note">
+<p><strong>提示</strong>: 如果您是在某些無法建立個人檔案的電腦/平板/其他裝置上進行,您可以在一些線上 coding program (如 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a>) 上測試程式碼範例。</p>
+</div>
+
+<h2 id="導覽">導覽</h2>
+
+<p>這個主題包含以下子題,將帶你了解所有 HTML 的基礎理論,並且提供充足的機會讓你測試所習得的技能。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 入門</a></dt>
+ <dd>包含 HTML 最基礎的部分──我們將定義元素(elements)、屬性(attributes)以及其他重要術語,並且介紹它們的使用方法。除此之外,我們也將說明典型的 HTML 網頁及其中的元素是如何構成的,並解釋其他重要的基本語言特性。還有,我們也會玩一些 HTML,好引發你的興趣!</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">在 head 中有什麼? HTML 中的後設資料(Metadata)</a></dt>
+ <dd>HTML 文件的 head 是在網頁加載完畢之後,不會顯示在瀏覽器上的部分。其中包含一些資訊,如頁面的標題({{htmlelement("title")}})、{{glossary("CSS")}} 的連結 (當你想利用 CSS 來妝點你的頁面 HTML 時,你會用到它們)、網頁圖示(favicon)的連結,以及 metadata (裡頭承載了有關於該 HTML 的資料,如作者、描述該文件的關鍵詞等。)</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 文字的基礎知識</a></dt>
+ <dd>一個 HTML 的主要作用是賦予純文字意義(又稱為<a href="https://wiki.developer.mozilla.org/en-US/docs/Glossary/Semantics">語義化</a>),好讓瀏覽器知道如何正確地顯示它。這篇文章將探討如何使用 HTML 來將文字區塊拆解為標題(heading)和段落(paragraph)、強調字詞、建立列表等等。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">建立超連結</a></dt>
+ <dd>超連結真的非常重要 — 它造就了我們現今所知的網路。這篇文章介紹超連結的使用語法,並且探討建立連結的最佳實踐方法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">進階文字格式</a></dt>
+ <dd>在 HTML 中還有許多可以用來格式化文字的元素,但我們沒有在 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 文字的基礎知識</a>中提及這些內容。雖然這些元素比較鮮為人知,不過還是相當值得一談。在這篇文章中,你將會學到如何表示引言、描述列表、程式碼、上下標,及聯繫訊息等等。 </dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">文件與網站架構</a></dt>
+ <dd>除了分別定義網頁的各個成分(例如:段落或是圖片),HTML 還能定義網頁上的區塊(例如:標頭、導航列或是主要內容)。這篇文章將介紹如何規劃一個基本的網頁架構,以及如何透過編寫 HTML 來表示網頁架構。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">HTML 除錯</a></dt>
+ <dd>如果 HTML 出錯了,卻找不到哪裡有錯誤該怎麼辦?這篇文章將會介紹一些能幫得上忙的實用工具。</dd>
+</dl>
+
+<h2 id="評量">評量</h2>
+
+<p>下面的評量將測試您對於以上的 HTML 基礎是否已經了解。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">標記信件內容</a></dt>
+ <dd>我們都學過怎麼寫信,而信件也是用來測試我們格式化文字技巧的好例子。在這份測驗中,你將需要以 HTML 將一封信標記成題目要求的樣子。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">組織網頁內容</a></dt>
+ <dd>這份測驗將要測試你利用 HTML 來組織網頁的能力,該網頁將包含頁眉(header)、頁腳(footer)、導覽列(navigation)、內文(main content)和側邊攔(sidebar)。</dd>
+</dl>
+
+<h2 id="另見">另見</h2>
+
+<dl>
+ <dt><a href="https://teach.mozilla.org/activities/web-lit-basics/">Web literacy basics 1</a></dt>
+ <dd>Mozilla 基金會所提供的一個優質課程。該課程探索並測驗了很多在本主題中所提及的技術。透過裡頭的六大學習主題,學習者能夠熟悉閱讀、撰寫以及參與網路,並經由實作與合作了解網路基礎。</dd>
+</dl>
+
+<div class="blockIndicator note">
+<h2 id="回饋">回饋</h2>
+
+<p>請填寫<a href="https://www.surveygizmo.com/s3/4871248/MDN-Guides-Survey">問卷</a>以協助改善我們的導覽與教學。</p>
+</div>
diff --git a/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html b/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html
new file mode 100644
index 0000000000..db41ab4ec4
--- /dev/null
+++ b/files/zh-tw/learn/html/introduction_to_html/the_head_metadata_in_html/index.html
@@ -0,0 +1,261 @@
+---
+title: What’s in the head? Metadata in HTML
+slug: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML
+tags:
+ - 初學者
+translation_of: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</div>
+
+<p class="summary">HTML 文件的 {{glossary("Head", "head")}} 是網頁在加載完畢之後,不會顯示在瀏覽器上的部分。其中包含一些資訊,如頁面的標題({{htmlelement("title")}})、{{glossary("CSS")}} 的連結 (當你想利用 CSS 來妝點你的頁面 HTML 時,你會用到它們)、網頁圖示(favicon)的連結,以及 metadata (裡頭承載了有關於該 HTML 的資料,如作者、描述該文件的關鍵詞等)。在這一章節裡,我們會討論以上的內容,甚至更多,藉此替你打下標記網頁的根基。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">需求:</th>
+ <td>對 HTML 的基礎認識,內容我們已在 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 入門</a>中提及。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>學習 HTML 的 head,了解它的目的、它能包含什麼重要東西,以及它對 HTML 文件產生的影響。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是_HTML_head">什麼是 HTML head?</h2>
+
+<p>讓我們再看一次之前所看過的 <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document">HTML 文件</a>:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;My test page&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;p&gt;This is my page&lt;/p&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>HTML 的 head 就是 {{htmlelement("head")}} 元素裡面的內容 — 跟 {{htmlelement("body")}} 元素中的內容不同(當網頁被載入瀏覽器中時,會呈現在頁面上),head 裡的內容不會顯示在頁面上,它的任務是要容納文件的 {{glossary("Metadata", "metadata")}}。在上例中,head 只有這樣:</p>
+
+<pre class="brush: html">&lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;My test page&lt;/title&gt;
+&lt;/head&gt;</pre>
+
+<p>假如換作是較大型的網頁,head 裡面可能就會有非常多東西了。現在你可以先到幾個你常去的網站,並利用<a href="/en-US/docs/Learn/Discover_browser_developer_tools">開發者工具</a>來檢視它們的 head。我們在這裡並不打算要向你展示所有能放在 head 中的東西,而是教你使用一些常用的元素,讓你熟悉熟悉它們。總而言之,讓我們開始吧!</p>
+
+<h2 id="加入標題title">加入標題(title)</h2>
+
+<p>我們已經看到活生生的 {{htmlelement("title")}} 元素了 — 這東西就是用來為文件加上標題的。你可能會把它跟 {{htmlelement("h1")}} 搞混,{{htmlelement("h1")}} 是用來為網頁主體加上標題的元素,有時也被叫做頁面標題 (page title),雖然聽起來功能很像,但他們是不同的東西!</p>
+
+<ul>
+ <li>{{htmlelement("h1")}} 元素在被載入瀏覽器時顯示在頁面上 — 通常它應該只會出現一次,用來為頁面內容加上標題 (如故事和新聞的標題,或是其他合適的用法)。</li>
+ <li>{{htmlelement("title")}} 元素是用來代表 HTML 文件標題的 metadata (即非文件內容)。</li>
+</ul>
+
+<h3 id="不要光是看:檢視一個簡單的範例">不要光是看:檢視一個簡單的範例</h3>
+
+<ol>
+ <li>在開始這次主動學習之前,請你先到我們的 GitHub repo 中下載一份 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html page</a>。要做到這件事情,你可以:
+
+ <ol>
+ <li>用你的文字編輯器開一個新檔案,並將原始碼複製到裡面,然後再儲存在一個合適的地方。</li>
+ <li>按下網頁上的 Raw 按鈕,它就會將原始碼以純文字的形式顯示在你瀏覽器的新分頁上。接著點按右鍵,將檔案儲存在你喜歡的地方。</li>
+ </ol>
+ </li>
+ <li>現在在你的瀏覽器中開啟檔案,你看到的東西應該會長這樣:
+ <p><img alt="A simple web page with the title set to &lt;title> element, and the &lt;h1> set to &lt;h1> element." src="https://mdn.mozillademos.org/files/12323/title-example.png" style="display: block; margin: 0 auto;">這樣子你應該可以很清楚地看到哪裡是 <code>&lt;h1&gt;</code>,而哪裡是 <code>&lt;title&gt;</code> 了!</p>
+ </li>
+ <li>試著開啟文字編輯器,修改兩元素的內容,儲存後再重整網頁,看看有什麼不同。</li>
+</ol>
+
+<p><code>&lt;title&gt;</code> 元素中的內容也被用在其他地方。舉個例子,如果你想要收藏這個網頁,(在 Firefox 上是<em> 書籤 &gt; 將本頁加入書籤</em> 或按下 URL 列的星星符號),你就會看到 <code>&lt;title&gt;</code> 的內容被設為建議的書籤名稱。</p>
+
+<p><img alt="A webpage being bookmarked in firefox; the bookmark name has been automatically filled in with the contents of the &lt;title> element " src="https://mdn.mozillademos.org/files/12337/bookmark-example.png" style="display: block; margin: 0 auto;"></p>
+
+<p>接下來你就會看到,<code>&lt;title&gt;</code> 的內容也會被用在搜尋當中。</p>
+
+<h2 id="Metadata_&lt;meta>_元素">Metadata: &lt;meta&gt; 元素</h2>
+
+<p>Metadata is data that describes data, and HTML has an "official" way of adding metadata to a document — the {{htmlelement("meta")}} element. Of course, the other stuff we are talking about in this article could also be thought of as metadata too. There are a lot of different types of <code>&lt;meta&gt;</code> element that can be included in your page's &lt;head&gt;, but we won't try to explain them all at this stage, as it would just get too confusing. Instead, we'll explain a few things that you might commonly see, just to give you an idea.</p>
+
+<h3 id="指定文件字元編碼">指定文件字元編碼</h3>
+
+<p>In the example we saw above, this line was included:</p>
+
+<pre class="brush: html">&lt;meta charset="utf-8"&gt;</pre>
+
+<p>This element simply specifies the document's character encoding — the character set that the document is permitted to use. <code>utf-8</code> is a universal character set that includes pretty much any character from any human language. This means that your web page will be able to handle displaying any language; it's therefore a good idea to set this on every web page you create! For example, your page could handle English and Japanese just fine:</p>
+
+<p><img alt="a web page containing English and Japanese characters, with the character encoding set to universal, or utf-8. Both languages display fine," src="https://mdn.mozillademos.org/files/12343/correct-encoding.png" style="display: block; margin: 0 auto;">If you set your character encoding to <code>ISO-8859-1</code>, for example (the character set for the Latin alphabet), your page rendering would be all messed up:</p>
+
+<p><img alt="a web page containing English and Japanese characters, with the character encoding set to latin. The Japanese characters don't display correctly" src="https://mdn.mozillademos.org/files/12341/bad-encoding.png" style="display: block; height: 365px; margin: 0px auto; width: 604px;"></p>
+
+<h3 id="Active_learning_Experiment_with_character_encoding">Active learning: Experiment with character encoding</h3>
+
+<p>To try this out, revisit the simple HTML template you obtained in the previous section on <code>&lt;title&gt;</code> (the <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html page</a>), try changing the meta charset value to <code>ISO-8859-1</code>, and add the Japanese to your page. This is the code we used:</p>
+
+<pre class="brush: html">&lt;p&gt;Japanese example: ご飯が熱い。&lt;/p&gt;</pre>
+
+<h3 id="加入作者author和描述description">加入作者(author)和描述(description)</h3>
+
+<p>Many <code>&lt;meta&gt;</code> elements include <code>name</code> and <code>content</code> attributes:</p>
+
+<ul>
+ <li><code>name</code> specifies the type of meta element it is; what type of information it contains.</li>
+ <li><code>content</code> specifies the actual meta content.</li>
+</ul>
+
+<p>Two such meta elements that are useful to include on your page define the author of the page, and provide a concise description of the page. Let's look at an example:</p>
+
+<pre class="brush: html">&lt;meta name="author" content="Chris Mills"&gt;
+&lt;meta name="description" content="The MDN Learning Area aims to provide
+complete beginners to the Web with all they need to know to get
+started with developing web sites and applications."&gt;</pre>
+
+<p>Specifying an author is useful in a few ways: it is useful to be able to work out who wrote the page, if you want to contact them with questions about the content. Some content management systems have facilities to automatically extract page author information and make it available for such purposes.</p>
+
+<p>Specifying a description that includes keywords relating to the content of your page is useful as it has the potential to make your page appear higher in relevant searches performed in search engines (such activities are termed <a href="/en-US/docs/Glossary/SEO">Search Engine Optimization</a>, or {{glossary("SEO")}}.)</p>
+
+<h3 id="Active_learning_The_descriptions_use_in_search_engines">Active learning: The description's use in search engines</h3>
+
+<p>The description is also used on search engine result pages. Let's go through an exercise to explore this</p>
+
+<ol>
+ <li>Go to the <a href="https://developer.mozilla.org/en-US/">front page of The Mozilla Developer Network</a>.</li>
+ <li>View the page's source (Right/<kbd>Ctrl</kbd> + click on the page, choose <em>View Page Source</em> from the context menu.)</li>
+ <li>Find the description meta tag. It will look like this:
+ <pre class="brush: html">&lt;meta name="description" content="The Mozilla Developer Network (MDN) provides
+information about Open Web technologies including HTML, CSS, and APIs for both
+Web sites and HTML5 Apps. It also documents Mozilla products, like Firefox OS."&gt;</pre>
+ </li>
+ <li>Now search for "Mozilla Developer Network" in your favorite search engine (We used Yahoo.) You'll notice the description <code>&lt;meta&gt;</code> and <code>&lt;title&gt;</code> element content used in the search result — definitely worth having!
+ <p><img alt='A Yahoo search result for "Mozilla Developer Network"' src="https://mdn.mozillademos.org/files/12347/search-result.png" style="display: block; margin: 0 auto;"></p>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: In Google, you will see some relevant subpages of MDN listed below the main MDN homepage link — these are called sitelinks, and are configurable in <a href="http://www.google.com/webmasters/tools/">Google's webmaster tools</a> — a way to make your site's search results better in the Google search engine.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: Many <code>&lt;meta&gt;</code> features just aren't used any more. For example, the keyword <code>&lt;meta&gt;</code> element (<code>&lt;meta name="keywords" content="fill, in, your, keywords, here"&gt;</code>) — which is supposed to provide keywords for search engines to determine relevance of that page for different search terms — is ignored by search engines, because spammers were just filling the keyword list with hundreds of keywords, biasing results.</p>
+</div>
+
+<h3 id="其他種類的metadata">其他種類的metadata</h3>
+
+<p>As you travel around the web, you'll find other types of metadata, too. A lot of the features you'll see on websites are proprietary creations, designed to provide certain sites (such as social networking sites) with specific pieces of information they can use.</p>
+
+<p>For example, <a href="http://ogp.me/">Open Graph Data</a> is a metadata protocol that Facebook invented to provide richer metadata for websites. In the MDN sourcecode, you'll find this:</p>
+
+<pre class="brush: html">&lt;meta property="og:image" content="https://developer.cdn.mozilla.net/static/img/opengraph-logo.dc4e08e2f6af.png"&gt;
+&lt;meta property="og:description" content="The Mozilla Developer Network (MDN) provides
+information about Open Web technologies including HTML, CSS, and APIs for both Web sites
+and HTML5 Apps. It also documents Mozilla products, like Firefox OS."&gt;
+&lt;meta property="og:title" content="Mozilla Developer Network"&gt;</pre>
+
+<p>One effect of this is that when you link to MDN on facebook, the link appears along with an image and description: a richer experience for users.</p>
+
+<p><img alt="Open graph protocol data from the MDN homepage as displayed on facebook, showing an image, title, and description." src="https://mdn.mozillademos.org/files/12349/facebook-output.png" style="display: block; margin: 0 auto;">Twitter also has its own similar proprietary metadata, which has a similar effect when the site's URL is displayed on twitter.com. For example:</p>
+
+<pre class="brush: html">&lt;meta name="twitter:title" content="Mozilla Developer Network"&gt;</pre>
+
+<h2 id="加入屬於自己的網頁icon">加入屬於自己的網頁icon</h2>
+
+<p>To further enrich your site design, you can add references to custom icons in your metadata, and these will be displayed in certain contexts.</p>
+
+<p>The humble favicon, which has been around for many years, was the first icon of this type, a 16 x 16 pixel icon used in multiple places. You'll see favicons displayed in the browser tab containing each open page, and next to bookmarked pages in the bookmarks panel.</p>
+
+<p>A favicon can be added to your page by:</p>
+
+<ol>
+ <li>Saving it in the same directory as the site's index page, saved in <code>.ico</code> format (most browsers will support favicons in more common formats like <code>.gif</code> or <code>.png</code>, but using the ICO format will ensure it works as far back as Internet Explorer 6.)</li>
+ <li>Adding the following line into your HTML <code>&lt;head&gt;</code> to reference it:
+ <pre class="brush: html">&lt;link rel="shortcut icon" href="favicon.ico" type="image/x-icon"&gt;</pre>
+ </li>
+</ol>
+
+<p>Here is an example of a favicon in a bookmarks panel:</p>
+
+<p><img alt="The Firefox bookmarks panel, showing a bookmarked example with a favicon displayed next to it." src="https://mdn.mozillademos.org/files/12351/bookmark-favicon.png" style="display: block; margin: 0 auto;"></p>
+
+<p>There are lots of other icon types to consider these days as well. For example, you'll find this in the source code of the MDN homepage:</p>
+
+<pre class="brush: html">&lt;!-- third-generation iPad with high-resolution Retina display: --&gt;
+&lt;link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://developer.cdn.mozilla.net/static/img/favicon144.a6e4162070f4.png"&gt;
+&lt;!-- iPhone with high-resolution Retina display: --&gt;
+&lt;link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://developer.cdn.mozilla.net/static/img/favicon114.0e9fabd44f85.png"&gt;
+&lt;!-- first- and second-generation iPad: --&gt;
+&lt;link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://developer.cdn.mozilla.net/static/img/favicon72.8ff9d87c82a0.png"&gt;
+&lt;!-- non-Retina iPhone, iPod Touch, and Android 2.1+ devices: --&gt;
+&lt;link rel="apple-touch-icon-precomposed" href="https://developer.cdn.mozilla.net/static/img/favicon57.a2490b9a2d76.png"&gt;
+&lt;!-- basic favicon --&gt;
+&lt;link rel="shortcut icon" href="https://developer.cdn.mozilla.net/static/img/favicon32.e02854fdcf73.png"&gt;</pre>
+
+<p>The comments explain what each icon is used for — these elements cover things like providing a nice high resolution icon to use when the website is saved to an iPad's home screen.</p>
+
+<p>Don't worry too much about implementing all these types of icon right now — this is a fairly advanced feature, and you won't be expected to have knowledge of this to progress through the course. The main purpose here is to let you know what such things are, in case you come across them while browsing other websites' source code.</p>
+
+<h2 id="在HTML中加入CSS和JavaScript">在HTML中加入CSS和JavaScript</h2>
+
+<p>Just about all websites you'll use in the modern day will employ {{glossary("CSS")}} to make them look cool, and {{glossary("JavaScript")}} to power interactive functionality, such as video players, maps, games, and more. These are most commonly applied to a web page using the {{htmlelement("link")}} element and the {{htmlelement("script")}} element, respectively.</p>
+
+<ul>
+ <li>
+ <p>The {{htmlelement("link")}} element always goes inside the head of your document. This takes two attributes, rel="stylesheet", which indicates that it is the document's stylesheet, and href, which contains the path to the stylesheet file:</p>
+
+ <pre class="brush: html">&lt;link rel="stylesheet" href="my-css-file.css"&gt;</pre>
+ </li>
+ <li>
+ <p>The {{htmlelement("script")}} element does not have to go in the head; in fact, often it is better to put it at the bottom of the document body (just before the closing <code>&lt;/body&gt;</code> tag), to make sure that all the HTML content has been read by the browser before it tries to apply JavaScript to it (if JavaScript tries to access an element that doesn't yet exist, the browser will throw an error.)</p>
+
+ <pre class="brush: html">&lt;script src="my-js-file.js"&gt;&lt;/script&gt;</pre>
+
+ <p><strong>Note</strong>: The <code>&lt;script&gt;</code> element may look like an empty element, but it's not, and so needs a closing tag. Instead of pointing to an external script file, you can also choose to put your script inside the <code>&lt;script&gt;</code> element.</p>
+ </li>
+</ul>
+
+<h3 id="Active_learning_applying_CSS_and_JavaScript_to_a_page">Active learning: applying CSS and JavaScript to a page</h3>
+
+<ol>
+ <li>To start this active learning, grab a copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/script.js">script.js</a> and <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/style.css">style.css</a> files, and save them on your local computer in the same directory. Make sure they are saved with the correct names and file extensions.</li>
+ <li>Open the HTML file in both your browser, and your text editor.</li>
+ <li>By following the information given above, add {{htmlelement("link")}} and {{htmlelement("script")}} elements to your HTML, so that your CSS and JavaScript are applied to your HTML.</li>
+</ol>
+
+<p>If done correctly, when you save your HTML and refresh your browser you'll see that things have changed:</p>
+
+<p><img alt="Example showing a page with CSS and JavaScript applied to it. The CSS has made the page go green, whereas the JavaScript has added a dynamic list to the page." src="https://mdn.mozillademos.org/files/12359/js-and-css.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+ <li>The JavaScript has added an empty list to the page. Now when you click anywhere on the list, a dialog box will pop up asking you to enter some text for a new list item. when you press the OK button, a new list item will be added to the list containing the text. When you click on an existing list item, a dialog box will pop up allowing you to change the item's text.</li>
+ <li>The CSS has caused the background to go green, and the text to become bigger. It has also styled some of the content that the JavaScript has added to the page (the red bar with the black border is the styling the CSS has added to the JS-generated list.)</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: If you get stuck in this exercise and can't get the CSS/JS to apply, try checking out our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/css-and-js.html">css-and-js.html</a> example page.</p>
+</div>
+
+<h2 id="預設文件語言">預設文件語言</h2>
+
+<p>Finally, it's worth mentioning that you can (and really should) set the language of your page. This can be done by adding the <a href="/en-US/docs/Web/HTML/Global_attributes/lang">lang attribute</a> to the opening HTML tag (as seen in the <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a> and shown below.)</p>
+
+<pre class="brush: html">&lt;html lang="en-US"&gt;</pre>
+
+<p>This is useful in many ways. Your HTML document will be indexed more effectively by search engines if its language is set (allowing it to appear correctly in language-specific results, for example), and it is useful to people with visual impairments using screen readers (for example, the word "six" exists in both French and English, but is pronounced differently.)</p>
+
+<p>You can also set subsections of your document to be recognised as different languages. For example, we could set our Japanese language section to be recognised as Japanese, like so:</p>
+
+<pre class="brush: html">&lt;p&gt;Japanese example: &lt;span lang="jp"&gt;ご飯が熱い。&lt;/span&gt;.&lt;/p&gt;</pre>
+
+<p>These codes are defined by the <a href="https://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a> standard. You can find more about them in <a href="https://www.w3.org/International/articles/language-tags/">Language tags in HTML and XML</a>.</p>
+
+<h2 id="總結">總結</h2>
+
+<p>That marks the end of our quickfire tour of the HTML head — there's a lot more you can do in here, but an exhaustive tour would be boring and confusing at this stage, and we just wanted to give you an idea of the most common things you'll find in there for now! In the next article we'll be looking at HTML text fundamentals.</p>
+
+<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</p>
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/html中的圖片/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/html中的圖片/index.html
new file mode 100644
index 0000000000..5a2dfd7eff
--- /dev/null
+++ b/files/zh-tw/learn/html/multimedia_and_embedding/html中的圖片/index.html
@@ -0,0 +1,502 @@
+---
+title: HTML中的圖片
+slug: Learn/HTML/Multimedia_and_embedding/HTML中的圖片
+translation_of: Learn/HTML/Multimedia_and_embedding/Images_in_HTML
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</div>
+
+<p class="summary">最初的網頁最初的發展階段,只是文字。而只有文字想當然爾令網頁讀起來十分的枯燥乏味。然而幸運的是沒有多久,將圖片(以及其他更有趣的內容類型)嵌入網頁的功能就誕生了。 在多媒體嵌入網頁的學習中,從<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img" title="The HTML &lt;img> element embeds an image into the document."><code>&lt;img&gt;</code></a>元素開始是相對適當,因為該元素用於在網頁中嵌入簡單的圖像。 在本文中,我們將研究如何深入使用它,包括在網頁中嵌入簡單圖像的基礎知識,使用&lt;figure&gt;增加標題說明以做註釋,以及詳細說明它與CSS背景圖片的關係。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">課成需求:</th>
+ <td>基本的電腦操作, <a href="/en-US/docs/">安裝軟體的能力</a>, <a href="/en-US/docs/">處理檔案的基本能力</a>, 熟悉最基本的HTML的 (<a href="/en-US/docs/">如HTML入門中所述</a>)</td>
+ </tr>
+ <tr>
+ <th scope="row">學習目標:</th>
+ <td>了解如何在HTML中嵌入簡單的圖片,為它們加上標題註釋,以及HTML圖片與CSS背景圖片之間的關係。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="如何將圖片放入網頁中">如何將圖片放入網頁中?</h2>
+
+<p>為了在網頁上放置一個簡單的圖像,我們使用&lt;img&gt;元素。 這是一個空元素(意味著它沒有文本內容或結束標記),並需要至少一個屬性(src)(有時稱為其完整標題,source)才有用。 src屬性包含指向要嵌入頁面的圖像的路徑,該路徑可以是相對路徑或絕對路徑URL,與&lt;a&gt;元素中的href屬性相同。</p>
+
+<div class="note">
+<p><strong>提醒</strong>: 在繼續之前,您應該閱讀有關URL和路徑的快速入門,以複習<a href="/en-US/docs/https://developer.mozilla.org/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#A_quick_primer_on_URLs_and_paths">相對路徑和絕對路徑URL</a>。</p>
+</div>
+
+<p>舉例來說, 如果您的圖片名為 dinosaur.jpg 且與HTML檔案位於同一資料夾中,可以這樣嵌入圖片:</p>
+
+<pre class="brush: html notranslate">&lt;img src="dinosaur.jpg"&gt;</pre>
+
+<p>如果圖片位於名為images的資料夾中,且該目錄與HTML頁面位於同一資料夾(Google建議這樣的編排,以利於SEO /索引目的),則應將其嵌入如下:</p>
+
+<pre class="brush: html notranslate">&lt;img src="images/dinosaur.jpg"&gt;</pre>
+
+<p>像這樣.</p>
+
+<div class="note">
+<p><strong>提醒</strong>: 搜索引擎還會讀取圖片名稱,並將其納入SEO中。 因此您應該為圖片提供一個描述性的檔名。 例如 dinosaur.jpg 的命名方式會比 img835.png 更好。</p>
+</div>
+
+<p>你也可以用絕對路徑URL來嵌入圖片,例如</p>
+
+<pre class="brush: html notranslate">&lt;img src="https://www.example.com/images/dinosaur.jpg"&gt;</pre>
+
+<p>但這麼做是沒有意義的,因為它只會使瀏覽器執行更多工作,瀏覽器需重複執行從DNS服務器中搜尋IP地址等等工作。您應將網站上的圖片與HTML存放在同一個伺服器上。</p>
+
+<div class="warning">
+<p><strong>注意:</strong> 大多數圖像均受版權保護。 請勿在你的網站上隨意顯示圖片,除非:</p>
+
+<ul>
+ <li>你是圖片的擁有者.</li>
+ <li>您已收到圖片所有者的白紙黑字認可。</li>
+ <li>您有充分的證據證明該圖片實際上是大家皆能使用。</li>
+</ul>
+
+<p>侵犯版權是違法及不道德的。 此外,切勿將src屬性指向您未被授權的他人網站上的圖便。 這稱為“熱連結”。再次重申,竊取某人的頻寬是違法的,且這會減慢您網站的速度。此外當別人變更、移除或換上令人尷尬的內容時你將無法做出改變。</p>
+</div>
+
+<p>我們上面的程式碼將有以下結果:</p>
+
+<p><img alt='A basic image of a dinosaur, embedded in a browser, with "Images in HTML" written above it' src="https://mdn.mozillademos.org/files/12700/basic-image.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p>
+
+<div class="note">
+<p><strong>提醒</strong>: &lt;img&gt;和&lt;video&gt;之類的元素有時也稱為替換元素。 這是因為元素的內容和圖片大小是由外部(例如圖片或影音檔)所定義的,而不是由元素的內容定義。</p>
+</div>
+
+<div class="note">
+<p><strong>提醒</strong>: 您可以從在<a href="/zh-TW/docs/https://mdn.github.io/learning-area/html/multimedia-and-embedding/images-in-html/index.html">Github</a>上找到本節完成的示例(參見<a href="/zh-TW/docs/https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/images-in-html/index.html">開源碼</a>。)</p>
+</div>
+
+<h3 id="替代性文字">替代性文字</h3>
+
+<p>我們下一個要看的屬性是alt。 它的功能算是圖片的文字描述,應用於因網路連接速度慢而無法看到/顯示圖片或需要長時間來跑圖等等情況。 例如,上面的程式碼我們可以像這樣修改:</p>
+
+<pre class="brush: html notranslate">&lt;img src="images/dinosaur.jpg"
+ alt="The head and torso of a dinosaur skeleton;
+ it has a large head with long sharp teeth"&gt;</pre>
+
+<p>測試替代文字最簡單方法是故意拼錯檔名。 例如,如果我們的圖片名稱為dinosooooor.jpg,則瀏覽器將不會顯示該圖片,而是顯示alt文本:<img alt="The Images in HTML title, but this time the dinosaur image is not displayed, and alt text is in its place." src="https://mdn.mozillademos.org/files/12702/alt-text.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p>
+
+<p>那麼,為什麼您會看到或需要替代文字? 它可以派上用場的原因有很多:</p>
+
+<ul>
+ <li>使用者視力不佳,正在使用<a href="https://zh.wikipedia.org/wiki/%E8%9E%A2%E5%B9%95%E9%96%B1%E8%AE%80%E5%99%A8">螢幕閱讀器</a>向他們朗讀網頁。 實際上,對於大多數使用者而言,擁有可用於描述圖像的替代文字是很有用的。</li>
+ <li>如上所述,文件或路徑名的拼寫可能不正確。</li>
+ <li>瀏覽器不支持圖像類型。 有些人仍然使用純文字瀏覽器,例如<a href="https://zh.wikipedia.org/wiki/Lynx">Lynx</a>,它可顯示圖片的替代文字。</li>
+ <li>您可能希望提供文字供搜索引擎使用; 例如,搜索引擎可以將替代文字與搜索查詢匹配。</li>
+ <li>使用者已關閉圖像以減少數據傳輸量和干擾。 這在手機以及網路頻寬有限或成本昂貴的國家中尤其常見。</li>
+</ul>
+
+<p>您應該在<code>alt</code>屬性中確切寫些什麼? 這取決於圖片為何而出現;也就是說,如果圖片不顯示,您將損失什麼:</p>
+
+<ul>
+ <li><strong>裝飾: </strong>你可以用 {{anch("CSS_背景圖片")}} 加入裝飾圖片,但如果必須使用HTML,可以添加一個空的 <code>alt=""</code>。如果圖片不是內容的一部分,那麼就不應該讓螢幕閱讀器浪費時間去閱讀它。</li>
+ <li><strong>內容: </strong>如果您的圖片提供了重要的資訊,請在簡短的<code>alt</code>文字中提供相同的資訊,甚至最好在所有人都能看到的主要文字中提供相同的資訊。請不要撰寫冗餘替代文字,試想如果所有段落都在主要內容中寫了兩次,對於用視力觀看的使用者有多煩人。如果圖像在正文中已充分敘述,請使用 <code>alt=""</code>。</li>
+ <li><strong>連結:</strong> 如果你在{{htmlelement("a")}} 標籤中放了圖片使其轉入連結,你仍應該提供<a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#%E4%BD%BF%E7%94%A8%E6%98%8E%E7%A2%BA%E7%9A%84%E5%AD%97%E8%A9%9E">明確的字詞</a>。在这种情况下,您可以根據適合你的情況,将其写在相同的<code>&lt;a&gt;</code>元素内,或是写在图像的<code>alt</code> 属性内。</li>
+ <li><strong>文字:</strong> 請不要在圖片中寫字。如果你的主要目的是為標題加上下拉式陰影,你可以<a href="/en-US/docs/Web/CSS/text-shadow">使用CSS</a>更甚於在圖片中描繪文字。 但如果你無法避免這麼做,也請將文字敘述加在<code>alt</code> 属性内。</li>
+</ul>
+
+<p>本質上,關鍵是即使在看不見圖片的情況下也能提供相同的體驗。這樣可以確保所有使用者都不會丟失任何內容。嘗試在瀏覽器中關閉圖像,然後查看外觀。您很快就會意識到,如果看不到圖片,替代文字會很有幫助。</p>
+
+<div class="note">
+<p><strong>Note</strong>: For more information, see our guide to <a href="/en-US/docs/Learn/Accessibility/HTML#Text_alternatives">Text Alternatives</a>.</p>
+</div>
+
+<h3 id="寬與高">寬與高</h3>
+
+<p>You can use the <code>width</code> and <code>height</code> attributes to specify the width and height of your image. You can find your image's width and height in a number of ways. For example on the Mac you can use <kbd>Cmd</kbd> + <kbd>I</kbd> to get the info display up for the image file. Returning to our example, we could do this:</p>
+
+<pre class="brush: html notranslate">&lt;img src="images/dinosaur.jpg"
+ alt="The head and torso of a dinosaur skeleton;
+ it has a large head with long sharp teeth"
+ width="400"
+ height="341"&gt;</pre>
+
+<p>This doesn't result in much difference to the display, under normal circumstances. But if the image isn't being displayed, for example, the user has just navigated to the page, and the image hasn't yet loaded, you'll notice the browser is leaving a space for the image to appear in:</p>
+
+<p><img alt="The Images in HTML title, with dinosaur alt text, displayed inside a large box that results from width and height settings" src="https://mdn.mozillademos.org/files/12706/alt-text-with-width-height.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p>
+
+<p>This is a good thing to do, resulting in the page loading quicker and more smoothly.</p>
+
+<p>However, you shouldn't alter the size of your images using HTML attributes. If you set the image size too big, you'll end up with images that look grainy, fuzzy, or too small, and wasting bandwidth downloading an image that is not fitting the user's needs. The image may also end up looking distorted, if you don't maintain the correct <a href="https://en.wikipedia.org/wiki/Aspect_ratio_%28image%29">aspect ratio</a>. You should use an image editor to put your image at the correct size before putting it on your webpage.</p>
+
+<div class="note">
+<p><strong>Note</strong>: If you do need to alter an image's size, you should use <a href="/en-US/docs/Learn/CSS">CSS</a> instead.</p>
+</div>
+
+<h3 id="圖片標題">圖片標題</h3>
+
+<p>As <a href="https://developer.mozilla.org/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Adding_supporting_information_with_%3Ctitle%3E">with links</a>, you can also add <code>title</code> attributes to images, to provide further supporting information if needed. In our example, we could do this:</p>
+
+<pre class="brush: html notranslate">&lt;img src="images/dinosaur.jpg"
+ alt="The head and torso of a dinosaur skeleton;
+ it has a large head with long sharp teeth"
+ width="400"
+ height="341"
+ title="A T-Rex on display in the Manchester University Museum"&gt;</pre>
+
+<p>This gives us a tooltip on mouse hover, just like link titles:</p>
+
+<p><img alt="The dinosaur image, with a tooltip title on top of it that reads A T-Rex on display at the Manchester University Museum " src="https://mdn.mozillademos.org/files/12708/image-with-title.png" style="display: block; height: 341px; margin: 0px auto; width: 400px;"></p>
+
+<p>However, this does not come recommended — <code>title</code> has a number of accessibility problems, mainly based around the fact that screen reader support is very unpredictable and most browsers won't show it unless you are hovering with a mouse (so e.g. no access to keyboard users). If you are interested in more information about this, read <a href="https://www.24a11y.com/2017/the-trials-and-tribulations-of-the-title-attribute/">The Trials and Tribulations of the Title Attribute</a> by Scott O'Hara.</p>
+
+<p>It is better to include such supporting information in the main article text, rather than attached to the image.</p>
+
+<h3 id="實戰練習:嵌入圖片">實戰練習:嵌入圖片</h3>
+
+<p>It is now your turn to play! This active learning section will have you up and running with a simple embedding exercise. You are provided with a basic {{htmlelement("img")}} tag; we'd like you to embed the image located at the following URL:</p>
+
+<p>https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg</p>
+
+<p>Earlier we said to never hotlink to images on other servers, but this is just for learning purposes, so we'll let you off this one time.</p>
+
+<p>We would also like you to:</p>
+
+<ul>
+ <li>Add some alt text, and check that it works by misspelling the image URL.</li>
+ <li>Set the image's correct <code>width</code> and <code>height</code> (hint: it is 200px wide and 171px high), then experiment with other values to see what the effect is.</li>
+ <li>Set a <code>title</code> on the image.</li>
+</ul>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see an answer:</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 100px; width: 95%"&gt;
+&lt;img&gt;
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171"\n title="A T-Rex on display in the Manchester University Museum"&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', 700, 350, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="用圖文和圖文標註說明圖像">用圖文和圖文標註說明圖像</h2>
+
+<p>Speaking of captions, there are a number of ways that you could add a caption to go with your image. For example, there would be nothing to stop you from doing this:</p>
+
+<pre class="brush: html notranslate">&lt;div class="figure"&gt;
+ &lt;img src="images/dinosaur.jpg"
+ alt="The head and torso of a dinosaur skeleton;
+ it has a large head with long sharp teeth"
+ width="400"
+ height="341"&gt;
+
+ &lt;p&gt;A T-Rex on display in the Manchester University Museum.&lt;/p&gt;
+&lt;/div&gt;</pre>
+
+<p>This is ok. It contains the content you need, and is nicely stylable using CSS. But there is a problem here: there is nothing that semantically links the image to its caption, which can cause problems for screen readers. For example, when you have 50 images and captions, which caption goes with which image?</p>
+
+<p>A better solution, is to use the HTML5 {{htmlelement("figure")}} and {{htmlelement("figcaption")}} elements. These are created for exactly this purpose: to provide a semantic container for figures, and to clearly link the figure to the caption. Our above example could be rewritten like this:</p>
+
+<pre class="notranslate">&lt;figure&gt;
+ &lt;img src="images/dinosaur.jpg"
+ alt="The head and torso of a dinosaur skeleton;
+ it has a large head with long sharp teeth"
+ width="400"
+ height="341"&gt;
+
+ &lt;figcaption&gt;A T-Rex on display in the Manchester University Museum.&lt;/figcaption&gt;
+&lt;/figure&gt;</pre>
+
+<p>The {{htmlelement("figcaption")}} element tells browsers, and assistive technology that the caption describes the other content of the {{htmlelement("figure")}} element.</p>
+
+<div class="note">
+<p><strong>Note</strong>: From an accessibility viewpoint, captions and {{htmlattrxref('alt','img')}} text have distinct roles. Captions benefit even people who can see the image, whereas {{htmlattrxref('alt','img')}} text provides the same functionality as an absent image. Therefore, captions and <code>alt</code> text shouldn't just say the same thing, because they both appear when the image is gone. Try turning images off in your browser and see how it looks.</p>
+</div>
+
+<p>A figure doesn't have to be an image. It is an independent unit of content that:</p>
+
+<ul>
+ <li>Expresses your meaning in a compact, easy-to-grasp way.</li>
+ <li>Could go in several places in the page's linear flow.</li>
+ <li>Provides essential information supporting the main text.</li>
+</ul>
+
+<p>A figure could be several images, a code snippet, audio, video, equations, a table, or something else.</p>
+
+<h3 id="實戰練習:建立圖文標註">實戰練習:建立圖文標註</h3>
+
+<p>In this active learning section, we'd like you to take the finished code from the previous active learning section, and turn it into a figure:</p>
+
+<ol>
+ <li>Wrap it in a {{htmlelement("figure")}} element.</li>
+ <li>Copy the text out of the <code>title</code> attribute, remove the <code>title</code> attribute, and put the text inside a {{htmlelement("figcaption")}} element below the image.</li>
+</ol>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see an answer:</p>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code 2</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 50px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="min-height: 100px; width: 95%"&gt;
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var output = document.querySelector('.output');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var htmlSolution = '&lt;figure&gt;\n &lt;img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171"&gt;\n &lt;figcaption&gt;A T-Rex on display in the Manchester University Museum&lt;/figcaption&gt;\n&lt;/figure&gt;';
+var solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', 700, 350, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="CSS_背景圖片">CSS 背景圖片</h2>
+
+<p>您還可以使用CSS將圖像嵌入網頁(JavaScript也可以,但這完全是另一回事了)。 CSS<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image" title="The background-image CSS property sets one or more background images on an element."><code>background-image</code></a>屬性和其他background- *屬性用於控制背景圖片的放置。 例如要將背景圖片放置在頁面的每個段落上,可以執行以下操作:</p>
+
+<pre class="brush: css notranslate">p {
+ background-image: url("images/dinosaur.jpg");
+}</pre>
+
+<p>這種嵌入圖片的方式比HTML圖像更容易定位和控制。 那麼,為什麼還要用HTML嵌入圖片呢? 如上所述,CSS背景圖像僅用於裝飾。 如果您只是想在頁面上添加一些漂亮的東西以增強視覺效果,那很好。 但是,此類圖像根本沒有語義。 它們與文字不同,對於螢幕閱讀器是不可見的,依此類推。 這裡需要的是HTML圖片!</p>
+
+<p>總結來說,如果圖片在內容上具有含義,則應使用HTML圖像。 如果圖像純粹是裝飾性的,則應使用CSS背景圖片。</p>
+
+<div class="note">
+<p><strong>提醒</strong>: 在我們的CSS主題中,您將學到更多關於CSS背景圖片的知識。</p>
+</div>
+
+<h2 id="試試看!">試試看!</h2>
+
+<p>您已經來到了本文的末端,但是您還記得最重要的內容嗎? 在繼續往下之前,這裡有些測驗讓您驗證看看您是否都學會了 — <a href="/zh-TW/docs/https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML/Test_your_skills:_HTML_images">測驗:HTML圖像</a>。</p>
+
+<h2 id="總結">總結</h2>
+
+<p>目前就是這樣啦。 我們已經詳細介紹了圖片和標題說明。 在下一篇文章中我們將進一步介紹,如何使用HTML將視頻和音頻嵌入在網頁中。</p>
+
+<p>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</p>
+
+<h2 id="在這個主題中">在這個主題中</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From &lt;object&gt; to &lt;iframe&gt; — other embedding technologies</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/index.html
new file mode 100644
index 0000000000..05d98a462b
--- /dev/null
+++ b/files/zh-tw/learn/html/multimedia_and_embedding/index.html
@@ -0,0 +1,53 @@
+---
+title: Multimedia and Embedding
+slug: Learn/HTML/Multimedia_and_embedding
+translation_of: Learn/HTML/Multimedia_and_embedding
+---
+<p>{{LearnSidebar}}</p>
+
+<p class="summary">到目前為止,我們已經看到了很多文字,但是只使用文字讓人感到無聊。讓我們開始研究如何透過更有趣的內容讓網絡變得活躍起來!本單元探討如何使用HTML在您的網頁中包增加媒體,包括可以嵌入圖像的不同方式,以及如何嵌入影片,音訊甚至整個網頁。</p>
+
+<h2 id="預備知識">預備知識</h2>
+
+<p>在此單元開始之前,我們假設你對HTML基礎知識 (如<a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML介紹</a>) 已經有一定的了解,如果還沒有,建議您先預習該部分再回來。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 如果你所操作的電腦、平板或裝置環境不允許你建立自己的檔案,你可以在諸如 <a href="https://jsbin.com/">JSBin</a> 或<a href="https://thimble.mozilla.org/">Thimble</a> 這樣的網站上嘗試(多數的)範例程式碼。</p>
+</div>
+
+<h2 id="導覽">導覽</h2>
+
+<p>本單元包含以下章節,它們將帶您了解在網頁上嵌入多媒體的所有基礎知識。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">HTML中的圖片</a></dt>
+ <dd>可以考慮到的多媒體種類很多,但是從用以將簡單圖像嵌入網頁中不起眼的{{htmlelement(" img")}}元素開始是很合乎邏輯的。在本文中,我們將研究如何更深入地使用它,包括基礎知識,使用{{htmlelement("figure")}}加上標題的註釋以及它與CSS背景圖像的關係。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">視訊與音訊內容</a></dt>
+ <dd>接著,我們將研究如何使用HTML5 {{htmlelement("video")}}和{{htmlelement("audio")}} 元素在頁面上嵌入視訊和音訊,包括基本知識,以提供對不同頁面的訪問文件格式添加到不同的瀏覽器,添加標題和字幕,以及如何為舊版瀏覽器添加後備廣告。</dd>
+ <dt><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies" rel="nofollow">從物件到 iframe — 其他嵌入技巧</a></dt>
+ <dd>在這裡,我們想橫跨一步,著眼於幾個元素,這些元素可以使您將各種內容類型嵌入到網頁中:{{htmlelement("iframe")}},{{htmlelement("embed")}}和 {{htmlelement("object")}}元素。 &lt;iframe&gt;用於嵌入其他網頁,另外兩個允許您嵌入PDF,SVG甚至Flash(一種即將消逝的技術,但您可能仍會定期看到它)。</dd>
+ <dt><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web" rel="nofollow">為 Web 新增向量圖</a></dt>
+ <dd>向量圖形在某些情況下可能非常有用。 與PNG / JPG等常見格式不同,它們在放大時不會失真/像素化-在縮放時可以保持平滑。 本文向您介紹什麼是向量圖,以及如何在網頁中加入流行的{{glossary("SVG")}}格式。</dd>
+ <dt><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images" rel="nofollow">適應性圖片</a></dt>
+ <dd>在本文中,我們將學習適應性圖片 (又稱響應式圖片)的概念。適應性圖片在不同螢幕尺寸,解析度和其他類似功能差異很大的設備上都能很好地運作。我們還會研究HTML提供了哪些工具來幫助實現它們。 這有助於提高不同設備之間的性能。 響應式圖片只是響應式設計的一部分,在將來您學習CSS的單元中還會有響應式圖片的單元。</dd>
+</dl>
+
+<h2 id="評量">評量</h2>
+
+<p>以下評量中將測試您對以上指南中介紹的HTML基礎的理解:</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla 啟動頁面</a></dt>
+ <dd>在此測驗中,我們將測試您對本區塊文章中討論的一些技術的了解,使您能夠向時髦的啟動頁面添加有關Mozilla的一些圖片和視訊!</dd>
+</dl>
+
+<h2 id="另見">另見</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">增加點擊映射到圖片上層</a></dt>
+ <dd>圖像映射提供了一種機制,可以使圖像的不同部分鏈接到不同的位置。(請試想在地圖上點擊每個不同國家/地區以取得更多資訊)此技術有時很有用。</dd>
+ <dt><a href="https://teach.mozilla.org/activities/web-lit-basics-two/">網頁知識基礎2</a></dt>
+ <dd>
+ <p>一個出色的Mozilla基礎課程,探索和測試此多媒體和嵌入單元中討論的一些技能。 深入研究網頁組成,可訪問性設計,共享資源,使用線上媒體和開放性工作的基礎知識(這意味著您的內容可以免費獲得併可以由他人共享)。</p>
+ </dd>
+</dl>
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html
new file mode 100644
index 0000000000..aa4de14fe3
--- /dev/null
+++ b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/index.html
@@ -0,0 +1,339 @@
+---
+title: Video and audio content
+slug: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content
+tags:
+ - Article
+ - Audio
+ - Beginner
+ - Guide
+ - HTML
+ - NeedsTranslation
+ - TopicStub
+ - Video
+ - captions
+ - subtitles
+ - track
+translation_of: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</div>
+
+<p class="summary"><span class="seoSummary">Now that we are comfortable with adding simple images to a webpage, the next step is to start adding video and audio players to your HTML documents! In this article we'll look at doing just that with the {{htmlelement("video")}} and {{htmlelement("audio")}} elements; we'll then finish off by looking at how to add captions/subtitles to your videos.</span></p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, familiarity with HTML fundamentals (as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>) and <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To learn how to embed video and audio content into a webpage, and add captions/subtitles to video.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Video_and_audio_on_the_web">Video and audio on the web</h2>
+
+<p>Web developers have wanted to use video and audio on the Web for a long time, ever since the early 2000s when we started to have bandwidth fast enough to support any kind of video (video files are much larger than text or even images.) In the early days, native web technologies such as HTML didn't have the ability to embed video and audio on the Web, so proprietary (or plugin-based) technologies like <a href="https://en.wikipedia.org/wiki/Adobe_Flash">Flash</a> (and later, <a href="https://en.wikipedia.org/wiki/Microsoft_Silverlight">Silverlight</a>) became popular for handling such content. This kind of technology worked ok, but it had a number of problems, including not working well with HTML/CSS features, security issues, and accessibility issues.</p>
+
+<p>A native solution would solve much of this if implemented correctly. Fortunately, a few years later the {{glossary("HTML5")}} specification had such features added, with the {{htmlelement("video")}} and {{htmlelement("audio")}} elements, and some shiny new {{Glossary("JavaScript")}} {{Glossary("API","APIs")}} for controlling them. We'll not be looking at JavaScript here — just the basic foundations that can be achieved with HTML.</p>
+
+<p>We won't be teaching you how to produce audio and video files — that requires a completely different skillset. We have provided you with <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/video-and-audio-content">sample audio and video files and example code</a> for your own experimentation, in case you are unable to get hold of your own.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Before you begin here, you should also know that there are quite a few OVPs (online video providers) like <a href="https://www.youtube.com/">YouTube</a>, <a href="https://www.dailymotion.com">Dailymotion</a>, and <a href="https://vimeo.com/">Vimeo</a>, and online audio providers like <a href="https://soundcloud.com/">Soundcloud</a>. Such companies offer a convenient, easy way to host and consume videos, so you don't have to worry about the enormous bandwidth consumption. OVPs even usually offer ready-made code for embedding video/audio in your webpages; if you use that route, you can avoid some of the difficulties we discuss in this article. We'll be discussing this kind of service a bit more in the next article.</p>
+</div>
+
+<h3 id="The_&lt;video>_element">The &lt;video&gt; element</h3>
+
+<p>The {{htmlelement("video")}} element allows you to embed a video very easily. A really simple example looks like this:</p>
+
+<pre class="brush: html notranslate">&lt;video src="rabbit320.webm" controls&gt;
+ &lt;p&gt;Your browser doesn't support HTML5 video. Here is a &lt;a href="rabbit320.webm"&gt;link to the video&lt;/a&gt; instead.&lt;/p&gt;
+&lt;/video&gt;</pre>
+
+<p>The features of note are:</p>
+
+<dl>
+ <dt>{{htmlattrxref("src","video")}}</dt>
+ <dd>In the same way as for the {{htmlelement("img")}} element, the <code>src</code> (source) attribute contains a path to the video you want to embed. It works in exactly the same way.</dd>
+ <dt>{{htmlattrxref("controls","video")}}</dt>
+ <dd>Users must be able to control video and audio playback (it's especially critical for people who have <a href="https://en.wikipedia.org/wiki/Epilepsy#Epidemiology">epilepsy</a>.) You must either use the <code>controls</code> attribute to include the browser's own control interface, or build your interface using the appropriate <a href="/en-US/docs/Web/API/HTMLMediaElement">JavaScript API</a>. At a minimum, the interface must include a way to start and stop the media, and to adjust the volume.</dd>
+ <dt>The paragraph inside the <code>&lt;video&gt;</code> tags</dt>
+ <dd>This is called <strong>fallback content</strong> — this will be displayed if the browser accessing the page doesn't support the <code>&lt;video&gt;</code> element, allowing us to provide a fallback for older browsers. This can be anything you like; in this case, we've provided a direct link to the video file, so the user can at least access it some way regardless of what browser they are using.</dd>
+</dl>
+
+<p>The embedded video will look something like this:</p>
+
+<p><img alt="A simple video player showing a video of a small white rabbit" src="https://mdn.mozillademos.org/files/12794/simple-video.png" style="display: block; height: 592px; margin: 0px auto; width: 589px;"></p>
+
+<p>You can <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">try the example live</a> here (see also the <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">source code</a>.)</p>
+
+<h3 id="Using_multiple_source_formats_to_improve_compatibility">Using multiple source formats to improve compatibility</h3>
+
+<p>There's a problem with the above example, which you may have noticed already if you've tried to access the live link above with an older browser like Internet Explorer or even an older version of Safari. The video won't play, because different browsers support different video (and audio) formats. Fortunately, there are things you can do to help prevent this from being a problem.</p>
+
+<h4 id="Contents_of_a_media_file">Contents of a media file</h4>
+
+<p>First, let's go through the terminology quickly. Formats like MP3, MP4 and WebM are called <strong><a href="/en-US/docs/Web/Media/Formats/Containers">container formats</a></strong>. They define a structure in which the audio and/or video tracks that make up the media are stored, along with metadata describing the media, what codecs are used to encode its channels, and so forth.</p>
+
+<p>A WebM file containing a movie which has a main video track and one alternate angle track, plus audio for both English and Spanish, in addition to audio for an English commentary track can be conceptualized as shown in the diagram below. Also included are text tracks containing closed captions for the feature film, Spanish subtitles for the film, and English captions for the commentary.</p>
+
+<p><a href="https://mdn.mozillademos.org/files/16898/ContainersAndTracks.svg"><img alt="Diagram conceptualizing the contents of a media file at the track level." src="https://mdn.mozillademos.org/files/16898/ContainersAndTracks.svg" style="height: 472px; width: 640px;"></a></p>
+
+<p>The audio and video tracks within the container hold data in the appropriate format for the codec used to encode that media. Different formats are used for audio tracks versus video tracks. Each audio track is encoded using an <a href="/en-US/docs/Web/Media/Formats/Audio_codecs">audio codec</a>, while video tracks are encoded using (as you probably have guessed) <a href="/en-US/docs/Web/Media/Formats/Video_codecs">a video codec</a>. As we talked about before, different browsers support different video and audio formats, and different container formats (like MP3, MP4, and WebM, which in turn can contain different types of video and audio).</p>
+
+<p>For example:</p>
+
+<ul>
+ <li>A WebM container typically packages Vorbis or Opus audio with VP8/VP9 video. This is supported in all modern browsers, though older versions may not work.</li>
+ <li>An MP4 container often packages AAC or MP3 audio with H.264 video. This is also supported in all modern browsers, as well as Internet Explorer.</li>
+ <li>The Ogg container tends to use Vorbis audio and Theora video. This is best supported in Firefox and Chrome, but has basically been superseded by the better quality WebM format.</li>
+</ul>
+
+<p>There are some special cases. For example, for some types of audio, a codec's data is often stored without a container, or with a simplified container. One such instance is the FLAC codec, which is stored most commonly in FLAC files, which are just raw FLAC tracks.</p>
+
+<p>Another such situation is the always-popular MP3 file. An "MP3 file" is actually an MPEG-1 Audio Layer III (MP3) audio track stored within an MPEG or MPEG-2 container. This is especially interesting since while most browsers don't support using MPEG media in the {{HTMLElement("video")}} and {{HTMLElement("audio")}} elements, they may still support MP3 due to its popularity.</p>
+
+<p>An audio player will tend to play an audio track directly, e.g. an MP3 or Ogg file. These don't need containers.</p>
+
+<h4 id="Media_file_support_in_browsers">Media file support in browsers</h4>
+
+<div class="callout-box">
+<p>Why do we have this problem? It turns out that several popular formats, such as MP3 and MP4/H.264, are excellent but are encumbered by patents; that is, there are patents covering some or all of the technology that they're based upon. In the United States, patents covered MP3 until 2017, and H.264 is encumbered by patents through at least 2027.</p>
+
+<p>Because of those patents, browsers that wish to implement support for those codecs must pay typically enormous license fees. In addition, some people simply prefer to avoid restricted software and prefer to use only open formats. Due to these legal and preferential reasons, web developers find themselves having to support multiple formats to capture their entire audience.</p>
+</div>
+
+<p>The codecs described in the previous section exist to compress video and audio into manageable files, since raw audio and video are both exceedingly large. Each web browser supports an assortment of <strong>{{Glossary("Codec","codecs")}}</strong>, like Vorbis or H.264, which are used to convert the compressed audio and video into binary data and back. Each codec offers its own advantages and drawbacks, and each container may also offer its own positive and negative features affecting your decisions about which to use.</p>
+
+<p>Things become slightly more complicated because not only does each browser support a different set of container file formats, they also each support a different selection of codecs. In order to maximize the likelihood that your web site or app will work on a user's browser, you may need to provide each media file you use in multiple formats. If your site and the user's browser don't share a media format in common, your media simply won't play.</p>
+
+<p>Due to the intricacies of ensuring your app's media is viewable across every combination of browsers, platforms, and devices you wish to reach, choosing the best combination of codecs and container can be a complicated task. See {{SectionOnPage("/en-US/docs/Web/Media/Formats/Containers", "Choosing the right container")}} for help selecting the container file format best suited for your needs; similarly, see {{SectionOnPage("/en-US/docs/Web/Media/Formats/Video_codecs", "Choosing a video codec")}} and {{SectionOnPage("/en-US/docs/Web/Media/Formats/Audio_codecs", "Choosing an audio codec")}} for help selecting the first media codecs to use for your content and your target audience.</p>
+
+<p>One additional thing to keep in mind: mobile browsers may support additional formats not supported by their desktop equivalents, just like they may not support all the same formats the desktop version does. On top of that, both desktop and mobile browsers <em>may</em> be designed to offload handling of media playback (either for all media or only for specific types it can't handle internally). This means media support is partly dependent on what software the user has installed.</p>
+
+<p>So how do we do this? Take a look at the following <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">updated example</a> (<a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">try it live here</a>, also):</p>
+
+<pre class="brush: html notranslate">&lt;video controls&gt;
+ &lt;source src="rabbit320.mp4" type="video/mp4"&gt;
+ &lt;source src="rabbit320.webm" type="video/webm"&gt;
+ &lt;p&gt;Your browser doesn't support HTML5 video. Here is a &lt;a href="rabbit320.mp4"&gt;link to the video&lt;/a&gt; instead.&lt;/p&gt;
+&lt;/video&gt;</pre>
+
+<p>Here we've taken the <code>src</code> attribute out of the actual {{HTMLElement("video")}} tag, and instead included separate {{htmlelement("source")}} elements that point to their own sources. In this case the browser will go through the {{HTMLElement("source")}} elements and play the first one that it has the codec to support. Including WebM and MP4 sources should be enough to play your video on most platforms and browsers these days.</p>
+
+<p>Each <code>&lt;source&gt;</code> element also has a {{htmlattrxref("type", "source")}} attribute. This is optional, but it is advised that you include it. The <code>type</code> attribute contains the {{glossary("MIME type")}} of the file specified by the <code>&lt;source&gt;</code>, and browsers can use the <code>type</code> to immediately skip videos they don't understand. If<code>type</code> isn't included, browsers will load and try to play each file until they find one that works, which obviously takes time and is an unnecessary use of resources.</p>
+
+<p>Refer to our <a href="/en-US/docs/Web/Media/Formats">guide to media types and formats</a> for help selecting the best containers and codecs for your needs, as well as to look up the right MIME types to specify for each.</p>
+
+<h3 id="Other_&lt;video>_features">Other &lt;video&gt; features</h3>
+
+<p>There are a number of other features you can include when displaying an HTML video. Take a look at our next example:</p>
+
+<pre class="brush: html notranslate">&lt;video controls width="400" height="400"
+ autoplay loop muted preload="auto"
+ poster="poster.png"&gt;
+ &lt;source src="rabbit320.mp4" type="video/mp4"&gt;
+ &lt;source src="rabbit320.webm" type="video/webm"&gt;
+ &lt;p&gt;Your browser doesn't support HTML video. Here is a &lt;a href="rabbit320.mp4"&gt;link to the video&lt;/a&gt; instead.&lt;/p&gt;
+&lt;/video&gt;
+</pre>
+
+<p>The resulting UI looks something like this:</p>
+
+<p><img alt="A video player showing a poster image before it plays. The poster image says HTML5 video example, OMG hell yeah!" src="https://mdn.mozillademos.org/files/16949/poster_screenshot_updated.png" style="border-style: solid; border-width: 1px; display: block; height: 470px; margin: 0px auto; width: 413px;"></p>
+
+<p>The new features are:</p>
+
+<dl>
+ <dt>{{htmlattrxref("width","video")}} and {{htmlattrxref("height","video")}}</dt>
+ <dd>You can control the video size either with these attributes or with {{Glossary("CSS")}}. In both cases, videos maintain their native width-height ratio — known as the <strong>aspect ratio</strong>. If the aspect ratio is not maintained by the sizes you set, the video will grow to fill the space horizontally, and the unfilled space will just be given a solid background color by default.</dd>
+ <dt>{{htmlattrxref("autoplay","video")}}</dt>
+ <dd>Makes the audio or video start playing right away, while the rest of the page is loading. You are advised not to use autoplaying video (or audio) on your sites, because users can find it really annoying.</dd>
+ <dt>{{htmlattrxref("loop","video")}}</dt>
+ <dd>Makes the video (or audio) start playing again whenever it finishes. This can also be annoying, so only use if really necessary.</dd>
+ <dt>{{htmlattrxref("muted","video")}}</dt>
+ <dd>Causes the media to play with the sound turned off by default.</dd>
+ <dt>{{htmlattrxref("poster","video")}}</dt>
+ <dd>The URL of an image which will be displayed before the video is played. It is intended to be used for a splash screen or advertising screen.</dd>
+ <dt>{{htmlattrxref("preload","video")}}</dt>
+ <dd>
+ <p>Used for buffering large files; it can take one of three values:</p>
+
+ <ul>
+ <li><code>"none"</code> does not buffer the file</li>
+ <li><code>"auto"</code> buffers the media file</li>
+ <li><code>"metadata"</code> buffers only the metadata for the file</li>
+ </ul>
+ </dd>
+</dl>
+
+<p>You can find the above example available to <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">play live on Github</a> (also <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">see the source code</a>.) Note that we haven't included the <code>autoplay</code> attribute in the live version — if the video starts to play as soon as the page loads, you don't get to see the poster!</p>
+
+<h3 id="The_&lt;audio>_element">The &lt;audio&gt; element</h3>
+
+<p>The {{htmlelement("audio")}} element works just like the {{htmlelement("video")}} element, with a few small differences as outlined below. A typical example might look like so:</p>
+
+<pre class="brush: html notranslate">&lt;audio controls&gt;
+ &lt;source src="viper.mp3" type="audio/mp3"&gt;
+ &lt;source src="viper.ogg" type="audio/ogg"&gt;
+ &lt;p&gt;Your browser doesn't support HTML5 audio. Here is a &lt;a href="viper.mp3"&gt;link to the audio&lt;/a&gt; instead.&lt;/p&gt;
+&lt;/audio&gt;</pre>
+
+<p>This produces something like the following in a browser:</p>
+
+<p><img alt="A simple audio player with a play button, timer, volume control, and progress bar" src="https://mdn.mozillademos.org/files/12798/audio-player.png" style="display: block; height: 413px; margin: 0px auto; width: 626px;"></p>
+
+<div class="note">
+<p><strong>Note</strong>: You can <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">run the audio demo live</a> on Github (also see the <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">audio player source code</a>.)</p>
+</div>
+
+<p>This takes up less space than a video player, as there is no visual component — you just need to display controls to play the audio. Other differences from HTML video are as follows:</p>
+
+<ul>
+ <li>The {{htmlelement("audio")}} element doesn't support the <code>width</code>/<code>height</code> attributes — again, there is no visual component, so there is nothing to assign a width or height to.</li>
+ <li>It also doesn't support the <code>poster</code> attribute — again, no visual component.</li>
+</ul>
+
+<p>Other than this, <code>&lt;audio&gt;</code> supports all the same features as <code>&lt;video&gt;</code> — review the above sections for more information about them.</p>
+
+<h3 id="Restarting_media_playback_requires_JavaScript">Restarting media playback (requires JavaScript)</h3>
+
+<p>At any time, you can reset the media to the beginning—including the process of selecting the best media source, if more than one is specified using {{HTMLElement("source")}} elements—by calling the element's {{domxref("HTMLMediaElement.load", "load()")}} method:</p>
+
+<pre class="brush: js notranslate">const mediaElem = document.getElementById("my-media-element");
+mediaElem.load();</pre>
+
+<h3 id="Detecting_track_addition_and_removal_requires_JavaScript">Detecting track addition and removal (requires JavaScript)</h3>
+
+<p>You can monitor the track lists within a media element to detect when tracks are added to or removed from the element's media. For example, you can watch for the {{event("addtrack")}} event being fired on the associated {{domxref("AudioTrackList")}} object (retrieved via {{domxref("HTMLMediaElement.audioTracks")}}) to be informed when audio tracks are added to the media:</p>
+
+<pre class="brush: js notranslate">const mediaElem = document.querySelector("video");
+mediaElem.audioTracks.onaddtrack = function(event) {
+ audioTrackAdded(event.track);
+}
+</pre>
+
+<p>You'll find more information about this in our {{domxref("TrackEvent")}} documentation.</p>
+
+<h2 id="Displaying_video_text_tracks">Displaying video text tracks</h2>
+
+<p>Now we'll discuss a slightly more advanced concept that is really useful to know about. Many people can't or don't want to hear the audio/video content they find on the Web, at least at certain times. For example:</p>
+
+<ul>
+ <li>Many people have auditory impairments (such as being hard of hearing or deaf) so can't hear the audio clearly if at all.</li>
+ <li>Others may not be able to hear the audio because they are in noisy environments (like a crowded bar when a sports game is being shown).</li>
+ <li>Similarly, in environments where having the audio playing would be a distraction or disruption (such as in a library or when a partner is trying to sleep), having captions can be very useful.</li>
+ <li>People who don't speak the language of the video might want a text transcript or even translation to help them understand the media content.</li>
+</ul>
+
+<p>Wouldn't it be nice to be able to provide these people with a transcript of the words being spoken in the audio/video? Well, thanks to HTML video, you can. To do so we use the <a href="/en-US/docs/Web/API/Web_Video_Text_Tracks_Format">WebVTT</a> file format and the {{htmlelement("track")}} element.</p>
+
+<div class="note">
+<p><strong>Note</strong>: "Transcribe" means "to write down spoken words as text." The resulting text is a "transcript."</p>
+</div>
+
+<p>WebVTT is a format for writing text files containing multiple strings of text along with metadata such as the time in the video at which each text string should be displayed, and even limited styling/positioning information. These text strings are called <strong>cues</strong>, and there are several kinds of cues which are used for different purposes. The most common cues are:</p>
+
+<dl>
+ <dt>subtitles</dt>
+ <dd>Translations of foreign material, for people who don't understand the words spoken in the audio.</dd>
+ <dt>captions</dt>
+ <dd>Synchronized transcriptions of dialog or descriptions of significant sounds, to let people who can't hear the audio understand what is going on.</dd>
+ <dt>timed descriptions</dt>
+ <dd>Text which should be spoken by the media player in order to describe important visuals to blind or otherwise visually impaired users.</dd>
+</dl>
+
+<p>A typical WebVTT file will look something like this:</p>
+
+<pre class="eval line-numbers language-html notranslate"><code class="language-html">WEBVTT
+
+1
+00:00:22.230 --&gt; 00:00:24.606
+This is the first subtitle.
+
+2
+00:00:30.739 --&gt; 00:00:34.074
+This is the second.
+
+ ...</code>
+</pre>
+
+<p>To get this displayed along with the HTML media playback, you need to:</p>
+
+<ol>
+ <li>Save it as a <code>.vtt</code> file in a sensible place.</li>
+ <li>Link to the <code>.vtt</code> file with the {{htmlelement("track")}} element. <code>&lt;track&gt;</code> should be placed within <code>&lt;audio&gt;</code> or <code>&lt;video&gt;</code>, but after all <code>&lt;source&gt;</code> elements. Use the {{htmlattrxref("kind","track")}} attribute to specify whether the cues are <code>subtitles</code>, <code>captions</code>, or <code>descriptions</code>. Further, use {{htmlattrxref("srclang","track")}} to tell the browser what language you have written the subtitles in.</li>
+</ol>
+
+<p>Here's an example:</p>
+
+<pre class="brush: html notranslate">&lt;video controls&gt;
+ &lt;source src="example.mp4" type="video/mp4"&gt;
+ &lt;source src="example.webm" type="video/webm"&gt;
+ &lt;track kind="subtitles" src="subtitles_es.vtt" srclang="es"&gt;
+&lt;/video&gt;</pre>
+
+<p>This will result in a video that has subtitles displayed, kind of like this:</p>
+
+<p><img alt='Video player with stand controls such as play, stop, volume, and captions on and off. The video playing shows a scene of a man holding a spear-like weapon, and a caption reads "Esta hoja tiene pasado oscuro."' src="https://mdn.mozillademos.org/files/7887/video-player-with-captions.png" style="display: block; height: 365px; margin: 0px auto; width: 593px;"></p>
+
+<p>For more details, please read <a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a>. You can <a href="http://iandevlin.github.io/mdn/video-player-with-captions/">find the example</a> that goes along with this article on Github, written by Ian Devlin (see the <a href="https://github.com/iandevlin/iandevlin.github.io/tree/master/mdn/video-player-with-captions">source code</a> too.) This example uses some JavaScript to allow users to choose between different subtitles. Note that to turn the subtitles on, you need to press the "CC" button and select an option — English, Deutsch, or Español.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Text tracks also help you with {{glossary("SEO")}}, since search engines especially thrive on text. Text tracks even allow search engines to link directly to a spot partway through the video.</p>
+</div>
+
+<h3 id="Active_learning_Embedding_your_own_audio_and_video">Active learning: Embedding your own audio and video</h3>
+
+<p>For this active learning, we'd (ideally) like you to go out into the world and record some of your own video and audio — most phones these days allow you to record audio and video very easily and, provided you can transfer it on to your computer, you can use it. You may have to do some conversion to end up with a WebM and MP4 in the case of video, and an MP3 and Ogg in the case of audio, but there are enough programs out there to allow you to do this without too much trouble, such as <a href="http://www.mirovideoconverter.com/">Miro Video Converter</a> and <a href="https://sourceforge.net/projects/audacity/">Audacity</a>. We'd like you to have a go!</p>
+
+<p>If you are unable to source any video or audio, then you can feel free to use our <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/video-and-audio-content">sample audio and video files</a> to carry out this exercise. You can also use our sample code for reference.</p>
+
+<p>We would like you to:</p>
+
+<ol>
+ <li>Save your audio and video files in a new directory on your computer.</li>
+ <li>Create a new HTML file in the same directory, called <code>index.html</code>.</li>
+ <li>Add {{HTMLElement("audio")}} and {{HTMLElement("video")}} elements to the page; make them display the default browser controls.</li>
+ <li>Give both of them {{HTMLElement("source")}} elements so that browsers will find the audio format they support best and load it. These should include {{htmlattrxref("type", "source")}} attributes.</li>
+ <li>Give the <code>&lt;video&gt;</code> element a poster that will be displayed before the video starts to be played. Have fun creating your own poster graphic.</li>
+</ol>
+
+<p>For an added bonus, you could try researching text tracks, and work out how to add some captions to your video.</p>
+
+<h2 id="Test_your_skills!">Test your skills!</h2>
+
+<p>You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding">Test your skills: Multimedia and embedding</a>. Note that the third assessment question in this test assumes knowledge of some of the techniques covered in the <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">next article</a>, so you may want to read that before attempting it.</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>And that's a wrap; we hope you had fun playing with video and audio in web pages! In the next article, we'll look at other ways of embedding content on the Web, using technologies like {{htmlelement("iframe")}} and {{htmlelement("object")}}.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li>The HTML media elements: {{htmlelement("audio")}}, {{htmlelement("video")}}, {{htmlelement("source")}}, and {{htmlelement("track")}}</li>
+ <li><a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a></li>
+ <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery">Audio and Video delivery</a>: A LOT of detail about putting audio and video onto web pages using HTML and JavaScript.</li>
+ <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_manipulation">Audio and Video manipulation</a>: A LOT of detail about manipulating audio and video using JavaScript (for example adding filters.)</li>
+ <li>Automated options to <a href="http://www.inwhatlanguage.com/blog/translate-video-audio/">translate multimedia</a>.</li>
+ <li><a href="/en-US/docs/Web/Media">Web media technologies</a></li>
+ <li><a href="/en-US/docs/Web/Media/Formats">Guide to media types and formats on the web</a></li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From &lt;object&gt; to &lt;iframe&gt; — other embedding technologies</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html
new file mode 100644
index 0000000000..951de62ef5
--- /dev/null
+++ b/files/zh-tw/learn/html/multimedia_and_embedding/video_and_audio_content/test_your_skills_colon__multimedia_and_embedding/index.html
@@ -0,0 +1,104 @@
+---
+title: 測試你的技能:多媒體和嵌入
+slug: >-
+ Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding
+tags:
+ - HTML
+ - 初學者
+ - 多媒體
+ - 學習
+ - 嵌入
+ - 測驗
+translation_of: >-
+ Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding
+---
+<div>{{learnsidebar}}</div>
+
+<div>這項技能測試的目的是評估您是否了解我們的<a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">視訊和音訊內容</a>以及<a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">從物件到iframe的其他嵌入技術</a>文章。</div>
+
+<div></div>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 您可以在下面的交互式編輯器中嘗試解決方案,但是下載代碼並使用在線工具如 <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, or <a href="https://glitch.com/">Glitch</a> 去完成測試。<br>
+ <br>
+ 如果您遇到困難,請向我們尋求幫助-請參閱 {{anch("Assessment or further help")}} 此頁面底部的部分。</p>
+</div>
+
+<h2 id="多媒體和嵌入1">多媒體和嵌入1</h2>
+
+<p>在此測試中,我們希望您將一個簡單的音檔嵌入到頁面上。你需要:</p>
+
+<ul>
+ <li>將音頻文件的路徑添加到適當的屬性,以將其嵌入頁面中。音檔名為<code>audio.mp3</code>,位於當前文件夾中的文件夾<code>media</code>中。</li>
+ <li>添加屬性讓瀏覽器顯示一些預設控制選項。</li>
+ <li>為不支持的音檔撥放的瀏覽器添加一些適當的備註。</li>
+</ul>
+
+<p>嘗試更新下面的程式碼以完成測驗:</p>
+
+<p>{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed1.html", '100%', 700)}}</p>
+
+<div class="blockIndicator note">
+<p><a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/tasks/media-embed/mediaembed1-download.html">下載此測驗的程式碼</a>在你自己的編輯器或線上編輯器中運行。</p>
+</div>
+
+<h2 id="多媒體和嵌入2">多媒體和嵌入2</h2>
+
+<p>在此測驗中,我們希望你標記一個稍微複雜一些的影片播放器,此外還具有多個來源、字幕和其他功能。你需要:</p>
+
+<ul>
+ <li>添加屬性以使瀏覽器顯示一些預設控制選項。</li>
+ <li>為不支持的影片撥放的瀏覽器添加一些適當的備註。</li>
+ <li>添加多個源,其中包含視頻文件的路徑。這些文件稱為 <code>video.mp4</code> 和 <code>video.webm</code>, 並且位於一個名為<code>media</code>的文件夾中。</li>
+ <li>讓瀏覽器提前知道影片來源的影片格式,以便可以提前選擇要下載的影片。</li>
+ <li>給予 <code>&lt;video&gt;</code> 寬度和高度等於固定大小(320 x 240像素)。</li>
+ <li>使影片默認為靜音。</li>
+ <li>顯示包含在 <code>media</code> 資料夾, 在一個名為 <code>subtitles_en.vtt</code>, 播放視頻時,您必須將類型明確設置為字幕,並且字幕語言為英語。</li>
+</ul>
+
+<p>嘗試更新下面的程式碼以完成測驗:</p>
+
+<p>{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed2.html", '100%', 700)}}</p>
+
+<div class="blockIndicator note">
+<p><a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/tasks/media-embed/mediaembed2-download.html">下載此測驗的程式碼</a>在你自己的編輯器或線上編輯器中運行。</p>
+</div>
+
+<h2 id="多媒體和嵌入3">多媒體和嵌入3</h2>
+
+<p>對於此最終測驗,你需要執行兩個測驗:</p>
+
+<ul>
+ <li>將PDF嵌入頁面。PDF檔名為 <code>mypdf.pdf</code>, 並存在 <code>media</code> 資料夾.</li>
+ <li>轉到YouTube或Google Maps這樣的共享網站,然後將影片或其他媒體項目嵌入頁面。</li>
+</ul>
+
+<p>T嘗試更新下面的程式碼以完成測驗:</p>
+
+<p>{{EmbedGHLiveSample("learning-area/html/multimedia-and-embedding/tasks/media-embed/mediaembed3.html", '100%', 700)}}</p>
+
+<div class="blockIndicator note">
+<p><a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/tasks/media-embed/mediaembed3-download.html">下載此測驗的程式碼</a>在你自己的編輯器或線上編輯器中運行。</p>
+</div>
+
+<h2 id="評估或進一步幫助">評估或進一步幫助</h2>
+
+<p>您可以在上面的Interactive Editors中練習這些示例。</p>
+
+<p>如果您希望對自己的工作進行評估,或者遇到困難希望尋求幫助:</p>
+
+<ol>
+ <li>將您的工作放入在線共享編輯器中,例如 <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, 或 <a href="https://glitch.com/">Glitch</a>. 您可以自己編寫程式碼,也可以使用以上各節中連接到的初始文件。</li>
+ <li>撰寫帖子,要求評估和/或幫助 <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. 你的貼文應包括:
+ <ul>
+ <li>描述性標題,例如“ HTML圖像基礎知識1技能測試所需的評估”。</li>
+ <li>您已經嘗試過的內容以及您希望我們做什麼的詳細信息,例如如果您陷入困境並需要幫助,或者需要評估。</li>
+ <li>聯機共享編輯器中您要評估或需要幫助的示例的鏈接(如上面的步驟1中所述)。這是進入的好習慣-如果看不到他們的代碼,很難幫助有編碼問題的人。</li>
+ <li>指向實際任務或評估頁面的鏈接,因此我們可以找到您需要幫助的問題。</li>
+ </ul>
+ </li>
+</ol>
+
+<div id="gtx-trans" style="position: absolute; left: 34px; top: 1931px;">
+<div class="gtx-trans-icon"></div>
+</div>
diff --git a/files/zh-tw/learn/html/multimedia_and_embedding/其他_嵌入_技術/index.html b/files/zh-tw/learn/html/multimedia_and_embedding/其他_嵌入_技術/index.html
new file mode 100644
index 0000000000..a1996f2537
--- /dev/null
+++ b/files/zh-tw/learn/html/multimedia_and_embedding/其他_嵌入_技術/index.html
@@ -0,0 +1,386 @@
+---
+title: 從物件到iframe - 其他嵌入技術
+slug: Learn/HTML/Multimedia_and_embedding/其他_嵌入_技術
+translation_of: Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}</div>
+
+<p class="summary">到現在為止,您應該真正掌握了將內容嵌入網頁的方法,包括圖片,影片和聲音。在這一點上,我們想採取一些橫向的措施,尋找一些元素,使您可以將各種內容類型嵌入到網頁中: {{htmlelement("iframe")}}, {{htmlelement("embed")}} 和 {{htmlelement("object")}} 元素。<code>&lt;iframe&gt;</code>用於嵌入其他網頁,另外兩個用於嵌入PDF,SVG甚至是Flash(這項技術正在淘汰,但您仍會半定期看到)。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, familiarity with HTML fundamentals (as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>) and the previous articles in this module.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To learn how to embed items into web pages using {{htmlelement("object")}}, {{htmlelement("embed")}}, and {{htmlelement("iframe")}}, like Flash movies and other webpages.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="A_short_history_of_embedding">A short history of embedding</h2>
+
+<p>A long time ago on the Web, it was popular to use <strong>frames</strong> to create websites — small parts of a website stored in individual HTML pages. These were embedded in a master document called a <strong>frameset</strong>, which allowed you to specify the area on the screen that each frame filled, rather like sizing the columns and rows of a table. These were considered the height of coolness in the mid to late 90s, and there was evidence that having a webpage split up into smaller chunks like this was better for download speeds — especially noticeable with network connections being so slow back then. They did however have many problems, which far outweighed any positives as network speeds got faster, so you don't see them being used anymore.</p>
+
+<p>A little while later (late 90s, early 2000s), plugin technologies became very popular, such as <a href="/en-US/docs/Glossary/Java">Java Applets</a> and <a href="/en-US/docs/Glossary/Adobe_Flash">Flash</a> — these allowed web developers to embed rich content into webpages such as videos and animations, which just weren't available through HTML alone. Embedding these technologies was achieved through elements like {{htmlelement("object")}}, and the lesser-used {{htmlelement("embed")}}, and they were very useful at the time. They have since fallen out of fashion due to many problems, including accessibility, security, file size, and more; these days most mobile devices don't support such plugins anymore, and desktop support is on the way out.</p>
+
+<p>Finally, the {{htmlelement("iframe")}} element appeared (along with other ways of embedding content, such as {{htmlelement("canvas")}}, {{htmlelement("video")}}, etc.) This provides a way to embed an entire web document inside another one, as if it were an {{htmlelement("img")}} or other such element, and is used regularly today.</p>
+
+<p>With the history lesson out of the way, let's move on and see how to use some of these.</p>
+
+<h2 id="Active_learning_classic_embedding_uses">Active learning: classic embedding uses</h2>
+
+<p>In this article we are going to jump straight into an active learning section, to immediately give you a real idea of just what embedding technologies are useful for. The online world is very familiar with <a href="https://www.youtube.com">Youtube</a>, but many people don't know about some of the sharing facilities it has available. Let's look at how Youtube allows us to embed a video in any page we like using an {{htmlelement("iframe")}}.</p>
+
+<ol>
+ <li>First, go to Youtube and find a video you like.</li>
+ <li>Below the video, you'll find a <em>Share</em> button — select this to display the sharing options.</li>
+ <li>Select the <em>Embed</em> button and you'll be given some <code>&lt;iframe&gt;</code> code — copy this.</li>
+ <li>Insert it into the <em>Input</em> box below, and see what the result is in the <em>Output</em>.</li>
+</ol>
+
+<p>For bonus points, you could also try embedding a <a href="https://www.google.com/maps/">Google Map</a> in the example:</p>
+
+<ol>
+ <li>Go to Google Maps and find a map you like.</li>
+ <li>Click on the "Hamburger Menu" (three horizontal lines) in the top left of the UI.</li>
+ <li>Select the <em>Share or embed map</em> option.</li>
+ <li>Select the Embed map option, which will give you some <code>&lt;iframe&gt;</code> code — copy this.</li>
+ <li>Insert it into the <em>Input</em> box below, and see what the result is in the <em>Output</em>.</li>
+</ol>
+
+<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see an answer.</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 250px;"&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="input" style="width: 95%;min-height: 100px;"&gt;
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">const textarea = document.getElementById('code');
+const reset = document.getElementById('reset');
+const solution = document.getElementById('solution');
+const output = document.querySelector('.output');
+let code = textarea.value;
+let userEntry = textarea.value;
+
+function updateCode() {
+ output.innerHTML = textarea.value;
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = htmlSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+const htmlSolution = '&lt;iframe width="420" height="315" src="https://www.youtube.com/embed/QH2-TGUlwu4" frameborder="0" allowfullscreen&gt;\n&lt;/iframe&gt;\n\n&lt;iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d37995.65748333395!2d-2.273568166412784!3d53.473310471916975!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487bae6c05743d3d%3A0xf82fddd1e49fc0a1!2sThe+Lowry!5e0!3m2!1sen!2suk!4v1518171785211" width="600" height="450" frameborder="0" style="border:0" allowfullscreen&gt;\n&lt;/iframe&gt;';
+let solutionEntry = htmlSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ const scrollPos = textarea.scrollTop;
+ const caretPos = textarea.selectionStart;
+
+ const front = (textarea.value).substring(0, caretPos);
+ const back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', 700, 600, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Iframes_in_detail">Iframes in detail</h2>
+
+<p>So, that was easy and fun, right? {{htmlelement("iframe")}} elements are designed to allow you to embed other web documents into the current document. This is great for incorporating third-party content into your website that you might not have direct control over and don't want to have to implement your own version of — such as video from online video providers, commenting systems like <a href="https://disqus.com/">Disqus</a>, maps from online map providers, advertising banners, etc. The live editable examples you've been using through this course are implemented using <code>&lt;iframe&gt;</code>s.</p>
+
+<p>There are some serious {{anch("Security concerns")}} to consider with <code>&lt;iframe&gt;</code>s, as we'll discuss below, but this doesn't mean that you shouldn't use them in your websites — it just requires some knowledge and careful thinking. Let's explore the code in a bit more detail. Say you wanted to include the MDN glossary on one of your web pages — you could try something like this:</p>
+
+<pre class="notranslate">&lt;iframe src="https://developer.mozilla.org/en-US/docs/Glossary"
+ width="100%" height="500" frameborder="0"
+ allowfullscreen sandbox&gt;
+ &lt;p&gt;
+  &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary"&gt;
+ Fallback link for browsers that don't support iframes
+ &lt;/a&gt;
+  &lt;/p&gt;
+&lt;/iframe&gt;</pre>
+
+<p>This example includes the basic essentials needed to use an <code>&lt;iframe&gt;</code>:</p>
+
+<dl>
+ <dt>{{htmlattrxref('allowfullscreen','iframe')}}</dt>
+ <dd>If set, the <code>&lt;iframe&gt;</code> is able to be placed in fullscreen mode using the <a href="/en-US/docs/Web/API/Fullscreen_API">Full Screen API</a> (somewhat beyond scope for this article.)</dd>
+ <dt>{{htmlattrxref('frameborder','iframe')}}</dt>
+ <dd>If set to 1, this tells the browser to draw a border between this frame and other frames, which is the default behaviour. 0 removes the border. Using this isn't really recommended any more, as the same effect can be better achieved using {{cssxref('border')}}<code>: none;</code> in your {{Glossary('CSS')}}.</dd>
+ <dt>{{htmlattrxref('src','iframe')}}</dt>
+ <dd>This attribute, as with {{htmlelement("video")}}/{{htmlelement("img")}}, contains a path pointing to the URL of the document to be embedded.</dd>
+ <dt>{{htmlattrxref('width','iframe')}} and {{htmlattrxref('height','iframe')}}</dt>
+ <dd>These attributes specify the width and height you want the iframe to be.</dd>
+ <dt><strong>F</strong>allback content</dt>
+ <dd>In the same way as other similar elements like {{htmlelement("video")}}, you can include fallback content between the opening and closing <code>&lt;iframe&gt;&lt;/iframe&gt;</code> tags that will appear if the browser doesn't support the <code>&lt;iframe&gt;</code>. In this case, we have included a link to the page instead. It is unlikely that you'll come across any browser that doesn't support <code>&lt;iframe&gt;</code>s these days.</dd>
+ <dt>{{htmlattrxref('sandbox','iframe')}}</dt>
+ <dd>This attribute, which works in slightly more modern browsers than the rest of the <code>&lt;iframe&gt;</code> features (e.g. IE 10 and above) requests heightened security settings; we'll say more about this in the next section.</dd>
+</dl>
+
+<div class="note">
+<p><strong>Note</strong>: In order to improve speed, it's a good idea to set the iframe's <code>src</code> attribute with JavaScript after the main content is done with loading. This makes your page usable sooner and decreases your official page load time (an important {{glossary("SEO")}} metric.)</p>
+</div>
+
+<h3 id="Security_concerns">Security concerns</h3>
+
+<p>Above we mentioned security concerns — let's go into this in a bit more detail now. We are not expecting you to understand all of this content perfectly the first time; we just want to make you aware of this concern, and provide a reference to come back to as you get more experienced and start considering using <code>&lt;iframe&gt;</code>s in your experiments and work. Also, there is no need to be scared and not use <code>&lt;iframe&gt;</code>s — you just need to be careful. Read on...</p>
+
+<p>Browser makers and Web developers have learned the hard way that iframes are a common target (official term: <strong>attack vector</strong>) for bad people on the Web (often termed <strong>hackers</strong>, or more accurately, <strong>crackers</strong>) to attack if they are trying to maliciously modify your webpage, or trick people into doing something they don't want to do, such as reveal sensitive information like usernames and passwords. Because of this, spec engineers and browser developers have developed various security mechanisms for making <code>&lt;iframe&gt;</code>s more secure, and there are also best practices to consider — we'll cover some of these below.</p>
+
+<div class="note">
+<p>{{interwiki('wikipedia','Clickjacking')}} is one kind of common iframe attack where hackers embed an invisible iframe into your document (or embed your document into their own malicious website) and use it to capture users' interactions. This is a common way to mislead users or steal sensitive data.</p>
+</div>
+
+<p>A quick example first though — try loading the previous example we showed above into your browser — you can <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/other-embedding-technologies/iframe-detail.html">find it live on Github</a> (<a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/other-embedding-technologies/iframe-detail.html">see the source code</a> too.) You won't actually see anything displayed on the page, and if you look at the <em>Console</em> in the <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools</a>, you'll see a message telling you why. In Firefox, you'll get told <em>Load denied by X-Frame-Options: https://developer.mozilla.org/en-US/docs/Glossary does not permit framing</em>. This is because the developers that built MDN have included a setting on the server that serves the website pages to disallow them from being embedded inside <code>&lt;iframe&gt;</code>s (see {{anch("Configure CSP directives")}}, below.) This makes sense — an entire MDN page doesn't really make sense to be embedded in other pages unless you want to do something like embed them on your site and claim them as your own — or attempt to steal data via clickjacking, which are both really bad things to do. Plus if everybody started to do this, all the additional bandwidth would start to cost Mozilla a lot of money.</p>
+
+<h4 id="Only_embed_when_necessary">Only embed when necessary</h4>
+
+<p>Sometimes it makes sense to embed third-party content — like youtube videos and maps — but you can save yourself a lot of headaches if you only embed third-party content when completely necessary. A good rule of thumb for web security is <em>"You can never be too cautious. If you made it, double-check it anyway. If someone else made it, assume it's dangerous until proven otherwise."</em></p>
+
+<div>
+<p>Besides security, you should also be aware of intellectual property issues. Most content is copyrighted, offline and online, even content you might not expect (for example, most images on <a href="https://commons.wikimedia.org/wiki/Main_Page">Wikimedia Commons</a>). Never display content on your webpage unless you own it or the owners have given you written, unequivocal permission. Penalties for copyright infringement are severe. Again, you can never be too cautious.</p>
+
+<p>If the content is licensed, you must obey the license terms. For example, the content on MDN is <a href="/en-US/docs/MDN/About#Copyrights_and_licenses">licensed under CC-BY-SA</a>. That means, you must <a href="https://wiki.creativecommons.org/wiki/Best_practices_for_attribution">credit us properly</a> when you quote our content, even if you make substantial changes.</p>
+</div>
+
+<h4 id="Use_HTTPS">Use HTTPS</h4>
+
+<p>{{Glossary("HTTPS")}} is the encrypted version of {{Glossary("HTTP")}}. You should serve your websites using HTTPS whenever possible:</p>
+
+<ol>
+ <li>HTTPS reduces the chance that remote content has been tampered with in transit,</li>
+ <li>HTTPS prevents embedded content from accessing content in your parent document, and vice versa.</li>
+</ol>
+
+<p>Using HTTPS requires a security certificate, which can be expensive (although <a href="https://letsencrypt.org/">Let's Encrypt</a> makes things easier) — if you can't get one, you may serve your parent document with HTTP. However, because of the second benefit of HTTPS above, <em>no matter what the cost, you must never embed third-party content with HTTP. </em>(In the best case scenario, your user's Web browser will give them a scary warning.) All reputable companies that make content available for embedding via an <code>&lt;iframe&gt;</code> will make it available via HTTPS — look at the URLs inside the <code>&lt;iframe&gt;</code> <code>src</code> attribute when you are embedding content from Google Maps or Youtube, for example.</p>
+
+<div class="note">
+<p><strong>Note</strong>: <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">Github pages</a> allow content to be served via HTTPS by default, so is useful for hosting content. If you are using different hosting and are not sure, ask your hosting provider about it.</p>
+</div>
+
+<h4 id="Always_use_the_sandbox_attribute">Always use the <code>sandbox</code> attribute</h4>
+
+<p>You want to give attackers as little power as you can to do bad things on your website, therefore you should give embedded content <em>only the permissions needed for doing its job. </em>Of course, this applies to your own content, too. A container for code where it can be used appropriately — or for testing — but can't cause any harm to the rest of the codebase (either accidental or malicious) is called a <a href="https://en.wikipedia.org/wiki/Sandbox_(computer_security)">sandbox</a>.</p>
+
+<p>Unsandboxed content can do way too much (executing JavaScript, submitting forms, popup windows, etc.) By default, you should impose all available restrictions by using the <code>sandbox</code> attribute with no parameters, as shown in our previous example.</p>
+
+<p>If absolutely required, you can add permissions back one by one (inside the <code>sandbox=""</code> attribute value) — see the {{htmlattrxref('sandbox','iframe')}} reference entry for all the available options. One important note is that you should <em>never</em> add both <code>allow-scripts</code> and <code>allow-same-origin</code> to your <code>sandbox</code> attribute — in that case, the embedded content could bypass the <a href="/en-US/docs/Glossary/Same-origin_policy">Same-origin policy</a> that stops sites from executing scripts, and use JavaScript to turn off sandboxing altogether.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Sandboxing provides no protection if attackers can fool people into visiting malicious content directly (outside an <code>iframe</code>). If there's any chance that certain content may be malicious (e.g., user-generated content), please serve it from a different {{glossary("domain")}} to your main site.</p>
+</div>
+
+<h4 id="Configure_CSP_directives">Configure CSP directives</h4>
+
+<p>{{Glossary("CSP")}} stands for <strong><a href="/en-US/docs/Web/Security/CSP">content security policy</a></strong> and provides <a href="/en-US/docs/Web/Security/CSP/CSP_policy_directives">a set of HTTP Headers</a> (metadata sent along with your web pages when they are served from a web server) designed to improve the security of your HTML document. When it comes to securing <code>&lt;iframe&gt;</code>s, you can <em><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options">configure your server to send an appropriate <code>X-Frame-Options</code>  header.</a></em> This can prevent other websites from embedding your content in their web pages (which would enable {{interwiki('wikipedia','clickjacking')}} and a host of other attacks), which is exactly what the MDN developers have done, as we saw earlier on.</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can read Frederik Braun's post <a href="https://blog.mozilla.org/security/2013/12/12/on-the-x-frame-options-security-header/">On the X-Frame-Options Security Header</a> for more background information on this topic. Obviously, it's rather out of scope for a full explanation in this article.</p>
+</div>
+
+<h2 id="The_&lt;embed>_and_&lt;object>_elements">The &lt;embed&gt; and &lt;object&gt; elements</h2>
+
+<p>The {{htmlelement("embed")}} and {{htmlelement("object")}} elements serve a different function to {{htmlelement("iframe")}} — these elements are general purpose embedding tools for embedding multiple types of external content, which include plugin technologies like Java Applets and Flash, PDF (which can be shown in a browser with a PDF plugin), and even content like videos, SVG and images!</p>
+
+<div class="note">
+<p><strong>Note</strong>: A <strong>plugin</strong>, in this context, refers to software that provides access to content the browser cannot read natively.</p>
+</div>
+
+<p>However, you are unlikely to use these elements very much — Applets haven't been used for years, Flash is no longer very popular, due to a number of reasons (see {{anch("The case against plugins")}}, below), PDFs tend to be better linked to than embedded, and other content such as images and video have much better, easier elements to handle those. Plugins and these embedding methods are really a legacy technology, and we are mainly mentioning them in case you come across them in certain circumstances like intranets, or enterprise projects.</p>
+
+<p>If you find yourself needing to embed plugin content, this is the kind of information you'll need, at a minimum:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col"></th>
+ <th scope="col">{{htmlelement("embed")}}</th>
+ <th scope="col">{{htmlelement("object")}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{{glossary("URL")}} of the embedded content</td>
+ <td>{{htmlattrxref('src','embed')}}</td>
+ <td>{{htmlattrxref('data','object')}}</td>
+ </tr>
+ <tr>
+ <td><em>accurate </em>{{glossary("MIME type", 'media type')}} of the embedded content</td>
+ <td>{{htmlattrxref('type','embed')}}</td>
+ <td>{{htmlattrxref('type','object')}}</td>
+ </tr>
+ <tr>
+ <td>height and width (in CSS pixels) of the box controlled by the plugin</td>
+ <td>{{htmlattrxref('height','embed')}}<br>
+ {{htmlattrxref('width','embed')}}</td>
+ <td>{{htmlattrxref('height','object')}}<br>
+ {{htmlattrxref('width','object')}}</td>
+ </tr>
+ <tr>
+ <td>names and values, to feed the plugin as parameters</td>
+ <td>ad hoc attributes with those names and values</td>
+ <td>single-tag {{htmlelement("param")}} elements, contained within <code>&lt;object&gt;</code></td>
+ </tr>
+ <tr>
+ <td>independent HTML content as fallback for an unavailable resource</td>
+ <td>not supported (<code>&lt;noembed&gt;</code> is obsolete)</td>
+ <td>contained within <code>&lt;object&gt;</code>, after <code>&lt;param&gt;</code> elements</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p><strong>Note</strong>: <code>&lt;object&gt;</code> requires a <code>data</code> attribute, a <code>type</code> attribute, or both. If you use both, you may also use the {{htmlattrxref('typemustmatch','object')}} attribute (only implemented in Firefox and Chrome, as of this writing). <code>typemustmatch</code> keeps the embedded file from running unless the <code>type</code> attribute provides the correct media type. <code>typemustmatch</code> can therefore confer significant security benefits when you're embedding content from a different {{glossary("origin")}} (it can keep attackers from running arbitrary scripts through the plugin).</p>
+</div>
+
+<p>Here's an example that uses the {{htmlelement("embed")}} element to embed a Flash movie (see this <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/other-embedding-technologies/embed-flash.html">live on Github</a>, and <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/other-embedding-technologies/embed-flash.html">check the source code</a> too):</p>
+
+<pre class="brush: html notranslate">&lt;embed src="whoosh.swf" quality="medium"
+ bgcolor="#ffffff" width="550" height="400"
+ name="whoosh" align="middle" allowScriptAccess="sameDomain"
+ allowFullScreen="false" type="application/x-shockwave-flash"
+ pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;</pre>
+
+<p>Pretty horrible, isn't it? The HTML generated by the Adobe Flash tool tended to be even worse, using an <code>&lt;object&gt;</code> element with an <code>&lt;embed&gt;</code> element embedded in it, to cover all bases (check out an example.) Flash was even used successfully as fallback content for HTML5 video, for a time, but this is increasingly being seen as not necessary.</p>
+
+<p>Now let's look at an <code>&lt;object&gt;</code> example that embeds a PDF into a page (see the <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/other-embedding-technologies/object-pdf.html">live example</a> and the <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/other-embedding-technologies/object-pdf.html">source code</a>):</p>
+
+<pre class="brush: html notranslate">&lt;object data="mypdf.pdf" type="application/pdf"
+ width="800" height="1200" typemustmatch&gt;
+ &lt;p&gt;You don't have a PDF plugin, but you can
+  &lt;a href="mypdf.pdf"&gt;download the PDF file.
+  &lt;/a&gt;
+ &lt;/p&gt;
+&lt;/object&gt;</pre>
+
+<p>PDFs were a necessary stepping stone between paper and digital, but they pose many <a href="http://webaim.org/techniques/acrobat/acrobat">accessibility challenges</a> and can be hard to read on small screens. They do still tend to be popular in some circles, but it is much better to link to them so they can be downloaded or read on a separate page, rather than embedding them in a webpage.</p>
+
+<h3 id="The_case_against_plugins">The case against plugins</h3>
+
+<p>Once upon a time, plugins were indispensable on the Web. Remember the days when you had to install Adobe Flash Player just to watch a movie online? And then you constantly got annoying alerts about updating Flash Player and your Java Runtime Environment. Web technologies have since grown much more robust, and those days are over. For virtually all applications, it's time to stop delivering content that depends on plugins and start taking advantage of Web technologies instead.</p>
+
+<ul>
+ <li><strong>Broaden your reach to everyone. </strong>Everyone has a browser, but plugins are increasingly rare, especially among mobile users. Since the Web is easily used without any plugins, people would rather just go to your competitors' websites than install a plugin.</li>
+ <li><strong>Give yourself a break from the <a href="https://webaim.org/techniques/flash/">extra accessibility headaches </a>that come with Flash and other plugins.</strong></li>
+ <li><strong>Stay clear of additional security hazards. </strong>Adobe Flash is <a href="https://www.cvedetails.com/product/6761/Adobe-Flash-Player.html?vendor_id=53">notoriously insecure,</a> even after countless patches. In 2015, Alex Stamos, then-Chief Security Officer at Facebook,  <a href="https://www.theverge.com/2015/7/13/8948459/adobe-flash-insecure-says-facebook-cso">requested that Adobe discontinue Flash.</a></li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note: </strong>Due to its inherent issues and the lack of support for Flash, Adobe announced that they would stop supporting it at the end of 2020.  As of January 2020, most browsers block Flash content by default, and by December 31st of 2020, all browsers will have completly removed all Flash functionality. Any existing Flash content will be inaccessable after that date.</p>
+</div>
+
+<p>So what should you do? If you need interactivity, HTML and {{glossary("JavaScript")}} can readily get the job done for you with no need for Java applets or outdated ActiveX/BHO technology. Instead of relying on Adobe Flash, you should use <a href="/en-US/docs/Learn/HTML/Howto/Add_audio_or_video_content_to_a_webpage">HTML5 video</a> for your media needs, <a href="/en-US/docs/Learn/HTML/Howto/Add_vector_image_to_a_webpage">SVG</a> for vector graphics, and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial">Canvas</a> for complex images and animations. <a href="https://plus.google.com/+PeterElst/posts/P5t4pFhptvp">Peter Elst was already writing some years ago</a> that Adobe Flash is rarely the right tool for the job. As for ActiveX, even Microsoft's {{glossary("Microsoft Edge","Edge")}} browser no longer supports it.</p>
+
+<h2 id="Test_your_skills!">Test your skills!</h2>
+
+<p>You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding">Test your skills: Multimedia and embedding</a>.</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>The topic of embedding other content in web documents can quickly become very complex, so in this article, we've tried to introduce it in a simple, familiar way that will immediately seem relevant, while still hinting at some of the more advanced features of the involved technologies. To start with, you are unlikely to use embedding for much beyond including third-party content like maps and videos on your pages. As you become more experienced, however, you are likely to start finding more uses for them.</p>
+
+<p>There are many other technologies that involve embedding external content besides the ones we discussed here. We saw some in earlier articles, such as {{htmlelement("video")}}, {{htmlelement("audio")}}, and {{htmlelement("img")}}, but there are others to discover, such as {{htmlelement("canvas")}} for JavaScript-generated 2D and 3D graphics, and {{SVGElement("svg")}} for embedding vector graphics. We'll look at <a href="/en-US/docs/Web/SVG">SVG</a> in the next article of the module.</p>
+
+<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From &lt;object&gt; to &lt;iframe&gt; — other embedding technologies</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li>
+</ul>
diff --git a/files/zh-tw/learn/html/tables/index.html b/files/zh-tw/learn/html/tables/index.html
new file mode 100644
index 0000000000..0e282b2a68
--- /dev/null
+++ b/files/zh-tw/learn/html/tables/index.html
@@ -0,0 +1,34 @@
+---
+title: HTML 表格
+slug: Learn/HTML/Tables
+translation_of: Learn/HTML/Tables
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">HTML 的常見任務就是建構表格資料,某些元素與屬性正是為此目的而生。HTML 以及用於樣式化的 <a href="/zh-TW/docs/Learn/CSS">CSS</a> 能方便顯示諸如讀書計劃、附近游泳池的開放時間、分析最喜歡的恐龍或足球隊……之類的表格資訊。本模塊將帶你認識建構 HTML 表格資料所需的一切。</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>開始本模塊之前,你要理解基本的 HTML:請參見 <a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a>。</p>
+
+<div class="note">
+<p><strong>注意</strong>:如果你用的電腦或平板之類的設備,無法允許建立自己的檔案,你可以把大部分的例子放在線上程式網站,例如 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a>。</p>
+</div>
+
+<h2 id="教學">教學</h2>
+
+<p>本模塊包含以下文章:</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Tables/Basics">HTML 表格基礎</a></dt>
+ <dd>這篇文章將介紹 HTML 表格,包含像是行列、標題、製作單元格、跨多行與列等基礎知識,還有如何把他們組合在一起,以方便樣式化。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Tables/Advanced">HTML 表格進階與無障礙</a></dt>
+ <dd>本模塊的第二篇文章將介紹一些 HTML 表格的進階功能:例如說明、摘要、將行分成標頭、身體、還有註腳三大部分。另外,我們也會探討針對視障人士的表格無障礙。</dd>
+</dl>
+
+<h2 id="評估">評估</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/HTML/Tables/Structuring_planet_data">建構行星數據</a></dt>
+ <dd>在我們的表格評估中,我們將提供太陽系中行星的一些數據,並讓你把他們構建到 HTML 表格中。</dd>
+</dl>
diff --git a/files/zh-tw/learn/html/tables/基礎/index.html b/files/zh-tw/learn/html/tables/基礎/index.html
new file mode 100644
index 0000000000..03325afbce
--- /dev/null
+++ b/files/zh-tw/learn/html/tables/基礎/index.html
@@ -0,0 +1,568 @@
+---
+title: HTML表格的基礎
+slug: Learn/HTML/Tables/基礎
+translation_of: Learn/HTML/Tables/Basics
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</div>
+
+<p class="summary">這篇文章將帶你從列、格、標頭,以及將各格以數欄、數列的方式合併等基礎開始探索HTML表格。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>
+ <p>HTML的基礎(見<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">介紹HTML</a>)</p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>對HTML表格有基本的認識</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是表格">什麼是表格?</h2>
+
+<p>表格是一個由列和欄組成的結構化資料(tabular data)。表格能幫助你快速查看不同資料類型間的關聯值。例如人和年紀、一周當中的某天或是地方游泳池的時間表。</p>
+
+<p><img alt="A sample table showing names and ages of some people - Chris 38, Dennis 45, Sarah 29, Karen 47." src="https://mdn.mozillademos.org/files/14583/numbers-table.png" style="display: block; height: 156px; margin: 0px auto; width: 350px;"></p>
+
+<p><img alt="A swimming timetable showing a sample data table" src="https://mdn.mozillademos.org/files/14587/swimming-timetable.png" style="display: block; height: 301px; margin: 0px auto; width: 794px;"></p>
+
+<p>表格在人類社會當中被廣泛使用且已經有很久的歷史,如下是美國1800年的人口普查紀錄表格。</p>
+
+<p><img alt="A very old parchment document; the data is not easily readable, but it clearly shows a data table being used." src="https://mdn.mozillademos.org/files/14585/1800-census.jpg" style="display: block; height: 505px; margin: 0px auto; width: 800px;"></p>
+
+<p>這也難怪HTML的開創者要提供一個在網路建立和呈現表格化資料的方法。</p>
+
+<h3 id="表格是怎麼運作的呢">表格是怎麼運作的呢?</h3>
+
+<p>表格是精確的,資訊可以透過列和欄位名稱之間的視覺關聯輕鬆呈現。觀察以下表格,利用列和欄目名稱找出有62個衛星的類木行星。</p>
+
+<p><span>有關太陽系星球的資訊 (真實資料取自 </span><a href="http://nssdc.gsfc.nasa.gov/planetary/factsheet/">Nasa's Planetary Fact Sheet - Metric</a><strong>. )</strong></p>
+
+<table>
+ <thead>
+ <tr>
+ <td colspan="2"></td>
+ <th scope="col">名稱</th>
+ <th scope="col">質量(10<sup>24</sup>kg)</th>
+ <th scope="col">直徑 (km)</th>
+ <th scope="col">密度(kg/m<sup>3</sup>)</th>
+ <th scope="col">重力(m/s<sup>2</sup>)</th>
+ <th scope="col">一天的長度(小時)</th>
+ <th scope="col">和太陽的距離(10<sup>6</sup>km)</th>
+ <th scope="col">平均溫度 (°C)</th>
+ <th scope="col">衛星的數目</th>
+ <th scope="col">備註</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th colspan="2" rowspan="4" scope="rowgroup">陸地行星</th>
+ <th scope="row">水星</th>
+ <td>0.330</td>
+ <td>4,879</td>
+ <td>5427</td>
+ <td>3.7</td>
+ <td>4222.6</td>
+ <td>57.9</td>
+ <td>167</td>
+ <td>0</td>
+ <td>最接近太陽</td>
+ </tr>
+ <tr>
+ <th scope="row">金星</th>
+ <td>4.87</td>
+ <td>12,104</td>
+ <td>5243</td>
+ <td>8.9</td>
+ <td>2802.0</td>
+ <td>108.2</td>
+ <td>464</td>
+ <td>0</td>
+ <td></td>
+ </tr>
+ <tr>
+ <th scope="row">地球</th>
+ <td>5.97</td>
+ <td>12,756</td>
+ <td>5514</td>
+ <td>9.8</td>
+ <td>24.0</td>
+ <td>149.6</td>
+ <td>15</td>
+ <td>1</td>
+ <td>我們的世界</td>
+ </tr>
+ <tr>
+ <th scope="row">火星</th>
+ <td>0.642</td>
+ <td>6,792</td>
+ <td>3933</td>
+ <td>3.7</td>
+ <td>24.7</td>
+ <td>227.9</td>
+ <td>-65</td>
+ <td>2</td>
+ <td>紅色星球</td>
+ </tr>
+ <tr>
+ <th rowspan="4" scope="rowgroup">類木行星</th>
+ <th rowspan="2" scope="rowgroup">氣態巨行星</th>
+ <th scope="row">木星</th>
+ <td>1898</td>
+ <td>142,984</td>
+ <td>1326</td>
+ <td>23.1</td>
+ <td>9.9</td>
+ <td>778.6</td>
+ <td>-110</td>
+ <td>67</td>
+ <td>最大的星球</td>
+ </tr>
+ <tr>
+ <th scope="row">土星</th>
+ <td>568</td>
+ <td>120,536</td>
+ <td>687</td>
+ <td>9.0</td>
+ <td>10.7</td>
+ <td>1433.5</td>
+ <td>-140</td>
+ <td>62</td>
+ <td></td>
+ </tr>
+ <tr>
+ <th rowspan="2" scope="rowgroup">冰質巨行星</th>
+ <th scope="row">天王星</th>
+ <td>86.8</td>
+ <td>51,118</td>
+ <td>1271</td>
+ <td>8.7</td>
+ <td>17.2</td>
+ <td>2872.5</td>
+ <td>-195</td>
+ <td>27</td>
+ <td></td>
+ </tr>
+ <tr>
+ <th scope="row">海王星</th>
+ <td>102</td>
+ <td>49,528</td>
+ <td>1638</td>
+ <td>11.0</td>
+ <td>16.1</td>
+ <td>4495.1</td>
+ <td>-200</td>
+ <td>14</td>
+ <td></td>
+ </tr>
+ <tr>
+ <th colspan="2" scope="rowgroup">矮行星</th>
+ <th scope="row">冥王星</th>
+ <td>0.0146</td>
+ <td>2,370</td>
+ <td>2095</td>
+ <td>0.7</td>
+ <td>153.3</td>
+ <td>5906.4</td>
+ <td>-225</td>
+ <td>5</td>
+ <td>在2006年被從行星類別中除名,但這還些<a href="http://www.usatoday.com/story/tech/2014/10/02/pluto-planet-solar-system/16578959/">爭議</a>。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>在正確執行之下,就連視障者都可以把表格資料詮釋為HTML格式的表格。一份成功的HTML表格就應該如此提升視障者的使用經驗。</p>
+
+<h3 id="表格樣式">表格樣式</h3>
+
+<p>你也可以在 <a href="https://mdn.github.io/learning-area/html/tables/assessment-finished/planets-data.html">GitHub </a> 上看看實際範例 ! 而你也許會注意到那裡的表格似乎更容易閱讀。那是因為這裡的表格只有加上很少樣式,而GitHub上的版本卻應用上了更多明顯的CSS 。</p>
+
+<p>需要弄清楚的一點是 : 要讓表格在網頁上有效呈現需要提供紮實的HTML架構和CSS樣式資訊,但將在這個模組中聚焦在HTML的部分。若想瞭解CSS的部分,可以在完成這部分閱讀之後造訪<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Styling_tables">表格樣式設計</a>的文章。</p>
+
+<p>在這個單元裡我們將不會聚焦在CSS上,但是我們提供基本的CSS樣式表讓你做使用,這將會使你製作的表格比起毫無修飾的預設樣式更方便閱讀。你能在這找到<a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">樣式表</a>,並且你也能找到一個適用於樣式表的<a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/blank-template.html">HTML模版</a> — 他們能一起讓你有個好起點來實驗HTML表格。</p>
+
+<h3 id="當何時你不應該使用HTML表格">當何時你不應該使用HTML表格?</h3>
+
+<p>HTML表格應該被使用在結構化資料(tabular data)上 — 這就是它們被設計的目的。<br>
+ 不幸地是,許多人習慣使用HTML表格去排版他們的網頁,例如: 使用一列去當header,一列當做內容欄位,一列當作footer...等等,你能在我們的<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Accessibility">輔助學習單元</a>裡的<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML#Page_layouts">頁面輸出</a>發現更多細節以及一個範例。它曾經被這麼使用是因為CSS過去在不同瀏覽器之間的支援程度十分可怕; 如今,已非常少在用表格做排版,但你仍然可能在網路的一些邊邊角角見到。</p>
+
+<p>簡單來說,使用表格排版而非使用<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout">CSS排版技術</a>是一件很糟的事情。<br>
+ 下列是主要原因:</p>
+
+<ol>
+ <li><strong>表格排版會減少對視障使用者的輔助 </strong>: 視障者使用的<a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">螢幕閱讀器</a>會翻譯存在於HTML網頁的標籤並對使用者念出內容。由於表格並不是正確的排版工具,並且標示方式遠複雜於CSS排版技術,所以螢幕閱讀器輸出的內容會使他們的使用者感到困惑。</li>
+ <li><strong>表格會產生標籤雜燴(tag soup)</strong>: 就像上面提到的,表格排版通常會比一般適當的輸出技術包含更複雜的標籤結構。這會導致程式碼本身更難撰寫、維護及debug。</li>
+ <li><strong>表格不會自適應(automatically responsive)</strong>: 當你使用合適的排版容器(像是{htmlelement("header")}, {{htmlelement("section")}}) 或是 {{htmlelement("div")}}),它們的寬度相對於父層預設為100%,而表格的預設大小是依據它們的內容物,所以當表格樣式要有效的在不同的裝置之間運行時,會需要做額外的測量調整。</li>
+</ol>
+
+<h2 id="主動學習建造你第一個表格">主動學習:建造你第一個表格</h2>
+
+<p>關於表格的理論我們已經談論夠了,所以,來深入實際的例子並建立一個簡單的表格吧!</p>
+
+<ol>
+ <li>第一件事,在自己的電腦複製一份新的<a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/blank-template.html">空白模板.html</a> 以及 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">簡易表格.css</a> </li>
+ <li>每一個表格裡的內容都是由這兩個標籤所組成:<strong><code><a href="/en-US/docs/Web/HTML/Element/table">&lt;table&gt;&lt;/table&gt;</a></code></strong> 將這些放入你的HTML中的body。</li>
+ <li>表格裡最小的容器是表格儲存格,由<strong><code><a href="/en-US/docs/Web/HTML/Element/td">&lt;td&gt;</a></code></strong>元素所組成('td' 代表 'table data')。將下列的程式碼加入你的表格標籤之中:
+ <pre class="brush: html notranslate">&lt;td&gt;Hi, I'm your first cell.&lt;/td&gt;</pre>
+ </li>
+ <li>如果我們想要一個四格儲存格寬的列(row), 我們需要複製這些標籤三次。<br>
+ 將你的表格內容更新成這樣:
+ <pre class="brush: html notranslate">&lt;td&gt;Hi, I'm your first cell.&lt;/td&gt;
+&lt;td&gt;I'm your second cell.&lt;/td&gt;
+&lt;td&gt;I'm your third cell.&lt;/td&gt;
+&lt;td&gt;I'm your fourth cell.&lt;/td&gt;</pre>
+ </li>
+</ol>
+
+<p>就像你看到的,儲存格不會在各自的下方,它們彼此自動排列在同一列上。每個 <code>&lt;td&gt;</code> 元素會創造單個儲存格並且使它們據在同一行,我們新增的每一個儲存格都會使列更長。</p>
+
+<p>要讓這個列停止增加並開始在下一列增加連續的儲存格的話,我們需要用 <strong><code><a href="/en-US/docs/Web/HTML/Element/tr">&lt;tr&gt;</a></code></strong> 元素 ('tr' 代表 'table row'),現在來探討一下:</p>
+
+<ol>
+ <li>放置四個你已新增在 <code>&lt;tr&gt;</code> 標籤裡的儲存格, 像這樣:
+
+ <pre class="brush: html notranslate">&lt;tr&gt;
+ &lt;td&gt;Hi, I'm your first cell.&lt;/td&gt;
+ &lt;td&gt;I'm your second cell.&lt;/td&gt;
+ &lt;td&gt;I'm your third cell.&lt;/td&gt;
+ &lt;td&gt;I'm your fourth cell.&lt;/td&gt;
+&lt;/tr&gt;</pre>
+ </li>
+ <li>現在你已經製作了一列了,可以再繼續做一、二列 — 每個列都需要被額外的 <code>&lt;tr&gt;</code> 元素包裹住, 並且每個儲存格都須包含在一個 <code>&lt;td&gt;</code>  內</li>
+</ol>
+
+<p>表格應該會看起來像下面這樣:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td>Hi, I'm your first cell.</td>
+ <td>I'm your second cell.</td>
+ <td>I'm your third cell.</td>
+ <td>I'm your fourth cell.</td>
+ </tr>
+ <tr>
+ <td>Second row, first cell.</td>
+ <td>Cell 2.</td>
+ <td>Cell 3.</td>
+ <td>Cell 4.</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p><strong>Note</strong>: 你也可以在GitHub 上看到 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/simple-table.html">simple-table.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/basic/simple-table.html">see it live also</a>).</p>
+</div>
+
+<h2 id="用_&lt;th>_加上標頭元素">用 &lt;th&gt; 加上標頭元素</h2>
+
+<p>現在,讓我們把注意力轉移到表格的標頭(table header) — 存在於一列或一欄開頭的特別儲存格並且定義了欄或列中內容的資料型態 (舉個例子, 看看這篇文章中第一個範例裡 的"Person" 和 "Age" 儲存格 )。<br>
+ 為了說明為什麼它們很有用,請看下面的表格例子, 首先是程式碼:</p>
+
+<pre class="brush: html notranslate">&lt;table&gt;
+ &lt;tr&gt;
+ &lt;td&gt;&amp;nbsp;&lt;/td&gt;
+ &lt;td&gt;Knocky&lt;/td&gt;
+ &lt;td&gt;Flor&lt;/td&gt;
+ &lt;td&gt;Ella&lt;/td&gt;
+ &lt;td&gt;Juan&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Breed&lt;/td&gt;
+ &lt;td&gt;Jack Russell&lt;/td&gt;
+ &lt;td&gt;Poodle&lt;/td&gt;
+ &lt;td&gt;Streetdog&lt;/td&gt;
+ &lt;td&gt;Cocker Spaniel&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Age&lt;/td&gt;
+ &lt;td&gt;16&lt;/td&gt;
+ &lt;td&gt;9&lt;/td&gt;
+ &lt;td&gt;10&lt;/td&gt;
+ &lt;td&gt;5&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Owner&lt;/td&gt;
+ &lt;td&gt;Mother-in-law&lt;/td&gt;
+ &lt;td&gt;Me&lt;/td&gt;
+ &lt;td&gt;Me&lt;/td&gt;
+ &lt;td&gt;Sister-in-law&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Eating Habits&lt;/td&gt;
+ &lt;td&gt;Eats everyone's leftovers&lt;/td&gt;
+ &lt;td&gt;Nibbles at food&lt;/td&gt;
+ &lt;td&gt;Hearty eater&lt;/td&gt;
+ &lt;td&gt;Will eat till he explodes&lt;/td&gt;
+ &lt;/tr&gt;
+&lt;/table&gt;</pre>
+
+<p>這是實際渲染出的表格:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td></td>
+ <td>Knocky</td>
+ <td>Flor</td>
+ <td>Ella</td>
+ <td>Juan</td>
+ </tr>
+ <tr>
+ <td>Breed</td>
+ <td>Jack Russell</td>
+ <td>Poodle</td>
+ <td>Streetdog</td>
+ <td>Cocker Spaniel</td>
+ </tr>
+ <tr>
+ <td>Age</td>
+ <td>16</td>
+ <td>9</td>
+ <td>10</td>
+ <td>5</td>
+ </tr>
+ <tr>
+ <td>Owner</td>
+ <td>Mother-in-law</td>
+ <td>Me</td>
+ <td>Me</td>
+ <td>Sister-in-law</td>
+ </tr>
+ <tr>
+ <td>Eating Habits</td>
+ <td>Eats everyone's leftovers</td>
+ <td>Nibbles at food</td>
+ <td>Hearty eater</td>
+ <td>Will eat till he explodes</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>這裡的問題在於,當你找到想知道的資料時,並不容易去找到資料之間對應的位置。如果欄跟列能有個明顯的標示,會比較好理解。</p>
+
+<h3 id="主動學習_表格標頭">主動學習 : 表格標頭</h3>
+
+<p>讓我們來繼續改善這個表格吧!</p>
+
+<ol>
+ <li>首先, 複製 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/dogs-table.html">dogs-table.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">minimal-table.css</a> 檔案到你的電腦。<br>
+ 這份HTML裡包含跟底下你看到的一樣的狗狗範例。</li>
+ <li>為了在語意上和視覺上辨識表格的標頭,你可以使用 <strong><code><a href="/en-US/docs/Web/HTML/Element/th">&lt;th&gt;</a></code></strong> 元素 ('th' 代表 'table header')。它的運作方式跟 <code>&lt;td&gt;</code> 完全相同,除了它表示的是標頭而非一般儲存格外。<br>
+ 繼續修改你的HTML將所有外圍的 <code>&lt;td&gt;</code> 元素變成 <code>&lt;th&gt;</code> 元素。</li>
+ <li>儲存你的HTML並在瀏覽器上執行,現在你應該可以看到標頭應有的樣子。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 你可以在GitHub上的<a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/dogs-table-fixed.html">dogs-table-fixed.html</a>找到我們寫好的完整的範例(<a href="https://mdn.github.io/learning-area/html/tables/basic/dogs-table-fixed.html">直接看看長怎樣</a>).</p>
+</div>
+
+<h3 id="標頭為什麼實用">標頭為什麼實用?</h3>
+
+<p>我們已經部分解答了這個問題 — 當有標頭清楚標示時,它能更簡單的使你找到資料並讓整體設計看起來更完整。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 表格標頭有具備預設樣式 — 粗體並置中,即使你不加上你自己的表格樣式,他們仍然能被凸顯。</p>
+</div>
+
+<p>表格標頭還有一個額外的好處 — 伴隨著 <code>作用域(scope)</code> 屬性 (我們將會在下一個章節中學到),當要連結每個標頭而所有資料都在同一列或欄時,這能允許表格使用起來更無障礙。並且,螢幕閱讀器能一次性讀出完整一列或一欄的資料,這是非常實用的。</p>
+
+<h2 id="允許列或欄的儲存格合併">允許列或欄的儲存格合併</h2>
+
+<p>有時我們想要儲存格涵蓋複數的列或欄,來看看下列顯示常見動物名稱的簡單例子。在某些案例,我們想要將名字代表雄性或雌性顯示在動物名字旁邊,但有些不需要,這種情況下我們只想將動物名字橫跨整個表格。</p>
+
+<p>初始架構會看起來像這樣:</p>
+
+<pre class="brush: html notranslate">&lt;table&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Animals&lt;/th&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Hippopotamus&lt;/th&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Horse&lt;/th&gt;
+ &lt;td&gt;Mare&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Stallion&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Crocodile&lt;/th&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Chicken&lt;/th&gt;
+ &lt;td&gt;Hen&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Rooster&lt;/td&gt;
+ &lt;/tr&gt;
+&lt;/table&gt;</pre>
+
+<p>但輸出的不如我們想要的樣子:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <th>Animals</th>
+ </tr>
+ <tr>
+ <th>Hippopotamus</th>
+ </tr>
+ <tr>
+ <th>Horse</th>
+ <td>Mare</td>
+ </tr>
+ <tr>
+ <td>Stallion</td>
+ </tr>
+ <tr>
+ <th>Crocodile</th>
+ </tr>
+ <tr>
+ <th>Chicken</th>
+ <td>Hen</td>
+ </tr>
+ <tr>
+ <td>Rooster</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>我們需要一種方式讓"Animals", "Hippopotamus", 和 "Crocodile" 橫跨兩個欄位, 然後讓 "Horse" and "Chicken" 向下合併兩列儲存格。幸運地是,表格標頭和儲存格有 <code>colspan</code> 和 <code>rowspan</code> 屬性,可以讓我們這樣做。 兩者都接受無單位的數值等同於你想合併的列或欄的數量。舉例來說,<code>colspan="2"</code> 會讓這個儲存格合併兩欄。</p>
+
+<p>來使用 <code>colspan</code> 和 <code>rowspan</code> 來改善這麼表格吧!</p>
+
+<ol>
+ <li>首先,複製一份我們的 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/animals-table.html">animals-table.html</a> 和 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">minimal-table.css</a> 檔案在你的電腦上。這個HTML包含跟上面同樣的動物範例。</li>
+ <li>接著,使用 <code>colspan</code> 來讓 "Animals", "Hippopotamus", 和 "Crocodile" 合併橫跨兩個欄位。</li>
+ <li>最後, 使用 <code>rowspan</code> 來讓 "Horse" and "Chicken" 合併橫跨兩列。</li>
+ <li>儲存並在瀏覽器上檢視你改善後的程式碼。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 你可以在GitHub上的 <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/animals-table-fixed.html">animals-table-fixed.html</a> 找到我們寫好的完整的範例 (<a href="http://mdn.github.io/learning-area/html/tables/basic/animals-table-fixed.html">see it live also</a>).</p>
+</div>
+
+<table id="tabular" style="background-color: white;">
+</table>
+
+<h2 id="Providing_common_styling_to_columns">Providing common styling to columns</h2>
+
+<p>在我們繼續下去前,我們將要告訴你這節文章最後一個重點。HTML有一個一次定義一整欄樣式資訊的方法 —  <strong><code><a href="/en-US/docs/Web/HTML/Element/col">&lt;col&gt;</a></code></strong>  <strong><code><a href="/en-US/docs/Web/HTML/Element/colgroup">&lt;colgroup&gt;</a></code></strong> 元素。These exist because it can be a bit annoying and inefficient having to specify styling on columns — you generally have to specify your styling information on <em>every</em> <code>&lt;td&gt;</code> or <code>&lt;th&gt;</code> in the column, or use a complex selector such as {{cssxref(":nth-child()")}}.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Styling columns like this is <a href="https://www.w3.org/TR/CSS22/tables.html#columns">limited to a few properties</a>: <code><a href="/en-US/docs/Web/CSS/border">border</a></code>, <code><a href="/en-US/docs/Web/CSS/background">background</a></code>, <code><a href="/en-US/docs/Web/CSS/width">width</a></code>, and <code><a href="/en-US/docs/Web/CSS/visibility">visibility</a></code>. To set other properties you'll have to either style every <code>&lt;td&gt;</code> or <code>&lt;th&gt;</code> in the column, or use a complex selector such as {{cssxref(":nth-child()")}}.</p>
+</div>
+
+<p>Take the following simple example:</p>
+
+<pre class="brush: html notranslate">&lt;table&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Data 1&lt;/th&gt;
+ &lt;th style="background-color: yellow"&gt;Data 2&lt;/th&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Calcutta&lt;/td&gt;
+ &lt;td style="background-color: yellow"&gt;Orange&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Robots&lt;/td&gt;
+ &lt;td style="background-color: yellow"&gt;Jazz&lt;/td&gt;
+ &lt;/tr&gt;
+&lt;/table&gt;</pre>
+
+<p>Which gives us the following result:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <th>Data 1</th>
+ <th style="background-color: yellow;">Data 2</th>
+ </tr>
+ <tr>
+ <td>Calcutta</td>
+ <td style="background-color: yellow;">Orange</td>
+ </tr>
+ <tr>
+ <td>Robots</td>
+ <td style="background-color: yellow;">Jazz</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>This isn't ideal, as we have to repeat the styling information across all three cells in the column (we'd probably have a <code>class</code> set on all three in a real project and specify the styling in a separate stylesheet). Instead of doing this, we can specify the information once, on a <code>&lt;col&gt;</code> element. <code>&lt;col&gt;</code> elements are  specified inside a <code>&lt;colgroup&gt;</code> container just below the opening <code>&lt;table&gt;</code> tag. We could create the same effect as we see above by specifying our table as follows:</p>
+
+<pre class="brush: html notranslate">&lt;table&gt;
+ &lt;colgroup&gt;
+ &lt;col&gt;
+ &lt;col style="background-color: yellow"&gt;
+ &lt;/colgroup&gt;
+ &lt;tr&gt;
+ &lt;th&gt;Data 1&lt;/th&gt;
+ &lt;th&gt;Data 2&lt;/th&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Calcutta&lt;/td&gt;
+ &lt;td&gt;Orange&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;Robots&lt;/td&gt;
+ &lt;td&gt;Jazz&lt;/td&gt;
+ &lt;/tr&gt;
+&lt;/table&gt;</pre>
+
+<p>Effectively we are defining two "style columns", one specifying styling information for each column. We are not styling the first column, but we still have to include a blank <code>&lt;col&gt;</code> element — if we didn't, the styling would just be applied to the first column.</p>
+
+<p>If we wanted to apply the styling information to both columns, we could just include one <code>&lt;col&gt;</code> element with a span attribute on it, like this:</p>
+
+<pre class="brush: html notranslate">&lt;colgroup&gt;
+ &lt;col style="background-color: yellow" span="2"&gt;
+&lt;/colgroup&gt;</pre>
+
+<p>Just like <code>colspan</code> and <code>rowspan</code>, <code>span</code> takes a unitless number value that specifies the number of columns you want the styling to apply to.</p>
+
+<h3 id="Active_learning_colgroup_and_col">Active learning: colgroup and col</h3>
+
+<p>Now it's time to have a go yourself.</p>
+
+<p>Below you can see the timetable of a languages teacher. On Friday she has a new class teaching Dutch all day, but she also teaches German for a few periods on Tuesday and Thursdays. She wants to highlight the columns containing the days she is teaching.</p>
+
+<p>{{EmbedGHLiveSample("learning-area/html/tables/basic/timetable-fixed.html", '100%', 320)}}</p>
+
+<p>Recreate the table by following the steps below.</p>
+
+<ol>
+ <li>First, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/timetable.html">timetable.html</a> file in a new directory on your local machine. The HTML contains the same table you saw above, minus the column styling information.</li>
+ <li>Add a <code>&lt;colgroup&gt;</code> element at the top of the table, just underneath the <code>&lt;table&gt;</code> tag, in which you can add your <code>&lt;col&gt;</code> elements (see the remaining steps below).</li>
+ <li>The first two columns need to be left unstyled.</li>
+ <li>Add a background color to the third column. The value for your <code>style</code> attribute is <code>background-color:#97DB9A;</code></li>
+ <li>Set a separate width on the fourth column. The value for your <code>style</code> attribute is <code>width: 42px;</code></li>
+ <li>Add a background color to the fifth column. The value for your <code>style</code> attribute is <code>background-color: #97DB9A;</code></li>
+ <li>Add a different background color plus a border to the sixth column, to signify that this is a special day and she's teaching a new class. The values for your <code>style</code> attribute are <code>background-color:#DCC48E; border:4px solid #C1437A;</code></li>
+ <li>The last two days are free days, so just set them to no background color but a set width; the value for the <code>style</code> attribute is <code>width: 42px;</code></li>
+</ol>
+
+<p>See how you get on with the example. If you get stuck, or want to check your work, you can find our version on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/timetable-fixed.html">timetable-fixed.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/basic/timetable-fixed.html">see it live also</a>).</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>That just about wraps up the basics of HTML Tables. In the next article we will look at some slightly more advanced table features, and start to think how accessible they are for visually impaired people.</p>
+
+<div>{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</div>
+
+<div>
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/HTML/Tables/Basics">HTML table basics</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Tables/Advanced">HTML table advanced features and accessibility</a></li>
+ <li><a href="/en-US/docs/Learn/HTML/Tables/Structuring_planet_data">Structuring planet data</a></li>
+</ul>
+</div>
diff --git a/files/zh-tw/learn/index.html b/files/zh-tw/learn/index.html
new file mode 100644
index 0000000000..729b0d7999
--- /dev/null
+++ b/files/zh-tw/learn/index.html
@@ -0,0 +1,238 @@
+---
+title: 學習該如何開發 Web
+slug: Learn
+tags:
+ - Beginner
+ - Index
+ - Landing
+ - Learn
+ - NeedsTranslation
+ - TopicStub
+ - Web
+translation_of: Learn
+---
+<div class="boxed translate-rendered">
+<div>
+<p class="summary"></p>
+
+<p>{{LearnSidebar}}</p>
+
+<p class="summary"></p>
+
+<p class="summary">歡迎來到 MDN 的「學習專區(Learning Area)」。本系列文章將提供撰寫程式碼的必要網站,讓剛接觸的新手也能開發 Web。</p>
+</div>
+
+<p>MDN 學習專區不是要讓「初學者」變成「專家」;而是想讓「初學者」能夠更怡然自得。你在這裡可完全安排自己的進度,逐步探索<a href="https://developer.mozilla.org/zh-TW/"> MDN 的其他部分</a>,再接觸進階資源來堆砌之前所習得的知識。</p>
+
+<p>如果你是完全的新手,那 Web 開發過程可能頗有難度。我們希望能帶領你輕鬆學習,另提供相關細節以培養你的正確觀念。不論你是要學習 Web 開發(自學或參與課程)的學生、尋找教材的老師、純粹興趣使然的業餘工程師,甚至只是想進一步了解 Web 技術的人,都希望你在這裡就像在家裡一樣自在。</p>
+
+<div class="warning">
+<p><strong>重要:</strong>此學習專區將定期新增更多資訊。如果你希望能納入其他自己感興趣的主題,或覺得某個地方尚有缺漏,請到下方的{{anch("聯絡我們")}}尋找相關資訊並取得聯繫。</p>
+</div>
+
+<h2 id="入門">入門</h2>
+
+<ul class="card-grid">
+ <li><span>完全新手:</span>如果你正打算接觸 Web 開發,我們建議先從提供了實用 Web 開發介紹的<a href="/zh-TW/docs/Learn/Getting_started_with_the_web">入門 Web</a>模組。</li>
+ <li><span>特殊問題:</span>如果你對 Web 開發有著特殊問題,<a href="/zh-TW/docs/Learn/Common_questions">常見問題</a>可能有你所需要的資訊。</li>
+ <li><span>基礎以外:</span>如果你已經具備基本知識,則下一步就是了解 {{glossary("HTML")}} 與 {{glossary("CSS")}} 的細節。可從<a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a>模組著手,再進到<a href="/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 介紹</a>。</li>
+ <li><span>寫些腳本:</span>如果你嫻熟 HTML 與 CSS 或想動手寫程式碼,要不要去 {{glossary("JavaScript")}} 或伺服器端語言那邊看看呢──就從我們的 <a href="/zh-TW/docs/Learn/JavaScript/First_steps">JavaScript 起步走</a>與<a href="/zh-TW/docs/Learn/Server-side/First_steps">伺服器端程式設計起步走</a>開始吧。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意:</strong>我們的<a href="https://developer.mozilla.org/zh-TW/docs/Glossary">字彙庫</a>另提供專有名詞的定義。</p>
+</div>
+
+<p>{{LearnBox({"title":"Random glossary entry"})}}</p>
+
+<h2 id="涵蓋主題">涵蓋主題</h2>
+
+<p>以下是 MDN 學習專區內涵蓋的主題清單。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Getting_started_with_the_web">Web 入門</a></dt>
+ <dd>針對完全新手提供實際介紹。</dd>
+ <dt><a href="/zh-TW/docs/Learn/HTML">HTML:構建 Web</a></dt>
+ <dd>HTML 是構建不同區域的內容、還有定義這些區域意義和用途的語言。這個主題詳述了 HTML。</dd>
+ <dt><a href="/zh-TW/docs/Learn/CSS">CSS:裝飾 Web</a></dt>
+ <dd>CSS 是用來妝點和編排 web 內容、添加動畫行為之類的語言。這個主題總括 CSS 的一切。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript">JavaScript:動態用戶端腳本</a></dt>
+ <dd>JavaScript 是給網頁添加動態功能的語言。這個主題會教你要自在理解並撰寫 JavaScript 所需的一切。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Accessibility">無障礙網頁:讓大家都能用上 Web</a></dt>
+ <dd>無障礙網頁是給盡可能給任何人提供 Web 內容的做法,無論那個人是否受障礙、設備、地點、或其他原因影響。這個主題提供你需要知道的一切。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing">工具與測試</a></dt>
+ <dd>這個主題介紹開發者用來改善工作的工具,如跨瀏覽器測試工具。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side">伺服端網站程式設計</a></dt>
+ <dd>就算對用戶端 Web 開發熟悉了,理解伺服器和伺服器端程式如何做動是很有用的。這個主題提供了伺服器端做動原理的總體介紹,並藉著兩大熱門框架──Django(Python)與 Express(node.js)──詳細說明如何建立伺服器端 app。</dd>
+</dl>
+
+<h2 id="取得我們的範例程式碼">取得我們的範例程式碼</h2>
+
+<p>在學習專區看到的所有程式碼都<a href="https://github.com/mdn/learning-area/">放在 GitHub 上了</a>。如果想把它們複製到自己的電腦,最簡單的方法是:</p>
+
+<ol>
+ <li>在電腦上<a href="http://git-scm.com/downloads">安裝 Git</a>。這個版本控制系統,是 GitHub 運作的基礎。</li>
+ <li><a href="https://github.com/join">在 GitHub 註冊一個帳號</a>。很簡單的。</li>
+ <li>註冊好後用自己的帳密登入 <a href="https://github.com">github.com</a>。</li>
+ <li>開啟你的<a href="https://www.lifewire.com/how-to-open-command-prompt-2618089">命令提示字元</a>(Windows)(譯註:如果使用 Windows 7 以後,建議使用 <a href="https://msdn.microsoft.com/en-us/powershell">Powershell</a>)或是終端機(<a href="https://help.ubuntu.com/community/UsingTheTerminal">Linux</a>、<a href="http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line">MacOSX</a>)</li>
+ <li>要把學習專區的 repo 透過命令提示字元/終端機複製到目錄裡面,稱作 learning-area 的資料夾,只要鍵入以下指令:
+ <pre class="brush: bash notranslate">git clone https://github.com/mdn/learning-area</pre>
+ </li>
+ <li>現在你能透過檔案管理員或 <a href="https://zh.wikipedia.org/wiki/Cd_(%E5%91%BD%E4%BB%A4)">cd 指令</a>進入目錄,找到想要的檔案了。</li>
+</ol>
+
+<p>你可以在 GitHub 的 <code>learning-area</code> repository 做任何更新,只要這麼做:</p>
+
+<ol>
+ <li>在命令提示字元/終端機裡面,用 <code>cd</code> 進到 <code>learning-area</code> 目錄,例如說你要是在上一層目錄的話:
+
+ <pre class="brush: bash notranslate">cd learning-area</pre>
+ </li>
+ <li>用這個指令更新 repository:
+ <pre class="brush: bash notranslate">git pull</pre>
+ </li>
+</ol>
+
+<p>{{LearnBox({"title":"隨機了解常見的相關術語"})}}</p>
+
+<h2 id="聯絡我們">聯絡我們</h2>
+
+<p>如果你想向我們詢問任何事情,最快的方式就是透過<a href="https://discourse.mozilla-community.org/t/learning-web-development-marking-guides-and-questions/16294">學習專區討論串</a>或 <a href="https://developer.mozilla.org/zh-TW/docs/MDN/Community/Conversations#Chat_in_IRC">IRC 頻道</a>留下訊息。不論你覺得網站有哪個地方做錯或缺漏,想看到新的學習主題、對自己不了解的地方尋求協助,或其他疑難雜症,都歡迎你提供意見給我們。</p>
+
+<p>如果你想幫我們添增\改善內容,則請先了解<a href="https://developer.mozilla.org/zh-TW/Learn/How_to_contribute">該如何協助</a>並聯絡我們!不論你是學生、教師、Web 開發老手,或是想幫我們改善學習經驗,都歡迎和我們聯絡。</p>
+
+<h2 id="另可參閱">另可參閱</h2>
+
+<dl>
+ <dt><a href="https://www.mozilla.org/zh-TW/newsletter/developer/">Mozilla Developer Newsletter</a></dt>
+ <dd>我們針對網頁開發者發行的電子報,對於所有程度的開發者都是很好的學習資源。</dd>
+ <dt><a href="https://exlskills.com/learn-en/courses">EXLskills</a> </dt>
+ <dd>免費和開放的課程,學習技術技能,指導和基於項目的學習</dd>
+ <dt><a href="https://www.codecademy.com/">Codecademy</a></dt>
+ <dd>絕妙的互動式網站,可從頭開始學習程式設計語言。</dd>
+ <dt><a href="https://code.org/">Code.org</a></dt>
+ <dd>基本的編碼理論與實作,主要為孩童與初學者所設計。</dd>
+ <dt><a href="https://www.freecodecamp.com/">freeCodeCamp.com</a></dt>
+ <dd>富含教學與專案實做的互動式網路開發學習網站。</dd>
+</dl>
+
+<dl>
+ <dt><a href="https://teach.mozilla.org/web-literacy/">Web Literacy Map</a></dt>
+ <dd>Web 素養與 21 世紀常見技術的入門,亦已分門別類提供教學活動。</dd>
+ <dt><a href="https://teach.mozilla.org/activities">Teaching activities</a></dt>
+ <dd>由 Mozilla 基金會所設計的一系列教學 (與學習) 活動,涵蓋 JavaScript 的基本 Web 素養與隱私概念,並可嘗試開發 Minecraft。</dd>
+</dl>
+
+<h5 id="Subnav">Subnav</h5>
+
+<ol>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/Getting_started_with_the_web">Web 入門</a>
+
+ <ol>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Installing_basic_software">安裝基本軟體</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/What_will_your_website_look_like">你的網站看起來會是什麼樣子?</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Dealing_with_files">與各式各樣檔案打交道</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/HTML_basics">HTML 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/CSS_basics">CSS 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基本概念</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/Publishing_your_website">將你的網站發佈上線</a></li>
+ <li><a href="/zh-TW/Learn/Getting_started_with_the_web/How_the_Web_works">網站的運作方式</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/HTML">HTML — 建構 Web</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/Learn/HTML">HTML 概述</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 介紹</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 基本介紹</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 入門</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">先入為主?HTML 的 Metadata</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 文字基本概念</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">建立超連結</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">進階文字格式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">文件與網站架構</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">HTML 除錯</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">評量習題:對字母標記</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">評量習題:建構內容網頁</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/HTML/Multimedia_and_embedding">多媒體與嵌入</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding">多媒體與嵌入概述</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">HTML 圖像</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">視訊與音訊內容</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">從物件到 iframe — 其他嵌入技術</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">為 Web 新增向量圖像</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">有所回應互動的圖像</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">評量習題:Mozilla splash 頁面</a></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/CSS">CSS — 讓 Web 別有風格</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/Learn/CSS">CSS 概述</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 介紹</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 基本介紹</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/How_CSS_works">CSS 運作方式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Syntax">CSS 語法</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Selectors">選擇器(Selectors)</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">CSS 數值與單位</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance">串接 (Cascade) 與繼承 (Inheritance)</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Box_model">區塊模型 (Box model)</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Debugging_CSS">CSS 除錯</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Fundamental_CSS_comprehension">評量習題:基礎的 CSS 綜合運算 (Comprehension)</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text">文字樣式</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text">文字樣式概述 </a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text/Fundamentals">文字與字體樣式基本原則</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text/Styling_lists">清單樣式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text/Styling_links">連結樣式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text/Web_fonts">Web 字型</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_text/Typesetting_a_homepage">評量習題:Typesetting a community school homepage</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes">框盒 (boxes) 樣式</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes">框盒樣式概述</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/Box_model_recap">框盒模型 (Box model) 回顧</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/Backgrounds">背景</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/Borders">邊框</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/Styling_tables">表格樣式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/Advanced_box_effects">進階框盒效果</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/CSS/Styling_boxes/Creating_fancy_letterheaded_paper">評量習題:Creating fancy letterheader paper</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Styling_boxes/A_cool_looking_box">評量習題:A cool looking box</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout">CSS 配置</a>
+ <ol>
+ <li><strong><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout">CSS 配置概述</a></strong></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout/Floats">浮動布局(Floats)</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">Practical positioning examples</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/CSS_layout/Flexbox">彈性盒子(Flexbox)</a></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/Other_learning_material">進階學習教材</a>
+ <ol>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/JavaScript">JavaScript — 動態指令</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/WebGL">WebGL — 圖像處理</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Common_questions">常見問題</a>
+ <ol>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/HTML/Howto">HTML 問題</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Howto">CSS 問題</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/Common_questions#How_the_Web_works">Web 運作方式</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/Common_questions#Tools_and_setup">工具與設定</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/Common_questions#Design_and_accessibility">設計與親和度</a></li>
+ </ol>
+ </li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Learn/How_to_contribute">該如何貢獻</a><a href="https://developer.mozilla.org/zh-TW/Learn/How_to_contribute"> </a></li>
+</ol>
+</div>
diff --git a/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html b/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html
new file mode 100644
index 0000000000..80b134992a
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/build_your_own_function/index.html
@@ -0,0 +1,246 @@
+---
+title: 建立自己的功能函數
+slug: Learn/JavaScript/Building_blocks/Build_your_own_function
+translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">通過前一篇文章中討論的大部分基本理論,本文提供了實踐經驗。 在這裡,您將學習構建自己的自定義功能函數。 在此過程中,我們還將解釋處理函數的一些有用細節。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a basic understanding of HTML and CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To provide some practice in building a custom function, and explain a few more useful associated details.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Active_learning_Let's_build_a_function">Active learning: Let's build a function</h2>
+
+<p>The custom function we are going to build will be called <code>displayMessage()</code>. It will display a custom message box on a web page and will act as a customized replacement for a browser's built-in <a href="/en-US/docs/Web/API/Window/alert">alert()</a> function. We've seen this before, but let's just refresh our memories. Type the following in your browser's JavaScript console, on any page you like:</p>
+
+<pre class="brush: js">alert('This is a message');</pre>
+
+<p>The <code>alert</code> function takes a single argument — the string that is displayed in the alert box. Try varying the string to change the message.</p>
+
+<p>The <code>alert</code> function is limited: you can alter the message, but you can't easily vary anything else, such as the color, icon, or anything else. We'll build one that will prove to be more fun.</p>
+
+<div class="note">
+<p><strong>Note</strong>: This example should work in all modern browsers fine, but the styling might look a bit funny in slightly older browsers. We'd recommend you doing this exercise in a modern browser like Firefox, Opera, or Chrome.</p>
+</div>
+
+<h2 id="The_basic_function">The basic function</h2>
+
+<p>To begin with, let's put together a basic function.</p>
+
+<div class="note">
+<p><strong>Note</strong>: For function naming conventions, you should follow the same rules as <a href="/en-US/Learn/JavaScript/First_steps/Variables#An_aside_on_variable_naming_rules">variable naming conventions</a>. This is fine, as you can tell them apart — function names appear with parentheses after them, and variables don't.</p>
+</div>
+
+<ol>
+ <li>Start by accessing the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a> file and making a local copy. You'll see that the HTML is simple — the body contains just a single button. We've also provided some basic CSS to style the custom message box, and an empty {{htmlelement("script")}} element to put our JavaScript in.</li>
+ <li>Next, add the following inside the <code>&lt;script&gt;</code> element:
+ <pre class="brush: js">function displayMessage() {
+
+}</pre>
+ We start off with the keyword <code>function</code>, which means we are defining a function. This is followed by the name we want to give to our function, a set of parentheses, and a set of curly braces. Any parameters we want to give to our function go inside the parentheses, and the code that runs when we call the function goes inside the curly braces.</li>
+ <li>Finally, add the following code inside the curly braces:
+ <pre class="brush: js">var html = document.querySelector('html');
+
+var panel = document.createElement('div');
+panel.setAttribute('class', 'msgBox');
+html.appendChild(panel);
+
+var msg = document.createElement('p');
+msg.textContent = 'This is a message box';
+panel.appendChild(msg);
+
+var closeBtn = document.createElement('button');
+closeBtn.textContent = 'x';
+panel.appendChild(closeBtn);
+
+closeBtn.onclick = function() {
+ panel.parentNode.removeChild(panel);
+}</pre>
+ </li>
+</ol>
+
+<p>This is quite a lot of code to go through, so we'll walk you through it bit by bit.</p>
+
+<p>The first line uses a DOM API function called {{domxref("document.querySelector()")}} to select the {{htmlelement("html")}} element and store a reference to it in a variable called <code>html</code>, so we can do things to it later on:</p>
+
+<pre class="brush: js">var html = document.querySelector('html');</pre>
+
+<p>The next section uses another DOM API function called {{domxref("Document.createElement()")}} to create a {{htmlelement("div")}} element and store a reference to it in a variable called <code>panel</code>. This element will be the outer container of our message box.</p>
+
+<p>We then use yet another DOM API function called {{domxref("Element.setAttribute()")}} to set a <code>class</code> attribute on our panel with a value of <code>msgBox</code>. This is to make it easier to style the element — if you look at the CSS on the page, you'll see that we are using a <code>.msgBox</code> class selector to style the message box and its contents.</p>
+
+<p>Finally, we call a DOM function called {{domxref("Node.appendChild()")}} on the <code>html</code> variable we stored earlier, which nests one element inside the other as a child of it. We specify the panel <code>&lt;div&gt;</code> as the child we want to append inside the <code>&lt;html&gt;</code> element. We need to do this as the element we created won't just appear on the page on its own — we need to specify where to put it.</p>
+
+<pre class="brush: js">var panel = document.createElement('div');
+panel.setAttribute('class', 'msgBox');
+html.appendChild(panel);</pre>
+
+<p>The next two sections make use of the same <code>createElement()</code> and <code>appendChild()</code> functions we've already seen to create two new elements — a {{htmlelement("p")}} and a {{htmlelement("button")}} — and insert them in the page as children of the panel <code>&lt;div&gt;</code>. We use their {{domxref("Node.textContent")}} property — which represents the text content of an element — to insert a message inside the paragraph, and an 'x' inside the button. This button will be what needs to be clicked/activated when the user wants to close the message box.</p>
+
+<pre class="brush: js">var msg = document.createElement('p');
+msg.textContent = 'This is a message box';
+panel.appendChild(msg);
+
+var closeBtn = document.createElement('button');
+closeBtn.textContent = 'x';
+panel.appendChild(closeBtn);</pre>
+
+<p>Finally, we use an {{domxref("GlobalEventHandlers.onclick")}} event handler to make it so that when the button is clicked, some code is run to delete the whole panel from the page — to close the message box.</p>
+
+<p>Briefly, the <code>onclick</code> handler is a property available on the button (or in fact, any element on the page) that can be set to a function to specify what code to run when the button is clicked. You'll learn a lot more about these in our later events article. We are making the <code>onclick</code> handler equal to an anonymous function, which contains the code to run when the button is clicked. The line inside the function uses the {{domxref("Node.removeChild()")}} DOM API function to specify that we want to remove a specific child element of the HTML element — in this case the panel <code>&lt;div&gt;</code>.</p>
+
+<pre class="brush: js">closeBtn.onclick = function() {
+ panel.parentNode.removeChild(panel);
+}</pre>
+
+<p>Basically, this whole block of code is generating a block of HTML that looks like so, and inserting it into the page:</p>
+
+<pre class="brush: html">&lt;div class="msgBox"&gt;
+ &lt;p&gt;This is a message box&lt;/p&gt;
+ &lt;button&gt;x&lt;/button&gt;
+&lt;/div&gt;</pre>
+
+<p>That was a lot of code to work through — don't worry too much if you don't remember exactly how every bit of it works right now! The main part we want to focus on here is the function's structure and usage, but we wanted to show something interesting for this example.</p>
+
+<h2 id="Calling_the_function">Calling the function</h2>
+
+<p>You've now got your function definition written into your <code>&lt;script&gt;</code> element just fine, but it will do nothing as it stands.</p>
+
+<ol>
+ <li>Try including the following line below your function to call it:
+ <pre class="brush: js">displayMessage();</pre>
+ This line invokes the function, making it run immediately. When you save your code and reload it in the browser, you'll see the little message box appear immediately, only once. We are only calling it once, after all.</li>
+ <li>
+ <p>Now open your browser developer tools on the example page, go to the JavaScript console and type the line again there, you'll see it appear again! So this is fun — we now have a reusable function that we can call any time we like.</p>
+
+ <p>But we probably want it to appear in response to user and system actions. In a real application, such a message box would probably be called in response to new data being available, or an error having occurred, or the user trying to delete their profile ("are you sure about this?"), or the user adding a new contact and the operation completing successfully ... etc.</p>
+
+ <p>In this demo, we'll get the message box to appear when the user clicks the button.</p>
+ </li>
+ <li>Delete the previous line you added.</li>
+ <li>Next, we'll select the button and store a reference to it in a variable. Add the following line to your code, above the function definition:
+ <pre class="brush: js">var btn = document.querySelector('button');</pre>
+ </li>
+ <li>Finally, add the following line below the previous one:
+ <pre class="brush: js">btn.onclick = displayMessage;</pre>
+ In a similar way to our <code>closeBtn.onclick...</code> line inside the function, here we are calling some code in response to a button being clicked. But in this case, instead of calling an anonymous function containing some code, we are calling our function name directly.</li>
+ <li>Try saving and refreshing the page — now you should see the message box appear when you click the button.</li>
+</ol>
+
+<p>You might be wondering why we haven't included the parentheses after the function name. This is because we don't want to call the function immediately — only after the button has been clicked. If you try changing the line to</p>
+
+<pre class="brush: js">btn.onclick = displayMessage();</pre>
+
+<p>and saving and reloading, you'll see that the message box appears without the button being clicked! The parentheses in this context are sometimes called the "function invocation operator". You only use them when you want to run the function immediately in the current scope. In the same respect, the code inside the anonymous function is not run immediately, as it is inside the function scope.</p>
+
+<p>If you tried the last experiment, make sure to undo the last change before carrying on.</p>
+
+<h2 id="Improving_the_function_with_parameters">Improving the function with parameters</h2>
+
+<p>As it stands, the function is still not very useful — we don't want to just show the same default message every time. Let's improve our function by adding some parameters, allowing us to call it with some different options.</p>
+
+<ol>
+ <li>First of all, update the first line of the function:
+ <pre class="brush: js">function displayMessage() {</pre>
+ to this:
+
+ <pre class="brush: js">function displayMessage(msgText, msgType) {</pre>
+ Now when we call the function, we can provide two variable values inside the parentheses to specify the message to display in the message box, and the type of message it is.</li>
+ <li>To make use of the first parameter, update the following line inside your function:
+ <pre class="brush: js">msg.textContent = 'This is a message box';</pre>
+ to
+
+ <pre class="brush: js">msg.textContent = msgText;</pre>
+ </li>
+ <li>Last but not least, you now need to update your function call to include some updated message text. Change the following line:
+ <pre class="brush: js">btn.onclick = displayMessage;</pre>
+ to this block:
+
+ <pre class="brush: js">btn.onclick = function() {
+ displayMessage('Woo, this is a different message!');
+};</pre>
+ If we want to specify parameters inside parentheses for the function we are calling, then we can't call it directly — we need to put it inside an anonymous function so that it isn't in the immediate scope and therefore isn't called immediately. Now it will not be called until the button is clicked.</li>
+ <li>Reload and try the code again and you'll see that it still works just fine, except that now you can also vary the message inside the parameter to get different messages displayed in the box!</li>
+</ol>
+
+<h3 id="A_more_complex_parameter">A more complex parameter</h3>
+
+<p>On to the next parameter. This one is going to involve slightly more work — we are going to set it so that depending on what the <code>msgType</code> parameter is set to, the function will display a different icon and a different background color.</p>
+
+<ol>
+ <li>First of all, download the icons needed for this exercise (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">warning</a> and <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">chat</a>) from GitHub. Save them in a new folder called <code>icons</code> in the same location as your HTML file.
+
+ <div class="note"><strong>Note</strong>: <a href="https://www.iconfinder.com/icons/1031466/alarm_alert_error_warning_icon">warning</a> and <a href="https://www.iconfinder.com/icons/1031441/chat_message_text_icon">chat</a> icons found on iconfinder.com, and designed by <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a>. Thanks!</div>
+ </li>
+ <li>Next, find the CSS inside your HTML file. We'll make a few changes to make way for the icons. First, update the <code>.msgBox</code> width from:
+ <pre class="brush: css">width: 200px;</pre>
+ to
+
+ <pre class="brush: css">width: 242px;</pre>
+ </li>
+ <li>Next, add the following lines inside the <code>.msgBox p { ... }</code> rule:
+ <pre class="brush: css">padding-left: 82px;
+background-position: 25px center;
+background-repeat: no-repeat;</pre>
+ </li>
+ <li>Now we need to add code to our <code>displayMessage()</code> function to handle displaying the icons. Add the following block just above the closing curly brace (<code>}</code>) of your function:
+ <pre class="brush: js">if (msgType === 'warning') {
+ msg.style.backgroundImage = 'url(icons/warning.png)';
+ panel.style.backgroundColor = 'red';
+} else if (msgType === 'chat') {
+ msg.style.backgroundImage = 'url(icons/chat.png)';
+ panel.style.backgroundColor = 'aqua';
+} else {
+ msg.style.paddingLeft = '20px';
+}</pre>
+ Here, if the <code>msgType</code> parameter is set as <code>'warning'</code>, the warning icon is displayed and the panel's background color is set to red. If it is set to <code>'chat'</code>, the chat icon is displayed and the panel's background color is set to aqua blue. If the <code>msgType</code> parameter is not set at all (or to something different), then the <code>else { ... }</code> part of the code comes into play, and the paragraph is simply given default padding and no icon, with no background panel color set either. This provides a default state if no <code>msgType</code> parameter is provided, meaning that it is an optional parameter!</li>
+ <li>Let's test out our updated function, try updating the <code>displayMessage()</code> call from this:
+ <pre class="brush: js">displayMessage('Woo, this is a different message!');</pre>
+ to one of these:
+
+ <pre class="brush: js">displayMessage('Your inbox is almost full — delete some mails', 'warning');
+displayMessage('Brian: Hi there, how are you today?','chat');</pre>
+ You can see how useful our (now not so) little function is becoming.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: If you have trouble getting the example to work, feel free to check your code against the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">finished version on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">see it running live</a> also), or ask us for help.</p>
+</div>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>Congratulations on reaching the end! This article took you through the entire process of building up a practical custom function, which with a bit more work could be transplanted into a real project. In the next article we'll wrap up functions by explaining another essential related concept — return values.</p>
+
+<ul>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html b/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html
new file mode 100644
index 0000000000..8b63b1034d
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/conditionals/index.html
@@ -0,0 +1,789 @@
+---
+title: 在代碼中做出決定 - 條件
+slug: Learn/JavaScript/Building_blocks/conditionals
+translation_of: Learn/JavaScript/Building_blocks/conditionals
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">在任何編程語言中,代碼都需要根據不同的輸入做出決策並相應地執行操作。 例如,在遊戲中,如果玩家的生命數量為0,則遊戲結束。 在天氣應用程序中,如果在早上查看,則顯示日出圖形; 如果是夜晚,則顯示星星和月亮。 在本文中,我們將探討條件結構如何在JavaScript中工作。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a basic understanding of HTML and CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand how to use conditional structures in JavaScript.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="你可以擁有一個條件..!">你可以擁有一個條件..!</h2>
+
+<p>從小到大,人們(和其它動物)作出決定的時間會影響到他們的生活 ("我應該吃一個或兩個餅乾?")  ("我應該留在我的家鄉並在我父親的農場工作還是應該要到美國研讀天體物理學?")</p>
+
+<p>條件敘述句(Conditional statements)讓我們能將這些決定的過程在Javascript表示出來,從一定得做出的選擇(例如:「吃一個或兩個餅乾」),到這些選擇的結果(或許「吃一個餅乾」會出現「還是會餓」這種結果,而「吃兩個餅乾」的結果會是「吃飽了,但因為吃了全部餅乾而被媽媽罵」)。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p>
+
+<h2 id="if_..._else_敘述句">if ... else 敘述句</h2>
+
+<p>讓我們來看Javascript中最常見的條件敘述句 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if ... else</a></code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else"> statement</a>.</p>
+
+<h3 id="基本的_if_..._else_語法">基本的 if ... else 語法</h3>
+
+<p>最基本的 <code>if...else</code> 語法看起來像以下 {{glossary("虛擬碼")}}:</p>
+
+<pre>if (condition) {
+ code to run if condition is true
+} else {
+ run some other code instead
+}</pre>
+
+<p>這邊我們可以得知基礎的架構:</p>
+
+<ol>
+ <li>關鍵字 <code>if</code> 和後頭的括號。</li>
+ <li>想測試的條件放在括號中(通常像是「這個值是否大於其他值」或是「這個值是否存在」等等)。這裡的條件會使用先前提過的 <a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">比較運算子</a>(<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">comparison operators</a>),並且最後會回傳 <code>true</code> 或是 <code>false</code>。</li>
+ <li>第一組大括號,在大括號裡面有一些程式碼 — 內容可以是任何我們所需要執行的程式碼,並且只有在條件句回傳 <code>true</code> 才會執行。</li>
+ <li>關鍵字 <code>else</code>。</li>
+ <li>另一組大括號,在大括號中我們一樣是放置所需的程式碼,並只有在條件句回傳 <code>false</code> 才會執行。</li>
+</ol>
+
+<p>這個程式碼的架構很容易理解  — 「如果條件回傳 <code>true</code> ,則執行程式A,否則執行程式B」。</p>
+
+<p>值得注意的是,<code>else</code> 和第二組大括號並不是必要的。如以下範例也能夠執行:</p>
+
+<pre>if (condition) {
+ code to run if condition is true
+}
+
+run some other code</pre>
+
+<p>然而,在這邊有一點要注意:在這個例子中的第二個區塊並沒有被條件式控制,也就是說無論條件式回傳的是 <code>true</code> 或是 <code>false</code>,它都會執行。這並不一定是件壞事,但它可能不會是你要的,通常你可能是想要執行程式碼的一個區塊或是另一塊,而不是兩個都執行。</p>
+
+<p>最後一點,你可能有時候會看到 <code>if...else</code> 敘述是不加大括弧的:</p>
+
+<pre>if (condition) code to run if condition is true
+else run some other code instead</pre>
+
+<p>這當然也是有效的程式碼,但不太建議這樣用。使用大括弧能夠很清楚地看到程式區塊、縮排,也能夠擁有多行程式碼,對於程式的可讀性會提高許多。</p>
+
+<h3 id="A_real_example">A real example</h3>
+
+<p>To understand this syntax better, let's consider a real example. Imagine a child being asked for help with a chore by their mother or father. The parent might say "Hey sweetheart, if you help me by going and doing the shopping, I'll give you some extra allowance so you can afford that toy you wanted." In JavaScript, we could represent this like so:</p>
+
+<pre class="brush: js">var shoppingDone = false;
+
+if (shoppingDone === true) {
+ var childsAllowance = 10;
+} else {
+ var childsAllowance = 5;
+}</pre>
+
+<p>This code as shown will always result in the <code>shoppingDone</code> variable returning <code>false</code>, meaning disappointment for our poor child. It'd be up to us to provide a mechanism for the parent to set the <code>shoppingDone</code> variable to <code>true</code> if the child did the shopping.</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can see a more <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">complete version of this example on GitHub</a> (also see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">running live</a>.)</p>
+</div>
+
+<h3 id="else_if">else if</h3>
+
+<p>The last example provided us with two choices, or outcomes — but what if we want more than two?</p>
+
+<p>There is a way to chain on extra choices/outcomes to your <code>if...else</code> — using <code>else if</code>. Each extra choice requires an additional block to put in between <code>if() { ... }</code> and <code>else { ... }</code> — check out the following more involved example, which could be part of a simple weather forecast application:</p>
+
+<pre class="brush: html">&lt;label for="weather"&gt;Select the weather type today: &lt;/label&gt;
+&lt;select id="weather"&gt;
+ &lt;option value=""&gt;--Make a choice--&lt;/option&gt;
+ &lt;option value="sunny"&gt;Sunny&lt;/option&gt;
+ &lt;option value="rainy"&gt;Rainy&lt;/option&gt;
+ &lt;option value="snowing"&gt;Snowing&lt;/option&gt;
+ &lt;option value="overcast"&gt;Overcast&lt;/option&gt;
+&lt;/select&gt;
+
+&lt;p&gt;&lt;/p&gt;</pre>
+
+<pre class="brush: js">var select = document.querySelector('select');
+var para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+function setWeather() {
+ var choice = select.value;
+
+ if (choice === 'sunny') {
+ para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+ } else if (choice === 'rainy') {
+ para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+ } else if (choice === 'snowing') {
+ para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+ } else if (choice === 'overcast') {
+ para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+ } else {
+ para.textContent = '';
+ }
+}
+
+</pre>
+
+<p>{{ EmbedLiveSample('else_if', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<ol>
+ <li>Here we've got an HTML {{htmlelement("select")}} element allowing us to make different weather choices, and a simple paragraph.</li>
+ <li>In the JavaScript, we are storing a reference to both the {{htmlelement("select")}} and {{htmlelement("p")}} elements, and adding an event listener to the <code>&lt;select&gt;</code> element so that when its value is changed, the <code>setWeather()</code> function is run.</li>
+ <li>When this function is run, we first set a variable called <code>choice</code> to the current value selected in the <code>&lt;select&gt;</code> element. We then use a conditional statement to show different text inside the paragraph depending on what the value of <code>choice</code> is. Notice how all the conditions are tested in <code>else if() {...}</code> blocks, except for the first one, which is tested in an <code>if() {...} block</code>.</li>
+ <li>The very last choice, inside the <code>else {...}</code> block, is basically a "last resort" option — the code inside it will be run if none of the conditions are <code>true</code>. In this case, it serves to empty the text out of the paragraph if nothing is selected, for example if a user decides to re-select the "--Make a choice--" placeholder option shown at the beginning.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">find this example on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">see it running live</a> on there also.)</p>
+</div>
+
+<h3 id="A_note_on_comparison_operators">A note on comparison operators</h3>
+
+<p>Comparison operators are used to test the conditions inside our conditional statements. We first looked at comparison operators back in our <a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Basic math in JavaScript — numbers and operators</a> article. Our choices are:</p>
+
+<ul>
+ <li><code>===</code> and <code>!==</code> — test if one value is identical to, or not identical to, another.</li>
+ <li><code>&lt;</code> and <code>&gt;</code> — test if one value is less than or greater than another.</li>
+ <li><code>&lt;=</code> and <code>&gt;=</code> — test if one value is less than or equal to, or greater than or equal to, another.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Review the material at the previous link if you want to refresh your memories on these.</p>
+</div>
+
+<p>We wanted to make a special mention of testing boolean (<code>true</code>/<code>false</code>) values, and a common pattern you'll come across again and again. Any value that is not <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code>, or an empty string (<code>''</code>) actually returns <code>true</code> when tested as a conditional statement, therefore you can simply use a variable name on its own to test whether it is <code>true</code>, or even that it exists (i.e. it is not undefined.) So for example:</p>
+
+<pre class="brush: js">var cheese = 'Cheddar';
+
+if (cheese) {
+ console.log('Yay! Cheese available for making cheese on toast.');
+} else {
+ console.log('No cheese on toast for you today.');
+}</pre>
+
+<p>And, returning to our previous example about the child doing a chore for their parent, you could write it like this:</p>
+
+<pre class="brush: js">var shoppingDone = false;
+
+if (shoppingDone) { // don't need to explicitly specify '=== true'
+ var childsAllowance = 10;
+} else {
+ var childsAllowance = 5;
+}</pre>
+
+<h3 id="Nesting_if_..._else">Nesting if ... else</h3>
+
+<p>It is perfectly OK to put one <code>if...else</code> statement inside another one — to nest them. For example, we could update our weather forecast application to show a further set of choices depending on what the temperature is:</p>
+
+<pre class="brush: js">if (choice === 'sunny') {
+ if (temperature &lt; 86) {
+ para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.';
+ } else if (temperature &gt;= 86) {
+ para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.';
+ }
+}</pre>
+
+<p>Even though the code all works together, each <code>if...else</code> statement works completely independently of the other one.</p>
+
+<h3 id="Logical_operators_AND_OR_and_NOT">Logical operators: AND, OR and NOT</h3>
+
+<p>If you want to test multiple conditions without writing nested <code>if...else</code> statements, <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">logical operators</a> can help you. When used in conditions, the first two do the following:</p>
+
+<ul>
+ <li><code>&amp;&amp;</code> — AND; allows you to chain together two or more expressions so that all of them have to individually evaluate to <code>true</code> for the whole expression to return <code>true</code>.</li>
+ <li><code>||</code> — OR; allows you to chain together two or more expressions so that one or more of them have to individually evaluate to <code>true</code> for the whole expression to return <code>true</code>.</li>
+</ul>
+
+<p>To give you an AND example, the previous example snippet can be rewritten to this:</p>
+
+<pre class="brush: js">if (choice === 'sunny' &amp;&amp; temperature &lt; 86) {
+ para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.';
+} else if (choice === 'sunny' &amp;&amp; temperature &gt;= 86) {
+ para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.';
+}</pre>
+
+<p>So for example, the first code block will only be run if <code>choice === 'sunny'</code> <em>and</em> <code>temperature &lt; 86</code> return <code>true</code>.</p>
+
+<p>Let's look at a quick OR example:</p>
+
+<pre class="brush: js">if (iceCreamVanOutside || houseStatus === 'on fire') {
+ console.log('You should leave the house quickly.');
+} else {
+ console.log('Probably should just stay in then.');
+}</pre>
+
+<p>The last type of logical operator, NOT, expressed by the <code>!</code> operator, can be used to negate an expression. Let's combine it with OR in the above example:</p>
+
+<pre class="brush: js">if (!(iceCreamVanOutside || houseStatus === 'on fire')) {
+ console.log('Probably should just stay in then.');
+} else {
+ console.log('You should leave the house quickly.');
+}</pre>
+
+<p>In this snippet, if the OR statement returns <code>true</code>, the NOT operator will negate it so that the overall expression returns <code>false</code>.</p>
+
+<p>You can combine as many logical statements together as you want, in whatever structure. The following example executes the code inside only if both OR statements return true, meaning that the overall AND statement will return true:</p>
+
+<pre class="brush: js">if ((x === 5 || y &gt; 3 || z &lt;= 10) &amp;&amp; (loggedIn || userName === 'Steve')) {
+ // run the code
+}</pre>
+
+<p>A common mistake when using the logical OR operator in conditional statements is to try to state the variable whose value you are checking once, and then give a list of values it could be to return true, separated by <code>||</code> (OR) operators. For example:</p>
+
+<pre class="example-bad brush: js">if (x === 5 || 7 || 10 || 20) {
+ // run my code
+}</pre>
+
+<p>In this case the condition inside <code>if(...)</code>  will always evaluate to true since 7 (or any other non-zero value) always evaluates to true. This condition is actually saying "if x equals 5, or 7 is true — which it always is". This is logically not what we want! To make this work you've got to specify a complete test either side of each OR operator:</p>
+
+<pre class="brush: js">if (x === 5 || x === 7 || x === 10 ||x === 20) {
+ // run my code
+}</pre>
+
+<h2 id="switch_statements">switch statements</h2>
+
+<p><code>if...else</code> statements do the job of enabling conditional code well, but they are not without their downsides. They are mainly good for cases where you've got a couple of choices, and each one requires a reasonable amount of code to be run, and/or the conditions are complex (e.g. multiple logical operators). For cases where you just want to set a variable to a certain choice of value or print out a particular statement depending on a condition, the syntax can be a bit cumbersome, especially if you've got a large number of choices.</p>
+
+<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch"><code>switch</code> statements</a> are your friend here — they take a single expression/value as an input, and then look through a number of choices until they find one that matches that value, executing the corresponding code that goes along with it. Here's some more pseudocode, to give you an idea:</p>
+
+<pre>switch (expression) {
+ case choice1:
+ run this code
+ break;
+
+ case choice2:
+ run this code instead
+ break;
+
+ // include as many cases as you like
+
+ default:
+ actually, just run this code
+}</pre>
+
+<p>Here we've got:</p>
+
+<ol>
+ <li>The keyword <code>switch</code>, followed by a set of parentheses.</li>
+ <li>An expression or value inside the parentheses.</li>
+ <li>The keyword <code>case</code>, followed by a choice that the expression/value could be, followed by a colon.</li>
+ <li>Some code to run if the choice matches the expression.</li>
+ <li>A <code>break</code> statement, followed by a semi-colon. If the previous choice matches the expression/value, the browser stops executing the code block here, and moves on to any code that appears below the switch statement.</li>
+ <li>As many other cases (bullets 3–5) as you like.</li>
+ <li>The keyword <code>default</code>, followed by exactly the same code pattern as one of the cases (bullets 3–5), except that <code>default</code> does not have a choice after it, and you don't need to <code>break</code> statement as there is nothing to run after this in the block anyway. This is the default option that runs if none of the choices match.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: You don't have to include the <code>default</code> section — you can safely omit it if there is no chance that the expression could end up equaling an unknown value. If there is a chance of this however, you need to include it to handle unknown cases.</p>
+</div>
+
+<h3 id="A_switch_example">A switch example</h3>
+
+<p>Let's have a look at a real example — we'll rewrite our weather forecast application to use a switch statement instead:</p>
+
+<pre class="brush: html">&lt;label for="weather"&gt;Select the weather type today: &lt;/label&gt;
+&lt;select id="weather"&gt;
+ &lt;option value=""&gt;--Make a choice--&lt;/option&gt;
+ &lt;option value="sunny"&gt;Sunny&lt;/option&gt;
+ &lt;option value="rainy"&gt;Rainy&lt;/option&gt;
+ &lt;option value="snowing"&gt;Snowing&lt;/option&gt;
+ &lt;option value="overcast"&gt;Overcast&lt;/option&gt;
+&lt;/select&gt;
+
+&lt;p&gt;&lt;/p&gt;</pre>
+
+<pre class="brush: js">var select = document.querySelector('select');
+var para = document.querySelector('p');
+
+select.addEventListener('change', setWeather);
+
+
+function setWeather() {
+ var choice = select.value;
+
+ switch (choice) {
+ case 'sunny':
+ para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.';
+ break;
+ case 'rainy':
+ para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.';
+ break;
+ case 'snowing':
+ para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.';
+ break;
+ case 'overcast':
+ para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.';
+ break;
+ default:
+ para.textContent = '';
+ }
+}</pre>
+
+<p>{{ EmbedLiveSample('A_switch_example', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">running live</a> on there also.)</p>
+</div>
+
+<h2 id="三元運算符">三元運算符</h2>
+
+<p>There is one final bit of syntax we want to introduce you to, before we get you to play with some examples. The <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary or conditional operator</a> is a small bit of syntax that tests a condition and returns one value/expression if it is <code>true</code>, and another if it is <code>false</code> — this can be useful in some situations, and can take up a lot less code than an <code>if...else</code> block if you simply have two choices that are chosen between via a <code>true</code>/<code>false</code> condition. The pseudocode looks like this:</p>
+
+<pre>( condition ) ? run this code : run this code instead</pre>
+
+<p>So let's look at a simple example:</p>
+
+<pre class="brush: js">var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';</pre>
+
+<p>Here we have a variable called <code>isBirthday</code> — if this is <code>true</code>, we give our guest a happy birthday message; if not, we give her the standard daily greeting.</p>
+
+<h3 id="Ternary_operator_example">Ternary operator example</h3>
+
+<p>You don't just have to set variable values with the ternary operator; you can also run functions, or lines of code — anything you like. The following live example shows a simple theme chooser where the styling for the site is applied using a ternary operator.</p>
+
+<pre class="brush: html">&lt;label for="theme"&gt;Select theme: &lt;/label&gt;
+&lt;select id="theme"&gt;
+ &lt;option value="white"&gt;White&lt;/option&gt;
+ &lt;option value="black"&gt;Black&lt;/option&gt;
+&lt;/select&gt;
+
+&lt;h1&gt;This is my website&lt;/h1&gt;</pre>
+
+<pre class="brush: js">var select = document.querySelector('select');
+var html = document.querySelector('html');
+document.body.style.padding = '10px';
+
+function update(bgColor, textColor) {
+ html.style.backgroundColor = bgColor;
+ html.style.color = textColor;
+}
+
+select.onchange = function() {
+ ( select.value === 'black' ) ? update('black','white') : update('white','black');
+}
+</pre>
+
+<p>{{ EmbedLiveSample('Ternary_operator_example', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>Here we've got a {{htmlelement('select')}} element to choose a theme (black or white), plus a simple {{htmlelement('h1')}} to display a website title. We also have a function called <code>update()</code>, which takes two colors as parameters (inputs). The website's background color is set to the first provided color, and its text color is set to the second provided color.</p>
+
+<p>Finally, we've also got an <a href="/en-US/docs/Web/API/GlobalEventHandlers/onchange">onchange</a> event listener that serves to run a function containing a ternary operator. It starts with a test condition — <code>select.value === 'black'</code>. If this returns <code>true</code>, we run the <code>update()</code> function with parameters of black and white, meaning that we end up with background color of black and text color of white. If it returns <code>false</code>, we run the <code>update()</code> function with parameters of white and black, meaning that the site color are inverted.</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">running live</a> on there also.)</p>
+</div>
+
+<h2 id="Active_learning_A_simple_calendar">Active learning: A simple calendar</h2>
+
+<p>In this example you are going to help us finish a simple calendar application. In the code you've got:</p>
+
+<ul>
+ <li>A {{htmlelement("select")}} element to allow the user to choose between different months.</li>
+ <li>An <code>onchange</code> event handler to detect when the value selected in the <code>&lt;select&gt;</code> menu is changed.</li>
+ <li>A function called <code>createCalendar()</code> that draws the calendar and displays the correct month in the {{htmlelement("h1")}} element.</li>
+</ul>
+
+<p>We need you to write a conditional statement inside the <code>onchange</code> handler function, just below the <code>// ADD CONDITIONAL HERE</code> comment. It should:</p>
+
+<ol>
+ <li>Look at the selected month (stored in the <code>choice</code> variable. This will be the <code>&lt;select&gt;</code> element value after the value changes, so "January" for example.)</li>
+ <li>Set a variable called <code>days</code> to be equal to the number of days in the selected month. To do this you'll have to look up the number of days in each month of the year. You can ignore leap years for the purposes of this example.</li>
+</ol>
+
+<p>Hints:</p>
+
+<ul>
+ <li>You are advised to use logical OR to group multiple months together into a single condition; many of them share the same number of days.</li>
+ <li>Think about which number of days is the most common, and use that as a default value.</li>
+</ul>
+
+<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="height: 500px;overflow: auto;"&gt;
+ &lt;label for="month"&gt;Select month: &lt;/label&gt;
+ &lt;select id="month"&gt;
+ &lt;option value="January"&gt;January&lt;/option&gt;
+ &lt;option value="February"&gt;February&lt;/option&gt;
+ &lt;option value="March"&gt;March&lt;/option&gt;
+ &lt;option value="April"&gt;April&lt;/option&gt;
+ &lt;option value="May"&gt;May&lt;/option&gt;
+ &lt;option value="June"&gt;June&lt;/option&gt;
+ &lt;option value="July"&gt;July&lt;/option&gt;
+ &lt;option value="August"&gt;August&lt;/option&gt;
+ &lt;option value="September"&gt;September&lt;/option&gt;
+ &lt;option value="October"&gt;October&lt;/option&gt;
+ &lt;option value="November"&gt;November&lt;/option&gt;
+ &lt;option value="December"&gt;December&lt;/option&gt;
+ &lt;/select&gt;
+
+ &lt;h1&gt;&lt;/h1&gt;
+
+ &lt;ul&gt;&lt;/ul&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 400px;width: 95%"&gt;
+var select = document.querySelector('select');
+var list = document.querySelector('ul');
+var h1 = document.querySelector('h1');
+
+select.onchange = function() {
+ var choice = select.value;
+
+ // ADD CONDITIONAL HERE
+
+ createCalendar(days, choice);
+}
+
+function createCalendar(days, choice) {
+ list.innerHTML = '';
+ h1.textContent = choice;
+ for (var i = 1; i &lt;= days; i++) {
+ var listItem = document.createElement('li');
+ listItem.textContent = i;
+ list.appendChild(listItem);
+ }
+}
+
+createCalendar(31,'January');
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css">.output * {
+ box-sizing: border-box;
+}
+
+.output ul {
+ padding-left: 0;
+}
+
+.output li {
+ display: block;
+ float: left;
+ width: 25%;
+ border: 2px solid white;
+ padding: 5px;
+ height: 40px;
+ background-color: #4A2DB6;
+ color: white;
+}
+
+html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+
+
+
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'February\') {\n days = 28;\n } else if(choice === \'April\' || choice === \'June\' || choice === \'September\'|| choice === \'November\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i &lt;= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'January\');';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+
+
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', '100%', 1110, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Active_learning_More_color_choices!">Active learning: More color choices!</h2>
+
+<p>In this example you are going to take the ternary operator example we saw earlier and convert the ternary operator into a switch statement that will allow us to apply more choices to the simple website. Look at the {{htmlelement("select")}} — this time you'll see that it has not two theme options, but five. You need to add a switch statement just underneath the <code>// ADD SWITCH STATEMENT</code> comment:</p>
+
+<ul>
+ <li>It should accept the <code>choice</code> variable as its input expression.</li>
+ <li>For each case, the choice should equal one of the possible values that can be selected, i.e. white, black, purple, yellow, or psychedelic.</li>
+ <li>For each case, the <code>update()</code> function should be run, and be passed two color values, the first one for the background color, and the second one for the text color. Remember that color values are strings, so need to be wrapped in quotes.</li>
+</ul>
+
+<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code 2</h6>
+
+<pre class="brush: html">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="height: 300px;"&gt;
+ &lt;label for="theme"&gt;Select theme: &lt;/label&gt;
+ &lt;select id="theme"&gt;
+ &lt;option value="white"&gt;White&lt;/option&gt;
+ &lt;option value="black"&gt;Black&lt;/option&gt;
+ &lt;option value="purple"&gt;Purple&lt;/option&gt;
+ &lt;option value="yellow"&gt;Yellow&lt;/option&gt;
+ &lt;option value="psychedelic"&gt;Psychedelic&lt;/option&gt;
+ &lt;/select&gt;
+
+ &lt;h1&gt;This is my website&lt;/h1&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 450px;width: 95%"&gt;
+var select = document.querySelector('select');
+var html = document.querySelector('.output');
+
+select.onchange = function() {
+ var choice = select.value;
+
+ // ADD SWITCH STATEMENT
+}
+
+function update(bgColor, textColor) {
+ html.style.backgroundColor = bgColor;
+ html.style.color = textColor;
+}&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+
+
+
+
+
+
+<pre class="brush: css">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+
+
+
+
+
+
+
+
+<pre class="brush: js">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+
+
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', '100%', 950, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>And that's all you really need to know about conditional structures in JavaScript right now! I'm sure you'll have understood these concepts and worked through the examples with ease; if there is anything you didn't understand, feel free to read through the article again, or <a href="/en-US/Learn#Contact_us">contact us</a> to ask for help.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Comparison operators</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements">Conditional statements in detail</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if...else reference</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Conditional (ternary) operator reference</a></li>
+</ul>
+
+<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/building_blocks/functions/index.html b/files/zh-tw/learn/javascript/building_blocks/functions/index.html
new file mode 100644
index 0000000000..719180656f
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/functions/index.html
@@ -0,0 +1,396 @@
+---
+title: 函數 - 可重複使用的代碼塊
+slug: Learn/JavaScript/Building_blocks/Functions
+translation_of: Learn/JavaScript/Building_blocks/Functions
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">編碼中的另一個基本概念是函數,它允許您存儲一段代碼,該代碼在定義的塊內執行單個任務,然後在需要時使用一個簡短命令調用該代碼 - 而不必輸入相同的代碼 代碼多次。 在本文中,我們將探索函數背後的基本概念,例如基本語法,如何調用和定義它們,範圍和參數。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a basic understanding of HTML and CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand the fundamental concepts behind JavaScript functions.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Where_do_I_find_functions">Where do I find functions?</h2>
+
+<p>In JavaScript, you'll find functions everywhere. In fact, we've been using functions all the way through the course so far; we've just not been talking about them very much. Now is the time, however, for us to start talking about functions explicitly, and really exploring their syntax.</p>
+
+<p>Pretty much anytime you make use of a JavaScript structure that features a pair of parentheses — <code>()</code> — and you're <strong>not</strong> using a common built-in language structure like a <a href="/en-US/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for loop</a>, <a href="/en-US/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">while or do...while loop</a>, or <a href="/en-US/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">if...else statement</a>, you are making use of a function.</p>
+
+<h2 id="Built-in_browser_functions">Built-in browser functions</h2>
+
+<p>We've made use of functions built in to the browser a lot in this course. Every time we manipulated a text string, for example:</p>
+
+<pre class="brush: js">var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// the replace() string function takes a string,
+// replaces one substring with another, and returns
+// a new string with the replacement made</pre>
+
+<p>Or every time we manipulated an array:</p>
+
+<pre class="brush: js">var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+console.log(madeAString);
+// the join() function takes an array, joins
+// all the array items together into a single
+// string, and returns this new string</pre>
+
+<p>Or every time we generated a random number:</p>
+
+<pre class="brush: js">var myNumber = Math.random();
+// the random() function generates a random
+// number between 0 and 1, and returns that
+// number</pre>
+
+<p>...we were using a function!</p>
+
+<div class="note">
+<p><strong>Note</strong>: Feel free to enter these lines into your browser's JavaScript console to re-familiarize yourself with their functionality, if needed.</p>
+</div>
+
+<p>The JavaScript language has many built-in functions to allow you to do useful things without having to write all that code yourself. In fact, some of the code you are calling when you <strong>invoke</strong> (a fancy word for run, or execute) a built in browser function couldn't be written in JavaScript — many of these functions are calling parts of the background browser code, which is written largely in low-level system languages like C++, not web languages like JavaScript.</p>
+
+<p>Bear in mind that some built-in browser functions are not part of the core JavaScript language — some are defined as part of browser APIs, which build on top of the default language to provide even more functionality (refer to <a href="/en-US/Learn/JavaScript/First_steps/What_is_JavaScript#So_what_can_it_really_do">this early section of our course</a> for more descriptions). We'll look at using browser APIs in more detail in a later module.</p>
+
+<h2 id="Functions_versus_methods">Functions versus methods</h2>
+
+<p>One thing we need to clear up before we move on — technically speaking, built in browser functions are not functions — they are <strong>methods</strong>. This sounds a bit scary and confusing, but don't worry — the words function and method are largely interchangeable, at least for our purposes, at this stage in your learning.</p>
+
+<p>The distinction is that methods are functions defined inside objects. Built-in browser functions (methods) and variables (which are called <strong>properties</strong>) are stored inside structured objects, to make the code more efficient and easier to handle.</p>
+
+<p>You don't need to learn about the inner workings of structured JavaScript objects yet — you can wait until our later module that will teach you all about the inner workings of objects, and how to create your own. For now, we just wanted to clear up any possible confusion of method versus function — you are likely to meet both terms as you look at the available related resources across the Web.</p>
+
+<h2 id="Custom_functions">Custom functions</h2>
+
+<p>You've also seen a lot of <strong>custom functions</strong> in the course so far — functions defined in your code, not inside the browser. Anytime you saw a custom name with parentheses straight after it, you were using a custom function. In our <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> example (see also the full <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">source code</a>) from our <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">loops article</a>, we included a custom <code>draw()</code> function that looked like this:</p>
+
+<pre class="brush: js">function draw() {
+ ctx.clearRect(0,0,WIDTH,HEIGHT);
+ for (var i = 0; i &lt; 100; i++) {
+ ctx.beginPath();
+ ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ ctx.fill();
+ }
+}</pre>
+
+<p>This function draws 100 random circles inside an {{htmlelement("canvas")}} element. Every time we want to do that, we can just invoke the function with this</p>
+
+<pre class="brush: js">draw();</pre>
+
+<p>rather than having to write all that code out again every time we want to repeat it. And functions can contain whatever code you like — you can even call other functions from inside functions. The above function for example calls the <code>random()</code> function three times, which is defined by the following code:</p>
+
+<pre class="brush: js">function random(number) {
+ return Math.floor(Math.random()*number);
+}</pre>
+
+<p>We needed this function because the browser's built-in <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> function only generates a random decimal number between 0 and 1. We wanted a random whole number between 0 and a specified number.</p>
+
+<h2 id="Invoking_functions">Invoking functions</h2>
+
+<p>You are probably clear on this by now, but just in case ... to actually use a function after it has been defined, you've got to run — or invoke — it. This is done by including the name of the function in the code somewhere, followed by parentheses.</p>
+
+<pre class="brush: js">function myFunction() {
+ alert('hello');
+}
+
+myFunction()
+// calls the function once</pre>
+
+<h2 id="Anonymous_functions">Anonymous functions</h2>
+
+<p>You may see functions defined and invoked in slightly different ways. So far we have just created a function like so:</p>
+
+<pre class="brush: js">function myFunction() {
+ alert('hello');
+}</pre>
+
+<p>But you can also create a function that doesn't have a name:</p>
+
+<pre class="brush: js">function() {
+ alert('hello');
+}</pre>
+
+<p>This is called an <strong>anonymous function</strong> — it has no name! It also won't do anything on its own. You generally use an anonymous function along with an event handler, for example the following would run the code inside the function whenever the associated button is clicked:</p>
+
+<pre class="brush: js">var myButton = document.querySelector('button');
+
+myButton.onclick = function() {
+ alert('hello');
+}</pre>
+
+<p>The above example would require there to be a {{htmlelement("button")}} element available on the page to select and click. You've already seen this structure a few times throughout the course, and you'll learn more about and see it in use in the next article.</p>
+
+<p>You can also assign an anonymous function to be the value of a variable, for example:</p>
+
+<pre class="brush: js">var myGreeting = function() {
+ alert('hello');
+}</pre>
+
+<p>This function could now be invoked using:</p>
+
+<pre class="brush: js">myGreeting();</pre>
+
+<p>This effectively gives the function a name; you can also assign the function to be the value of multiple variables, for example:</p>
+
+<pre class="brush: js">var anotherGreeting = function() {
+ alert('hello');
+}</pre>
+
+<p>This function could now be invoked using either of</p>
+
+<pre class="brush: js">myGreeting();
+anotherGreeting();</pre>
+
+<p>But this would just be confusing, so don't do it! When creating functions, it is better to just stick to this form:</p>
+
+<pre class="brush: js">function myGreeting() {
+ alert('hello');
+}</pre>
+
+<p>You will mainly use anonymous functions to just run a load of code in response to an event firing — like a button being clicked — using an event handler. Again, this looks something like this:</p>
+
+<pre class="brush: js">myButton.onclick = function() {
+ alert('hello');
+ // I can put as much code
+ // inside here as I want
+}</pre>
+
+<h2 id="Function_parameters">Function parameters</h2>
+
+<p>Some functions require <strong>parameters</strong> to be specified when you are invoking them — these are values that need to be included inside the function parentheses, which it needs to do its job properly.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Parameters are sometimes called arguments, properties, or even attributes.</p>
+</div>
+
+<p>As an example, the browser's built-in <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> function doesn't require any parameters. When called, it always returns a random number between 0 and 1:</p>
+
+<pre class="brush: js">var myNumber = Math.random();</pre>
+
+<p>The browser's built-in string <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> function however needs two parameters — the substring to find in the main string, and the substring to replace that string with:</p>
+
+<pre class="brush: js">var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');</pre>
+
+<div class="note">
+<p><strong>Note</strong>: When you need to specify multiple parameters, they are separated by commas.</p>
+</div>
+
+<p>It should also be noted that sometimes parameters are optional — you don't have to specify them. If you don't, the function will generally adopt some kind of default behavior. As an example, the array <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join">join()</a> function's parameter is optional:</p>
+
+<pre class="brush: js">var myArray = ['I', 'love', 'chocolate', 'frogs'];
+var madeAString = myArray.join(' ');
+// returns 'I love chocolate frogs'
+var madeAString = myArray.join();
+// returns 'I,love,chocolate,frogs'</pre>
+
+<p>If no parameter is included to specify a joining/delimiting character, a comma is used by default.</p>
+
+<h2 id="Function_scope_and_conflicts">Function scope and conflicts</h2>
+
+<p>Let's talk a bit about {{glossary("scope")}} — a very important concept when dealing with functions. When you create a function, the variables and other things defined inside the function are inside their own separate <strong>scope</strong>, meaning that they are locked away in their own separate compartments, unreachable from inside other functions or from code outside the functions.</p>
+
+<p>The top level outside all your functions is called the <strong>global scope</strong>. Values defined in the global scope are accessible from everywhere in the code.</p>
+
+<p>JavaScript is set up like this for various reasons — but mainly because of security and organization. Sometimes you don't want variables to be accessible from everywhere in the code — external scripts that you call in from elsewhere could start to mess with your code and cause problems because they happen to be using the same variable names as other parts of the code, causing conflicts. This might be done maliciously, or just by accident.</p>
+
+<p>For example, say you have an HTML file that is calling in two external JavaScript files, and both of them have a variable and a function defined that use the same name:</p>
+
+<pre class="brush: html">&lt;!-- Excerpt from my HTML --&gt;
+&lt;script src="first.js"&gt;&lt;/script&gt;
+&lt;script src="second.js"&gt;&lt;/script&gt;
+&lt;script&gt;
+ greeting();
+&lt;/script&gt;</pre>
+
+<pre class="brush: js">// first.js
+var name = 'Chris';
+function greeting() {
+ alert('Hello ' + name + ': welcome to our company.');
+}</pre>
+
+<pre class="brush: js">// second.js
+var name = 'Zaptec';
+function greeting() {
+ alert('Our company is called ' + name + '.');
+}</pre>
+
+<p>Both functions you want to call are called <code>greeting()</code>, but you can only ever access the <code>second.js</code> file's <code>greeting()</code> function — it is applied to the HTML later on in the source code, so its variable and function overwrite the ones in <code>first.js</code>.</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can see this example <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">running live on GitHub</a> (see also the <a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">source code</a>).</p>
+</div>
+
+<p>Keeping parts of your code locked away in functions avoids such problems, and is considered best practice.</p>
+
+<p>It is a bit like a zoo. The lions, zebras, tigers, and penguins are kept in their own enclosures, and only have access to the things inside their enclosures — in the same manner as the function scopes. If they were able to get into other enclosures, problems would occur. At best, different animals would feel really uncomfortable inside unfamiliar habitats — a lion or tiger would feel terrible inside the penguins' watery, icy domain. At worst, the lions and tigers might try to eat the penguins!</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p>
+
+<p>The zoo keeper is like the global scope — he or she has the keys to access every enclosure, to restock food, tend to sick animals, etc.</p>
+
+<h3 id="Active_learning_Playing_with_scope">Active learning: Playing with scope</h3>
+
+<p>Let's look at a real example to demonstrate scoping.</p>
+
+<ol>
+ <li>First, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html">function-scope.html</a> example. This contains two functions called <code>a()</code> and <code>b()</code>, and three variables — <code>x</code>, <code>y</code>, and <code>z</code> — two of which are defined inside the functions, and one in the global scope. It also contains a third function called <code>output()</code>, which takes a single parameter and outputs it in a paragraph on the page.</li>
+ <li>Open the example up in a browser and in your text editor.</li>
+ <li>Open the JavaScript console in your browser developer tools. In the JavaScript console, enter the following command:
+ <pre class="brush: js">output(x);</pre>
+ You should see the value of variable <code>x</code> output to the screen.</li>
+ <li>Now try entering the following in your console
+ <pre class="brush: js">output(y);
+output(z);</pre>
+ Both of these should return an error along the lines of "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: y is not defined</a>". Why is that? Because of function scope — <code>y</code> and <code>z</code> are locked inside the <code>a()</code> and <code>b()</code> functions, so <code>output()</code> can't access them when called from the global scope.</li>
+ <li>However, what about when it's called from inside another function? Try editing <code>a()</code> and <code>b()</code> so they look like this:
+ <pre class="brush: js">function a() {
+ var y = 2;
+ output(y);
+}
+
+function b() {
+ var z = 3;
+ output(z);
+}</pre>
+ Save the code and reload it in your browser, then try calling the <code>a()</code> and <code>b()</code> functions from the JavaScript console:
+
+ <pre class="brush: js">a();
+b();</pre>
+ You should see the <code>y</code> and <code>z</code> values output in the page. This works fine, as the <code>output()</code> function is being called inside the other functions — in the same scope as the variables it is printing are defined in, in each case. <code>output()</code> itself is available from anywhere, as it is defined in the global scope.</li>
+ <li>Now try updating your code like this:
+ <pre class="brush: js">function a() {
+ var y = 2;
+ output(x);
+}
+
+function b() {
+ var z = 3;
+ output(x);
+}</pre>
+ Save and reload again, and try this again in your JavaScript console:
+
+ <pre class="brush: js">a();
+b();</pre>
+ Both the <code>a()</code> and <code>b()</code> call should output the value of x — 1. These work fine because even though the <code>output()</code> calls are not in the same scope as <code>x</code> is defined in, <code>x</code> is a global variable so is available inside all code, everywhere.</li>
+ <li>Finally, try updating your code like this:
+ <pre class="brush: js">function a() {
+ var y = 2;
+ output(z);
+}
+
+function b() {
+ var z = 3;
+ output(y);
+}</pre>
+ Save and reload again, and try this again in your JavaScript console:
+
+ <pre class="brush: js">a();
+b();</pre>
+ This time the <code>a()</code> and <code>b()</code> calls will both return that annoying "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" error — this is because the <code>output()</code> calls and the variables they are trying to print are not defined inside the same function scopes — the variables are effectively invisible to those function calls.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: The same scoping rules do not apply to loop (e.g. <code>for() { ... }</code>) and conditional blocks (e.g. <code>if() { ... }</code>) — they look very similar, but they are not the same thing! Take care not to get these confused.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: The <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: "x" is not defined</a> error is one of the most common you'll encounter. If you get this error and you are sure that you have defined the variable in question, check what scope it is in.</p>
+</div>
+
+<ul>
+</ul>
+
+<h3 id="Functions_inside_functions">Functions inside functions</h3>
+
+<p>Keep in mind that you can call a function from anywhere, even inside another function.  This is often used as a way to keep code tidy — if you have a big complex function, it is easier to understand if you break it down into several sub-functions:</p>
+
+<pre class="brush: js">function myBigFunction() {
+ var myValue;
+
+ subFunction1();
+ subFunction2();
+ subFunction3();
+}
+
+function subFunction1() {
+ console.log(myValue);
+}
+
+function subFunction2() {
+ console.log(myValue);
+}
+
+function subFunction3() {
+ console.log(myValue);
+}
+</pre>
+
+<p>Just make sure that the values being used inside the function are properly in scope. The example above would throw an error <code>ReferenceError: myValue is not defined</code>, because although the <code>myValue</code> variable is defined in the same scope as the function calls, it is not defined inside the function definitions — the actual code that is run when the functions are called. To make this work, you'd have to pass the value into the function as a parameter, like this:</p>
+
+<pre class="brush: js">function myBigFunction() {
+ var myValue = 1;
+
+ subFunction1(myValue);
+ subFunction2(myValue);
+ subFunction3(myValue);
+}
+
+function subFunction1(value) {
+ console.log(value);
+}
+
+function subFunction2(value) {
+ console.log(value);
+}
+
+function subFunction3(value) {
+ console.log(value);
+}</pre>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Functions">Functions detailed guide</a> — covers some advanced features not included here.</li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Functions reference</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">Default parameters</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Arrow functions</a> — advanced concept references</li>
+</ul>
+
+<ul>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html b/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html
new file mode 100644
index 0000000000..32c5a1867a
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/image_gallery/index.html
@@ -0,0 +1,135 @@
+---
+title: 影像圖庫
+slug: Learn/JavaScript/Building_blocks/Image_gallery
+tags:
+ - JavaScript
+ - 事件
+ - 事件處理器
+ - 優先國際化
+ - 初學者
+ - 學習
+ - 條件式
+ - 編碼腳本
+ - 評量
+ - 迴圈
+translation_of: Learn/JavaScript/Building_blocks/Image_gallery
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">現在我們已經看過了基本的JavaScript組建,我們將讓你做一個測試,從建立一個在很多網站上常見的事物 — JavaScript基礎的影像圖庫,來測試你對迴圈、函數、條件式及事件的知識。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先修課程:</th>
+ <td>在進行這個評量前,你應已閱讀、練習了本模組中所有的文章。</td>
+ </tr>
+ <tr>
+ <th scope="row">目的:</th>
+ <td>測試對JavaScript中迴圈、函數、條件式及事件的瞭解程度。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="從這裡開始">從這裡開始</h2>
+
+<p>要進行這個評量,你要先下載 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/gallery/gallery-start.zip?raw=true">grab the ZIP</a> 檔案,解壓縮在你電腦中的某個檔案夾作為範例。</p>
+
+<div class="note">
+<p><strong>提醒:</strong>你也可以在某些網站進行評鑑,如 <a class="external external-icon" href="http://jsbin.com/">JSBin</a> 或<a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a>。你可以把這些HTML、CSS和JavaScript貼到這些線上編輯器中。如果你用了一個沒法把JavaScript/CSS分別放在不同面板的線上編輯器,你可以放心的把這些<code>&lt;script&gt;</code>/<code>&lt;style&gt;</code>元件改成inline貼進HTML網頁裡。</p>
+</div>
+
+<h2 id="專案簡報">專案簡報</h2>
+
+<p>你手上已有我們提供的一些 HTML、CSS 和圖片資料,以及幾行 JavaScript 程式碼;你要寫一些必要的 JavaScript 讓它變成可運作的程式。這些 HTML 的 body 看起來如下:</p>
+
+<pre class="brush: html">&lt;h1&gt;Image gallery example&lt;/h1&gt;
+
+&lt;div class="full-img"&gt;
+ &lt;img class="displayed-img" src="images/pic1.jpg"&gt;
+ &lt;div class="overlay"&gt;&lt;/div&gt;
+ &lt;button class="dark"&gt;Darken&lt;/button&gt;
+&lt;/div&gt;
+
+&lt;div class="thumb-bar"&gt;
+
+&lt;/div&gt;</pre>
+
+<p>完成後看起來像下圖:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13787/gallery.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+</ul>
+
+<p>範例 CSS 檔案中最有趣的部分是:</p>
+
+<ul>
+ <li>在 <code>full-img &lt;div&gt;</code> 裡有的三個組成元素使用絕對位置 —  <code>&lt;img&gt;</code> 展示全尺寸圖片,在它正上方有個與它尺寸相同的空 <code>&lt;div&gt;</code> (用來放置用半透明的背景色彩讓圖片產生變暗效果的層),然後 <code>&lt;button&gt;</code> 用來控制變暗效果。</li>
+ <li>設定 <code>thumb-bar &lt;div&gt;</code> (一般叫做「縮圖」的圖片)裡的圖片讓它縮小成原來的20%,之後讓它浮(float)在左邊讓縮圖能一個個相鄰的排成一列。</li>
+</ul>
+
+<p>在你的 JavaScript 裡需要:</p>
+
+<ul>
+ <li>讓所有圖片迴圈(Loop) through all the images, 在 <code>thumb-bar &lt;div&gt;</code> 裡的每個 <code>&lt;img&gt;</code> 塞進一個 <code>&lt;img&gt;</code> ,讓圖片內嵌在頁面上。</li>
+ <li>在 <code>thumb-bar &lt;div&gt;</code> 裡的每個 <code>&lt;img&gt;</code> 添加一個  <code>onclick</code> 處理器使這個圖片被點擊時會放大展示在 <code>displayed-img &lt;img&gt;</code> 裡。</li>
+ <li>在 <code>&lt;button&gt;</code> 添加一個  <code>onclick</code> 處理器,當點擊時,全尺寸圖片產生暗化效果,再次點擊時移除暗化效果。</li>
+</ul>
+
+<p>為了讓你更清楚,你可以看看這個 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/gallery/">完成的範例</a> (但別偷看原始碼!)</p>
+
+<h2 id="一步步完成">一步步完成</h2>
+
+<p>接下來幾節描述你該怎麼做。</p>
+
+<h3 id="讓所有圖片迴圈">讓所有圖片迴圈</h3>
+
+<p>我們已提供了幾行程式碼:將<code>thumb-bar</code>和 <code>&lt;div&gt;</code>儲存在 <code>thumbBar</code>這個變數裡、建立一個新的 <code>&lt;img&gt;</code> 元件、將它的 <code>src</code> 屬性設定在一個值為 <code>xxx</code> 的佔位符中,以及在 <code>thumbBar</code> 裡增加新 <code>&lt;img&gt;</code> 。</p>
+
+<p>你要做的是:</p>
+
+<ol>
+ <li>Put the section of code below the "Looping through images" comment inside a loop that loops through all 5 images — you just need to loop through five numbers, one representing each image.</li>
+ <li>In each loop iteration, replace the <code>xxx</code> placeholder value with a string that will equal the path to the image in each case. We are setting the value of the <code>src</code> attribute to this value in each case. Bear in mind that in each case, the image is inside the images directory and its name is <code>pic1.jpg</code>, <code>pic2.jpg</code>, etc.</li>
+</ol>
+
+<h3 id="在每個縮圖上添加onclick事件處理器">在每個縮圖上添加onclick事件處理器</h3>
+
+<p>In each loop iteration, you need to add an <code>onclick</code> handler to the current <code>newImage</code> — this should:</p>
+
+<ol>
+ <li>在每個 <code>&lt;img&gt;</code> 中把<code>"src"</code>作為運行<code>getAttribute()</code> 函數的參數,取得現在這張圖片的 <code>src</code> 屬性的值。但是要怎麼抓到現在這張圖片?如果用<code>newImage</code> 是做不到的,當在添加事件處理器前,迴圈已經先完成了;所以你每次都獲得前一個 <code>&lt;img&gt;</code>的回傳的 <code>src</code> 值。解法是,記住,在每個事件中,事件處理器的目標是 <code>&lt;img&gt;</code> ,如何獲得事件物件的資訊呢?</li>
+ <li>Run a function, passing it the returned <code>src</code> value as a parameter. You can call this function whatever you like.</li>
+ <li>This event handler function should set the <code>src</code> attribute value of the <code>displayed-img &lt;img&gt;</code> to the <code>src</code> value passed in as a parameter. We've already provided you with a line that stores a reference to the relevant <code>&lt;img&gt;</code> in a variable called <code>displayedImg</code>. Note that we want a defined named function here.</li>
+</ol>
+
+<h3 id="寫一個讓暗化亮化按鈕可以運作的處理器">寫一個讓暗化/亮化按鈕可以運作的處理器</h3>
+
+<p>That just leaves our darken/lighten <code>&lt;button&gt;</code> — we've already provided a line that stores a reference to the <code>&lt;button&gt;</code> in a variable called <code>btn</code>. You need to add an <code>onclick</code> handler that:</p>
+
+<ol>
+ <li>Checks the current class name set on the <code>&lt;button&gt;</code> — you can again achieve this by using <code>getAttribute()</code>.</li>
+ <li>If the class name is <code>"dark"</code>, changes the <code>&lt;button&gt;</code> class to <code>"light"</code> (using <code><a href="/en-US/docs/Web/API/Element/setAttribute">setAttribute()</a></code>), its text content to "Lighten", and the {{cssxref("background-color")}} of the overlay <code>&lt;div&gt;</code> to <code>"rgba(0,0,0,0.5)"</code>.</li>
+ <li>If the class name not <code>"dark"</code>, changes the <code>&lt;button&gt;</code> class to <code>"dark"</code>, its text content back to "Darken", and the {{cssxref("background-color")}} of the overlay <code>&lt;div&gt;</code> to <code>"rgba(0,0,0,0)"</code>.</li>
+</ol>
+
+<p>The following lines provide a basis for achieving the changes stipulated in points 2 and 3 above.</p>
+
+<pre class="brush: js">btn.setAttribute('class', xxx);
+btn.textContent = xxx;
+overlay.style.backgroundColor = xxx;</pre>
+
+<h2 id="提醒與提示">提醒與提示</h2>
+
+<ul>
+ <li>你完全不需要去編輯任何的HTML或CSS。</li>
+</ul>
+
+<h2 id="評量">評量</h2>
+
+<p>If you are following this assessment as part of an organized course, you should be able to give your work to your teacher/mentor for marking. If you are self-learning, then you can get the marking guide fairly easily by asking on the <a href="https://discourse.mozilla-community.org/t/learning-web-development-marking-guides-and-questions/16294">Learning Area Discourse thread</a>, or in the <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC channel on <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Try the exercise first — there is nothing to be gained by cheating!</p>
+
+<p>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p>
diff --git a/files/zh-tw/learn/javascript/building_blocks/index.html b/files/zh-tw/learn/javascript/building_blocks/index.html
new file mode 100644
index 0000000000..500b7d28ed
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/index.html
@@ -0,0 +1,52 @@
+---
+title: JavaScript building blocks
+slug: Learn/JavaScript/Building_blocks
+tags:
+ - JavaScript
+ - TopicStub
+ - 事件
+ - 入門者
+ - 函式
+ - 指南
+ - 模組
+ - 評量
+ - 迴圈
+translation_of: Learn/JavaScript/Building_blocks
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">在本單元中,我們繼續介紹所有JavaScript的關鍵基本功能,將注意力轉向常見的代碼塊類型,如條件語句,循環,函數和事件。 你已經在課程中看到了這些東西,但只是順便說一下 - 在這裡我們將明確地討論它。</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>開始這個模組之前,你應該已經熟悉 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML</a> 和 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS</a> 的基礎知識了,你也應該閱讀完前一個模組 - <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript 入門</a> - 的內容了。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 假如你正使用平板、電腦或任何無法讓你可以建立檔案的裝置時,你可以試著透過線上程式碼工具 (像是 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a>) 測試文章的測試碼。</p>
+</div>
+
+<h2 id="指南">指南</h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/%E6%A2%9D%E4%BB%B6">在代碼中做出決定 - 條件</a></dt>
+ <dd>在任何編程語言中,代碼都需要根據不同的輸入做出決策並相應地執行操作。 例如,在遊戲中,如果玩家的生命數量為0,則遊戲結束。 在天氣應用程序中,如果在早上查看,則顯示日出圖形; 如果是夜晚,則顯示星星和月亮。 在本文中,我們將探討條件結構如何在JavaScript中工作。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Looping_code" rel="nofollow">程式碼迴圈</a></dt>
+ <dd>有時候你需要超過一行的程式碼完成一項任務,舉例來說:尋找一個擁有許多名字的清單。透過編輯程式,迴圈可以幫助你完美的完成這項工作,在本文中,我們將探討迴圈的結構如何在 JavaScript 中運作。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Functions" rel="nofollow">函式 — 可重複使用的程式碼區塊</a></dt>
+ <dd>撰寫程式的另一個基本概念是函式 (function),它允許你在一個定義好的區塊內,存放一些程式碼。定義好的函式後,無論你需要在一個單一簡短的指令列用到它,或者是重複使用相同的片段程式碼,你都可以不段重複地呼叫這些函式執行對應的內容。在本文中,我們將探索函式的基本概念,像是基本語法、如何定義函式內容、以及函式將會使用的參數。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Build_your_own_function" rel="nofollow">建立自己的函式</a></dt>
+ <dd>前面許多文章已經提到大部分的基本理論基礎了,在本文中,我們將分享一個實際的經驗,你將學習到關於打造自定義函式的實務範例。透過這樣的學習方式,我們也進一步解釋一些函式相關的細節知識。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Return_values" rel="nofollow">函式回傳值</a></dt>
+ <dd>這堂課程中最後一個想要說明的基本概念就是函式的回傳值,一些函式執行完畢後,不會回傳一個數值;但有些函式則會。理解這些函式的回傳值是重要的概念,本文中,你將學會如何在自定義的函式中,回傳有用的數值提供給其他函式使用。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Events" rel="nofollow">事件介紹</a></dt>
+ <dd>事件代表你所撰寫的程式在一套系統內所產生的動作或發生的事情,舉例來說:假如一位使用者在網頁點擊一個按鈕時,你可能想要讓使用者點擊該按鈕後,在畫面呈現一個訊息方塊。在本課程最後一篇文章內,我們將討論一些與事件相關的重要概念、以及這些事件在瀏覽器中,如何呈現給使用者。</dd>
+</dl>
+
+<h2 id="評量">評量</h2>
+
+<p>下方的試題將會測驗你對於上述幾項概念的 JavaScript 基本知識。</p>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Building_blocks/Image_gallery">圖庫</a></dt>
+ <dd>我們已經看過許多 JavaScript 的基礎程式碼,我們將測驗你關於迴圈、函式、條件式迴圈與事件等相關的知識,測驗的方式是透過建立一個由 JavaScript 打造而成的圖庫應用程式。</dd>
+</dl>
diff --git a/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html b/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html
new file mode 100644
index 0000000000..0e1e400b4d
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/looping_code/index.html
@@ -0,0 +1,928 @@
+---
+title: 循環代碼
+slug: Learn/JavaScript/Building_blocks/Looping_code
+translation_of: Learn/JavaScript/Building_blocks/Looping_code
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">編程語言對於快速完成重複性任務非常有用,從多個基本計算到幾乎任何其他需要完成大量類似工作的情況。 在這裡,我們將看看JavaScript中可用於處理此類需求的循環結構。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a basic understanding of HTML and CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand how to use loops in JavaScript.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="保持循環">保持循環</h2>
+
+<p>循環,循環,循環。 除了與受歡迎的早餐穀物,過山車和音樂作品有關聯,它們還是編程中的關鍵概念。 編程循環都是一遍又一遍地做同一件事-在編程方面被稱為迭代。</p>
+
+<p>讓我們考慮一個農民的例子,他要確保他有足夠的食物來養家糊口。 他可能使用以下循環來實現此目的:</p>
+
+<p><br>
+ <img alt="" src="https://mdn.mozillademos.org/files/13755/loop_js-02-farm.png" style="display: block; margin: 0 auto;"></p>
+
+<p>循環通常具有以下一項或多項功能:</p>
+
+<ul>
+ <li> 一個用一定值初始化的計數器-這是循環的起點(上面的“開始:我沒有食物”)。</li>
+ <li>一種條件,它是對/錯測試,用於確定循環是繼續運行還是停止(通常在計數器達到某個值時)。 “我是否有足夠的食物?”對此進行了說明。 以上。 假設他需要10份食物來養家糊口的話。</li>
+ <li>一個迭代器,通常在每個連續循環上使計數器增加一小部分,直到條件不再成立為止。 上面我們沒有明確說明這一點,但是我們可以考慮一下農民每小時可以收集2份食物。 每小時之後,他收集的食物數量增加了2,然後他檢查是否有足夠的食物。 如果他已達到10個部分(此時條件不再成立,則循環退出),他可以停止收集並回家。</li>
+</ul>
+
+<p>In {{glossary("pseudocode")}}, this would look something like the following:</p>
+
+<pre class="notranslate">loop(food = 0; foodNeeded = 10) {
+ if (food = foodNeeded) {
+ exit loop;
+ // We have enough food; let's go home
+ } else {
+ food += 2; // Spend an hour collecting 2 more food
+ // loop will then run again
+ }
+}</pre>
+
+<p>因此,所需的食物數量設置為10,而農民當前擁有的食物數量設置為0。在循環的每次迭代中,我們檢查農民擁有的食物數量是否等於他所需的數量。 如果是這樣,我們可以退出循環。 如果不是這樣,農民將花一個小時收集兩份食物,然後循環再次運行。</p>
+
+<h3 id="不用麻煩">不用麻煩</h3>
+
+<p>在這一點上,您可能了解了循環背後的高級概念,但您可能在想:“好,很好,但這如何幫助我編寫更好的JavaScript代碼?” 如前所述,循環與一次又一次地執行同一操作有關,這對於快速完成重複性任務非常有用。</p>
+
+<p>通常,代碼在每次循環的每次迭代中都會略有不同,這意味著您可以完成全部相似但略有不同的任務,一般情況,如果您要執行許多不同的計算,則需要不斷地執行不同的式子,而不能一遍又一遍重複!</p>
+
+<p>讓我們看一個示例,以完美地說明為什麼循環是如此便利。 Let's say we wanted to draw 100 random circles on a {{htmlelement("canvas")}} element (press the <em>Update</em> button to run the example again and again to see different random sets):</p>
+
+<div class="hidden">
+<h6 id="Hidden_code">Hidden code</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Random canvas circles&lt;/title&gt;
+ &lt;style&gt;
+ html {
+ width: 100%;
+ height: inherit;
+ background: #ddd;
+ }
+
+ canvas {
+ display: block;
+ }
+
+ body {
+ margin: 0;
+ }
+
+ button {
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ }
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+ &lt;button&gt;Update&lt;/button&gt;
+
+ &lt;canvas&gt;&lt;/canvas&gt;
+
+
+ &lt;script&gt;
+ var btn = document.querySelector('button');
+ var canvas = document.querySelector('canvas');
+ var ctx = canvas.getContext('2d');
+
+ var WIDTH = document.documentElement.clientWidth;
+ var HEIGHT = document.documentElement.clientHeight;
+
+ canvas.width = WIDTH;
+ canvas.height = HEIGHT;
+
+ function random(number) {
+ return Math.floor(Math.random()*number);
+ }
+
+ function draw() {
+ ctx.clearRect(0,0,WIDTH,HEIGHT);
+ for (var i = 0; i &lt; 100; i++) {
+ ctx.beginPath();
+ ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ }
+
+ btn.addEventListener('click',draw);
+
+ &lt;/script&gt;
+
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code', '100%', 400, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>您現在不必了解所有代碼,但讓我們看一下實際繪製100個圓圈的代碼部分:</p>
+
+<pre class="brush: js notranslate">for (var i = 0; i &lt; 100; i++) {
+ ctx.beginPath();
+ ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ ctx.fill();
+}</pre>
+
+<ul>
+ <li><code>代碼前面定義的random(),返回0到x-1之間的整數。</code></li>
+ <li><code>WIDTH和HEIGHT是內部瀏覽器窗口的寬度和高度。</code></li>
+</ul>
+
+<p>您應該了解基本概念-我們正在使用一個循環來運行此代碼的100次迭代,每個迭代在頁面上的隨機位置繪製一個圓圈。 無論我們繪製100個圓,1000個還是10,000個,所需的代碼量都是相同的。 只需更改一個數字。</p>
+
+<p>如果我們不在此處使用循環,則必須為每個要繪製的圓重複以下代碼:</p>
+
+<pre class="brush: js notranslate">ctx.beginPath();
+ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ctx.fill();</pre>
+
+<p>這將變得很無聊,並且很難很快維護。 循環確實是最好的。</p>
+
+<h2 id="循環的規範">循環的規範</h2>
+
+<p>讓我們開始探索一些特定的循環結構。 第一個是for循環,您將在大多數時候使用它,它具有以下語法:</p>
+
+<pre class="notranslate">for (initializer; exit-condition; final-expression) {
+ // code to run
+}</pre>
+
+<p>這裡我們有:</p>
+
+<ol>
+ <li>關鍵字“ for”,即跟隨其後的一些括號。</li>
+ <li>在括號內,我們有三個項目,以 ; 分隔:
+ <ol>
+ <li>初始化程序-通常是一個設置為數字的變量,該變量將遞增以計算循環運行的次數。 有時也稱為計數器變量。</li>
+ <li>退出條件-如前所述,它定義了循環何時應停止循環。 通常,這是一個具有比較運算符的表達式,該測試用於檢驗是否滿足退出條件。</li>
+ <li>最終表達式—每當循環經過完整的迭代時,總是對它進行評估(或運行)。 它通常用於遞增(或在某些情況下遞減)計數器變量,以使其更接近退出條件值。</li>
+ </ol>
+ </li>
+ <li>一些花括號包含一個代碼塊-每次循環迭代時都將運行此代碼。</li>
+</ol>
+
+<p>讓我們看一個真實的例子,以便我們可以更清楚地看到它們的作用。</p>
+
+<pre class="brush: js notranslate">var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
+var info = 'My cats are called ';
+var para = document.querySelector('p');
+
+for (var i = 0; i &lt; cats.length; i++) {
+ info += cats[i] + ', ';
+}
+
+para.textContent = info;</pre>
+
+<p>這為我們提供了以下輸出:</p>
+
+<div class="hidden">
+<h6 id="Hidden_code_2">Hidden code 2</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Basic for loop example&lt;/title&gt;
+ &lt;style&gt;
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+ &lt;p&gt;&lt;/p&gt;
+
+
+ &lt;script&gt;
+ var cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
+ var info = 'My cats are called ';
+ var para = document.querySelector('p');
+
+ for (var i = 0; i &lt; cats.length; i++) {
+ info += cats[i] + ', ';
+ }
+
+ para.textContent = info;
+
+ &lt;/script&gt;
+
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can find this <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">see it running live</a>).</p>
+</div>
+
+<p>這顯示了一個循環,該循環用於遍歷數組中的項目並對其進行處理-這是JavaScript中非常常見的模式。 這裡:</p>
+
+<ol>
+ <li>迭代器i從0開始(變量i = 0)。</li>
+ <li>它被告知運行,直到它不再小於cats數組的長度為止。 這很重要,退出條件顯示了循環仍將運行的條件。 因此,在這種情況下,儘管i &lt;cats.length仍然為true,循環仍將運行。</li>
+ <li>在循環內部,我們將當前循環項(cats [i]是cats [無論 i 當時是什麼])與一個逗號和一個空格連接到info變量的末尾。 所以:
+ <ol>
+ <li>在第一次運行中,i = 0,因此cats [0] +','將連接到info(“ Bill,”)上。</li>
+ <li>在第二次運行中,i = 1,因此cats [1] +','將連接到info(“ Jeff,”)上</li>
+ <li>等等。 每次循環運行後,將1加到i(i ++),然後該過程將再次開始。</li>
+ </ol>
+ </li>
+ <li>當 i 等於cats.length時,循環將停止,瀏覽器將繼續循環下方的下一段代碼。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: We have made the exit condition <code>i &lt; cats.length</code>, not <code>i &lt;= cats.length</code>, because computers count from 0, not 1 — we are starting <code>i</code> at <code>0</code>, and going up to <code>i = 4</code> (the index of the last array item). <code>cats.length</code> returns 5, as there are 5 items in the array, but we don't want to get up to <code>i = 5</code>, as that would return <code>undefined</code> for the last item (there is no array item with an index of 5). So therefore we want to go up to 1 less than <code>cats.length</code> (<code>i &lt;</code>), not the same as <code>cats.length</code> (<code>i &lt;=</code>).</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: A common mistake with exit conditions is making them use "equal to" (<code>===</code>) rather than say "less than or equal to" (<code>&lt;=</code>). If we wanted to run our loop up to <code>i = 5</code>, the exit condition would need to be <code>i &lt;= cats.length</code>. If we set it to <code>i === cats.length</code>, the loop would not run at all because <code>i</code> is not equal to <code>5</code> on the first loop iteration, so it would stop immediately.</p>
+</div>
+
+<p>我們剩下的一個小問題是最終輸出語句的格式不太正確:</p>
+
+<blockquote>
+<p>My cats are called Bill, Jeff, Pete, Biggles, Jasmin,</p>
+</blockquote>
+
+<p>理想情況下,我們希望在最終循環迭代中更改串聯,以使句子的末尾沒有逗號。 好吧,沒問題-我們可以很高興地在for循環中插入一個條件來處理這種特殊情況:</p>
+
+<pre class="brush: js notranslate">for (var i = 0; i &lt; cats.length; i++) {
+ if (i === cats.length - 1) {
+ info += 'and ' + cats[i] + '.';
+ } else {
+ info += cats[i] + ', ';
+ }
+}</pre>
+
+<div class="note">
+<p><strong>Note</strong>: You can find this <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">see it running live</a>).</p>
+</div>
+
+<div class="warning">
+<p><strong>Important</strong>: With for — as with all loops — you must make sure that the initializer is iterated so that it eventually reaches the exit condition. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an <strong>infinite loop</strong>.</p>
+</div>
+
+<h2 id="中斷退出循環">中斷退出循環</h2>
+
+<p>如果要在所有迭代完成之前退出循環,可以使用break語句。 在查看switch語句時,我們已經在上一篇文章中遇到了這一問題—當在switch語句中遇到與輸入表達式匹配的case時,break語句立即退出switch語句並移至其後的代碼上。</p>
+
+<p>循環也是如此,-break語句將立即退出循環,並使瀏覽器繼續執行緊隨其後的任何代碼。</p>
+
+<p>假設我們要搜索一系列聯繫人和電話號碼,然後僅返回我們要查找的號碼? 首先,提供一些簡單的HTML-文本 {{htmlelement(“ input”)}} 允許我們輸入要搜索的名稱,{{htmlelement(“ button”)}} 元素以提交搜索,以及 {{htmlelement (“ p”)}} 元素以在以下位置顯示結果:</p>
+
+<pre class="brush: html notranslate">&lt;label for="search"&gt;Search by contact name: &lt;/label&gt;
+&lt;input id="search" type="text"&gt;
+&lt;button&gt;Search&lt;/button&gt;
+
+&lt;p&gt;&lt;/p&gt;</pre>
+
+<p>Now on to the JavaScript:</p>
+
+<pre class="brush: js notranslate">var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
+var para = document.querySelector('p');
+var input = document.querySelector('input');
+var btn = document.querySelector('button');
+
+btn.addEventListener('click', function() {
+ var searchName = input.value;
+ input.value = '';
+ input.focus();
+ for (var i = 0; i &lt; contacts.length; i++) {
+ var splitContact = contacts[i].split(':');
+ if (splitContact[0] === searchName) {
+ para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
+ break;
+ } else {
+ para.textContent = 'Contact not found.';
+ }
+ }
+});</pre>
+
+<div class="hidden">
+<h6 id="Hidden_code_3">Hidden code 3</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Simple contact search example&lt;/title&gt;
+ &lt;style&gt;
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+ &lt;label for="search"&gt;Search by contact name: &lt;/label&gt;
+ &lt;input id="search" type="text"&gt;
+ &lt;button&gt;Search&lt;/button&gt;
+
+ &lt;p&gt;&lt;/p&gt;
+
+
+ &lt;script&gt;
+ var contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
+ var para = document.querySelector('p');
+ var input = document.querySelector('input');
+ var btn = document.querySelector('button');
+
+ btn.addEventListener('click', function() {
+ var searchName = input.value;
+ input.value = '';
+ input.focus();
+ for (var i = 0; i &lt; contacts.length; i++) {
+ var splitContact = contacts[i].split(':');
+ if (splitContact[0] === searchName) {
+ para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
+ break;
+ } else if (i === contacts.length-1)
+  para.textContent = 'Contact not found.';
+  }
+ });
+ &lt;/script&gt;
+
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<ol>
+ <li>首先,我們有一些變量定義-我們有一個聯繫信息陣列,每個項目都是一個字符串,其中包含用冒號分隔的姓名和電話號碼。</li>
+ <li>接下來,我們將事件監聽器附加到按鈕(btn),以便在按下按鈕時,將運行一些代碼來執行搜索並返回結果。</li>
+ <li>我們將輸入到文本輸入中的值存儲在一個名為searchName的變量中,然後清空文本輸入並再次對其進行聚焦,以準備進行下一次搜索。</li>
+ <li>現在到有趣的部分,for循環:
+ <ol>
+ <li>我們從0開始啟動計數器,運行循環直到計數器不再小於contact.length,然後在每次循環之後將i遞增1。</li>
+ <li>在循環內部,我們首先將當前觸點(contacts [i])分割為冒號字符,並將得到的兩個值存儲在名為 splitContact 的數組中。</li>
+ <li>然後,我們使用條件語句來測試splitContact [0](聯繫人的姓名)是否等於輸入的searchName。 如果是這樣,我們在段落中輸入一個字符串以報告聯繫人的電話號碼,然後使用break結束循環。</li>
+ </ol>
+ </li>
+ <li>
+ <p>在(contacts.length-1)迭代之後,如果聯繫人姓名與輸入的搜索不匹配,則將段落文本設置為“找不到聯繫人。”,然後循環繼續進行迭代。</p>
+ </li>
+</ol>
+
+<div class="note">
+<p>Note: You can view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">see it running live</a>).</p>
+</div>
+
+<h2 id="Skipping_iterations_with_continue">Skipping iterations with continue</h2>
+
+<p>The <a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a> statement works in a similar manner to <code>break</code>, but instead of breaking out of the loop entirely, it skips to the next iteration of the loop. Let's look at another example that takes a number as an input, and returns only the numbers that are squares of integers (whole numbers).</p>
+
+<p>The HTML is basically the same as the last example — a simple text input, and a paragraph for output. The JavaScript is mostly the same too, although the loop itself is a bit different:</p>
+
+<pre class="brush: js notranslate">var num = input.value;
+
+for (var i = 1; i &lt;= num; i++) {
+ var sqRoot = Math.sqrt(i);
+ if (Math.floor(sqRoot) !== sqRoot) {
+ continue;
+ }
+
+ para.textContent += i + ' ';
+}</pre>
+
+<p>Here's the output:</p>
+
+<div class="hidden">
+<h6 id="Hidden_code_4">Hidden code 4</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Integer squares generator&lt;/title&gt;
+ &lt;style&gt;
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+ &lt;label for="number"&gt;Enter number: &lt;/label&gt;
+ &lt;input id="number" type="text"&gt;
+ &lt;button&gt;Generate integer squares&lt;/button&gt;
+
+ &lt;p&gt;Output: &lt;/p&gt;
+
+
+ &lt;script&gt;
+ var para = document.querySelector('p');
+ var input = document.querySelector('input');
+ var btn = document.querySelector('button');
+
+ btn.addEventListener('click', function() {
+ para.textContent = 'Output: ';
+ var num = input.value;
+ input.value = '';
+ input.focus();
+ for (var i = 1; i &lt;= num; i++) {
+ var sqRoot = Math.sqrt(i);
+ if (Math.floor(sqRoot) !== sqRoot) {
+ continue;
+ }
+
+ para.textContent += i + ' ';
+ }
+ });
+ &lt;/script&gt;
+
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<ol>
+ <li>In this case, the input should be a number (<code>num</code>). The <code>for</code> loop is given a counter starting at 1 (as we are not interested in 0 in this case), an exit condition that says the loop will stop when the counter becomes bigger than the input <code>num</code>, and an iterator that adds 1 to the counter each time.</li>
+ <li>Inside the loop, we find the square root of each number using <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt">Math.sqrt(i)</a>, then check whether the square root is an integer by testing whether it is the same as itself when it has been rounded down to the nearest integer (this is what <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a> does to the number it is passed).</li>
+ <li>If the square root and the rounded down square root do not equal one another (<code>!==</code>), it means that the square root is not an integer, so we are not interested in it. In such a case, we use the <code>continue</code> statement to skip on to the next loop iteration without recording the number anywhere.</li>
+ <li>If the square root IS an integer, we skip past the if block entirely so the <code>continue</code> statement is not executed; instead, we concatenate the current <code>i</code> value plus a space on to the end of the paragraph content.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: You can view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">see it running live</a>).</p>
+</div>
+
+<h2 id="while_and_do_..._while">while and do ... while</h2>
+
+<p><code>for</code> is not the only type of loop available in JavaScript. There are actually many others and, while you don't need to understand all of these now, it is worth having a look at the structure of a couple of others so that you can recognize the same features at work in a slightly different way.</p>
+
+<p>First, let's have a look at the <a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> loop. This loop's syntax looks like so:</p>
+
+<pre class="notranslate">initializer
+while (exit-condition) {
+ // code to run
+
+ final-expression
+}</pre>
+
+<p>This works in a very similar way to the for loop, except that the initializer variable is set before the loop, and the final-expression is included inside the loop after the code to run — rather than these two items being included inside the parentheses. The exit-condition is included inside the parentheses, which are preceded by the <code>while</code> keyword rather than <code>for</code>.</p>
+
+<p>The same three items are still present, and they are still defined in the same order as they are in the for loop — this makes sense, as you still have to have an initializer defined before you can check whether it has reached the exit-condition; the final-condition is then run after the code inside the loop has run (an iteration has been completed), which will only happen if the exit-condition has still not been reached.</p>
+
+<p>Let's have a look again at our cats list example, but rewritten to use a while loop:</p>
+
+<pre class="brush: js notranslate">var i = 0;
+
+while (i &lt; cats.length) {
+ if (i === cats.length - 1) {
+ info += 'and ' + cats[i] + '.';
+ } else {
+ info += cats[i] + ', ';
+ }
+
+ i++;
+}</pre>
+
+<div class="note">
+<p><strong>Note</strong>: This still works just the same as expected — have a look at it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/while.html">full source code</a>).</p>
+</div>
+
+<p>The <a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> loop is very similar, but provides a variation on the while structure:</p>
+
+<pre class="notranslate">initializer
+do {
+ // code to run
+
+ final-expression
+} while (exit-condition)</pre>
+
+<p>In this case, the initializer again comes first, before the loop starts. The <code>do</code> keyword directly precedes the curly braces containing the code to run and the final-expression.</p>
+
+<p>The differentiator here is that the exit-condition comes after everything else, wrapped in parentheses and preceded by a <code>while</code> keyword. In a <code>do...while</code> loop, the code inside the curly braces is always run once before the check is made to see if it should be executed again (in while and for, the check comes first, so the code might never be executed).</p>
+
+<p>Let's rewrite our cat listing example again to use a <code>do...while</code> loop:</p>
+
+<pre class="brush: js notranslate">var i = 0;
+
+do {
+ if (i === cats.length - 1) {
+ info += 'and ' + cats[i] + '.';
+ } else {
+ info += cats[i] + ', ';
+ }
+
+ i++;
+} while (i &lt; cats.length);</pre>
+
+<div class="note">
+<p><strong>Note</strong>: Again, this works just the same as expected — have a look at it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/do-while.html">full source code</a>).</p>
+</div>
+
+<div class="warning">
+<p><strong>Important</strong>: With while and do...while — as with all loops — you must make sure that the initializer is iterated so that it eventually reaches the exit condition. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an <strong>infinite loop</strong>.</p>
+</div>
+
+<h2 id="Active_learning_Launch_countdown!">Active learning: Launch countdown!</h2>
+
+<p>In this exercise, we want you to print out a simple launch countdown to the output box, from 10 down to Blast off. Specifically, we want you to:</p>
+
+<ul>
+ <li>Loop from 10 down to 0. We've provided you with an initializer — <code>var i = 10;</code>.</li>
+ <li>For each iteration, create a new paragraph and append it to the output <code>&lt;div&gt;</code>, which we've selected using <code>var output = document.querySelector('.output');</code>. In comments, we've provided you with three code lines that need to be used somewhere inside the loop:
+ <ul>
+ <li><code>var para = document.createElement('p');</code> — creates a new paragraph.</li>
+ <li><code>output.appendChild(para);</code> — appends the paragraph to the output <code>&lt;div&gt;</code>.</li>
+ <li><code>para.textContent =</code> — makes the text inside the paragraph equal to whatever you put on the right hand side, after the equals sign.</li>
+ </ul>
+ </li>
+ <li>Different iteration numbers require different text to be put in the paragraph for that iteration (you'll need a conditional statement and multiple <code>para.textContent =</code> lines):
+ <ul>
+ <li>If the number is 10, print "Countdown 10" to the paragraph.</li>
+ <li>If the number is 0, print "Blast off!" to the paragraph.</li>
+ <li>For any other number, print just the number to the paragraph.</li>
+ </ul>
+ </li>
+ <li>Remember to include an iterator! However, in this example we are counting down after each iteration, not up, so you <strong>don't</strong> want <code>i++</code> — how do you iterate downwards?</li>
+</ul>
+
+<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p>
+
+<div class="hidden">
+<h6 id="Active_learning">Active learning</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="height: 410px;overflow: auto;"&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+&lt;textarea id="code" class="playable-code" style="height: 300px;width: 95%"&gt;
+var output = document.querySelector('.output');
+output.innerHTML = '';
+
+// var i = 10;
+
+// var para = document.createElement('p');
+// para.textContent = ;
+// output.appendChild(para);
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<p class="brush: js"></p>
+
+<p class="brush: js"></p>
+
+<p class="brush: js"></p>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<p class="brush: js"></p>
+
+<p class="brush: js"></p>
+
+<p class="brush: js"></p>
+
+<p class="brush: js"></p>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nvar i = 10;\n\nwhile(i &gt;= 0) {\n var para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+
+<p class="brush: js"></p>
+</div>
+
+<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Active_learning_Filling_in_a_guest_list">Active learning: Filling in a guest list</h2>
+
+<p>In this exercise, we want you to take a list of names stored in an array, and put them into a guest list. But it's not quite that easy — we don't want to let Phil and Lola in because they are greedy and rude, and always eat all the food! We have two lists, one for guests to admit, and one for guests to refuse.</p>
+
+<p>Specifically, we want you to:</p>
+
+<ul>
+ <li>Write a loop that will iterate from 0 to the length of the <code>people</code> array. You'll need to start with an initializer of  <code>var i = 0;</code>, but what exit condition do you need?</li>
+ <li>During each loop iteration, check if the current array item is equal to "Phil" or "Lola" using a conditional statement:
+ <ul>
+ <li>If it is, concatenate the array item to the end of the <code>refused</code> paragraph's <code>textContent</code>, followed by a comma and a space.</li>
+ <li>If it isn't, concatenate the array item to the end of the <code>admitted</code> paragraph's <code>textContent</code>, followed by a comma and a space.</li>
+ </ul>
+ </li>
+</ul>
+
+<p>We've already provided you with:</p>
+
+<ul>
+ <li><code>var i = 0;</code> — Your initializer.</li>
+ <li><code>refused.textContent +=</code> — the beginnings of a line that will concatenate something on to the end of <code>refused.textContent</code>.</li>
+ <li><code>admitted.textContent +=</code> — the beginnings of a line that will concatenate something on to the end of <code>admitted.textContent</code>.</li>
+</ul>
+
+<p>Extra bonus question — after completing the above tasks successfully, you will be left with two lists of names, separated by commas, but they will be untidy — there will be a comma at the end of each one. Can you work out how to write lines that slice the last comma off in each case, and add a full stop to the end? Have a look at the <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> article for help.</p>
+
+<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p>
+
+<div class="hidden">
+<h6 id="Active_learning_2">Active learning 2</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="height: 100px;overflow: auto;"&gt;
+ &lt;p class="admitted"&gt;Admit: &lt;/p&gt;
+  &lt;p class="refused"&gt;Refuse: &lt;/p&gt;
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+&lt;textarea id="code" class="playable-code" style="height: 400px;width: 95%"&gt;
+var people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce'];
+
+var admitted = document.querySelector('.admitted');
+var refused = document.querySelector('.refused');
+admitted.textContent = 'Admit: ';
+refused.textContent = 'Refuse: '
+
+// var i = 0;
+
+// refused.textContent += ;
+// admitted.textContent += ;
+
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var people = [\'Chris\', \'Anne\', \'Colin\', \'Terri\', \'Phil\', \'Lola\', \'Sam\', \'Kay\', \'Bruce\'];\n\nvar admitted = document.querySelector(\'.admitted\');\nvar refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Admit: \';\nrefused.textContent = \'Refuse: \'\nvar i = 0;\n\ndo {\n if(people[i] === \'Phil\' || people[i] === \'Lola\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i &lt; people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Which_loop_type_should_you_use">Which loop type should you use?</h2>
+
+<p>For basic uses, <code>for</code>, <code>while</code>, and <code>do...while</code> loops are largely interchangeable. They can all be used to solve the same problems, and which one you use will largely depend on your personal preference — which one you find easiest to remember or most intuitive. Let's have a look at them again.</p>
+
+<p>First <code>for</code>:</p>
+
+<pre class="notranslate">for (initializer; exit-condition; final-expression) {
+ // code to run
+}</pre>
+
+<p><code>while</code>:</p>
+
+<pre class="notranslate">initializer
+while (exit-condition) {
+ // code to run
+
+ final-expression
+}</pre>
+
+<p>and finally <code>do...while</code>:</p>
+
+<pre class="notranslate">initializer
+do {
+ // code to run
+
+ final-expression
+} while (exit-condition)</pre>
+
+<p>We would recommend <code>for</code>, at least to begin with, as it is probably the easiest for remembering everything — the initializer, exit-condition, and final-expression all have to go neatly into the parentheses, so it is easy to see where they are and check that you aren't missing them.</p>
+
+<div class="note">
+<p><strong>Note</strong>: There are other loop types/features too, which are useful in advanced/specialized situations and beyond the scope of this article. If you want to go further with your loop learning, read our advanced <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration guide</a>.</p>
+</div>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>This article has revealed to you the basic concepts behind, and different options available when, looping code in JavaScript. You should now be clear on why loops are a good mechanism for dealing with repetitive code, and be raring to use them in your own examples!</p>
+
+<p>If there is anything you didn't understand, feel free to read through the article again, or <a href="/en-US/Learn#Contact_us">contact us</a> to ask for help.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration in detail</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for statement reference</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> references</li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a> references</li>
+ <li>
+ <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — some advanced loop best practices</p>
+ </li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/building_blocks/return_values/index.html b/files/zh-tw/learn/javascript/building_blocks/return_values/index.html
new file mode 100644
index 0000000000..f77f37d46c
--- /dev/null
+++ b/files/zh-tw/learn/javascript/building_blocks/return_values/index.html
@@ -0,0 +1,172 @@
+---
+title: 函數回傳值
+slug: Learn/JavaScript/Building_blocks/Return_values
+translation_of: Learn/JavaScript/Building_blocks/Return_values
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div>
+
+<p class="summary">我們將在本課程中討論最後一個基本概念,即關閉函數 - 回傳值。 有些函數在完成後沒有回傳重要值,但其他函數會,並且了解它們的值是什麼,如何在代碼中使用它們以及如何使自己的自定義函數返回有用值非常重要。 我們將在下面介紹所有這些內容。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>
+ <p>Basic computer literacy, a basic understanding of HTML and CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a>.</p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand function return values, and how to make use of them.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="What_are_return_values">What are return values?</h2>
+
+<p><strong>Return values</strong> are just what they sound like — values returned by the function when it completes. You've already met return values a number of times, although you may not have thought about them explicitly. Let's return to some familiar code:</p>
+
+<pre class="brush: js">var myText = 'I am a string';
+var newString = myText.replace('string', 'sausage');
+console.log(newString);
+// the replace() string function takes a string,
+// replaces one substring with another, and returns
+// a new string with the replacement made</pre>
+
+<p>We saw exactly this block of code in our first function article. We are invoking the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> function on the <code>myText</code> string, and passing it two parameters — the substring to find, and the substring to replace it with. When this function completes (finishes running), it returns a value, which is a new string with the replacement made. In the code above, we are saving this return value as the value of the <code>newString</code> variable.</p>
+
+<p>If you look at the replace function MDN reference page, you'll see a section called <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Return_value">Return value</a>. It is very useful to know and understand what values are returned by functions, so we try to include this information wherever possible.</p>
+
+<p>Some functions don't return a return value as such (in our reference pages, the return value is listed as <code>void</code> or <code>undefined</code> in such cases). For example, in the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html#L50">displayMessage() function</a> we built in the previous article, no specific value is returned as a result of the function being invoked. It just makes a box appear somewhere on the screen — that's it!</p>
+
+<p>Generally, a return value is used where the function is an intermediate step in a calculation of some kind. You want to get to a final result, which involves some values. Those values need to be calculated by a function, which then returns the results so they can be used in the next stage of the calculation.</p>
+
+<h3 id="Using_return_values_in_your_own_functions">Using return values in your own functions</h3>
+
+<p>To return a value from a custom function, you need to use ... wait for it ... the <a href="/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a> keyword. We saw this in action recently in our <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> example. Our <code>draw()</code> function draws 100 random circles somewhere on an HTML {{htmlelement("canvas")}}:</p>
+
+<pre class="brush: js">function draw() {
+ ctx.clearRect(0,0,WIDTH,HEIGHT);
+ for (var i = 0; i &lt; 100; i++) {
+ ctx.beginPath();
+ ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
+ ctx.fill();
+ }
+}</pre>
+
+<p>Inside each loop iteration, three calls are made to the <code>random()</code> function, to generate a random value for the current circle's x coordinate, y coordinate, and radius, respectively. The <code>random()</code> function takes one parameter — a whole number — and it returns a whole random number between 0 and that number. It looks like this:</p>
+
+<pre class="brush: js">function randomNumber(number) {
+ return Math.floor(Math.random()*number);
+}</pre>
+
+<p>This could be written as follows:</p>
+
+<pre class="brush: js">function randomNumber(number) {
+ var result = Math.floor(Math.random()*number);
+ return result;
+}</pre>
+
+<p>But the first version is quicker to write, and more compact.</p>
+
+<p>We are returning the result of the calculation <code>Math.floor(Math.random()*number)</code> each time the function is called. This return value appears at the point the function was called, and the code continues. So for example, if we ran the following line:</p>
+
+<pre class="brush: js">ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);</pre>
+
+<p>and the three <code>random()</code> calls returned the values 500, 200, and 35, respectively, the line would actually be run as if it were this:</p>
+
+<pre class="brush: js">ctx.arc(500, 200, 35, 0, 2 * Math.PI);</pre>
+
+<p>The function calls on the line are run first and their return values substituted for the function calls, before the line itself is then executed.</p>
+
+<h2 id="Active_learning_our_own_return_value_function">Active learning: our own return value function</h2>
+
+<p>Let's have a go at writing our own functions featuring return values.</p>
+
+<ol>
+ <li>First of all, make a local copy of the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library.html">function-library.html</a> file from GitHub. This is a simple HTML page containing a text {{htmlelement("input")}} field and a paragraph. There's also a {{htmlelement("script")}} element in which we have stored a reference to both HTML elements in two variables. This little page will allow you to enter a number into the text box, and display different numbers related to it in the paragraph below.</li>
+ <li>Let's add some useful functions to this <code>&lt;script&gt;</code> element. Below the existing two lines of JavaScript, add the following function definitions:
+ <pre class="brush: js">function squared(num) {
+ return num * num;
+}
+
+function cubed(num) {
+ return num * num * num;
+}
+
+function factorial(num) {
+ var x = num;
+ while (x &gt; 1) {
+ num *= x-1;
+ x--;
+ }
+ return num;
+}</pre>
+ The <code>squared()</code> and <code>cubed()</code> functions are fairly obvious — they return the square or cube of the number given as a parameter. The <code>factorial()</code> function returns the <a href="https://en.wikipedia.org/wiki/Factorial">factorial</a> of the given number.</li>
+ <li>Next, we're going to include a way to print out information about the number entered into the text input. Enter the following event handler below the existing functions:
+ <pre class="brush: js">input.onchange = function() {
+ var num = input.value;
+ if (isNaN(num)) {
+ para.textContent = 'You need to enter a number!';
+ } else {
+ para.textContent = num + ' squared is ' + squared(num) + '. ' +
+ num + ' cubed is ' + cubed(num) + '. ' +
+ num + ' factorial is ' + factorial(num) + '.';
+ }
+}</pre>
+
+ <p>Here we are creating an <code>onchange</code> event handler that runs whenever the change event fires on the text input — that is, when a new value is entered into the text input, and submitted (enter a value then press tab for example). When this anonymous function runs, the existing value entered into the input is stored in the <code>num</code> variable.</p>
+
+ <p>Next, we do a conditional test — if the entered value is not a number, we print an error message into the paragraph. The test looks at whether the expression <code>isNaN(num)</code> returns true. We use the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN">isNaN()</a> function to test whether the num value is not a number — if so, it returns <code>true</code>, and if not, <code>false</code>.</p>
+
+ <p>If the test returns <code>false</code>, the <code>num</code> value is a number, so we print out a sentence inside the paragraph element stating what the square, cube, and factorial of the number are. The sentence calls the <code>squared()</code>, <code>cubed()</code>, and <code>factorial()</code> functions to get the required values.</p>
+ </li>
+ <li>Save your code, load it in a browser, and try it out.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: If you have trouble getting the example to work, feel free to check your code against the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library-finished.html">finished version on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-library-finished.html">see it running live</a> also), or ask us for help.</p>
+</div>
+
+<p>At this point, we'd like you to have a go at writing out a couple of functions of your own and adding them to the library. How about the square or cube root of the number, or the circumference of a circle with a radius of length <code>num</code>?</p>
+
+<p>This exercise has brought up a couple of important points besides being a study on how to use the <code>return</code> statement. In addition, we have:</p>
+
+<ul>
+ <li>Looked at another example of writing error handling into our functions. It is generally a good idea to check that any necessary parameters have been provided, and in the right datatype, and if they are optional, that some kind of default value is provided to allow for that. This way, your program will be less likely to throw errors.</li>
+ <li>Thought about the idea of creating a function library. As you go further into your programming career, you'll start to do the same kinds of things over and over again. It is a good idea to start keeping your own library of utility functions that you use very often — you can then copy them over to your new code, or even just apply it to any HTML pages where you need it.</li>
+</ul>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>So there we have it — functions are fun, very useful and, although there's a lot to talk about in regards to their syntax and functionality, fairly understandable given the right articles to study.</p>
+
+<p>If there is anything you didn't understand, feel free to read through the article again, or <a href="/en-US/Learn#Contact_us">contact us</a> to ask for help.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions">Functions in-depth</a> — a detailed guide covering more advanced functions-related information.</li>
+ <li><a href="https://www.impressivewebs.com/callback-functions-javascript/">Callback functions in JavaScript</a> — a common JavaScript pattern is to pass a function into another function as an argument, which is then called inside the first function. This is a little beyond the scope of this course, but worth studying before too long.</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/javascript/client-side_web_apis/index.html b/files/zh-tw/learn/javascript/client-side_web_apis/index.html
new file mode 100644
index 0000000000..c678aae7ae
--- /dev/null
+++ b/files/zh-tw/learn/javascript/client-side_web_apis/index.html
@@ -0,0 +1,39 @@
+---
+title: 客戶端 web APIs
+slug: Learn/JavaScript/Client-side_web_APIs
+translation_of: Learn/JavaScript/Client-side_web_APIs
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">在為網站或應用程序編寫客戶端JavaScript時,您將很快遇到應用程式介面(API)。 API是應用程式介面,用於操作運行站點的瀏覽器和操作系統的不同方面,或操縱來自其他網站或服務的資料。 在本單元中,我們將探討API是什麼,以及如何使用您在開發工作中經常遇到的一些最常見的API。</p>
+
+<h2 id="必備知識">必備知識</h2>
+
+<p>To get the most out of this module, you should have worked your way through the previous JavaScript modules in the series (<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>, and <a href="/en-US/docs/Learn/JavaScript/Objects">JavaScript objects</a>). Those modules typically involve simple API usage, as it is often difficult to write client-side JavaScript examples without them. For this tutorial, we will assume that you are knowledgable about the core JavaScript language, and we will explore common Web APIs in a bit more detail.</p>
+
+
+
+<p>了解 <a href="/en-US/docs/Learn/HTML">HTML</a> 和 <a href="/en-US/docs/Learn/CSS">CSS</a> 的基礎知識也會有所幫助。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 假如你正在使用 電腦/平板/其他裝置,你不需要建立自己的檔案,你可以嘗試線上程式撰寫系統來撰寫範例程式,像是<a href="http://jsbin.com/">JSBin</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p>
+</div>
+
+<h2 id="概觀">概觀</h2>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Web API簡介</a></dt>
+ <dd>First up, we'll start by looking at APIs from a high level — what are they, how do they work, how do you use them in your code, and how are they structured? We'll also take a look at what the different main classes of APIs are, and what kind of uses they have.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">文檔操作</a></dt>
+ <dd>When writing web pages and apps, one of the most common things you'll want to do is manipulate web documents in some way. This is usually done by using the Document Object Model (DOM), a set of APIs for controlling HTML and styling information that makes heavy use of the {{domxref("Document")}} object. In this article, we'll look at how to use the DOM in detail, along with some other interesting APIs that can alter your environment in interesting ways.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">從服務器獲取數據</a></dt>
+ <dd>Another very common task in modern websites and applications is retrieving individual data items from the server to update sections of a webpage without having to load an entirely new page. This seemingly small detail has had a huge impact on the performance and behavior of sites.  In this article, we'll explain the concept, and look at technologies that make it possible, such as {{domxref("XMLHttpRequest")}} and the <a href="/en-US/docs/Web/API/Fetch_API">Fetch API</a>.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">第三方API</a></dt>
+ <dd>The APIs we've covered so far are built into the browser, but not all APIs are. Many large websites and services such as Google Maps, Twitter, Facebook, PayPal, etc. provide APIs allowing developers to make use of their data (e.g. displaying your twitter stream on your blog) or services (e.g. displaying custom Google Maps on your site, or using Facebook login to log in your users). This article looks at the difference between browser APIs and 3rd party APIs and shows some typical uses of the latter.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">繪製圖形</a></dt>
+ <dd>The browser contains some very powerful graphics programming tools, from the Scalable Vector Graphics (<a href="/en-US/docs/Web/SVG">SVG</a>) language, to APIs for drawing on HTML {{htmlelement("canvas")}} elements, (see <a href="/en-US/docs/Web/API/Canvas_API">The Canvas API</a> and <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a>). This article provides an introduction to the Canvas API, and further resources to allow you to learn more.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">視頻和音頻API</a></dt>
+ <dd>HTML5 comes with elements for embedding rich media in documents — {{htmlelement("video")}} and {{htmlelement("audio")}} — which in turn come with their own APIs for controlling playback, seeking, etc. This article shows you how to do common tasks such as creating custom playback controls.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">客戶端存儲</a></dt>
+ <dd>Modern web browsers feature a number of different technologies that allow you to store data related to web sites and retrieve it when necessary allowing you to persist data long term, save sites offline, and more. This article explains the very basics of how these work.</dd>
+</dl>
diff --git a/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html
new file mode 100644
index 0000000000..5b04033cb1
--- /dev/null
+++ b/files/zh-tw/learn/javascript/client-side_web_apis/manipulating_documents/index.html
@@ -0,0 +1,314 @@
+---
+title: 文檔操作(文件操作)
+slug: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents
+translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<p class="summary">當你在撰寫網頁(web pages)或網路應用程式(web apps),其中一個最常見的事,你會希望能夠操作(網頁)文件結構。最常看見的方式是基於<a href="/zh-TW/docs/Web/API/Document_Object_Model"><strong>文件物件模型</strong> ( Document Object Model, DOM )</a> 概念上,透過使用 API (<a href="/zh-TW/docs/Web/API/">Web APIs</a>) 來控制 HTML 及 樣式;而這種方式也被大量使用在操作 <code><a href="/zh-TW/docs/Web/API/Document">Document</a></code> 物件上。接下來的文章中,我們將會詳細的介紹如何操作 DOM,藉著使用有趣的 API 能帶來些新奇的體驗。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">你事先需要了解:</th>
+ <td>基礎電腦知識, 了解基礎 HTML、CSS、JavaScript 概念 — 包含 JavaScript 物件概念.</td>
+ </tr>
+ <tr>
+ <th scope="row">你將學會:</th>
+ <td>更加熟悉 DOM 核心 API, 和常用來操作 DOM 的 API</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="The_important_parts_of_a_web_browser">The important parts of a web browser</h2>
+
+<p>Web browsers are very complicated pieces of software with a lot of moving parts, many of which can't be controlled or manipulated by a web developer using JavaScript. You might think that such limitations are a bad thing, but browsers are locked down for good reasons, mostly centering around security. Imagine if a web site could get access to your stored passwords or other sensitive information, and log into websites as if it were you?</p>
+
+<p>Despite the limitations, Web APIs still give us access to a lot of functionality that enable us to do a great many things with web pages. There are a few really obvious bits you'll reference regularly in your code — consider the following diagram, which represents the main parts of a browser directly involved in viewing web pages:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14557/document-window-navigator.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+ <li>The window is the browser tab that a web page is loaded into; this is represented in JavaScript by the {{domxref("Window")}} object. Using methods available on this object you can do things like return the window's size (see {{domxref("Window.innerWidth")}} and {{domxref("Window.innerHeight")}}), manipulate the document loaded into that window, store data specific to that document on the client-side (for example using a local database or other storage mechanism), attach an <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#A_series_of_fortunate_events">event handler</a> to the current window, and more.</li>
+ <li>The navigator represents the state and identity of the browser (i.e. the user-agent) as it exists on the web. In JavaScript, this is represented by the {{domxref("Navigator")}} object. You can use this object to retrieve things like the user's preferred language, a media stream from the user's webcam, etc.</li>
+ <li>The document (represented by the DOM in browsers) is the actual page loaded into the window, and is represented in JavaScript by the {{domxref("Document")}} object. You can use this object to return and manipulate information on the HTML and CSS that comprises the document, for example get a reference to an element in the DOM, change its text content, apply new styles to it, create new elements and add them to the current element as children, or even delete it altogether.</li>
+</ul>
+
+<p>In this article we'll focus mostly on manipulating the document, but we'll show a few other useful bits besides.</p>
+
+<h2 id="The_document_object_model">The document object model</h2>
+
+<p>The document currently loaded in each one of your browser tabs is represented by a document object model. This is a "tree structure" representation created by the browser that enables the HTML structure to be easily accessed by programming languages — for example the browser itself uses it to apply styling and other information to the correct elements as it renders a page, and developers like you can manipulate the DOM with JavaScript after the page has been rendered.</p>
+
+<p>We have created a simple example page at <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example.html">see it live also</a>). Try opening this up in your browser — it is a very simple page containing a {{htmlelement("section")}} element inside which you can find an image, and a paragraph with a link inside. The HTML source code looks like this:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Simple DOM example&lt;/title&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;section&gt;
+ &lt;img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."&gt;
+ &lt;p&gt;Here we will add a link to the &lt;a href="https://www.mozilla.org/"&gt;Mozilla homepage&lt;/a&gt;&lt;/p&gt;
+ &lt;/section&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>The DOM on the other hand looks like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14559/dom-screenshot.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<div class="note">
+<p><strong>Note</strong>: This DOM tree diagram was created using Ian Hickson's <a href="https://software.hixie.ch/utilities/js/live-dom-viewer/">Live DOM viewer</a>.</p>
+</div>
+
+<p>You can see here that each element and bit of text in the document has its own entry in the tree — each one is called a <strong>node</strong>. You will also encounter various terms used to describe the type of node, and their position in the tree in relation to one another:</p>
+
+<ul>
+ <li><strong>Element node</strong>: An element, as it exists in the DOM.</li>
+ <li><strong>Root node</strong>: The top node in the tree, which in the case of HTML is always the <code>HTML</code> node (other markup vocabularies like SVG and custom XML will have different root elements).</li>
+ <li><strong>Child node</strong>: A node <em>directly</em> inside another node. For example, <code>IMG</code> is a child of <code>SECTION</code> in the above example.</li>
+ <li><strong>Descendant node</strong>: A node <em>anywhere</em> inside another node. For example, <code>IMG</code> is a child of <code>SECTION</code> in the above example, and it is also a descendant. <code>IMG</code> is not a child of <code>BODY</code>, as it is two levels below it in the tree, but it is a descendant of <code>BODY</code>.</li>
+ <li><strong>Parent node</strong>: A node which has another node inside it. For example, <code>BODY</code> is the parent node of <code>SECTION</code> in the above example.</li>
+ <li><strong>Sibling nodes</strong>: Nodes that sit on the same level in the DOM tree. For example, <code>IMG</code> and <code>P</code> are siblings in the above example.</li>
+ <li><strong>Text node</strong>: A node containing a text string.</li>
+</ul>
+
+<p>It is useful to familiarize yourself with this terminology before working with the DOM, as a number of the code terms you'll come across make use of them. You may have also come across them if you have studied CSS (e.g. descendant selector, child selector).</p>
+
+<h2 id="Active_learning_Basic_DOM_manipulation">Active learning: Basic DOM manipulation</h2>
+
+<p>To start learning about DOM manipulation, let's begin with a practical example.</p>
+
+<ol>
+ <li>Take a local copy of the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html page</a> and the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dinosaur.png">image</a> that goes along with it.</li>
+ <li>Add a <code>&lt;script&gt;&lt;/script&gt;</code> element just above the closing <code>&lt;/body&gt;</code> tag.</li>
+ <li>To manipulate an element inside the DOM, you first need to select it and store a reference to it inside a variable. Inside your script element, add the following line:
+ <pre class="brush: js">var link = document.querySelector('a');</pre>
+ </li>
+ <li>Now we have the element reference stored in a variable, we can start to manipulate it using properties and methods available to it (these are defined on interfaces like {{domxref("HTMLAnchorElement")}} in the case of {{htmlelement("a")}} element, its more general parent interface {{domxref("HTMLElement")}}, and {{domxref("Node")}} — which represents all nodes in a DOM). First of all, let's change the text inside the link by updating the value of the {{domxref("Node.textContent")}} property. Add the following line below the previous one:
+ <pre class="brush: js">link.textContent = 'Mozilla Developer Network';</pre>
+ </li>
+ <li>We should also change the URL the link is pointing to, so that it doesn't go to the wrong place when it is clicked on. Add the following line, again at the bottom:
+ <pre class="brush: js">link.href = 'https://developer.mozilla.org';</pre>
+ </li>
+</ol>
+
+<div>
+<p>Note that, as with many things in JavaScript, there are many ways to select an element and store a reference to it in a variable. {{domxref("Document.querySelector()")}} is the recommended modern approach, which is convenient because it allows you to select elements using CSS selectors. The above <code>querySelector()</code> call will match the first {{htmlelement("a")}} element that appears in the document. If you wanted to match and do things to multiple elements, you could use {{domxref("Document.querySelectorAll()")}}, which matches every element in the document that matches the selector, and stores references to them in an <a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">array</a>-like object called a NodeList.</p>
+
+<p>There are older methods available for grabbing element references, such as:</p>
+
+<ul>
+ <li>{{domxref("Document.getElementById()")}}, which selects an element with a given <code>id</code> attribute value, e.g. <code>&lt;p id="myId"&gt;My paragraph&lt;/p&gt;</code>. The ID is passed to the function as a parameter, i.e. <code>var elementRef = document.getElementById('myId')</code>.</li>
+ <li>{{domxref("Document.getElementsByTagName()")}}, which returns an array containing all the elements on the page of a given type, for example <code>&lt;p&gt;</code>s, <code>&lt;a&gt;</code>s, etc. The element type is passed to the function as a parameter, i.e. <code>var elementRefArray = document.getElementsByTagName('p')</code>.</li>
+</ul>
+
+<p>These two work in older browsers than the modern methods like <code>querySelector()</code>, but are not as convenient. Have a look and see what others you can find!</p>
+</div>
+
+<h3 id="Creating_and_placing_new_nodes">Creating and placing new nodes</h3>
+
+<p>The above has given you a little taste of what you can do, but let's go further and look at how we can create new elements.</p>
+
+<ol>
+ <li>Going back to the current example, let's start by grabbing a reference to the our {{htmlelement("section")}} element — add the following code at the bottom of your existing script (do the same with the other lines too):
+ <pre class="brush: js">var sect = document.querySelector('section');</pre>
+ </li>
+ <li>Now let's create a new paragraph using {{domxref("Document.createElement()")}} and give it some text content in the same way as before:
+ <pre class="brush: js">var para = document.createElement('p');
+para.textContent = 'We hope you enjoyed the ride.';</pre>
+ </li>
+ <li>You can now append the new paragraph at the end of the section using {{domxref("Node.appendChild()")}}:
+ <pre class="brush: js">sect.appendChild(para);</pre>
+ </li>
+ <li>Finally for this part, let's add a text node to the paragraph the link sits inside, to round off the sentence nicely. First we will create the text node using {{domxref("Document.createTextNode()")}}:
+ <pre class="brush: js">var text = document.createTextNode(' — the premier source for web development knowledge.');</pre>
+ </li>
+ <li>Now we'll grab a reference to the paragraph the link is inside, and append the text node to it:
+ <pre class="brush: js">var linkPara = document.querySelector('p');
+linkPara.appendChild(text);</pre>
+ </li>
+</ol>
+
+<p>That's most of what you need for adding nodes to the DOM — you'll make a lot of use of these methods when building dynamic interfaces (we'll look at some examples later).</p>
+
+<h3 id="Moving_and_removing_elements">Moving and removing elements</h3>
+
+<p>There may be times when you want to move nodes, or delete them from the DOM altogether. This is perfectly possible.</p>
+
+<p>If we wanted to move the paragraph with the link inside it to the bottom of the section, we could simply do this:</p>
+
+<pre class="brush: js">sect.appendChild(linkPara);</pre>
+
+<p>This moves the paragraph down to the bottom of the section. You might have thought it would make a second copy of it, but this is not the case — <code>linkPara</code> is a reference to the one and only copy of that paragraph. If you wanted to make a copy and add that as well, you'd need to use {{domxref("Node.cloneNode()")}} instead.</p>
+
+<p>Removing a node is pretty simple as well, at least when you have a reference to the node to be removed and its parent. In our current case, we just use {{domxref("Node.removeChild()")}}, like this:</p>
+
+<pre class="brush: js">sect.removeChild(linkPara);</pre>
+
+<p>It gets slightly more complex when you want to remove a node based only on a reference to itself, which is fairly common. There is no method to tell a node to remove itself, so you'd have to do the following.</p>
+
+<pre class="brush: js">linkPara.parentNode.removeChild(linkPara);</pre>
+
+<p>Have a go at adding the above lines to your code.</p>
+
+<h3 id="Manipulating_styles">Manipulating styles</h3>
+
+<p>It is possible to manipulate CSS styles via JavaScript in a variety of ways.</p>
+
+<p>To start with, you can get a list of all the stylesheets attached to a document using {{domxref("Document.stylesheets")}}, which returns an array of {{domxref("CSSStyleSheet")}} objects. You can then add/remove styles as wished. However, we're not going to expand on those features because they are a somewhat archaic and difficult way to manipulate style. There are much easier ways.</p>
+
+<p>The first way is to add inline styles directly onto elements you want to dynamically style. This is done with the {{domxref("HTMLElement.style")}} property, which contains inline styling information for each element in the document. You can set properties of this object to directly update element styles.</p>
+
+<ol>
+ <li>As an example, try adding these lines to our ongoing example:
+ <pre class="brush: js">para.style.color = 'white';
+para.style.backgroundColor = 'black';
+para.style.padding = '10px';
+para.style.width = '250px';
+para.style.textAlign = 'center';</pre>
+ </li>
+ <li>Reload the page and you'll see that the styles have been applied to the paragraph. If you look at that paragraph in your browser's <a href="/en-US/docs/Tools/Page_Inspector">Page Inspector/DOM inspector</a>, you'll see that these lines are indeed adding inline styles to the document:
+ <pre class="brush: html">&lt;p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;"&gt;We hope you enjoyed the ride.&lt;/p&gt;</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: Notice how the JavaScript property versions of the CSS styles are written in lower camel case whereas the CSS versions are hyphenated (e.g. <code>backgroundColor</code> versus <code>background-color</code>). Make sure you don't get these mixed up, otherwise it won't work.</p>
+</div>
+
+<p>There is another common way to dynamically manipulate styles on your document, which we'll look at now.</p>
+
+<ol>
+ <li>Delete the previous five lines you added to the JavaScript.</li>
+ <li>Add the following inside your HTML {{htmlelement("head")}}:
+ <pre>&lt;style&gt;
+.highlight {
+ color: white;
+ background-color: black;
+ padding: 10px;
+ width: 250px;
+ text-align: center;
+}
+&lt;/style&gt;</pre>
+ </li>
+ <li>Now we'll turn to a very useful method for general HTML manipulation — {{domxref("Element.setAttribute()")}} — this takes two arguments, the attribute you want to set on the element, and the value you want to set it to. In this case we will set a class name of highlight on our paragraph:
+ <pre class="brush: js">para.setAttribute('class', 'highlight');</pre>
+ </li>
+ <li>Refresh your page, and you'll see no change — the CSS is still applied to the paragraph, but this time by giving it a class that is selected by our CSS rule, not as inline CSS styles.</li>
+</ol>
+
+<p>Which method you choose is up to you; both have their advantages and disadvantages. The first method takes less setup and is good for simple uses, whereas the second method is more purist (no mixing CSS and JavaScript, no inline styles, which are seen as a bad practice). As you start building larger and more involved apps, you will probably start using the second method more, but it is really up to you.</p>
+
+<p>At this point, we haven't really done anything useful! There is no point using JavaScript to create static content — you might as well just write it into your HTML and not use JavaScript. It is more complex than HTML, and creating your content with JavaScript also has other issues attached to it (such as not being readable by search engines).</p>
+
+<p>In the next couple of sections we will look at a couple of more practical uses of DOM APIs.</p>
+
+<div class="note">
+<p><strong>Note</strong>: You can find our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example-manipulated.html">finished version of the dom-example.html</a> demo on GitHub (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example-manipulated.html">see it live also</a>).</p>
+</div>
+
+<h2 id="Active_learning_Getting_useful_information_from_the_Window_object">Active learning: Getting useful information from the Window object</h2>
+
+<p>So far we've only really looked at using {{domxref("Node")}} and {{domxref("Document")}} features to manipulate documents, but there is no reason why you can't get data from other sources and use it in your UI. Think back to our simple <a href="http://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">maps-example.html</a> demo from the last article — there we retrieved some location data and used it to display a map of your area. You just have to make sure your data is in the right format; JavaScript makes it easier than many other languages, being weakly typed — for example numbers will convert to strings automatically when you want to print them to the screen.</p>
+
+<p>In this example we will solve a common problem — making sure your application is as big as the window it is viewed in, whatever size it is. This is often useful in situations like games, where you want to use as much of the screen area as possible to play the game in.</p>
+
+<p>To start with, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example.html">window-resize-example.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/bgtile.png">bgtile.png</a> demo files. Open it and have a look — you'll see that we've got a {{htmlelement("div")}} element covering a small part of the screen, which has got a background tile applied to it. We'll use that to represent our app UI area.</p>
+
+<ol>
+ <li>First of all, let's grab a reference to the div, and then grab the width and height of the viewport (the inner window, where your document is displayed) and store them in variables — these two values are handily contained in the {{domxref("Window.innerWidth")}} and {{domxref("Window.innerHeight")}} properties. Add the following lines inside the existing {{htmlelement("script")}} element:
+ <pre class="brush: js">var div = document.querySelector('div');
+var WIDTH = window.innerWidth;
+var HEIGHT = window.innerHeight;</pre>
+ </li>
+ <li>Next, we'll dynamically alter the width and height of the div to equal that of the viewport. Add the following two lines below your first ones:
+ <pre class="brush: js">div.style.width = WIDTH + 'px';
+div.style.height = HEIGHT + 'px';</pre>
+ </li>
+ <li>Save and try refreshing your browser — you should now see the div become as big as your viewport, whatever size of screen your are using. If you now try resizing your window to make it bigger, you'll see that the div stays the same size — we are only setting it once.</li>
+ <li>How about we use an event so that the div resizes as we resize the window? The {{domxref("Window")}} object has an event available on it called resize, which is fired every time the window is resized — let's access that via the {{domxref("Window.onresize")}} event handler and rerun our sizing code each time it changes. Add the following to the bottom of your code:
+ <pre class="brush: js">window.onresize = function() {
+ WIDTH = window.innerWidth;
+ HEIGHT = window.innerHeight;
+ div.style.width = WIDTH + 'px';
+ div.style.height = HEIGHT + 'px';
+}</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: If you get stuck, have a look at our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example-finished.html">finished window resize example</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/window-resize-example-finished.html">see it live also</a>).</p>
+</div>
+
+<h2 id="Active_learning_A_dynamic_shopping_list">Active learning: A dynamic shopping list</h2>
+
+<p>To round off the article, we'd like to set you a little challenge — we want to make a simple shopping list example that allows you to dynamically add items to the list using a form input and button. When you add an item to the input and press the button:</p>
+
+<ul>
+ <li>The item should appear in the list.</li>
+ <li>Each item should be given a button that can be pressed to delete that item off the list.</li>
+ <li>The input should be emptied and focused ready for you to enter another item.</li>
+</ul>
+
+<p>The finished demo will look something like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14563/shopping-list.png" style="border-style: solid; border-width: 1px; display: block; height: 225px; margin: 0px auto; width: 369px;"></p>
+
+<p>To complete the exercise, follow the steps below, and make sure that the list behaves as described above.</p>
+
+<ol>
+ <li>To start with, download a copy of our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list.html">shopping-list.html</a> starting file and make a copy of it somewhere. You'll see that it has some minimal CSS, a list with a label, input, and button, and an empty list and {{htmlelement("script")}} element. You'll be making all your additions inside the script.</li>
+ <li>Create three variables that hold references to the list ({{htmlelement("ul")}}), {{htmlelement("input")}}, and {{htmlelement("button")}} elements.</li>
+ <li>Create a <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">function</a> that will run in response to the button being clicked.</li>
+ <li>Inside the function body, start off by storing the current <a href="/en-US/docs/Web/API/HTMLInputElement#Properties">value</a> of the input element in a variable.</li>
+ <li>Next, empty the input element by setting its value to an empty string — <code>''</code>.</li>
+ <li>Create three new elements — a list item ({{htmlelement('li')}}), {{htmlelement('span')}}, and {{htmlelement('button')}}, and store them in variables.</li>
+ <li>Append the span and the button as children of the list item.</li>
+ <li>Set the text content of the span to the input element value you saved earlier, and the text content of the button to 'Delete'.</li>
+ <li>Append the list item as a child of the list.</li>
+ <li>Attach an event handler to the delete button, so that when clicked it will delete the entire list item it is inside.</li>
+ <li>Finally, use the <code><a href="/en-US/docs/Web/API/HTMLElement/focus">focus()</a></code> method to focus the input element ready for entering the next shopping list item.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: If you get really stuck, have a look at our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list-finished.html">finished shopping list</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/shopping-list-finished.html">see it running live also</a>.)</p>
+</div>
+
+<h2 id="Summary">Summary</h2>
+
+<p>We have reached the end of our study of document and DOM manipulation. At this point you should understand what the important parts of a web browser are with respect to controlling documents and other aspects of the user's web experience. Most importantly, you should understand what the Document Object Model is, and how to manipulate it to create useful functionality.</p>
+
+<h2 id="See_also">See also</h2>
+
+<p>There are lots more features you can use to manipulate your documents. Check out some of our references and see what you can discover:</p>
+
+<ul>
+ <li>{{domxref("Document")}}</li>
+ <li>{{domxref("Window")}}</li>
+ <li>{{domxref("Node")}}</li>
+ <li>{{domxref("HTMLElement")}}, {{domxref("HTMLInputElement")}}, {{domxref("HTMLImageElement")}}, etc.</li>
+</ul>
+
+<p>(See our <a href="https://developer.mozilla.org/en-US/docs/Web/API">Web API index</a> for the full list of Web APIs documented on MDN!)</p>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div>
+
+<div>
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li>
+</ul>
+</div>
diff --git a/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html b/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html
new file mode 100644
index 0000000000..38c7e4a4c4
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/a_first_splash/index.html
@@ -0,0 +1,706 @@
+---
+title: 初次接觸Javascript
+slug: Learn/JavaScript/First_steps/A_first_splash
+translation_of: Learn/JavaScript/First_steps/A_first_splash
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">目前你已經學會了一些JavaScript的理論,以及你能用它做些什麼。我們現在要透過一個完整的實際範例給你一個JavaScript基本功能的速成班。你將能一步一步地做出一個簡單的"猜數字"遊戲</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基礎的電腦知識 , 有基礎的 HTML 跟 CSS 知識 ,<br>
+ 還有知道 JavaScript 是甚麼 .</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>獲得第一次寫 JavaScript 的經驗 ,<br>
+ 還有知道最基礎的 JavaScript 程式該怎麼寫 .</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>並不會要求你馬上就能仔細地了解所有程式碼 — 目前我們只是想介紹一些概觀,並向你介紹一些關於JavaScript(以及其他程式語言)如何運作的知識。在接下來的章節你將會更仔細地瞭解這些功能!</p>
+
+<div class="note">
+<p>Note: 你會在 JavaScript 看到許多跟其他程式語言一樣的特徵 — functions , loops 之類的 ,雖然程式語法看起來有差 ,但概念大部分都差不多 .</p>
+</div>
+
+<h2 id="像程式工程師一樣思考">像程式工程師一樣思考</h2>
+
+<p>寫程式中最困難的事情之一,不是您需要學習的語法,而是如何應用它來解決現實世界中的問題。 您需要開始像個程式設計師一樣思考 — 這通常與檢視程式目標的說明有關,並確定實現這些功能所需的程式碼,以及如何使它們協同工作。</p>
+
+<p>這需要辛勤工作,程式語法經驗和練習 — 以及一點創造力。 你寫了越多程式碼,你就會越熟練。 我們不能保證你會在5分鐘內開發出“程式設計師的大腦”,但我們會給你很多機會在整個課程中練習"像程式設計師一樣思考"。</p>
+
+<p>考慮到這一點,讓我們看一下我們將在本文中構建的範例,並審視將其分解為具體任務的大致流程。</p>
+
+<h2 id="範例_—_猜數字遊戲">範例 — 猜數字遊戲</h2>
+
+<p>在本文中,我們將向您展示如何構建您可以在下面看到的簡單遊戲:</p>
+
+<div class="hidden">
+<h6 id="Top_hidden_code">Top hidden code</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+
+&lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;Number guessing game&lt;/title&gt;
+ &lt;style&gt;
+ html {
+ font-family: sans-serif;
+ }
+
+ body {
+ width: 50%;
+ max-width: 800px;
+ min-width: 480px;
+ margin: 0 auto;
+ }
+
+ .lastResult {
+ color: white;
+ padding: 3px;
+ }
+ &lt;/style&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+
+ &lt;h1&gt;Number guessing game&lt;/h1&gt;
+ &lt;p&gt;We have selected a random number between 1 and 100. See if you can guess it in 10 turns or fewer. We'll tell you if your guess was too high or too low.&lt;/p&gt;
+ &lt;div class="form"&gt; &lt;label for="guessField"&gt;Enter a guess: &lt;/label&gt;&lt;input type="text" id="guessField" class="guessField"&gt; &lt;input type="submit" value="Submit guess" class="guessSubmit"&gt; &lt;/div&gt;
+ &lt;div class="resultParas"&gt;
+ &lt;p class="guesses"&gt;&lt;/p&gt;
+ &lt;p class="lastResult"&gt;&lt;/p&gt;
+ &lt;p class="lowOrHi"&gt;&lt;/p&gt;
+ &lt;/div&gt;
+
+&lt;script&gt;
+ // Your JavaScript goes here
+ let randomNumber = Math.floor(Math.random() * 100) + 1;
+ const guesses = document.querySelector('.guesses');
+ const lastResult = document.querySelector('.lastResult');
+ const lowOrHi = document.querySelector('.lowOrHi');
+ const guessSubmit = document.querySelector('.guessSubmit');
+ const guessField = document.querySelector('.guessField');
+ let guessCount = 1;
+ let resetButton;
+
+ function checkGuess() {
+ let userGuess = Number(guessField.value);
+ if (guessCount === 1) {
+ guesses.textContent = 'Previous guesses: ';
+ }
+
+ guesses.textContent += userGuess + ' ';
+
+ if (userGuess === randomNumber) {
+ lastResult.textContent = 'Congratulations! You got it right!';
+ lastResult.style.backgroundColor = 'green';
+ lowOrHi.textContent = '';
+ setGameOver();
+ } else if (guessCount === 10) {
+ lastResult.textContent = '!!!GAME OVER!!!';
+ lowOrHi.textContent = '';
+ setGameOver();
+ } else {
+ lastResult.textContent = 'Wrong!';
+ lastResult.style.backgroundColor = 'red';
+ if(userGuess &lt; randomNumber) {
+ lowOrHi.textContent='Last guess was too low!' ;
+ } else if(userGuess &gt; randomNumber) {
+ lowOrHi.textContent = 'Last guess was too high!';
+ }
+ }
+
+ guessCount++;
+ guessField.value = '';
+ }
+
+ guessSubmit.addEventListener('click', checkGuess);
+
+ function setGameOver() {
+ guessField.disabled = true;
+ guessSubmit.disabled = true;
+ resetButton = document.createElement('button');
+ resetButton.textContent = 'Start new game';
+ document.body.appendChild(resetButton);
+ resetButton.addEventListener('click', resetGame);
+ }
+
+ function resetGame() {
+ guessCount = 1;
+ const resetParas = document.querySelectorAll('.resultParas p');
+ for(let i = 0 ; i &lt; resetParas.length ; i++) {
+ resetParas[i].textContent='';
+ }
+
+ resetButton.parentNode.removeChild(resetButton);
+ guessField.disabled = false;
+ guessSubmit.disabled = false;
+ guessField.value='';
+ guessField.focus();
+ lastResult.style.backgroundColor='white';
+ randomNumber=Math.floor(Math.random() * 100) + 1;
+ }
+&lt;/script&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Top_hidden_code', '100%', 320, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>好好玩一下遊戲再繼續吧 —— 在繼續前先與這個遊戲熟悉起來。</p>
+
+<p>讓我們假設你的老闆給了你以下關於創建這個遊戲的簡介:</p>
+
+<blockquote>
+<p>我要你幫我做一個很簡單的猜數字遊戲 .<br>
+ 玩家要在 10 回合內猜中一個1到100之間的隨機數字 ,<br>
+ 每回合結束時都要告訴玩家他們猜對還是猜錯 ,<br>
+ 然後要是他們猜錯 , 要告訴他們數字猜的太小還是太大 ,<br>
+ 這個遊戲會在玩家猜對 , 或是猜超過 10 次時結束 ,<br>
+ 且遊戲結束時 , 要提供一個選項讓玩家可以再玩一次 .</p>
+</blockquote>
+
+<p>當看到上面的介紹後,我們可以做的第一件事就是開始拆解,盡可能的像個程式設計師,將它拆解為簡單可執行的任務:</p>
+
+<ol>
+ <li>產生一個1到100間的隨機數字。</li>
+ <li>從一開始,紀錄玩家目前回合數。</li>
+ <li>提供玩家猜數字的方向(太大還是太小)。</li>
+ <li>當玩家送出第一個猜測後,將猜測記錄下來,讓玩家可以看到他們之前的猜測。</li>
+ <li>接著檢查數字是否猜中。</li>
+ <li>如果數字猜對:
+ <ol>
+ <li>顯示恭喜訊息。</li>
+ <li>使玩家不能再輸入更多猜測(避免把遊戲玩壞)。</li>
+ <li>顯示控制鈕讓玩家可以重新開始遊戲。</li>
+ </ol>
+ </li>
+ <li>如果數字猜錯而且玩家有剩餘回合數:
+ <ol>
+ <li>告訴玩家他猜錯了。</li>
+ <li>讓玩家輸入其他的猜測</li>
+ <li>回合數增加1。</li>
+ </ol>
+ </li>
+ <li>如果數字猜錯而且玩家沒有剩餘回合數:
+ <ol>
+ <li>告訴玩家遊戲結束。</li>
+ <li>使玩家不能再輸入更多猜測(避免把遊戲玩壞)。</li>
+ <li>顯示控制鈕讓玩家可以重新開始遊戲。</li>
+ </ol>
+ </li>
+ <li>當遊戲重新開始,確保遊戲邏輯和畫面(UI,使用這介面)全面重設,然後回到第一步。</li>
+</ol>
+
+<p>現在,讓我們繼續向前,一路上我們檢視如何將這些步驟轉化為程式碼、建構出上面的範例與探索JavaScript的功能。</p>
+
+<h3 id="初步設定">初步設定</h3>
+
+<p>在課程開始前,我們希望你可以複製一份<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">number-guessing-game-start.html</a>到自己的電腦中(<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">see it live here</a>)。用瀏覽器與文字編輯器將檔案打開時,你會看到簡單的標題、說明段落還有輸入猜測的表單,然而表單目前還不會做任何事情。</p>
+
+<p>所有的程式碼都會放入置於HTML底部的{{htmlelement("script")}}元素裡:</p>
+
+<pre class="brush: html notranslate">&lt;script&gt;
+
+ // Your JavaScript goes here
+
+&lt;/script&gt;
+</pre>
+
+<h3 id="加入變數儲存我們的資料">加入變數儲存我們的資料</h3>
+
+<p>我們一起開始吧。首先,在你的{{htmlelement("script")}} 元素裡加入以下幾行:</p>
+
+<pre class="brush: js notranslate">let randomNumber = Math.floor(Math.random() * 100) + 1;
+
+const guesses = document.querySelector('.guesses');
+const lastResult = document.querySelector('.lastResult');
+const lowOrHi = document.querySelector('.lowOrHi');
+
+const guessSubmit = document.querySelector('.guessSubmit');
+const guessField = document.querySelector('.guessField');
+
+let guessCount = 1;
+let resetButton;</pre>
+
+<p>這一區塊的程式碼設定我們的程式中用來儲存資料的變數。簡單的來說,「變數」是「值」的容器(值可以是數字、一串文字或是其他東西)。你可以用「關鍵字」(keyword) <code>let</code>(或是<code>var</code>)後面加上變數的名字來建立變數(在<a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Variables#The_difference_between_var_and_let">之後的文章</a>你會看到兩者的差別)。利用關鍵字 <code>const</code> 建立常數,常數(Constant)是用來儲存你不會更改的值。我們用常數儲存使用者介面的參照,使用者介面中的文字可能會改變,但是參照所指的HTML元素的不會改變。</p>
+
+<p>藉由等於符號(<code>=</code>)後面加上一個值,你可以指定變數或是常數的值。</p>
+
+<p>在我們的範例中:</p>
+
+<ul>
+ <li>第一個變數 — <code>randomNumber</code> — 被指定成一個由數學運算的1到100間的隨機數字</li>
+ <li>接著的三個常數,分別儲存HTML中結果段落的參照,在後面的程式碼中,參照被用來插入一些數值 (注意他們都位於一個{{htmlelement("div")}}元素裡,後者在之後我們重置遊戲時會被用來選取所有三個{{htmlelement("p")}}元素):
+ <pre class="brush: html notranslate">&lt;div class="resultParas"&gt;
+ &lt;p class="guesses"&gt;&lt;/p&gt;
+ &lt;p class="lastResult"&gt;&lt;/p&gt;
+ &lt;p class="lowOrHi"&gt;&lt;/p&gt;
+&lt;/div&gt;
+</pre>
+ </li>
+ <li>接著的兩個常數,分別儲存表單中的文字輸入和送出按鈕,之後會用來控制送出玩家猜測的數字。
+ <pre class="brush: html notranslate">&lt;label for="guessField"&gt;Enter a guess: &lt;/label&gt;&lt;input type="text" id="guessField" class="guessField"&gt;
+&lt;input type="submit" value="Submit guess" class="guessSubmit"&gt;</pre>
+ </li>
+ <li>最後兩個變數,一個儲存回合數1,另一個儲存指向重新開始按鈕的參照 (按鈕現在還不存在,之後會加上的)。</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: 從<a href="https://developer.mozilla.org/en-US/docs/user:chrisdavidmills/variables">下一篇文章</a>開始,你會學到更多有關變數的事。</p>
+</div>
+
+<h3 id="函式">函式</h3>
+
+<p>下一步,將下面這段添加到之前寫的那段程式碼:</p>
+
+<pre class="brush: js notranslate">function checkGuess() {
+ alert('I am a placeholder');
+}</pre>
+
+<p>函式是一段可重複利用的程式碼塊。建立一個函式便可以反複運行並避免撰寫重複的程式碼。定義函式有很多方法,在此我們先專注在一種簡單的方式。這裡我們以關鍵字 <code>function</code> 、自訂的函式名、一對括號以及一對花括號(<code>{ }</code>)建立函式。花括號中的程式碼便是我們調用函式時所要實際執行的程式碼。</p>
+
+<p>輸入函式名稱與括號便可以執行函式。</p>
+
+<p>讓我們來試試吧。儲存你的程式碼並重新整理瀏覽器畫面。進入 <a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools">開發者工具 JavaScript console</a>, 並輸入下面這行:</p>
+
+<pre class="brush: js notranslate">checkGuess();</pre>
+
+<p> 當按下 <kbd>Return</kbd>/<kbd>Enter</kbd> 時,你會看到一個警告跳窗顯示「I am a placeholder」。我們已經在程式中定義好一個函式,只要我們調用這個函式,函式便會彈出一個警告視窗。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 你會在後續的課程中學習到更多關於函式的事。</p>
+</div>
+
+<h3 id="運算子">運算子</h3>
+
+<p>JavaScript 運算子可以讓我們執行比較、數學運算、連接字符串等。</p>
+
+<p>儲存我們的程式碼並重整頁面,開啟 <a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools">開發者工具 JavaScript console</a> 。接下來你可以試著輸入以下的範例 —— 輸入跟每個「範例」欄位中一樣的內容,每輸入一個就按下<kbd>Return</kbd> / <kbd>Enter</kbd>, 接著看看回傳的結果。</p>
+
+<p>如果你不能快速打開瀏覽器開發工具, 你可以使用内嵌的應用程式中輸入以下範例:</p>
+
+<div class="hidden">
+<h6 id="Hidden_code">Hidden code</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;JavaScript console&lt;/title&gt;
+ &lt;style&gt;
+ * {
+ box-sizing: border-box;
+ }
+
+ html {
+ background-color: #0C323D;
+ color: #809089;
+ font-family: monospace;
+ }
+
+ body {
+ max-width: 700px;
+ }
+
+ p {
+ margin: 0;
+ width: 1%;
+ padding: 0 1%;
+ font-size: 16px;
+ line-height: 1.5;
+ float: left;
+ }
+
+ .input p {
+ margin-right: 1%;
+ }
+
+ .output p {
+ width: 100%;
+ }
+
+ .input input {
+ width: 96%;
+ float: left;
+ border: none;
+ font-size: 16px;
+ line-height: 1.5;
+ font-family: monospace;
+ padding: 0;
+ background: #0C323D;
+ color: #809089;
+ }
+
+ div {
+ clear: both;
+ }
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+
+ &lt;/body&gt;
+
+ &lt;script&gt;
+ var geval = eval;
+
+ function createInput() {
+ var inputDiv = document.createElement('div');
+ var inputPara = document.createElement('p');
+ var inputForm = document.createElement('input');
+
+ inputDiv.setAttribute('class','input');
+ inputPara.textContent = '&gt;';
+ inputDiv.appendChild(inputPara);
+ inputDiv.appendChild(inputForm);
+ document.body.appendChild(inputDiv);
+ inputDiv.focus();
+
+ if(document.querySelectorAll('div').length &gt; 1) {
+        inputForm.focus();
+      }
+
+ inputForm.addEventListener('change', executeCode);
+ }
+
+ function executeCode(e) {
+ try {
+ var result = geval(e.target.value);
+ } catch(e) {
+ var result = 'error — ' + e.message;
+ }
+
+ var outputDiv = document.createElement('div');
+ var outputPara = document.createElement('p');
+
+ outputDiv.setAttribute('class','output');
+ outputPara.textContent = 'Result: ' + result;
+ outputDiv.appendChild(outputPara);
+ document.body.appendChild(outputDiv);
+
+ e.target.disabled = true;
+ e.target.parentNode.style.opacity = '0.5';
+
+ createInput()
+ }
+
+ createInput();
+
+ &lt;/script&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>首先讓我們看看以下的算數運算子:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">運算子</th>
+ <th scope="col">名稱</th>
+ <th scope="col">範例</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>+</code></td>
+ <td>加法</td>
+ <td><code>6 + 9</code></td>
+ </tr>
+ <tr>
+ <td><code>-</code></td>
+ <td>減法</td>
+ <td><code>20 - 15</code></td>
+ </tr>
+ <tr>
+ <td><code>*</code></td>
+ <td>乘法</td>
+ <td><code>3 * 7</code></td>
+ </tr>
+ <tr>
+ <td><code>/</code></td>
+ <td>除法</td>
+ <td><code>10 / 5</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<p>你也可以使用 <code>+</code> 來連接字串 (在程式設計中,這稱爲<strong>連接</strong>)。試著輸入以下幾行程式,每次一行:</p>
+
+<pre class="brush: js notranslate">var name = 'Bingo';
+name;
+var hello = ' says hello!';
+hello;
+var greeting = name + hello;
+greeting;</pre>
+
+<p>你也可以使用一些捷徑,這些被稱爲增量賦值運算子。如果你只是簡單想將兩個字串加在一起,你可以這樣做:</p>
+
+<pre class="brush: js notranslate">name += ' says hello!';</pre>
+
+<p>相當於</p>
+
+<pre class="brush: js notranslate">name = name + ' says hello!';</pre>
+
+<p>當我們進行真假值測試時 (例如{{anch("條件", "下面")}}),我們可以使用比較運算子,如:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">運算子</th>
+ <th scope="col">名稱</th>
+ <th scope="col">範例</th>
+ </tr>
+ <tr>
+ <td><code>===</code></td>
+ <td>嚴格等於 (是否完全一樣?)</td>
+ <td><code>5 === 2 + 4</code></td>
+ </tr>
+ <tr>
+ <td><code>!==</code></td>
+ <td>不等於 (是否不一樣?)</td>
+ <td><code>'Chris' !== 'Ch' + 'ris'</code></td>
+ </tr>
+ <tr>
+ <td><code>&lt;</code></td>
+ <td>小於</td>
+ <td><code>10 &lt; 6</code></td>
+ </tr>
+ <tr>
+ <td><code>&gt;</code></td>
+ <td>大於</td>
+ <td><code>10 &gt; 20</code></td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="條件">條件</h3>
+
+<p>回到 <code>checkGuess()</code> 函式,我們希望的結果當然不只是彈出簡單訊息而已。我們更想要知道這個函式將如何檢查玩家的猜測是否準確,並回傳正確的結果。</p>
+
+<p>所以現在將 <code>checkGuess()</code> 函式替換成下面這個版本:</p>
+
+<pre class="brush: js notranslate">function checkGuess() {
+ var userGuess = Number(guessField.value);
+ if (guessCount === 1) {
+ guesses.textContent = 'Previous guesses: ';
+ }
+ guesses.textContent += userGuess + ' ';
+
+ if (userGuess === randomNumber) {
+ lastResult.textContent = 'Congratulations! You got it right!';
+ lastResult.style.backgroundColor = 'green';
+ lowOrHi.textContent = '';
+ setGameOver();
+ } else if (guessCount === 10) {
+ lastResult.textContent = '!!!GAME OVER!!!';
+ setGameOver();
+ } else {
+ lastResult.textContent = 'Wrong!';
+ lastResult.style.backgroundColor = 'red';
+ if(userGuess &lt; randomNumber) {
+ lowOrHi.textContent = 'Last guess was too low!';
+ } else if(userGuess &gt; randomNumber) {
+ lowOrHi.textContent = 'Last guess was too high!';
+ }
+ }
+
+ guessCount++;
+ guessField.value = '';
+ guessField.focus();
+}</pre>
+
+<p>哇,突然出現了很多程式碼!我們來完整地看一遍這些程式並介紹它們是如何運行的。</p>
+
+<ul>
+ <li>第一行(上面的第2行)宣告一個名為 <code>userGuess</code> 的變數,並將其值設置為在表單中文字輸入格內的當前值。我們還通過內建的 <code>Number()</code> 方法運行此值,以確保該值絕對是一個數字。</li>
+ <li>接下來,我們遇到第一個條件程式碼區塊(上面的第3-5行)。條件程式碼區塊允許您能基於某個條件是否為真來選擇性地執行程式碼。它看起來有點像函式,但其實並非如此。最簡單的條件區塊格式從 <code>if</code> 關鍵字開始,然後是一些括號,然後是一些花括號。在括號內包含一個比較測試。如果括號內的比較測試回傳 <code>true</code>,花括號內的程式碼則會被執行;否則不會執行,而會繼續執行接下來的程式碼。在這個情況下,我們的比較測試是檢查 <code>guessCount</code> 變數是否等於 <code>1</code>(即,這是否為玩家的第一次嘗試):
+ <pre class="notranslate"><code>guessCount === 1</code></pre>
+ 如果是,我們將 <code>guesses</code> 段落的文字內容設為 “Previous guesses: ”。</li>
+ <li>第6行將當前 <code>userGuess</code> 的值附加到 <code>guesses</code> 段落的尾端,並加上一個空格,讓顯示的每次猜測紀錄之間都有一個空格。</li>
+ <li>下一個條件區塊(上面第8-24行)做了一些檢查:
+ <ul>
+ <li>第一個 <code>if(){ }</code> 檢查用戶的猜測是否等於<code>我們</code>JavaScript頂部設置的 <code>randomNumber</code>。如果是,代表玩家猜對了,贏了遊戲,所以我們向玩家顯示一個漂亮的綠色祝賀訊息,清除 <code>lowOrHigh</code> 段落的內容,並運行一個叫做 <code>setGameOver()</code> 的函式,這個函式我們稍後再討論。</li>
+ <li>現在我們使用 <code>else if(){ }</code> 區塊將另一個測試連接到上一個測試的後面。這個測試檢查本次猜測是否為玩家的最後一次猜測機會。如果是,則執行與上一個條件區塊相同的操作,只是這次是遊戲結束訊息,漂亮的綠色祝賀訊息。</li>
+ <li>連接到此條件區塊後面的最後一個區塊(<code>else { }</code>)只會在其他兩個測試都沒有返回 <code>true</code> 時執行(即,玩家沒有猜對,但他們還有更多的猜測機會)。在這種情況下,我們告訴他們猜錯了,然後我們執行另一個條件測試以檢查猜測是高於還是低於正確答案 <code>randomNumber</code>,並顯示進一步的訊息來告訴他們要猜得更高或更低。</li>
+ </ul>
+ </li>
+ <li>函式中的最後三行(上面的第26-28行)讓玩家可以提交下一個猜測。我們將<code>guessCount</code>變數加1,來增加玩家已使用的猜測次數(<code>++</code>是遞增操作 - 遞增1),並將表單中文字輸入格內的文字清空並給予其焦點(顯示文字輸入游標),準備好讓玩家輸入下一個猜測。</li>
+</ul>
+
+<h3 id="事件">事件</h3>
+
+<p>現在我們有了一個很好的 <code>checkGuess()</code> 函式,但它並不會做任何事情,因為我們還沒有呼叫它。我們想在按下 “Submit guess” 按鈕時呼叫它,為此,我們需要使用<strong>事件</strong>。事件是在瀏覽器中發生的操作,例如單擊按鈕,加載頁面或播放影片,以讓我們可以在這些操作發生時執行程式碼。偵聽事件發生的構造稱為<strong>事件偵聽器</strong>,偵聽事件而觸發執行的程式碼稱為<strong>事件處理器</strong>。</p>
+
+<p>在 <code>checkGuess()</code> 函式下面添加下行(不是指函式內部的後面,而是函式外):</p>
+
+<pre class="brush: js notranslate">guessSubmit.addEventListener('click', checkGuess);</pre>
+
+<p>這裡我們為 <code>guessSubmit</code> 按鈕添加一個事件偵聽器。這是一個函式,它接受兩個輸入值(稱為<em>參數</em>) - 我們正在監聽的事件類型字串(本例中的 <code>click</code>),以及我們想要在事件發生時運行的程式碼(在這種情況下是<code>checkGuess()</code>函式) — 請注意,在編寫 <a href="https://developer.mozilla.org/zh-TW/docs/Web/API/EventTarget/addEventListener" title="EventTarget.addEventListener() 方法能將指定的事件監聽器註冊到 EventTarget 實作物件上。EventTarget 可能是 Document 中的 Element 物件、Document 物件本身、Window 物件,或是其它支援事件的物件(如:XMLHttpRequest)。"><code>addEventListener()</code></a> 內部時我們不需要為函式加上括號。</p>
+
+<p>現在保存並重整頁面,現在你的範例應該可以正常執行了。現在唯一的問題是,如果你猜對了正確的答案或用完了猜測機會,那麼遊戲就會出錯,因為我們還沒有定義 <code>setGameOver()</code> — 遊戲結束後應該執行的函式。現在讓我們加上缺少的程式碼並完成範例功能。</p>
+
+<h3 id="完成遊戲功能">完成遊戲功能</h3>
+
+<p>讓我們加入 <code>setGameOver()</code> 這個函式到我們程式碼的底部並演練它。 現在,在你的 JavaScript 尾端加上這些:</p>
+
+<pre class="brush: js notranslate">function setGameOver() {
+ guessField.disabled = true;
+ guessSubmit.disabled = true;
+ resetButton = document.createElement('button');
+ resetButton.textContent = 'Start new game';
+ document.body.appendChild(resetButton);
+ resetButton.addEventListener('click', resetGame);
+}</pre>
+
+<ul>
+ <li>函數中的前兩行透過將表單的文字輸入和按鈕的 <code>disabled</code> 屬性設為 <code>true</code> 來將兩者無效化。這很重要,因為如果沒有這麼做,使用者可能會在遊戲結束後繼續送出更多猜測值,這也許會把東西弄得一團糟。</li>
+ <li>接下來的三行會生成一個新的 {{htmlelement("button")}} 元素,將它的文字標籤設為「Start new game」後,添加到我們的HTML的最尾端。</li>
+ <li>最後一行則會在我們的新按鈕上設置一個事件偵聽器,來讓使用者按下按鈕時執行一個叫 <code>resetGame()</code> 的函數。</li>
+</ul>
+
+<p>現在讓我們來定義 <code>resetGame()</code>!再次將下面這些程式碼加進你的 JavaScript 的最下方。</p>
+
+<pre class="brush: js notranslate">function resetGame() {
+ guessCount = 1;
+
+ var resetParas = document.querySelectorAll('.resultParas p');
+ for (var i = 0 ; i &lt; resetParas.length ; i++) {
+ resetParas[i].textContent = '';
+ }
+
+ resetButton.parentNode.removeChild(resetButton);
+
+ guessField.disabled = false;
+ guessSubmit.disabled = false;
+ guessField.value = '';
+ guessField.focus();
+
+ lastResult.style.backgroundColor = 'white';
+
+ randomNumber = Math.floor(Math.random() * 100) + 1;
+}</pre>
+
+<p>這段相對較常的程式碼會完全將所有東西重置到遊戲的初始狀態,讓玩家可以再玩一次。這段程式碼做了下面這些事:</p>
+
+<ul>
+ <li>將 <code>guessCount</code> 設回 1。</li>
+ <li>清除所有訊息段落。</li>
+ <li>將重置按鈕移除。</li>
+ <li>將表單元素有效化,清空文字輸入並給予其焦點,準備好讓玩家能夠進行新一輪的猜測。</li>
+ <li><code>將lastResult</code> 段落的背景顏色設回白色。</li>
+ <li>生成一個新的隨機數值,才不會讓玩家又猜一次重複的答案!</li>
+</ul>
+
+<p><strong>現在,你應該有了一個完整且能正常執行的簡單遊戲了 — 恭喜你啦!</strong></p>
+
+<p>接下來這篇文章的工作只剩下來談談其他幾個很重要的程式功能,你應該已經看過了,只是還沒察覺罷了。</p>
+
+<h3 id="迴圈">迴圈</h3>
+
+<p>上面的程式碼中,一個我們需要仔細看看的部份是 <a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/for">for</a> 迴圈。迴圈在程式設計中是一個非常重要的內容,可以讓你在滿足條件前反覆執行同一段程式碼。</p>
+
+<p>開始吧,打開你的 <a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools">開發者工具 JavaScript console</a>,然後輸入下面這行:</p>
+
+<pre class="brush: js notranslate">for (var i = 1 ; i &lt; 21 ; i++) { console.log(i) }</pre>
+
+<p>看見了嗎?在你的主控台內印出了數字 1到 20。這就是迴圈的效果。一個 for 迴圈需要三個參數:</p>
+
+<ol>
+ <li><strong>起始動作:</strong>這個例子中我們從 1 開始累加,這個起始數值可以是任何你想要的值。你也可以不要使用 <code>i</code> 這個變數名稱,但習慣上我們會使用 <code>i</code> ,因為它簡單好記。 </li>
+ <li><strong>離開條件:</strong>這裡我們指定了 <code>i &lt; 21</code> — 這個迴圈會一直執行直到 <code>i</code> 不再小於 21。當 <code>i</code> 達到 21,這個迴圈就會停止執行。</li>
+ <li><strong>增加動作:</strong>我們指定了 <code>i++</code>,「將 <code>i</code> 的值加 1」。這個迴圈會對每個 <code>i</code> 的值執行一次,直到 <code>i</code> 達到 21(如上一條所述)。這個例子中,我們簡單的透過 {{domxref("Console.log", "console.log()")}} 將每次迴圈中 <code>i</code> 的值輸出到主控台中。</li>
+</ol>
+
+<p>現在我們來看看在猜謎遊戲中的迴圈 — 這可以在 <code>resetGame()</code> 函式中找到:</p>
+
+<pre class="brush: js notranslate">var resetParas = document.querySelectorAll('.resultParas p');
+for (var i = 0 ; i &lt; resetParas.length ; i++) {
+ resetParas[i].textContent = '';
+}</pre>
+
+<p>這段程式碼透過呼叫 {{domxref("Document.querySelectorAll", "querySelectorAll()")}} 創建一個變數並存著一個在 <code>&lt;div class="resultParas"&gt;</code> 中的所有段落清單,然後使用迴圈來遍歷每個段落元素,並移除其內容。</p>
+
+<h3 id="稍微討論一下物件">稍微討論一下物件</h3>
+
+<p>在開始討論這個段落的話題前,先來做點小小修改。在你的 JavaScript 接近頂部的 <code>var resetButton</code> 下一行加上:</p>
+
+<pre class="brush: js notranslate">guessField.focus();</pre>
+
+<p>,然後存檔。</p>
+
+<p>這一行呼叫了 {{domxref("HTMLElement.focus", "focus()")}} 方法來在頁面讀取時,將輸入游標自動放進 {{htmlelement("input")}} 文字欄裡面,這意味著使用者在開啟頁面後就可以直接使用鍵盤來在文字欄內輸入文字,而不用先點選文字欄。這只是個小修改,可是大大的提升了使用體驗,也給了使用者清楚的提示 — 提示他們要做些什麼來遊玩這個遊戲。</p>
+
+<p>讓我們來分析一下究竟發生了什麼事。在JavaScript中,所有東西都是一個<strong>物件</strong>。物件是一個集合,由許多相關的功能打包成一體。你可以創建一個你自己的物件,不過這比較進階,我們現在並不會涵蓋這個內容,這些會在課程的後期提到。現在,我們只會簡要的提到一些你的瀏覽器內建的物件,他們能夠讓你做到許多有用的事。</p>
+
+<p>在這個例子中,我們首先創建了一個 <code>guessField</code> 變數,儲存著一個指向HTML表單中文字輸入欄的參照 — 這可以在我們定義變數的區塊中找到:</p>
+
+<pre class="brush: js notranslate">var guessField = document.querySelector('.guessField');</pre>
+
+<p>我們使用了 {{domxref("document.querySelector", "querySelector()")}} 來取得這個參照,前者是 {{domxref("document")}} 物件的方法。<code>querySelector()</code> 接受一個參數 — 一個 <a href="/zh-TW/docs/Learn/CSS/Introduction_to_CSS/Selectors">CSS 選擇器</a>, 會回傳你想要的元素參照。</p>
+
+<p>因為現在 <code>guessField</code> 中存著一個指向 {{htmlelement("input")}} 元素的參照,它現在可以存取這個元素的屬性(基本上就是存在物件中的變數,其中有一些可能會是常數)和方法(基本上就是存在物件中的函式)了。文字輸入欄的其中一個方法便是 <code>focus()</code>,我們便可以透過呼叫這個方法來給予其焦點:</p>
+
+<pre class="brush: js notranslate">guessField.focus();</pre>
+
+<p>沒有存著表單元素參照的變數就不會有 <code>focus()</code> 方法能使用。<br>
+ 例如存著一個 {{htmlelement("p")}} 元素的 <code>guesses</code> 和存著一個數值的 <code>guessCount</code>。</p>
+
+<h3 id="來玩玩瀏覽器物件">來玩玩瀏覽器物件</h3>
+
+<p>讓我們來稍微玩一點瀏覽器內建的物件吧。</p>
+
+<ol>
+ <li>首先在瀏覽器中開啟你的程式。</li>
+ <li>接下來,打開你的<a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools">開發者工具 JavaScript console</a>。</li>
+ <li>輸入 <code>guessField</code>,可以看到主控台顯示這個變數儲存著一個 {{htmlelement("input")}} 元素。你還可以發現主控台會自動幫你完成已存在的物件名稱!</li>
+ <li>接下來輸入:
+ <pre class="brush: js notranslate">guessField.value = 'Hello';</pre>
+ <code>value</code> 屬性儲存著現在文字輸入欄內的內容參照。現在按下 <kbd>Enter</kbd>,看看文字欄內的內容是不是變了?</li>
+ <li>試著輸入 <code>guesses</code> 然後按下 <kbd>Enter</kbd>,主控台會顯示這個變數儲存著一個 {{htmlelement("p")}} 元素。</li>
+ <li>現在輸入:
+ <pre class="brush: js notranslate">guesses.value</pre>
+ 瀏覽器會回傳 <code>undefined</code>,因為 <code>value</code> 不存在在段落元素裡面。</li>
+ <li>要更改段落元素中的文字,你需要的是 {{domxref("Node.textContent", "textContent")}} 屬性。試試這個:
+ <pre class="brush: js notranslate">guesses.textContent = 'Where is my paragraph?';</pre>
+ </li>
+ <li>現在來做些好玩的事。一行一行輸入並 <kbd>Enter</kbd>:
+ <pre class="brush: js notranslate">guesses.style.backgroundColor = 'yellow';
+guesses.style.fontSize = '200%';
+guesses.style.padding = '10px';
+guesses.style.boxShadow = '3px 3px 6px black';</pre>
+ 每個在頁面上的元素都有一個 <code>style</code> 屬性,其本身又是另一個物件,包含著許多該元素的行內 CSS 屬性。這讓我們能透過 JavaScript 來動態的為元素設置 CSS 屬性。</li>
+</ol>
+
+<h2 id="差不多就到這了">差不多就到這了</h2>
+
+<p>這就是我們的範例 — 你順利地來到結尾了,做得不錯!試試你的最終成品,或試試<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game.html">我們的版本</a>。如果你仍然有困難沒有解決,再看看<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game.html">我們的原始碼</a>。</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/arrays/index.html b/files/zh-tw/learn/javascript/first_steps/arrays/index.html
new file mode 100644
index 0000000000..895183b811
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/arrays/index.html
@@ -0,0 +1,571 @@
+---
+title: Arrays
+slug: Learn/JavaScript/First_steps/Arrays
+translation_of: Learn/JavaScript/First_steps/Arrays
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">在本單元的最後一篇文章中,我們將介紹陣列——一種在單個變數名下儲存資料項列表的簡潔方法。在這裡,我們看看為什麼這很有用,然後探討如何建立陣列,檢索、增加和刪除儲存在陣列中的項目等等。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基本計算機知識、基本理解 HTML 與 CSS、知道 JavaScript 是什麼。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>理解何謂陣列並在 JavaScript 操作之。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是陣列?">什麼是陣列?</h2>
+
+<p>陣列通常描述為「像列表的物件」:也就是一個列表物件,裡面含有幾個數值。陣列物件能放在變數裡面,處理方式也與資料型別大致相同。不過主要差異為,陣列可以獨立存取、並高效處理裡面的數值:像是利用迴圈,對每個數值作相同處理。例如我們的陣列是一組有項目和價格的產品、我們可以用迴圈把單價印在發票上、最後在發票底下印出合計。</p>
+
+<p>不用陣列的話,就會需要註冊、並單獨呼叫很多獨立變數。這樣會花更多時間寫程式、效率更低、還更容易寫錯。只有十個的話還好解決,但如果有一百個,甚至一千個呢?我們會在接下來闡述之。</p>
+
+<p>與前幾篇文章一樣,讓我們在 JavaScript 控制台中輸入一些示例,來了解陣列的基礎知識吧。</p>
+
+<h3 id="建立陣列">建立陣列</h3>
+
+<p>陣列用方括弧包起來,每個單位會用逗號分隔起來。</p>
+
+<ol>
+ <li>來作一個購物清單的陣列吧:我們會做類似下面的事情。在主控台中輸入以下程式:
+ <pre class="brush: js notranslate">var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
+shopping;</pre>
+ </li>
+ <li>在此,陣列的每個單位都是字串。但請記住,陣列可以儲存任何單位:字串、數字、物件、另一個變數、甚至是另一個陣列。也可以混合單位的型別:它們不一定都要是數字或字串。來試試這個:
+ <pre class="brush: js notranslate">var sequence = [1, 1, 2, 3, 5, 8, 13];
+var random = ['tree', 795, [0, 1, 2]];</pre>
+ </li>
+ <li>看下去之前,試著自己作幾個陣列。</li>
+</ol>
+
+<h3 id="存取並修改陣列的單位">存取並修改陣列的單位</h3>
+
+<p>你可以使用括號標記法存取個別單位,同時也可以<a href="/en-US/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">存取字串中的字母</a>。</p>
+
+<ol>
+ <li>在主控台輸入以下程式:
+ <pre class="brush: js notranslate">shopping[0];
+// returns "bread"</pre>
+ </li>
+ <li>也可以透過賦予陣列新數值修改該單位。試試這個:
+ <pre class="brush: js notranslate">shopping[0] = 'tahini';
+shopping;
+// shopping 回傳 [ "tahini", "milk", "cheese", "hummus", "noodles" ]</pre>
+
+ <div class="note"><strong>注:</strong>前面有說過,但還是提醒下:電腦從 0 開始數!</div>
+ </li>
+ <li>請注意,陣列裡面的陣列稱為多維陣列(multidimensional array)。你可以撰寫兩組方括弧,來存取陣列裡面的陣列單位。例如說,存取前述 <code>random</code> 變數內的陣列單位就可以這麼寫:
+ <pre class="brush: js notranslate">random[2][2];</pre>
+ </li>
+ <li>看下去之前,試著進一步使用並修改陣列。</li>
+</ol>
+
+<h3 id="找出陣列長度">找出陣列長度</h3>
+
+<p>找出陣列長度(意即有幾個單位在陣列內)的方法,跟找出字串長度(含有幾個字元)的方式一樣——都是使用 {{jsxref("Array.prototype.length","length")}} 屬性。試試下方程式行:</p>
+
+<pre class="brush: js notranslate">shopping.length;
+// should return 5</pre>
+
+<p>這還有其他用途,但最常見的用法是讓迴圈一直循環直到所有的單元都走過一次。 舉個例子:</p>
+
+<pre class="brush: js notranslate">var sequence = [1, 1, 2, 3, 5, 8, 13];
+for (var i = 0; i &lt; sequence.length; i++) {
+ console.log(sequence[i]);
+}</pre>
+
+<p>在後續的章節,你會學到更多關於迴圈的部分;簡而言之,上述程式碼的意思是:</p>
+
+<ol>
+ <li>從陣列中索引為 0 的單元開始循環。</li>
+ <li>當索引值等於陣列的長度時,停止循環。這個方法對任何長度的陣列都可行,但在這個例子中,迴圈會當索引等於 7 時停止循環(這樣很好,因為最後一個單元——我們希望有包含到的——是6)。</li>
+ <li>我們在瀏覽器 console 中用 <code><a href="/en-US/docs/Web/API/Console/log">console.log()</a></code> 將每個單元列印出來。</li>
+</ol>
+
+<h2 id="好用的陣列方法">好用的陣列方法</h2>
+
+<p>在這個小節中,我們會介紹一些相當有用、有關陣列的方法。例如將字串拆分為陣列,反之亦然,以及增加新的單位到陣列中。</p>
+
+<h3 id="在字串與陣列之間轉換">在字串與陣列之間轉換</h3>
+
+<p>通常你會看到一組含有原始資料的長字串,而你可能會希望將有用的單元拆分、組成更好用的形式,對他進行操作。為了達成這個目的,我們可以使用 {{jsxref("String.prototype.split()","split()")}} 方法。它最簡單的形式是只使用一個參數,你想分離的字串位置的字元(分隔符),而後它會返回陣列中在分隔符之間的子字串。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 好的,在技術上它屬於字串的方法,而非陣列的方法。但因為它可以很順利地對陣列進行操作,因此我們把它列在這邊。</p>
+</div>
+
+<ol>
+ <li>來試試這個,看它如何運作。首先,建立一個字串在你的 console:
+ <pre class="brush: js notranslate">var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';</pre>
+ </li>
+ <li>現在我們用逗點來分隔字串:
+ <pre class="brush: js notranslate">var myArray = myData.split(',');
+myArray;</pre>
+ </li>
+ <li>最後,試著找出你新的陣列的長度,並且從中取出一些單元:
+ <pre class="brush: js notranslate">myArray.length;
+myArray[0]; // the first item in the array
+myArray[1]; // the second item in the array
+myArray[myArray.length-1]; // the last item in the array</pre>
+ </li>
+ <li>相對地,你也可以用 {{jsxref("Array.prototype.join()","join()")}} 方法。試試下面這段:
+ <pre class="brush: js notranslate">var myNewString = myArray.join(',');
+myNewString;</pre>
+ </li>
+ <li>另一個將陣列轉換為字串的方法是用 {{jsxref("Array.prototype.toString()","toString()")}} 。<code>toString()</code> 因為不需要參數而比 <code>join()</code> 更簡潔,但因此也更多限制。使用 <code>join()</code> 你可以使用特定的分隔符(試著使用其他不同的字元來執行步驟 4)。
+ <pre class="brush: js notranslate">var dogNames = ['Rocket','Flash','Bella','Slugger'];
+dogNames.toString(); //Rocket,Flash,Bella,Slugger</pre>
+ </li>
+</ol>
+
+<h3 id="新增與移除陣列單位">新增與移除陣列單位</h3>
+
+<p>我們還沒談到增加與移除陣列的單位,現在來看看吧!我們使用上一個小節中的 <code>myArray</code> 陣列。如果你沒跟隨到上一個小節,那就先在你的 console 建立下面這個陣列:</p>
+
+<pre class="brush: js notranslate">var myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];</pre>
+
+<p>首先,我們可以分別使用 {{jsxref("Array.prototype.push()","push()")}} 和 {{jsxref("Array.prototype.pop()","pop()")}} 來增加或移除一個在陣列最末端的單元 。</p>
+
+<ol>
+ <li>Let's use <code>push()</code> first — note that you need to include one or more items that you want to add to the end of your array. Try this:
+
+ <pre class="brush: js notranslate">myArray.push('Cardiff');
+myArray;
+myArray.push('Bradford', 'Brighton');
+myArray;
+</pre>
+ </li>
+ <li>The new length of the array is returned when the method call completes. If you wanted to store the new array length in a variable, you could do something like this:
+ <pre class="brush: js notranslate">var newLength = myArray.push('Bristol');
+myArray;
+newLength;</pre>
+ </li>
+ <li>Removing the last item from the array is as simple as running <code>pop()</code> on it. Try this:
+ <pre class="brush: js notranslate">myArray.pop();</pre>
+ </li>
+ <li>The item that was removed is returned when the method call completes. To save that item in a new variable, you could do this:
+ <pre class="brush: js notranslate">var removedItem = myArray.pop();
+myArray;
+removedItem;</pre>
+ </li>
+</ol>
+
+<p>{{jsxref("Array.prototype.unshift()","unshift()")}} and {{jsxref("Array.prototype.shift()","shift()")}} work in exactly the same way as <code>push()</code> and <code>pop()</code>, respectively, except that they work on the beginning of the array, not the end.</p>
+
+<ol>
+ <li>First <code>unshift()</code> — try the following commands:
+
+ <pre class="brush: js notranslate">myArray.unshift('Edinburgh');
+myArray;</pre>
+ </li>
+ <li>Now <code>shift()</code>; try these!
+ <pre class="brush: js notranslate">var removedItem = myArray.shift();
+myArray;
+removedItem;</pre>
+ </li>
+</ol>
+
+<h2 id="Active_learning_Printing_those_products!">Active learning: Printing those products!</h2>
+
+<p>Let's return to the example we described earlier — printing out product names and prices on an invoice, then totaling the prices and printing them at the bottom. In the editable example below there are comments containing numbers — each of these marks a place where you have to add something to the code. They are as follows:</p>
+
+<ol>
+ <li>Below the <code>// number 1</code> comment are a number of strings, each one containing a product name and price separated by a colon. We'd like you to turn this into an array and store it in an array called <code>products</code>.</li>
+ <li>On the same line as the <code>// number 2</code> comment is the beginning of a for loop. In this line we currently have <code>i &lt;= 0</code>, which is a conditional test that causes the <a href="/en-US/Learn/JavaScript/First_steps/A_first_splash#Loops">for loop</a> to stop immediately, because it is saying "stop when <code>i</code> is no longer less than or equal to 0", and <code>i</code> starts at 0. We'd like you to replace this with a conditional test that stops the loop when <code>i</code> is no longer less than the <code>products</code> array's length.</li>
+ <li>Just below the <code>// number 3</code> comment we want you to write a line of code that splits the current array item (<code>name:price</code>) into two separate items, one containing just the name and one containing just the price. If you are not sure how to do this, consult the <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> article for some help, or even better, look at the {{anch("Converting between strings and arrays")}} section of this article.</li>
+ <li>As part of the above line of code, you'll also want to convert the price from a string to a number. If you can't remember how to do this, check out the <a href="/en-US/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">first strings article</a>.</li>
+ <li>There is a variable called <code>total</code> that is created and given a value of 0 at the top of the code. Inside the loop (below <code>// number 4</code>) we want you to add a line that adds the current item price to that total in each iteration of the loop, so that at the end of the code the correct total is printed onto the invoice. You might need an <a href="/en-US/Learn/JavaScript/First_steps/Math#Assignment_operators">assignment operator</a> to do this.</li>
+ <li>We want you to change the line just below <code>// number 5</code> so that the <code>itemText</code> variable is made equal to "current item name — $current item price", for example "Shoes — $23.99" in each case, so the correct information for each item is printed on the invoice. This is just simple string concatenation, which should be familiar to you.</li>
+</ol>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 150px;"&gt;
+
+&lt;ul&gt;
+
+&lt;/ul&gt;
+
+&lt;p&gt;&lt;/p&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 410px;width: 95%"&gt;
+var list = document.querySelector('.output ul');
+var totalBox = document.querySelector('.output p');
+var total = 0;
+list.innerHTML = '';
+totalBox.textContent = '';
+// number 1
+ 'Underpants:6.99'
+ 'Socks:5.99'
+ 'T-shirt:14.99'
+ 'Trousers:31.99'
+ 'Shoes:23.99';
+
+for (var i = 0; i &lt;= 0; i++) { // number 2
+ // number 3
+
+ // number 4
+
+ // number 5
+ itemText = 0;
+
+ var listItem = document.createElement('li');
+ listItem.textContent = itemText;
+ list.appendChild(listItem);
+}
+
+totalBox.textContent = 'Total: $' + total.toFixed(2);
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar totalBox = document.querySelector(\'.output p\');\nvar total = 0;\nlist.innerHTML = \'\';\ntotalBox.textContent = \'\';\n\nvar products = [\'Underpants:6.99\',\n \'Socks:5.99\',\n \'T-shirt:14.99\',\n \'Trousers:31.99\',\n \'Shoes:23.99\'];\n\nfor(var i = 0; i &lt; products.length; i++) {\n var subArray = products[i].split(\':\');\n var name = subArray[0];\n var price = Number(subArray[1]);\n total += price;\n itemText = name + \' — $\' + price;\n\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n}\n\ntotalBox.textContent = \'Total: $\' + total.toFixed(2);';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+
+  if (e.keyCode === 27) {
+    textarea.blur();
+  }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+
+
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background-color: #f5f9fa;
+}</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', '100%', 730, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Active_learning_Top_5_searches">Active learning: Top 5 searches</h2>
+
+<p>A good use for array methods like {{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} is when you are maintaining a record of currently active items in a web app. In an animated scene for example, you might have an array of objects representing the background graphics currently displayed, and you might only want 50 displayed at once, for performance or clutter reasons. As new objects are created and added to the array, older ones can be deleted from the array to maintain the desired number.</p>
+
+<p>In this example we're going to show a much simpler use — here we're giving you a fake search site, with a search box. The idea is that when terms are entered in the search box, the top 5 previous search terms are displayed in the list. When the number of terms goes over 5, the last term starts being deleted each time a new term is added to the top, so the 5 previous terms are always displayed.</p>
+
+<div class="note">
+<p><strong>Note</strong>: In a real search app, you'd probably be able to click the previous search terms to return to previous searches, and it would display actual search results! We are just keeping it simple for now.</p>
+</div>
+
+<p>To complete the app, we need you to:</p>
+
+<ol>
+ <li>Add a line below the <code>// number 1</code> comment that adds the current value entered into the search input to the start of the array. This can be retrieved using <code>searchInput.value</code>.</li>
+ <li>Add a line below the <code>// number 2</code> comment that removes the value currently at the end of the array.</li>
+</ol>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code 2</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+&lt;div class="output" style="min-height: 150px;"&gt;
+
+&lt;input type="text"&gt;&lt;button&gt;Search&lt;/button&gt;
+
+&lt;ul&gt;
+
+&lt;/ul&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+
+&lt;textarea id="code" class="playable-code" style="height: 370px; width: 95%"&gt;
+var list = document.querySelector('.output ul');
+var searchInput = document.querySelector('.output input');
+var searchBtn = document.querySelector('.output button');
+
+list.innerHTML = '';
+
+var myHistory = [];
+
+searchBtn.onclick = function() {
+ // we will only allow a term to be entered if the search input isn't empty
+ if (searchInput.value !== '') {
+ // number 1
+
+ // empty the list so that we don't display duplicate entries
+ // the display is regenerated every time a search term is entered.
+ list.innerHTML = '';
+
+ // loop through the array, and display all the search terms in the list
+ for (var i = 0; i &lt; myHistory.length; i++) {
+ itemText = myHistory[i];
+ var listItem = document.createElement('li');
+ listItem.textContent = itemText;
+ list.appendChild(listItem);
+ }
+
+ // If the array length is 5 or more, remove the oldest search term
+ if (myHistory.length &gt;= 5) {
+ // number 2
+
+ }
+
+ // empty the search input and focus it, ready for the next term to be entered
+ searchInput.value = '';
+ searchInput.focus();
+ }
+}
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;</pre>
+
+
+
+
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+
+
+
+
+
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar searchInput = document.querySelector(\'.output input\');\nvar searchBtn = document.querySelector(\'.output button\');\n\nlist.innerHTML = \'\';\n\nvar myHistory= [];\n\nsearchBtn.onclick = function() {\n if(searchInput.value !== \'\') {\n myHistory.unshift(searchInput.value);\n\n list.innerHTML = \'\';\n\n for(var i = 0; i &lt; myHistory.length; i++) {\n itemText = myHistory[i];\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n }\n\n if(myHistory.length &gt;= 5) {\n myHistory.pop();\n }\n\n searchInput.value = \'\';\n searchInput.focus();\n }\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+
+
+
+
+
+
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', '100%', 700, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>After reading through this article, we are sure you will agree that arrays seem pretty darn useful; you'll see them crop up everywhere in JavaScript, often in association with loops in order to do the same thing to every item in an array. We'll be teaching you all the useful basics there are to know about loops in the next module, but for now you should give yourself a clap and take a well-deserved break; you've worked through all the articles in this module!</p>
+
+<p>The only thing left to do is work through this module's assessment, which will test your understanding of the articles that came before it.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> — an advanced level guide to arrays and their cousins, typed arrays.</li>
+ <li>{{jsxref("Array")}} — the <code>Array</code> object reference page — for a detailed reference guide to the features discussed in this page, and many more.</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</p>
+
+
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/index.html b/files/zh-tw/learn/javascript/first_steps/index.html
new file mode 100644
index 0000000000..418325ca8f
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/index.html
@@ -0,0 +1,71 @@
+---
+title: JavaScript 初探
+slug: Learn/JavaScript/First_steps
+tags:
+ - JavaScript
+ - 初學者
+ - 字串
+ - 指引
+ - 撰寫程式
+ - 數值
+ - 數學
+ - 文章
+ - 變數
+ - 運算子
+ - 陣列
+translation_of: Learn/JavaScript/First_steps
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">帶領各位開始體驗撰寫 JavaScript 前,在第一個 JavaScript 單元中,我們首先來回答一些基本的問題,像是「什麼是 JavaScript 啊?」、「它長什麼樣子?」以及「它能拿來做什麼?」。之後我們會詳細討論幾個關鍵元素,諸如變量(variables)、字串(strings)、數字(numbers)和陣列(arrays)。</p>
+
+<h2 id="事前準備">事前準備</h2>
+
+<p>在開始這個教學之前,你不需要具備任何的 JavaScript 相關知識,但是你應該對 HTML 及 CSS 有一點熟悉。建議你在開始學習 JavaScript 前,先看過下列內容 :</p>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Getting_started_with_the_web">開始使用 Web </a> (包括 <a href="/zh-TW/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基礎簡介</a>).</li>
+ <li><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 簡介</a>.</li>
+ <li><a href="/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 簡介</a>.</li>
+</ul>
+
+<div class="note">
+<p><span style="font-size: 14px;"><strong>注意</strong></span>: 假如你正在使用 電腦/平板/其他裝置,你還不需要知道如何建立自己的檔案,你可以在線上程式撰寫系統來嘗試範例程式,像是 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a>.</p>
+</div>
+
+<h2 id="概觀">概觀</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></dt>
+ <dd>歡迎來到 MDN JavaScript 新手村教學!在第一個章節中我們將一個較高的層次看 JavaScript,回答像是「它是什麼?」、「有什麼用?」之類的問題,並且確保你能了解 JavaScript 的目的。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></dt>
+ <dd>現在你已經學到一些關於 JavaScript 的原理,以及可以用它來作什麼,我們將經由完整的引導,給你一個關於 JavaScript 基礎功能的速成課。這裡你將會一步一步地建立一個簡單的「猜數字」遊戲。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></dt>
+ <dd>當你在前一章節建立的「猜數字」遊戲過程中,你可能會發現它不能運作。不要慌,這個章節的目的是提供一些提示,用來找出及修正在 JavaScript 程式裡的錯誤,讓你不會因為這些問題而煩惱。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></dt>
+ <dd>在讀過前面幾個章節後,你現在應該能由較高的層次了解 JavaScript 是什麼,它能為你做些什麼,如何與其他的網站技術一起使用,以及它的主要的特性。在本章節中,我們將深入探討真正的基礎知識,看看 JavaScript 最基本的組成 — 變數(Variables)是如何運作 。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></dt>
+ <dd>本章的重點,我們討論 JavaScript 的數值計算 — 我們如何依我們的要求組合運算子與其它元素來操控數值。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></dt>
+ <dd>接下來我們將焦點轉到字串(strings) — 這是程式裡對一段文字的稱呼。這個章節我們將會檢視學習 JavaScript 中,所有你通常想要知道於字串事情,例如創建字串、字串跳脫(escaping)操作,以及把它們組合起來。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></dt>
+ <dd>我們已經看過了字串的基礎知識,現在讓我們加快腳步,看看可以使用內建的方法對字串進行哪些有用的操作 ,例如:取得字串的長度、串接或分割字串、替換字串中的某個字……等等。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></dt>
+ <dd>在這個單元的最後一個章節,我們來看看陣列 (Array) — 把一連串資料整齊地儲存在一個變數中。我們會看到為什麼它有用,然後探索如何創建一個陣列,對陣列內的項目進行檢索、新增、刪除……等操作。</dd>
+</dl>
+
+<h2 id="測試一下">測試一下</h2>
+
+<p>下面的任務會測試你對於前面提到的 JavaScript 基本概念是否了解。</p>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">傻故事產生器</a></dt>
+ <dd>本次測試中,你的任務是使用在這個單元所學到的知識,建立一個能隨機產生笑話的有趣程式。祝你愉快!</dd>
+</dl>
+
+<h2 id="參考資源">參考資源</h2>
+
+<dl>
+ <dt><a class="external" href="https://learnjavascript.online/" rel="noopener">Learn JavaScript</a></dt>
+ <dd>對於想成為網站開發者一個很好的資源,以互動的方式學習 JavaScript ,包含短課程、互動測驗,自動評估狀況給予指引。前 40 堂課是免費,完整的課程可以在一次付費買下。</dd>
+</dl>
diff --git a/files/zh-tw/learn/javascript/first_steps/math/index.html b/files/zh-tw/learn/javascript/first_steps/math/index.html
new file mode 100644
index 0000000000..4c7f1d4cba
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/math/index.html
@@ -0,0 +1,426 @@
+---
+title: JavaScript中的基本數學 - 數字和運算符
+slug: Learn/JavaScript/First_steps/Math
+translation_of: Learn/JavaScript/First_steps/Math
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">在本課程的這一點上,我們將討論JavaScript中的數學 - 我們如何使用{{Glossary("Operator","operators")}} 和其他功能來成功操縱數字來進行我們的出價。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>電腦基礎知識,了解基本的 HTML 和 CSS ,了解 JavaScript 是什麼。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>熟悉JavaScript中的基礎數學。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="每個人都喜歡數學">每個人都喜歡數學</h2>
+
+<p>好吧,也許不是。 我們中的一些人喜歡數學,我們有些人討厭數學,因為我們必須在學校學習乘法和除法,而我們中的一些人兩者皆要。 但我們都不能否認數學是生活中的一個基本組成部分,我們離不開它們。 當我們學習JavaScript(或任何其他語言)的程式時,尤其如此 - 我們所做的很多事情都依賴於處理數值數據,計算新值等等,你不會驚訝學習JavaScript 有一套功能齊全的數學函數。</p>
+
+<p>本文僅討論你現在需了解的基本部分。</p>
+
+<h3 id="數字的種類">數字的種類</h3>
+
+<p><font>在程式裡,即使眾所周知的十進位數字系統也比您想像的要複雜。</font><font>我們使用不同的術語來描述不同類型的十進位數字,例如:</font></p>
+
+<ul>
+ <li><strong>Integers </strong>是整數,如:10,400,或 -5。</li>
+ <li><strong>Floating point numbers</strong> (floats) 浮點數具有小數點跟小數位,例如12.5和56.7786543。</li>
+ <li><strong>Doubles</strong> 是一種特定型態的浮點數 that have greater precision than standard floating point numbers (meaning that they are accurate to a greater number of decimal places).</li>
+</ul>
+
+<p><font>我們甚至有不同類型的號碼系統!</font><font>十進位以10為單位(表示每列使用0–9),但是也有像這些:</font></p>
+
+<ul>
+ <li><strong><font><font>二進位</font></font></strong><font><font> —計算機的最底層語言;</font><font>0和1。</font></font></li>
+ <li><strong><font><font>八進位</font></font></strong><font><font> —以8為</font>單位<font>,每列使用0–7。</font></font></li>
+ <li><strong><font><font>十六進位</font></font></strong><font><font> —以16為</font>單位<font>,在每列中使用0–9,然後使用a–f。</font></font><a href="https://translate.googleusercontent.com/translate_c?depth=1&amp;pto=aue&amp;rurl=translate.google.com.tw&amp;sl=en&amp;sp=nmt4&amp;tl=zh-TW&amp;u=https://developer.mozilla.org/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units&amp;usg=ALkJrhjxtle73XLvao6e9e-CZv6u2Hq68g#Hexadecimal_values"><font><font>在CSS中</font></font></a><font><font>設置</font><a href="https://translate.googleusercontent.com/translate_c?depth=1&amp;pto=aue&amp;rurl=translate.google.com.tw&amp;sl=en&amp;sp=nmt4&amp;tl=zh-TW&amp;u=https://developer.mozilla.org/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units&amp;usg=ALkJrhjxtle73XLvao6e9e-CZv6u2Hq68g#Hexadecimal_values"><font>顏色</font></a><font>之前,您可能已經遇到過這些數字</font><font>。</font></font></li>
+</ul>
+
+<p><strong><font><font>在開始擔心大腦融化之前,先等等!</font></font></strong><font><font>首先,我們將在整個課程中完全使用十進位數;您很少會想到其他類型的需求,如果有的話。</font></font> </p>
+
+<p>第二個好消息是JavaScript只有一種數字資料類型 ,猜對了!就是{{jsxref("Number")}}。這代表無論你在JavaScript需要處理哪種數字,處理方法都是一樣的。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 事實上, JavaScript 有第二種數字型態, {{Glossary("BigInt")}}, 用於非常、非常、非常大的整數。但這節課我只需要擔心 <code>Number</code> 的值。</p>
+</div>
+
+<h3 id="我怎麼看都是些數字!">我怎麼看都是些數字!</h3>
+
+<p>讓我們來快速操作一些數字來重新認識一下我們會需要用到的基本語法。將下面的需求表輸入進你的開發者工具js控制台(<a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>),或是簡單建立在任何你偏好的控制台。</p>
+
+<ol>
+ <li>首先,先來宣告兩個變數,並分別賦予他們初始值為整數與浮點數,然後接著打上變數名稱來確認萬事預備:
+ <pre class="brush: js notranslate">var myInt = 5;
+var myFloat = 6.667;
+myInt;
+myFloat;</pre>
+ </li>
+ <li>數字的值不需要引號框起來 — 試著宣告和賦予更多初始值為數字的變數,在繼續下去之前。</li>
+ <li>現在,來確認Now let's check that both our original variables are of the same datatype. There is an operator called {{jsxref("Operators/typeof", "typeof")}} in JavaScript that does this. Enter the below two lines as shown:
+ <pre class="brush: js notranslate">typeof myInt;
+typeof myFloat;</pre>
+ You should get <code>"number"</code> returned in both cases — this makes things a lot easier for us than if different numbers had different data types, and we had to deal with them in different ways. Phew!</li>
+</ol>
+
+<h2 id="算術運算符">算術運算符</h2>
+
+<p>Arithmetic operators are the basic operators that we use to do sums:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Operator</th>
+ <th scope="col">Name</th>
+ <th scope="col">Purpose</th>
+ <th scope="col">Example</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>+</code></td>
+ <td>加法</td>
+ <td>Adds two numbers together.</td>
+ <td><code>6 + 9</code></td>
+ </tr>
+ <tr>
+ <td><code>-</code></td>
+ <td>減法</td>
+ <td>Subtracts the right number from the left.</td>
+ <td><code>20 - 15</code></td>
+ </tr>
+ <tr>
+ <td><code>*</code></td>
+ <td>乘法</td>
+ <td>Multiplies two numbers together.</td>
+ <td><code>3 * 7</code></td>
+ </tr>
+ <tr>
+ <td><code>/</code></td>
+ <td>除法</td>
+ <td>Divides the left number by the right.</td>
+ <td><code>10 / 5</code></td>
+ </tr>
+ <tr>
+ <td><code>%</code></td>
+ <td>餘數 (sometimes called modulo)</td>
+ <td>
+ <p>Returns the remainder left over after you've divided the left number into a number of integer portions equal to the right number.</p>
+ </td>
+ <td><code>8 % 3</code> (returns 2, as three goes into 8 twice, leaving 2 left over.)</td>
+ </tr>
+ <tr>
+ <td>**</td>
+ <td>指數</td>
+ <td>Raises a <code>base</code> number to the <code>exponent</code> power, that is, the <code>base</code> number multiplied by itself, <code>exponent</code> times. It was first Introduced in EcmaScript 2016.</td>
+ <td><code>5 ** 2</code> (5的2次方得 <code>25</code>,跟 <code>5 * 5</code>結果相同)</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="note">
+<p><strong>Note</strong>: You'll sometimes see numbers involved in sums referred to as {{Glossary("Operand", "operands")}}.</p>
+</div>
+
+<p><strong>Note</strong>: You may sometimes see exponents expressed using the older {{jsxref("Math.pow()")}} method, which works in a very similar way. For example, in <code>Math.pow(7, 3)</code>, <code>7</code> is the base and <code>3</code> is the exponent, so the result of the expression is <code>343</code>. <code>Math.pow(7, 3)</code> is equivalent to <code>7**3</code>.</p>
+
+<p>We probably don't need to teach you how to do basic math, but we would like to test your understanding of the syntax involved. Try entering the examples below into your <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>, or use the simple built in console seen earlier if you'd prefer, to familiarize yourself with the syntax.</p>
+
+<ol>
+ <li>First try entering some simple examples of your own, such as
+ <pre class="brush: js notranslate">10 + 7
+9 * 8
+60 % 3</pre>
+ </li>
+ <li>You can also try declaring and initializing some numbers inside variables, and try using those in the sums — the variables will behave exactly like the values they hold for the purposes of the sum. For example:
+ <pre class="brush: js notranslate">var num1 = 10;
+var num2 = 50;
+9 * num1;
+num2 / num1;</pre>
+ </li>
+ <li>Last for this section, try entering some more complex expressions, such as:
+ <pre class="brush: js notranslate">5 + 10 * 3;
+num2 % 9 * num1;
+num2 + num1 / 8 + 2;</pre>
+ </li>
+</ol>
+
+<p>Some of this last set of sums might not give you quite the result you were expecting; the below section might well give the answer as to why.</p>
+
+<h3 id="Operator_precedence">Operator precedence</h3>
+
+<p>Let's look at the last example from above, assuming that <code>num2</code> holds the value 50 and <code>num1</code> holds the value 10 (as originally stated above):</p>
+
+<pre class="brush: js notranslate">num2 + num1 / 8 + 2;</pre>
+
+<p>As a human being, you may read this as <em>"50 plus 10 equals 60"</em>, then <em>"8 plus 2 equals 10"</em>, and finally <em>"60 divided by 10 equals 6"</em>.</p>
+
+<p>But the browser does <em>"10 divided by 8 equals 1.25"</em>, then <em>"50 plus 1.25 plus 2 equals 53.25"</em>.</p>
+
+<p>This is because of <strong>operator precedence</strong> — some operators will be applied before others when calculating the result of a sum (referred to as an expression, in programming).  Operator precedence in JavaScript is the same as is taught in math classes in school — Multiply and divide are always done first, then add and subtract (the sum is always evaluated from left to right).</p>
+
+<p>If you want to override operator precedence, you can put parentheses round the parts that you want to be explicitly dealt with first. So to get a result of 6, we could do this:</p>
+
+<pre class="brush: js notranslate">(num2 + num1) / (8 + 2);</pre>
+
+<p>Try it and see.</p>
+
+<div class="note">
+<p><strong>Note</strong>: A full list of all JavaScript operators and their precedence can be found in <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Operator_precedence">Expressions and operators</a>.</p>
+</div>
+
+<h2 id="遞增和遞減運算符">遞增和遞減運算符</h2>
+
+<p>Sometimes you'll want to repeatedly add or subtract one to/from a numeric variable value. This can be conveniently done using the increment (<code>++</code>) and decrement(<code>--</code>) operators. We used <code>++</code> in our  "Guess the number" game back in our <a href="/en-US/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">first splash into JavaScript</a> article, when we added 1 to our <code>guessCount</code> variable to keep track of how many guesses the user has left after each turn.</p>
+
+<pre class="brush: js notranslate">guessCount++;</pre>
+
+<div class="note">
+<p><strong>Note</strong>: They are most commonly used in <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">loops</a>, which you'll learn about later on in the course. For example, say you wanted to loop through a list of prices, and add sales tax to each one. You'd use a loop to go through each value in turn and do the necessary calculation for adding the sales tax in each case. The incrementor is used to move to the next value when needed. We've actually provided a simple example showing how this is done — <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/loop.html">check it out live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/maths/loop.html">look at the source code</a> to see if you can spot the incrementors! We'll look at loops in detail later on in the course.</p>
+</div>
+
+<p>Let's try playing with these in your console. For a start, note that you can't apply these directly to a number, which might seem strange, but we are assigning a variable a new updated value, not operating on the value itself. The following will return an error:</p>
+
+<pre class="brush: js notranslate">3++;</pre>
+
+<p>So, you can only increment an existing variable. Try this:</p>
+
+<pre class="brush: js notranslate">var num1 = 4;
+num1++;</pre>
+
+<p>Okay, strangeness number 2! When you do this, you'll see a value of 4 returned — this is because the browser returns the current value, <em>then</em> increments the variable. You can see that it's been incremented if you return the variable value again:</p>
+
+<pre class="brush: js notranslate">num1;</pre>
+
+<p>The same is true of <code>--</code> : try the following</p>
+
+<pre class="brush: js notranslate">var num2 = 6;
+num2--;
+num2;</pre>
+
+<div class="note">
+<p><strong>Note</strong>: You can make the browser do it the other way round — increment/decrement the variable <em>then</em> return the value — by putting the operator at the start of the variable instead of the end. Try the above examples again, but this time use <code>++num1</code> and <code>--num2</code>.</p>
+</div>
+
+<h2 id="賦值運算符">賦值運算符</h2>
+
+<p>Assignment operators are operators that assign a value to a variable. We have already used the most basic one, <code>=</code>, loads of times — it simply assigns the variable on the left the value stated on the right:</p>
+
+<pre class="brush: js notranslate">var x = 3; // x contains the value 3
+var y = 4; // y contains the value 4
+x = y; // x now contains the same value y contains, 4</pre>
+
+<p>But there are some more complex types, which provide useful shortcuts to keep your code neater and more efficient. The most common are listed below:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Operator</th>
+ <th scope="col">Name</th>
+ <th scope="col">Purpose</th>
+ <th scope="col">Example</th>
+ <th scope="col">Shortcut for</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>+=</code></td>
+ <td>Addition assignment</td>
+ <td>Adds the value on the right to the variable value on the left, then returns the new variable value</td>
+ <td><code>x = 3;<br>
+ x += 4;</code></td>
+ <td><code>x = 3;<br>
+ x = x + 4;</code></td>
+ </tr>
+ <tr>
+ <td><code>-=</code></td>
+ <td>Subtraction assignment</td>
+ <td>Subtracts the value on the right from the variable value on the left, and returns the new variable value</td>
+ <td><code>x = 6;<br>
+ x -= 3;</code></td>
+ <td><code>x = 6;<br>
+ x = x - 3;</code></td>
+ </tr>
+ <tr>
+ <td><code>*=</code></td>
+ <td>Multiplication assignment</td>
+ <td>Multiples the variable value on the left by the value on the right, and returns the new variable value</td>
+ <td><code>x = 2;<br>
+ x *= 3;</code></td>
+ <td><code>x = 2;<br>
+ x = x * 3;</code></td>
+ </tr>
+ <tr>
+ <td><code>/=</code></td>
+ <td>Division assignment</td>
+ <td>Divides the variable value on the left by the value on the right, and returns the new variable value</td>
+ <td><code>x = 10;<br>
+ x /= 5;</code></td>
+ <td><code>x = 10;<br>
+ x = x / 5;</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Try typing some of the above examples into your console, to get an idea of how they work. In each case, see if you can guess what the value is before you type in the second line.</p>
+
+<p>Note that you can quite happily use other variables on the right hand side of each expression, for example:</p>
+
+<pre class="brush: js notranslate">var x = 3; // x contains the value 3
+var y = 4; // y contains the value 4
+x *= y; // x now contains the value 12</pre>
+
+<div class="note">
+<p><strong>Note</strong>: There are lots of <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment_operators">other assignment operators available</a>, but these are the basic ones you should learn now.</p>
+</div>
+
+<h2 id="Active_learning_sizing_a_canvas_box">Active learning: sizing a canvas box</h2>
+
+<p>In this exercise, you will manipulate some numbers and operators to change the size of a box. The box is drawn using a browser API called the {{domxref("Canvas API", "", "", "true")}}. There is no need to worry about how this works — just concentrate on the math for now. The width and height of the box (in pixels) are defined by the variables <code>x</code> and <code>y</code>, which are initially both given a value of 50.</p>
+
+<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html", '100%', 620)}}</p>
+
+<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html">Open in new window</a></strong></p>
+
+<p>In the editable code box above, there are two lines marked with a comment that we'd like you to update to make the box grow/shrink to certain sizes, using certain operators and/or values in each case. Let's try the following:</p>
+
+<ul>
+ <li>Change the line that calculates x so the box is still 50px wide, but the 50 is calculated using the numbers 43 and 7 and an arithmetic operator.</li>
+ <li>Change the line that calculates y so the box is 75px high, but the 75 is calculated using the numbers 25 and 3 and an arithmetic operator.</li>
+ <li>Change the line that calculates x so the box is 250px wide, but the 250 is calculated using two numbers and the remainder (modulo) operator.</li>
+ <li>Change the line that calculates y so the box is 150px high, but the 150 is calculated using three numbers and the subtraction and division operators.</li>
+ <li>Change the line that calculates x so the box is 200px wide, but the 200 is calculated using the number 4 and an assignment operator.</li>
+ <li>Change the line that calculates y so the box is 200px high, but the 200 is calculated using the numbers 50 and 3, the multiplication operator, and the addition assignment operator.</li>
+</ul>
+
+<p>Don't worry if you totally mess the code up. You can always press the Reset button to get things working again. After you've answered all the above questions correctly, feel free to play with the code some more or create your own challenges.</p>
+
+<h2 id="比較運算符">比較運算符</h2>
+
+<p>Sometimes we will want to run true/false tests, then act accordingly depending on the result of that test — to do this we use <strong>comparison operators</strong>.</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Operator</th>
+ <th scope="col">Name</th>
+ <th scope="col">Purpose</th>
+ <th scope="col">Example</th>
+ </tr>
+ <tr>
+ <td><code>===</code></td>
+ <td>Strict equality</td>
+ <td>Tests whether the left and right values are identical to one another</td>
+ <td><code>5 === 2 + 4</code></td>
+ </tr>
+ <tr>
+ <td><code>!==</code></td>
+ <td>Strict-non-equality</td>
+ <td>Tests whether the left and right values <strong>not</strong> identical to one another</td>
+ <td><code>5 !== 2 + 3</code></td>
+ </tr>
+ <tr>
+ <td><code>&lt;</code></td>
+ <td>Less than</td>
+ <td>Tests whether the left value is smaller than the right one.</td>
+ <td><code>10 &lt; 6</code></td>
+ </tr>
+ <tr>
+ <td><code>&gt;</code></td>
+ <td>Greater than</td>
+ <td>Tests whether the left value is greater than the right one.</td>
+ <td><code>10 &gt; 20</code></td>
+ </tr>
+ <tr>
+ <td><code>&lt;=</code></td>
+ <td>Less than or equal to</td>
+ <td>Tests whether the left value is smaller than or equal to the right one.</td>
+ <td><code>3 &lt;= 2</code></td>
+ </tr>
+ <tr>
+ <td><code>&gt;=</code></td>
+ <td>Greater than or equal to</td>
+ <td>Tests whether the left value is greater than or equal to the right one.</td>
+ <td><code>5 &gt;= 4</code></td>
+ </tr>
+ </thead>
+</table>
+
+<div class="note">
+<p><strong>Note</strong>: You may see some people using <code>==</code> and <code>!=</code> in their tests for equality and non-equality. These are valid operators in JavaScript, but they differ from <code>===</code>/<code>!==</code>. The former versions test whether the values are the same but not whether the values' datatypes are the same. The latter, strict versions test the equality of both the values and their datatypes. The strict versions tend to result in fewer errors, so we recommend you use them.</p>
+</div>
+
+<p>If you try entering some of these values in a console, you'll see that they all return <code>true</code>/<code>false</code> values — those booleans we mentioned in the last article. These are very useful, as they allow us to make decisions in our code, and they are used every time we want to make a choice of some kind. For example, booleans can be used to:</p>
+
+<ul>
+ <li>Display the correct text label on a button depending on whether a feature is turned on or off</li>
+ <li>Display a game over message if a game is over or a victory message if the game has been won</li>
+ <li>Display the correct seasonal greeting depending what holiday season it is</li>
+ <li>Zoom a map in or out depending on what zoom level is selected</li>
+</ul>
+
+<p>We'll look at how to code such logic when we look at conditional statements in a future article. For now, let's look at a quick example:</p>
+
+<pre class="brush: html notranslate">&lt;button&gt;Start machine&lt;/button&gt;
+&lt;p&gt;The machine is stopped.&lt;/p&gt;
+</pre>
+
+<pre class="brush: js notranslate">var btn = document.querySelector('button');
+var txt = document.querySelector('p');
+
+btn.addEventListener('click', updateBtn);
+
+function updateBtn() {
+ if (btn.textContent === 'Start machine') {
+ btn.textContent = 'Stop machine';
+ txt.textContent = 'The machine has started!';
+ } else {
+ btn.textContent = 'Start machine';
+ txt.textContent = 'The machine is stopped.';
+ }
+}</pre>
+
+<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/conditional.html", '100%', 100)}}</p>
+
+<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/conditional.html">Open in new window</a></strong></p>
+
+<p>You can see the equality operator being used just inside the <code>updateBtn()</code> function. In this case, we are not testing if two mathemetical expressions have the same value — we are testing whether the text content of a button contains a certain string — but it is still the same principle at work. If the button is currently saying "Start machine" when it is pressed, we change its label to  "Stop machine", and update the label as appropriate. If the button is currently saying "Stop machine" when it is pressed, we swap the display back again.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Such a control that swaps between two states is generally referred to as a <strong>toggle</strong>. It toggles between one state and another — light on, light off, etc.</p>
+</div>
+
+<h2 id="Summary">Summary</h2>
+
+<p>In this article we have covered the fundamental information you need to know about numbers in JavaScript, for now. You'll see numbers used again and again, all the way through your JavaScript learning, so it's a good idea to get this out of the way now. If you are one of those people that doesn't enjoy math, you can take comfort in the fact that this chapter was pretty short.</p>
+
+<p>In the next article, we'll explore text and how JavaScript allows us to manipulate it.</p>
+
+<div class="note">
+<p><strong>Note</strong>: If you do enjoy math and want to read more about how it is implemented in JavaScript, you can find a lot more detail in MDN's main JavaScript section. Great places to start are our <a href="/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates">Numbers and dates</a> and <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a> articles.</p>
+</div>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html b/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html
new file mode 100644
index 0000000000..2659623210
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/silly_story_generator/index.html
@@ -0,0 +1,149 @@
+---
+title: 傻故事產生器
+slug: Learn/JavaScript/First_steps/Silly_story_generator
+tags:
+ - JavaScript
+ - 初學者
+ - 字串
+ - 測試
+ - 變數
+ - 運算子
+ - 陣列
+translation_of: Learn/JavaScript/First_steps/Silly_story_generator
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">在本次評估中,您被賦予的任務內容將與本單元學習到的知識息息相關,並將其應用於創建一個能隨機生成傻故事的有趣應用程式。 祝玩的開心!</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">事先具備:</th>
+ <td>進行此測驗之前你應先完成此區塊的所有內容</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>測試對於JavaScript基礎的理解程度, 例如 變數, 數字, 運算子, 字串 以及陣列.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="前置作業">前置作業</h2>
+
+<p>在開始本測驗前,你應該:</p>
+
+<ul>
+ <li>開啟右方網頁: <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/index.html">grab the HTML file</a> ,將HTML範本儲存到您的本地電腦的新資料夾中,並命名為<code>index.html</code> 。範本也包含相應的CSS檔案。</li>
+ <li>開啟右方網頁: <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/raw-text.txt">page containing the raw text</a> ,並保持網頁開啟在瀏覽器的另一分頁上,以便稍後使用。</li>
+</ul>
+
+<div class="note">
+<p><strong>備註</strong>: 除了將檔案下載到自己的電腦中,您也能使用線上編輯程式的網頁,像是: <a class="external external-icon" href="http://jsbin.com/">JSBin</a> 或者<a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> 來完成評估測驗。您可以將 HTML, CSS 以及 JavaScript 貼到前述的線上編輯器中。如果您使用的線上編輯器沒有獨立給 JavaScript 的編輯區,您也能透過<code>&lt;script&gt;</code>直接將JS語法放到 HTML檔案中。</p>
+</div>
+
+<h2 id="任務簡介">任務簡介</h2>
+
+<p>透過前述網頁您已經得到初版HTML/CSS 與一些JavaScript 字串、函數;您需要再寫一些必要的JavaScript語法來將這些檔案轉變為可運作的程式,任務如下: </p>
+
+<ul>
+ <li>當 "Generate random story" (產生隨機故事)的按鈕被點擊,請產出一則傻故事</li>
+ <li>若在點擊產生故事按鈕前將自定義名字輸入於輸入框"Enter custom name" (譯:輸入自定義名字),則將故事中預設的名字 "Bob" 代換為自定義名字</li>
+ <li>若在點擊產生故事按鈕前,也點擊UK的單選按鈕,則將預設的美制重量、溫度單位轉換為英制單位</li>
+ <li>每點擊一次產生故事的按鈕,即產生新一則隨機傻故事(不限次數)</li>
+</ul>
+
+<p>以下截圖為完成品的範例:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13667/assessment-1.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>點擊右方連結可以參考與測試完成品: <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/assessment-finished/">have a look at the finished example</a> (請不要偷看原始碼喔!)</p>
+
+<h2 id="任務開始">任務開始</h2>
+
+<p>以下清楚地描述了完成任務需要哪些動作。</p>
+
+<p>基本設定:</p>
+
+<ol>
+ <li>在有<code>index.html</code>的資料夾中建立一個新檔案稱之為 <code>main.js</code></li>
+ <li>請在<code>index.html</code>中引用第一點建立的外部JavaScript 檔案,引用方法是在<code>&lt;/body&gt;</code> tag 前插入一組 {{htmlelement("script")}}元素 ,並在opening tag上加入<code>src=" main.js"​​​​​​</code></li>
+</ol>
+
+<p>初始化變數與函數:</p>
+
+<ol>
+ <li>在原始文件檔中(raw text file),請複製標題1. COMPLETE VARIABLE AND FUNCTION DEFINITIONS" 以下到第2點前的所有程式碼,並貼到<code>main.js</code>中。這給你三個變數來標記:文字輸入框 "Enter custom name" (輸入自定義名字) ,變數為 (<code>customName</code>) 與按鈕 "Generate random story"(產生隨機故事) ,變數為 (<code>randomize</code>), 以及HTML中接近body底部的 {{htmlelement("p")}} 元素,故事將會被複製進第三個變數(<code>story</code>)中。此外您還會得到一個函數稱為: <code>randomValueFromArray()</code> ,從命名中可以得知這是一個陣列,它會隨機提供一則儲存其中的故事。</li>
+ <li>接著讓我們查看原始文件檔中(raw text file)的第2點: "2. RAW TEXT STRINGS"。 其包含的這些字串在程式運行時會被放進來,請幫忙在<code>main.js</code>中將這些字串分別存進對應的變數裡:
+ <ol>
+ <li>將第一行超級長的字串存進變數 <code>storyText</code>中。</li>
+ <li>將第一組三個字串存進一陣列,並命名為<code>insertX</code>。</li>
+ <li>將第二組三個字串存進一陣列,並命名為<code>insertY</code>.</li>
+ <li>將第三組三個字串存進一陣列,並命名為<code>insertZ</code>.</li>
+ </ol>
+ </li>
+</ol>
+
+<p>放置事件監聽器與未完善的函數:</p>
+
+<ol>
+ <li>再度回到原始文件檔中(raw text file)</li>
+ <li>複製第3標題,"3. EVENT LISTENER AND PARTIAL FUNCTION DEFINITION" 以下的內容,並貼到 <code>main.js</code> 檔案中的最下方,這包含:
+ <ul>
+ <li>給變數<code>randomize</code>增加一個點擊事件監聽器(clickevent listener) ,所以當產生故事的按鈕被點擊,<code>result()</code>函數會運行 。</li>
+ <li>增加一個部分完成的函數 <code>result()</code> ,完成測驗您需要完善這個函數。</li>
+ </ul>
+ </li>
+</ol>
+
+<p>完善 <code>result()</code> 函數:</p>
+
+<ol>
+ <li>創造一個新變數稱為:<code>newStory</code>,讓這個變數的值等於<code>storyText</code>;我們需要這個變數以便每次產生故事按鈕被點擊時,函數都能再次運作並產生新故事,如果我們只在<code>storyText</code>之上做改變,我們只能產生一次新故事。</li>
+ <li>額外增加三個變數:<code>xItem</code>、<code>yItem</code> 與 <code>zItem</code>,並使這三個變數等於函數<code>randomValueFromArray()</code>中三個陣列的結果(每次會從各陣列中隨機挑出一項)。舉例,你能透過寫<code>randomValueFromArray(insertX)</code>來從<code>insertX</code>得到任一隨機字串。</li>
+ <li>接著我們需要將<code>newStory</code>中三個placeholders字串 <code>:insertx:</code>、<code>:inserty:</code>跟 <code>:insertz:</code>換成<code>xItem</code>、<code>yItem</code>、 <code>zItem</code>。有些字串方法在這裡特別有用,請讓字串方法的返回值等於 <code>newStory</code> ,所以之後每次 <code>newStory</code> 被呼叫時,is made equal to itself, but with substitutions made. So each time the button is pressed, these placeholders are each replaced with a random silly string. As a further hint, the method in question only replaces the first instance of the substring it finds, so you might need to make one of the calls twice.</li>
+ <li>Inside the first <code>if</code> block, add another string replacement method call to replace the name 'Bob' found in the <code>newStory</code> string with the <code>name</code> variable. In this block we are saying "If a value has been entered into the <code>customName</code> text input, replace Bob in the story with that custom name."</li>
+ <li>Inside the second <code>if</code> block, we are checking to see if the <code>uk</code> radio button has been selected. If so, we want to convert the weight and temperature values in the story from pounds and Fahrenheit into stones and centigrade. What you need to do is as follows:
+ <ol>
+ <li>Look up the formulae for converting pounds to stone, and Fahrenheit to centigrade.</li>
+ <li>Inside the line that defines the <code>weight</code> variable, replace 300 with a calculation that converts 300 pounds into stones. Concatenate <code>' stone'</code> onto the end of the result of the overall <code>Math.round()</code> call.</li>
+ <li>Inside the line that defines the <code>temperature</code> variable, replace 94 with a calculation that converts 94 Fahrenheit into centigrade. Concatenate <code>' centigrade'</code> onto the end of the result of the overall <code>Math.round()</code> call.</li>
+ <li>Just under the two variable definitions, add two more string replacement lines that replace '94 farenheit' with the contents of the <code>temperature</code> variable, and '300 pounds' with the contents of the <code>weight</code> variable.</li>
+ </ol>
+ </li>
+ <li>Finally, in the second-to-last line of the function, make the <code>textContent</code> property of the <code>story</code> variable (which references the paragraph) equal to <code>newStory</code>.</li>
+</ol>
+
+<h2 id="Hints_and_tips">Hints and tips</h2>
+
+<ul>
+ <li>You don't need to edit the HTML in any way, except to apply the JavaScript to your HTML.</li>
+ <li>If you are unsure whether the JavaScript is applied to your HTML properly, try removing everything else from the JavaScript file temporarily, adding in a simple bit of JavaScript that you know will create an obvious effect, then saving and refreshing. The following for example turns the background of the {{htmlelement("html")}} element red — so the entire browser window should go red if the JavaScript is applied properly:
+ <pre class="brush: js notranslate">document.querySelector('html').style.backgroundColor = 'red';</pre>
+ </li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round">Math.round()</a> is a built-in JavaScript method that simply rounds the result of a calculation to the nearest whole number.</li>
+ <li>There are three instances of strings that need to be replaced. You may repeat the <code>replace()</code> method multiple times, or you can use regular expressions. For instance, <code>var text = 'I am the biggest lover, I love my love'; text.replace(/love/g,'like');</code> will replace all instances of 'love' to 'like'. Remember, Strings are immutable!</li>
+</ul>
+
+<h2 id="測驗一下">測驗一下</h2>
+
+<p>如果您將這個測驗視為正規課程的一部分,建議將成果提供您的老師或指導者以利幫助您達到最好的學習效益。如果您是自學者,您可以輕鬆的透過右方網頁 <a href="https://discourse.mozilla.org/t/silly-story-generator-assessment/24686">discussion thread for this exercise</a> 得到建議,或者在<a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>上的 <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC 頻道。提醒您:第一次嘗試這個測驗時,作弊可不會得到任何收穫喔!</p>
+
+<p>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p>
+
+
+
+<h2 id="相關學習模組">相關學習模組</h2>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> <a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a> <a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">傻故事產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/strings/index.html b/files/zh-tw/learn/javascript/first_steps/strings/index.html
new file mode 100644
index 0000000000..8e4a3b1f6a
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/strings/index.html
@@ -0,0 +1,352 @@
+---
+title: 處理文字 - JavaScript中的字串
+slug: Learn/JavaScript/First_steps/Strings
+tags:
+ - JavaScript
+ - 初學者
+ - 字串
+ - 引號
+ - 文章
+ - 連接字串
+translation_of: Learn/JavaScript/First_steps/Strings
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">接下來我們將把注意力轉向字串——這就是程式設計中調用的文字片段。在本文中,我們將介紹在學習JavaScript時您應該了解所有有關字串的常見事項,例如建立字串,跳脫字串中的引號以及將字串連接在一起。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基本的電腦素養、對 HTML 與 CSS 有基本的認識、對 JavaScript 有認識。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>熟悉 JavaScript 字串的基礎。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="文字的力量">文字的力量</h2>
+
+<p>文字對人類而言非常重要——它關乎我們如何交流、溝通。Web 以文字為基底的媒介,它的設計讓人類可以進行交流並分享資訊,因此掌握文字如何在 Web 上呈現是很有用的。{{glossary("HTML")}} 提供文字的結構以及定義;{{glossary("CSS")}} 讓我們更精確地設定樣式;而 JavaScript 則包含許多操作字串的特性,例如:製作客製化的歡迎訊息、正確地顯示所需的文字標籤、排列所需的詞語順序等。</p>
+
+<p>到目前為止,所有我們課程上的編碼幾乎都包含一些字串的操作。</p>
+
+<h2 id="字串_—_基礎">字串 — 基礎</h2>
+
+<p>剛開始你會覺得字串與數字的處理方式很類似,但當你越深入就會了解到一些明顯的差異。讓我們從在 console 裡輸入一些基本的程式行來熟悉它吧!在下方,我們提供一個 Console (你也可以另開一個頁籤或視窗<a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">使用他</a> ,或者使用瀏覽器的<a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">開發者工具</a>)。</p>
+
+<div class="hidden">
+<h6 id="Hidden_code">Hidden code</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;JavaScript console&lt;/title&gt;
+ &lt;style&gt;
+ * {
+ box-sizing: border-box;
+ }
+
+ html {
+ background-color: #0C323D;
+ color: #809089;
+ font-family: monospace;
+ }
+
+ body {
+ max-width: 700px;
+ }
+
+ p {
+ margin: 0;
+ width: 1%;
+ padding: 0 1%;
+ font-size: 16px;
+ line-height: 1.5;
+ float: left;
+ }
+
+ .input p {
+ margin-right: 1%;
+ }
+
+ .output p {
+ width: 100%;
+ }
+
+ .input input {
+ width: 96%;
+ float: left;
+ border: none;
+ font-size: 16px;
+ line-height: 1.5;
+ font-family: monospace;
+ padding: 0;
+ background: #0C323D;
+ color: #809089;
+ }
+
+ div {
+ clear: both;
+ }
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+
+ &lt;/body&gt;
+
+ &lt;script&gt;
+ var geval = eval;
+ function createInput() {
+ var inputDiv = document.createElement('div');
+ var inputPara = document.createElement('p');
+ var inputForm = document.createElement('input');
+
+ inputDiv.setAttribute('class','input');
+ inputPara.textContent = '&gt;';
+ inputDiv.appendChild(inputPara);
+ inputDiv.appendChild(inputForm);
+ document.body.appendChild(inputDiv);
+
+ if(document.querySelectorAll('div').length &gt; 1) {
+        inputForm.focus();
+      }
+
+ inputForm.addEventListener('change', executeCode);
+ }
+
+ function executeCode(e) {
+ try {
+ var result = geval(e.target.value);
+ } catch(e) {
+ var result = 'error — ' + e.message;
+ }
+
+ var outputDiv = document.createElement('div');
+ var outputPara = document.createElement('p');
+
+ outputDiv.setAttribute('class','output');
+ outputPara.textContent = 'Result: ' + result;
+ outputDiv.appendChild(outputPara);
+ document.body.appendChild(outputDiv);
+
+ e.target.disabled = true;
+ e.target.parentNode.style.opacity = '0.5';
+
+ createInput()
+ }
+
+ createInput();
+
+ &lt;/script&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="建立字串">建立字串</h3>
+
+<ol>
+ <li>首先,先輸入下面幾行程式碼:
+ <pre class="brush: js notranslate">let string = 'The revolution will not be televised.';
+string;</pre>
+ 就像我們對數字的操作,我們聲明一個變數,並用一個值(字串)來初始化它,而後傳回這個值。唯一的差異在於,你需要用引號包住你的值。</li>
+ <li>如果你沒有使用引號包住值,或缺少單一邊的引號,都會導致錯誤產生。試著輸入下面幾行程式碼:
+ <pre class="brush: js example-bad notranslate">let badString = This is a test;
+let badString = 'This is a test;
+let badString = This is a test';</pre>
+ 上述的程式無法運作,因為未使用引號包圍的文字都將被視為變數名稱、屬性名稱和保留字等。如果瀏覽器無法辨識它,便會產生錯誤(例如:「missing ; before statement」)。如果瀏覽器可以識別字段從哪裡開始,但無法找到字段的終點,意即缺少第二個引號,則會產生「unterminated string literal」的錯誤。如果你的程式出現了這樣的錯誤,檢查並確認自己的字串是否遺漏了任何引號。</li>
+ <li>如果你先定義了變數 <code>string</code> ,則以下程式碼可以正常運作。馬上來試試看:
+ <pre class="brush: js notranslate">let badString = string;
+badString;</pre>
+ <code>badString</code> 會被設定跟 <code>string</code> 具有一樣的值。</li>
+</ol>
+
+<h3 id="單引號與雙引號">單引號與雙引號</h3>
+
+<ol>
+ <li>在 JavaScript 中,你可以選擇用單引號或雙引號來包住字串。兩種方式都可行:
+ <pre class="brush: js notranslate">let sgl = 'Single quotes.';
+let dbl = "Double quotes";
+sgl;
+dbl;</pre>
+ </li>
+ <li>兩種之間的差異非常小,取決於你個人的習慣與喜好。你可以選擇一種,並且固定使用它。交互使用兩種方式,容易造成混亂。特別是當你使用兩種不同的引號包住一個字串!這會導致錯誤回傳:
+ <pre class="brush: js example-bad notranslate">let badQuotes = 'What on earth?";</pre>
+ </li>
+ <li>瀏覽器會認為字串並沒有結束,沒有作為包住字串的引號,是可以出現在字串裡面的。看看下面的例子,兩種都是可行的:
+ <pre class="brush: js notranslate">let sglDbl = 'Would you eat a "fish supper"?';
+let dblSgl = "I'm feeling blue.";
+sglDbl;
+dblSgl;</pre>
+ </li>
+ <li>但是,字串中不可以再使用那個作為包住字串的引號。以下的程式行會出錯,因為瀏覽器無法判斷字串的結尾:
+ <pre class="brush: js example-bad notranslate">let bigmouth = 'I've got no right to take my place...';</pre>
+ This leads us very nicely into our next subject.</li>
+</ol>
+
+<h3 id="字串中的跳脫字元(Escaping_characters)">字串中的跳脫字元(Escaping characters)</h3>
+
+<p>要修復先前出錯的那一行程式碼,我們需要解決引號的問題。跳脫字元(Escaping characters)的意思是我們需要確保它們被辨識為文字,而非程式碼本身。在 JavaScript 中,我們在字元的前面放一個反斜線解決這個問題。試試看這個:</p>
+
+<pre class="brush: js notranslate">let bigmouth = 'I\'ve got no right to take my place...';
+bigmouth;</pre>
+
+<p>這是可行的!你可以用一樣的方法跳脫其他字元,例如 <code>\"</code>。除此之外,還有一些特殊方法。更詳細的部分,請參閱<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation">跳脫符號</a> 。</p>
+
+<h2 id="連接字串(Concatenating_strings)">連接字串(Concatenating strings)</h2>
+
+<ol>
+ <li>連接(Concatenate)是一個新潮的程式用語。在 JavaScript 中,使用加號(+)將字串連接;這也是我們做數字相加的方式。但在這個狀況下,它有不同的作用。讓我們在 console 中示範:</li>
+ <li>
+ <pre class="brush: js notranslate">let one = 'Hello, ';
+let two = 'how are you?';
+let joined = one + two;
+joined;</pre>
+ 這邊的結果是 <code>joined</code>  這個變數中,有了 「Hello, how are you?」這個值。</li>
+ <li>在上一個範例中,我們只連接了兩個字串。但只要你在兩個字串之間加上 <code>+</code> ,那你要連接幾個都可以。試試看這個:
+ <pre class="brush: js notranslate">let multiple = one + one + one + one + two;
+multiple;</pre>
+ </li>
+ <li>你也可以結合變數和字串。試試看這個:
+ <pre class="brush: js notranslate">let response = one + 'I am fine — ' + two;
+response;</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 當你輸入一個字串在你的程式碼中,並用單引號或雙引號將它括起來,它稱為<strong>字串文字</strong>(<strong>string literal</strong>)。</p>
+</div>
+
+<h3 id="Concatenation_in_context">Concatenation in context</h3>
+
+<p>讓我們看看實際運用連接字串的例子——以下是這堂課中稍早的範例:</p>
+
+<pre class="brush: html notranslate">&lt;button&gt;Press me&lt;/button&gt;</pre>
+
+<pre class="brush: js notranslate">const button = document.querySelector('button');
+
+button.onclick = function() {
+ let name = prompt('What is your name?');
+ alert('Hello ' + name + ', nice to see you!');
+}</pre>
+
+<p>{{ EmbedLiveSample('Concatenation_in_context', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>在程式第四行我們用了 {{domxref("window.prompt()", "window.prompt()")}} 這個函式,可以要求使用者透過彈出的對話框去回答問題,並將使用者輸入的文字儲存在給訂的變數內(在這個例子中就是 <code>name</code>)。接著我們在第五行用了 {{domxref("window.alert()", "window.alert()")}} 函式,顯示另一個彈出視窗,以連接的方式將兩段字串文字以及 <code>name</code> 這個變數結合成一個字串。</p>
+
+<h3 id="數字_vs._字串">數字 vs. 字串</h3>
+
+<ol>
+ <li>那麼我們將字串和數字連接會發生什麼事呢?讓我們在console中試試看:
+ <pre class="brush: js notranslate">'Front ' + 242;
+</pre>
+ 或許你預期會跑出錯誤訊息,但看來依然正常運作。若將字串表示成數字似乎不太合理,但將數字表示成字串看來是可行的,所以瀏覽器便會巧妙地將數字轉換成字串,並將這兩個字串連接在一起。</li>
+ <li>你也可以用兩個數字做這個例子 — 將這兩個數字包在引號中強制將它們轉換成字串。試試看(並使用typeof這個運算子去檢查變數是數字或字串):
+ <pre class="brush: js notranslate">let myDate = '19' + '67';
+typeof myDate;</pre>
+ </li>
+ <li>如果你想轉換數字變數成字串,但不要更動到原本的變數;或是想轉換字串變數成數字,也不要更動到原本的變數,你可以使用以下兩種方式:
+ <ul>
+ <li>物件 {{jsxref("Number")}} 會將欲處理的變數轉換成數字(如果可行的話)。試試以下例子:
+ <pre class="brush: js notranslate">let myString = '123';
+let myNum = Number(myString);
+typeof myNum;</pre>
+ </li>
+ <li>另一方面,也有 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString">toString()</a></code> 方法能夠讓數字轉換為相等的字串。試試看:
+ <pre class="brush: js notranslate">let myNum = 123;
+let myString = myNum.toString();
+typeof myString;</pre>
+ </li>
+ </ul>
+ 這些結構在某些情況相當好用。舉例來說:如果使用者在文字表單中輸入了一個數字,這個數字將會是字串格式。而若想要把這個數字加上另一個數字,那你會希望它是數字格式(才能做數字相加),所以可以使用 <code>Number()</code> 來處理這個情況。可以看看實際案例:<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game.html#L61">猜數字遊戲, 第61行</a>。</li>
+</ol>
+
+<h2 id="模版字符串Template_literals">模版字符串(Template literals)</h2>
+
+<p>另一種你會遇上的字串語法是<strong>模版字符串(template literals)</strong> (也稱做模版字串 template strings)。這是一種更新的語法提供更彈性、簡單的方式去理解字串。</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 嘗試在你的瀏覽器上測試下面的範例,來看看會得到什麼結果。</p>
+</div>
+
+<p>將標準字串轉變為模版字符串,你需要將引號 (<code>' '</code>, or <code>" "</code>) 換為重音符 (backtick characters (<code>` `</code>) ),接著來看一個簡單的例子:</p>
+
+<pre class="brush: js notranslate">let song = 'Fight the Youth';</pre>
+
+<p>轉換成模版字符串會像這樣子:</p>
+
+<pre class="brush: js notranslate">song = `Fight the Youth`;</pre>
+
+<p>如果我們想要連接字串,或是將算式的結果包含在裡面,用傳統的字串去寫會很瑣碎且麻煩:</p>
+
+<pre class="brush: js notranslate">let score = 9;
+let highestScore = 10;
+let output = 'I like the song "' + song + '". I gave it a score of ' + (score/highestScore * 100) + '%.';</pre>
+
+<p>模版字符串能大量簡化這串程式碼:</p>
+
+<pre class="brush: js notranslate">output = `I like the song "${ song }". I gave it a score of ${ score/highestScore * 100 }%.`;</pre>
+
+<p>全部一串都只需要包含在一對重音符號裡,不再需要切開、合起一堆字串碎片。<br>
+ 當你想要包含變數或者算式在字串裡時,你只需要將它放在 <em>佔位符 </em><code>${ } </code>裡。</p>
+
+<p>你能將複雜的算式包含在模版字符串裡,舉個例子:</p>
+
+<pre class="brush: js notranslate">let examScore = 45;
+let examHighestScore = 70;
+examReport = `You scored ${ examScore }/${ examHighestScore } (${ Math.round((examScore/examHighestScore*100)) }%). ${ examScore &gt;= 49 ? 'Well done, you passed!' : 'Bad luck, you didn\'t pass this time.' }`;
+</pre>
+
+<ul>
+ <li>前兩個佔位符非常好理解,字串裡只包含了單一值。</li>
+ <li>第三個計算了一個百分比的結果且四捨五入進整數。</li>
+ <li>第四個使用了三元運算符來檢查分數是否高於指定分數且印出一個通過或著失敗的訊息結果。</li>
+</ul>
+
+<p>另一個可以注意的點是,如果你想要將傳統字串拆分成多行,你需要加上一個斷行字母, <code>\n</code></p>
+
+<pre class="brush: js notranslate">output = 'I like the song "' + song + '".\nI gave it a score of ' + (score/highestScore * 100) + '%.';</pre>
+
+<p>模版字符串保留了程式碼中的斷行方式,所以不再需要使用斷行字母。<br>
+ 這樣也能達到相同的結果:</p>
+
+<pre class="brush: js notranslate">output = `I like the song "${ song }".
+I gave it a score of ${ score/highestScore * 100 }%.`;</pre>
+
+<p>我們建議你盡可能習慣使用模版字符串。現今流行的瀏覽器都能完好的支援它,只有一個地方你能發現它並不支援外: Internet Explorer。<br>
+ 我們有許多的例子仍然使用目前標準的字串語法,但我們未來將會加入更多模版字符串的應用。</p>
+
+<p>來我們的<a href="/en-US/docs/Web/JavaScript/Reference/Template_literals">Template literals</a> 相關頁面看看更多的範例與進階的特色細節。</p>
+
+<h2 id="測試您的技能!">測試您的技能!</h2>
+
+<p>你已到達文章的結尾了,但你能記得最重要的資訊嗎?<br>
+ 在繼續學習之前,你可以找些難一點的測驗,來檢測你有記得這些知識 —  <a href="/en-US/docs/Learn/JavaScript/First_steps/Test_your_skills:_Strings">Test your skills: Strings</a>. 記住,接下來的文章也需要這些知識,所以你可能想先看看。</p>
+
+<h2 id="結語">結語</h2>
+
+<p>以上是JavaScript中基礎的字串觀念。下個文章中,我們會依循這些概念並試試一些適用於字串的內建方法,進而運用這些方法讓字串能照我們想要的方式呈現。</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了?JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 - JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html b/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html
new file mode 100644
index 0000000000..e5efb51e1b
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/useful_string_methods/index.html
@@ -0,0 +1,714 @@
+---
+title: 有用的字符串方法
+slug: Learn/JavaScript/First_steps/Useful_string_methods
+translation_of: Learn/JavaScript/First_steps/Useful_string_methods
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">現在我們已經了解了字符串的基礎知識,讓我們開始思考我們可以使用內置方法對字符串執行哪些有用的操作,例如查找文本字符串的長度,連接和拆分字符串 ,將字符串中的一個字符替換為另一個字符,等等。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基礎的電腦素養、基本的HTML和CSS、以及清楚什麼是JavaScript。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解字串是物件,學習使用一些能夠應用這些字串的基礎方法。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="把字串當作物件">把字串當作物件</h2>
+
+<p id="Useful_string_methods">我們曾經說過,現在我們重申一遍—在javascript中,一切東西都可以被當作物件。例如我們創建一個字串。</p>
+
+<pre class="brush: js notranslate">var string = 'This is my string';</pre>
+
+<p>你的變數成為一個字串的實體物件,因此它將有許多性質(properties)與功能(methods)可以使用。</p>
+
+<p>你的變數成為一個字串的實體物件,因此它將有許多性質(properties)與功能(methods)可以使用。你可以到 {{jsxref("String")}} 物件頁面的左方列表查看這些性質與功能!</p>
+
+<p><strong>好的,在你腦袋燒壞之前先別擔心!</strong>在這趟學習旅程中,關於這些大部分對於現在的你其實還不需要知道。不過有一些你可能會經常使用,我們將在這裡介紹。</p>
+
+<p>Let's enter some examples into a fresh console. We've provided one below (you can also <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">open this console</a> in a separate tab or window, or use the <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer console</a> if you'd prefer).</p>
+
+<div class="hidden">
+<h6 id="Hidden_code">Hidden code</h6>
+
+<pre class="brush: html notranslate">&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;meta charset="utf-8"&gt;
+ &lt;title&gt;JavaScript console&lt;/title&gt;
+ &lt;style&gt;
+ * {
+ box-sizing: border-box;
+ }
+
+ html {
+ background-color: #0C323D;
+ color: #809089;
+ font-family: monospace;
+ }
+
+ body {
+ max-width: 700px;
+ }
+
+ p {
+ margin: 0;
+ width: 1%;
+ padding: 0 1%;
+ font-size: 16px;
+ line-height: 1.5;
+ float: left;
+ }
+
+ .input p {
+ margin-right: 1%;
+ }
+
+ .output p {
+ width: 100%;
+ }
+
+ .input input {
+ width: 96%;
+ float: left;
+ border: none;
+ font-size: 16px;
+ line-height: 1.5;
+ font-family: monospace;
+ padding: 0;
+ background: #0C323D;
+ color: #809089;
+ }
+
+ div {
+ clear: both;
+ }
+
+ &lt;/style&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+
+
+ &lt;/body&gt;
+
+ &lt;script&gt;
+ var geval = eval;
+ function createInput() {
+ var inputDiv = document.createElement('div');
+ var inputPara = document.createElement('p');
+ var inputForm = document.createElement('input');
+
+ inputDiv.setAttribute('class', 'input');
+ inputPara.textContent = '&gt;';
+ inputDiv.appendChild(inputPara);
+ inputDiv.appendChild(inputForm);
+ document.body.appendChild(inputDiv);
+
+ inputForm.addEventListener('change', executeCode);
+ }
+
+ function executeCode(e) {
+ try {
+ var result = geval(e.target.value);
+ } catch(e) {
+ var result = 'error — ' + e.message;
+ }
+
+ var outputDiv = document.createElement('div');
+ var outputPara = document.createElement('p');
+
+ outputDiv.setAttribute('class','output');
+ outputPara.textContent = 'Result: ' + result;
+ outputDiv.appendChild(outputPara);
+ document.body.appendChild(outputDiv);
+
+ e.target.disabled = true;
+ e.target.parentNode.style.opacity = '0.5';
+
+ createInput()
+ }
+
+ createInput();
+
+ &lt;/script&gt;
+&lt;/html&gt;</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="找出字串的長度(length)">找出字串的長度(length)</h3>
+
+<p>這很簡單,你可以用 {{jsxref("String.prototype.length", "length")}} 屬性。試著輸入下面幾行:</p>
+
+<pre class="brush: js notranslate">var browserType = 'mozilla';
+browserType.length;</pre>
+
+<p>結果應該會回傳數字7,因為 "mozilla" 字元長度是7。 這在很多狀況下很好用,舉例來說:你會想知道序列的長度,這樣才能將這些序列按照長度排序,或是讓使用者知道他們輸入的名稱是否太長。</p>
+
+<h3 id="取得字串中的特定字元(string_character)">取得字串中的特定字元(string character)</h3>
+
+<p>On a related note, you can return any character inside a string by using <strong>square bracket notation</strong> — this means you include square brackets (<code>[]</code>) on the end of your variable name. Inside the square brackets you include the number of the character you want to return, so for example to retrieve the first letter you'd do this:</p>
+
+<pre class="brush: js notranslate">browserType[0];</pre>
+
+<p>記得電腦計數從0開始,不是1! 如果要在<em>任何</em>一個字串中取得最後一個字元,我們可以使用以下程式碼,結合了取得字元的技巧和上面學過的長度屬性:</p>
+
+<pre class="brush: js notranslate">browserType[browserType.length-1];</pre>
+
+<p>"mozilla" 這個詞的長度是7,但因為電腦是從0開始計數,所以最後一個位置是6,因此我們會將 <code>length-1</code> 。你也可以試試用這個方法找各序列的第一個字母,並將這些序列按字母順序排好 。</p>
+
+<h3 id="尋找字串中的子字串(substring)並提出子字串">尋找字串中的子字串(substring)並提出子字串</h3>
+
+<ol>
+ <li>Sometim有時候你會想搜尋是否有一個較小的字串存在於比較大的字串中(<em>我們通常會說是否有個子字串存在於字串中</em>)。這可以用 {{jsxref("String.prototype.indexOf()", "indexOf()")}} 方法,當中需要一個參數( {{glossary("parameter")}} ),也就是你想搜尋的子字串:</li>
+ <li>
+ <pre class="brush: js notranslate">browserType.indexOf('zilla');</pre>
+ 結果會傳回2,因為子字串 "zilla" 在 "mozilla" 中是從位置2開始的。(依然要記得電腦計數是從0開始)。這個方法可以用篩選字串,舉例來說:我們有一串網址的清單,而我們只想印出那些包含 "mozilla" 的網址。</li>
+</ol>
+
+<ol start="2">
+ <li>This can be done in another way, which is possibly even more effective. Try the following:
+ <pre class="brush: js notranslate">browserType.indexOf('vanilla');</pre>
+ This should give you a result of <code>-1</code> — this is returned when the substring, in this case 'vanilla', is not found in the main string.<br>
+ <br>
+ You could use this to find all instances of strings that <strong>don't</strong> contain the substring 'mozilla', or <strong>do,</strong> if you use the negation operator, as shown below. You could do something like this:
+
+ <pre class="brush: js notranslate">if(browserType.indexOf('mozilla') !== -1) {
+ // do stuff with the string
+}</pre>
+ </li>
+ <li>When you know where a substring starts inside a string, and you know at which character you want it to end, {{jsxref("String.prototype.slice()", "slice()")}} can be used to extract it. Try the following:
+ <pre class="brush: js notranslate">browserType.slice(0,3);</pre>
+ This returns "moz" — the first parameter is the character position to start extracting at, and the second parameter is the character position after the last one to be extracted. So the slice happens from the first position, up to, but not including, the last position. In this example, since the starting index is 0, the second parameter is equal to the length of the string being returned.<br>
+  </li>
+ <li>Also, if you know that you want to extract all of the remaining characters in a string after a certain character, you don't have to include the second parameter! Instead, you only need to include the character position from where you want to extract the remaining characters in a string. Try the following:
+ <pre class="brush: js notranslate">browserType.slice(2);</pre>
+ This returns "zilla" — this is because the character position of 2 is the letter z, and because you didn't include a second parameter, the substring that was returned was all of the remaining characters in the string. </li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: The second parameter of <code>slice()</code> is optional: if you don't include it, the slice ends at the end of the original string. There are other options too; study the {{jsxref("String.prototype.slice()", "slice()")}} page to see what else you can find out.</p>
+</div>
+
+<h3 id="改變大小寫">改變大小寫</h3>
+
+<p>The string methods {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} and {{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} take a string and convert all the characters to lower- or uppercase, respectively. This can be useful for example if you want to normalize all user-entered data before storing it in a database.</p>
+
+<p>Let's try entering the following lines to see what happens:</p>
+
+<pre class="brush: js notranslate">var radData = 'My NaMe Is MuD';
+radData.toLowerCase();
+radData.toUpperCase();</pre>
+
+<h3 id="更動部分字串">更動部分字串</h3>
+
+<p>You can replace one substring inside a string with another substring using the {{jsxref("String.prototype.replace()", "replace()")}} method. This works very simply at a basic level, although there are some advanced things you can do with it that we won't go into yet.</p>
+
+<p>It takes two parameters — the string you want to replace, and the string you want to replace it with. Try this example:</p>
+
+<pre class="brush: js notranslate">browserType.replace('moz','van');</pre>
+
+<p>Note that to actually get the updated value reflected in the <code>browserType</code> variable in a real program, you'd have to set the variable value to be the result of the operation; it doesn't just update the substring value automatically. So you'd have to actually write this: <code>browserType = browserType.replace('moz','van');</code></p>
+
+<h2 id="Active_learning_examples">Active learning examples</h2>
+
+<p>In this section we'll get you to try your hand at writing some string manipulation code. In each exercise below, we have an array of strings, and a loop that processes each value in the array and displays it in a bulleted list. You don't need to understand arrays or loops right now — these will be explained in future articles. All you need to do in each case is write the code that will output the strings in the format that we want them in.</p>
+
+<p>Each example comes with a "Reset" button, which you can use to reset the code if you make a mistake and can't get it working again, and a "Show solution" button you can press to see a potential answer if you get really stuck.</p>
+
+<h3 id="Filtering_greeting_messages">Filtering greeting messages</h3>
+
+<p>In the first exercise we'll start you off simple — we have an array of greeting card messages, but we want to sort them to list just the Christmas messages. We want you to fill in a conditional test inside the <code>if( ... )</code> structure, to test each string and only print it in the list if it is a Christmas message.</p>
+
+<ol>
+ <li>First think about how you could test whether the message in each case is a Christmas message. What string is present in all of those messages, and what method could you use to test whether it is present?</li>
+ <li>You'll then need to write a conditional test of the form <em>operand1 operator operand2</em>. Is the thing on the left equal to the thing on the right? Or in this case, does the method call on the left return the result on the right?</li>
+ <li>Hint: In this case it is probably more useful to test whether the method call <em>isn't</em> equal to a certain result.</li>
+</ol>
+
+<div class="hidden">
+<h6 id="Playable_code">Playable code</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 125px;"&gt;
+
+&lt;ul&gt;
+
+&lt;/ul&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 290px; width: 95%"&gt;
+var list = document.querySelector('.output ul');
+list.innerHTML = '';
+var greetings = ['Happy Birthday!',
+ 'Merry Christmas my love',
+ 'A happy Christmas to all the family',
+ 'You\'re all I want for Christmas',
+ 'Get well soon'];
+
+for (var i = 0; i &lt; greetings.length; i++) {
+ var input = greetings[i];
+ // Your conditional test needs to go inside the parentheses
+ // in the line below, replacing what's currently there
+ if (greetings[i]) {
+ var result = input;
+ var listItem = document.createElement('li');
+ listItem.textContent = result;
+ list.appendChild(listItem);
+ }
+}
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar greetings = [\'Happy Birthday!\',\n \'Merry Christmas my love\',\n \'A happy Christmas to all the family\',\n \'You\\\'re all I want for Christmas\',\n \'Get well soon\'];\n\nfor(var i = 0; i &lt; greetings.length; i++) {\n var input = greetings[i];\n if(greetings[i].indexOf(\'Christmas\') !== -1) {\n var result = input;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n }\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code', '100%', 590, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Fixing_capitalization">Fixing capitalization</h3>
+
+<p>In this exercise we have the names of cities in the United Kingdom, but the capitalization is all messed up. We want you to change them so that they are all lower case, except for a capital first letter. A good way to do this is to:</p>
+
+<ol>
+ <li>Convert the whole of the string contained in the <code>input</code> variable to lower case and store it in a new variable.</li>
+ <li>Grab the first letter of the string in this new variable and store it in another variable.</li>
+ <li>Using this latest variable as a substring, replace the first letter of the lowercase string with the first letter of the lowercase string changed to upper case. Store the result of this replace procedure in another new variable.</li>
+ <li>Change the value of the <code>result</code> variable to equal to the final result, not the <code>input</code>.</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: A hint — the parameters of the string methods don't have to be string literals; they can also be variables, or even variables with a method being invoked on them.</p>
+</div>
+
+<div class="hidden">
+<h6 id="Playable_code_2">Playable code 2</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 125px;"&gt;
+
+&lt;ul&gt;
+
+&lt;/ul&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 250px; width: 95%"&gt;
+var list = document.querySelector('.output ul');
+list.innerHTML = '';
+var cities = ['lonDon', 'ManCHESTer', 'BiRmiNGHAM', 'liVERpoOL'];
+for(var i = 0; i &lt; cities.length; i++) {
+ var input = cities[i];
+ // write your code just below here
+
+ var result = input;
+ var listItem = document.createElement('li');
+ listItem.textContent = result;
+ list.appendChild(listItem);
+}
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar cities = [\'lonDon\', \'ManCHESTer\', \'BiRmiNGHAM\', \'liVERpoOL\'];\n\nfor(var i = 0; i &lt; cities.length; i++) {\n var input = cities[i];\n var lower = input.toLowerCase();\n var firstLetter = lower.slice(0,1);\n var capitalized = lower.replace(firstLetter,firstLetter.toUpperCase());\n var result = capitalized;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_2', '100%', 550, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h3 id="Making_new_strings_from_old_parts">Making new strings from old parts</h3>
+
+<p>In this last exercise, the array contains a bunch of strings containing information about train stations in the North of England. The strings are data items that contain the three-letter station code, followed by some machine-readable data, followed by a semicolon, followed by the human-readable station name. For example:</p>
+
+<pre class="notranslate">MAN675847583748sjt567654;Manchester Piccadilly</pre>
+
+<p>We want to extract the station code and name, and put them together in a string with the following structure:</p>
+
+<pre class="notranslate">MAN: Manchester Piccadilly</pre>
+
+<p>We'd recommend doing it like this:</p>
+
+<ol>
+ <li>Extract the three-letter station code and store it in a new variable.</li>
+ <li>Find the character index number of the semicolon.</li>
+ <li>Extract the human-readable station name using the semicolon character index number as a reference point, and store it in a new variable.</li>
+ <li>Concatenate the two new variables and a string literal to make the final string.</li>
+ <li>Change the value of the <code>result</code> variable to equal to the final string, not the <code>input</code>.</li>
+</ol>
+
+<div class="hidden">
+<h6 id="Playable_code_3">Playable code 3</h6>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Live output&lt;/h2&gt;
+
+&lt;div class="output" style="min-height: 125px;"&gt;
+
+&lt;ul&gt;
+
+&lt;/ul&gt;
+
+&lt;/div&gt;
+
+&lt;h2&gt;Editable code&lt;/h2&gt;
+&lt;p class="a11y-label"&gt;Press Esc to move focus away from the code area (Tab inserts a tab character).&lt;/p&gt;
+
+&lt;textarea id="code" class="playable-code" style="height: 285px; width: 95%"&gt;
+var list = document.querySelector('.output ul');
+list.innerHTML = '';
+var stations = ['MAN675847583748sjt567654;Manchester Piccadilly',
+ 'GNF576746573fhdg4737dh4;Greenfield',
+ 'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street',
+ 'SYB4f65hf75f736463;Stalybridge',
+ 'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield'];
+
+for (var i = 0; i &lt; stations.length; i++) {
+ var input = stations[i];
+ // write your code just below here
+
+ var result = input;
+ var listItem = document.createElement('li');
+ listItem.textContent = result;
+ list.appendChild(listItem);
+}
+&lt;/textarea&gt;
+
+&lt;div class="playable-buttons"&gt;
+ &lt;input id="reset" type="button" value="Reset"&gt;
+ &lt;input id="solution" type="button" value="Show solution"&gt;
+&lt;/div&gt;
+</pre>
+
+<pre class="brush: css notranslate">html {
+ font-family: sans-serif;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+.a11y-label {
+ margin: 0;
+ text-align: right;
+ font-size: 0.7rem;
+ width: 98%;
+}
+
+body {
+ margin: 10px;
+ background: #f5f9fa;
+}
+</pre>
+
+<pre class="brush: js notranslate">var textarea = document.getElementById('code');
+var reset = document.getElementById('reset');
+var solution = document.getElementById('solution');
+var code = textarea.value;
+var userEntry = textarea.value;
+
+function updateCode() {
+ eval(textarea.value);
+}
+
+reset.addEventListener('click', function() {
+ textarea.value = code;
+ userEntry = textarea.value;
+ solutionEntry = jsSolution;
+ solution.value = 'Show solution';
+ updateCode();
+});
+
+solution.addEventListener('click', function() {
+ if(solution.value === 'Show solution') {
+ textarea.value = solutionEntry;
+ solution.value = 'Hide solution';
+ } else {
+ textarea.value = userEntry;
+ solution.value = 'Show solution';
+ }
+ updateCode();
+});
+
+var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar stations = [\'MAN675847583748sjt567654;Manchester Piccadilly\',\n \'GNF576746573fhdg4737dh4;Greenfield\',\n \'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street\',\n \'SYB4f65hf75f736463;Stalybridge\',\n \'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield\'];\n\nfor(var i = 0; i &lt; stations.length; i++) {\n var input = stations[i];\n var code = input.slice(0,3);\n var semiC = input.indexOf(\';\');\n var name = input.slice(semiC + 1);\n var result = code + \': \' + name;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n}';
+var solutionEntry = jsSolution;
+
+textarea.addEventListener('input', updateCode);
+window.addEventListener('load', updateCode);
+
+// stop tab key tabbing out of textarea and
+// make it write a tab at the caret position instead
+
+textarea.onkeydown = function(e){
+ if (e.keyCode === 9) {
+ e.preventDefault();
+ insertAtCaret('\t');
+ }
+
+ if (e.keyCode === 27) {
+ textarea.blur();
+ }
+};
+
+function insertAtCaret(text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+
+ var front = (textarea.value).substring(0, caretPos);
+ var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+}
+
+// Update the saved userCode every time the user updates the text area code
+
+textarea.onkeyup = function(){
+ // We only want to save the state when the user code is being shown,
+ // not the solution, so that solution is not saved over the user code
+ if(solution.value === 'Show solution') {
+ userEntry = textarea.value;
+ } else {
+ solutionEntry = textarea.value;
+ }
+
+ updateCode();
+};</pre>
+</div>
+
+<p>{{ EmbedLiveSample('Playable_code_3', '100%', 585, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<h2 id="結語">結語</h2>
+
+<p>不可否認當網站在跟人們互相溝通時,處理文字和句子在程式設計中是相當重要的,尤其是在 JavaScript 中。這篇文章已經傳授你如何去處理字串的方法,應該對以後深入了解其他更複雜主題的你會很有幫助。接下來,我們將會看看最後一個近期內我們需要關注的主要的資料型態 — 陣列。</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/variables/index.html b/files/zh-tw/learn/javascript/first_steps/variables/index.html
new file mode 100644
index 0000000000..1fce3a98fe
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/variables/index.html
@@ -0,0 +1,344 @@
+---
+title: 存儲您需要的資訊 - 變數
+slug: Learn/JavaScript/First_steps/Variables
+tags:
+ - JavaScript
+ - 變數
+ - 陣列
+translation_of: Learn/JavaScript/First_steps/Variables
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">閱讀完最後幾篇文章之後,您現在應該知道 JavaScript 是什麼,它可以為您做什麼,如何將它與其他 Web 技術一起使用,以及它的主要功能從高層看起來如何。 在本文中,我們將深入了解真正的基礎知識,了解如何使用 JavaScript 的大多數基本構建塊 - 變數。</p>
+
+<table class="learn-box">
+ <tbody>
+ <tr>
+ <th scope="row">必備知識:</th>
+ <td>電腦基礎知識,了解基本的 HTML 和 CSS ,了解 JavaScript 是什麼。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>熟悉 JavaScript 變數的基本知識。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="您需要的工具">您需要的工具</h2>
+
+<p>在此篇文章中,您將被要求輸入程式碼行來測試您對內容的理解。如果您使用的是網頁瀏覽器,最適合輸入代碼的地方便是 JavaScript 主控台, (請參閱<a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">什麼是瀏覽器開發工具</a>這篇文章以取得更多關於此工具的資訊).</p>
+
+<h2 id="什麼是變量/變數_variable_?">什麼是變量/變數 (variable) ?</h2>
+
+<p>變量是值的容器,就像我們可能在總和中使用的數字,或者我們可能用作句子一部分的字符串。 但關於變量的一個特殊之處在於它們包含的值可以改變。 我們來看一個簡單的例子:</p>
+
+<pre class="brush: html notranslate">&lt;button&gt;請按我&lt;/button&gt;
+</pre>
+
+<pre class="brush: js notranslate">const button = document.querySelector('button');
+
+button.onclick = function() {
+  let name = prompt('你叫什麼名字?');
+  alert('你好 ' + name + ', 很高興認識你!');
+}
+</pre>
+
+<p>{{ EmbedLiveSample('什麼是變量/變數_variable_?','100%', 50, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>在此示例中,按下按鈕會運行幾行代碼。 第一行在屏幕上彈出一個框,要求讀者輸入其名稱,然後將值存儲在變量中。 第二行顯示歡迎消息,其中包含從變量值中獲取的名稱。</p>
+
+<p>要理解為什麼這麼有用,讓我們考慮如何在不使用變量的情況下編寫此示例。 它最終會看起來像這樣:</p>
+
+<pre class="example-bad notranslate">let name = prompt('What is your name?');
+
+if (name === 'Adam') {
+ alert('Hello Adam, nice to see you!');
+} else if (name === 'Alan') {
+ alert('Hello Alan, nice to see you!');
+} else if (name === 'Bella') {
+ alert('Hello Bella, nice to see you!');
+} else if (name === 'Bianca') {
+ alert('Hello Bianca, nice to see you!');
+} else if (name === 'Chris') {
+ alert('Hello Chris, nice to see you!');
+}
+
+// ... 等等 ...
+</pre>
+
+<p><font>你可能暫時還沒有完全理解這些代碼和語法,但是你應該能夠理解到</font> — <font>如果我們沒有變量,我們就不得不寫大量的代碼去檢查輸入的名字,然後顯示相應名稱的消息 。這樣做顯然是低效率(雖然例子中只有5種選擇,但代碼卻相對地長)和不可行的</font> — <font>你沒有辦法列舉出所有可能的名字。</font></p>
+
+<p>使用變量才是明智的。隨著您對 JavaScript 越來越了解,您會開始習慣使用變量。</p>
+
+<p><font>變量的另一個特性就是它們能夠存儲任何的東西</font> — <font>不只是字符串和數字。變量可以存儲更複雜的數據,甚至是函數。</font><font>你將在後續的內容中體驗到這些用法。</font></p>
+
+<div class="note">
+<p><strong><font><font>提示</font></font></strong>:變量是用來儲存數值的,而變量和數值是兩個不同的概念。變量不是數值本身,它們僅僅是一個用於儲存數值的容器。你可以把變量想像成一個個用來裝東西的紙皮箱。</p>
+</div>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13506/boxes.png" style="display: block; height: 436px; margin: 0px auto; width: 1052px;"></p>
+
+<h2 id="定義變量_Declaring_a_variable">定義<font><font>變量 (Declaring a variable)</font></font></h2>
+
+<p><font>要想使用變量,你需要做的第一步就是創建它</font> — <font>更準確的說,是</font>定義<font>一個變量。</font>定義<font>一個變量的語法是在關鍵字</font> <code>var</code> 或 <code>let</code> <font>之後加上變量的名字:</font></p>
+
+<pre class="brush: js notranslate">let myName;
+let myAge;
+</pre>
+
+<p><font><font>在這裡我們</font></font>定義<font><font>了兩個變量  </font></font><code>myName</code><font><font> 和 </font></font><code>myAge</code><font><font>。那麼現在嘗試輸入這些代碼到你的瀏覽器終端。之後,嘗試使用您自己選擇的名稱來創建一兩個變量。</font></font></p>
+
+<div class="note">
+<p><strong>提示</strong>:<font><font>在 JavaScript 中,所有代碼指令都會以分號結尾( </font></font><code>;</code><font><font>)- 如果忘記加分號,你的單行代碼可能正常執行,但是在執行多行代碼的時候就可能出錯。所以,最好是養成主動以分號作為代碼結尾的習慣。</font></font></p>
+</div>
+
+<p><font>你可以輸入變量的名稱,來驗證這個變量的數值是否在執行環境(</font>execution environment)<font>中已經存在。例如,</font></p>
+
+<pre class="brush: js notranslate">myName;
+myAge;
+</pre>
+
+<p><font><font>以上這兩個變量並沒有數值,他們是空的容器。當你輸入變量名並按輸入鍵後,你會得到一個 </font></font><code>undefined</code><font><font> (</font></font>沒有定義的值<font><font>)的返回值。如果</font>變量<font>並不存在的話,你就會得到一個錯誤信息。請嘗試輸入:</font></font></p>
+
+<pre class="brush: js notranslate">scoobyDoo;</pre>
+
+<div class="note">
+<p><strong><font><font>提示:</font></font></strong><font><font>千萬不要把兩個概念弄混淆了,「一個變量<strong>存在,但是沒有數值</strong>」和「一個變量<strong>並不存在</strong>」— 他們完全是兩回事。在前面你看到的盒子的類比中,不存在意味著沒有可以存放變量的「盒子」。</font><font>沒有定義的值意味著<strong>有</strong>一個「盒子」,但是它裡面沒有任何數值。</font></font></p>
+</div>
+
+<h2 id="初始化變量_Initializing_a_variable">初始化變量 (Initializing a variable)</h2>
+
+<p>一旦你定義了一個變量,你就能夠初始化它來儲存數值。方法如下:在變量名之後跟上一個等號 (<code>=</code>),然後是數值。例如:</p>
+
+<pre class="brush: js notranslate">myName = 'Chris';
+myAge = 37;</pre>
+
+<p>Try going back to the console now and typing in these lines. You should see the value you've assigned to the variable returned in the console to confirm it, in each case. Again, you can return your variable values by simply typing their name into the console — try these again:</p>
+
+<pre class="brush: js notranslate">myName;
+myAge;</pre>
+
+<p>你可以同時定義並初始化變量,像是:</p>
+
+<pre class="brush: js notranslate">let myDog = 'Rover';</pre>
+
+<p>This is probably what you'll do most of the time, as it is quicker than doing the two actions on two separate lines.</p>
+
+<h2 id="比較var和let的不同_The_difference_between_var_and_let">比較var和let的不同 (The difference between var and let)</h2>
+
+<p>此刻你或許會思考「為什麼我們需要兩種方法來定義變數??<font><font>」</font></font>「為甚麼要有<code>var</code>和<code>let</code>??<font><font>」</font></font></p>
+
+<p>原因有些歷史淵源。在Javascript剛被創造的時候,只有<code>var</code>可以使用。在大部分的情況下都很正常,但是<code>var</code>的運作方式有些問題 — 它的設計有時會令人困惑甚至惹惱人。所以<code>let</code>在現代版本中的Javascript被創造出來,一個與<code>var</code>工作原理有些不同的創建變數的關鍵字,修復了<code>var</code>的種種問題。</p>
+
+<p>以下將介紹幾個簡單的分別。我們現在不會一一講解全部的不同,但是當你慢慢深入Javascript,你將會開始發現它們的(如果你真的很想現在知道,歡迎看看我們的<a href="/zh-TW/docs/Web/JavaScript/Reference/Statements/let">let 介紹頁</a>)。</p>
+
+<p>如下,假設你需要宣告、初始化一個變數<code>myName</code>,即使你是初始化之後才宣告也是可行的:</p>
+
+<pre class="brush: js notranslate">myName = 'Chris';
+
+function logName() {
+ console.log(myName);
+}
+
+logName();
+
+var myName;</pre>
+
+<div class="note">
+<p><strong>Note</strong>: This won't work when typing individual lines into a JavaScript console, just when running multiple lines of JavaScript in a web document.</p>
+</div>
+
+<p>This works because of <strong>hoisting</strong> — read <a href="/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting">var hoisting</a> for more detail on the subject.</p>
+
+<p>Hoisting no longer works with <code>let</code>. If we changed <code>var</code> to <code>let</code> in the above example, it would fail with an error. This is a good thing — declaring a variable after you initialize it makes for confusing, harder to understand code.</p>
+
+<p>Secondly, when you use <code>var</code>, you can declare the same variable as many times as you like, but with <code>let</code> you can't. The following would work:</p>
+
+<pre class="brush: js notranslate">var myName = 'Chris';
+var myName = 'Bob';</pre>
+
+<p>But the following would throw an error on the second line:</p>
+
+<pre class="brush: js notranslate">let myName = 'Chris';
+let myName = 'Bob';</pre>
+
+<p>You'd have to do this instead:</p>
+
+<pre class="brush: js notranslate">let myName = 'Chris';
+myName = 'Bob';</pre>
+
+<p>Again, this is a sensible language decision. There is no reason to redeclare variables — it just makes things more confusing.</p>
+
+<p>For these reasons and more, we recommend that you use <code>let</code> as much as possible in your code, rather than <code>var</code>. There is no reason to use <code>var</code>, unless you need to support old versions of Internet Explorer with your code (it doesn't support <code>let</code> until version 11; the modern Windows Edge browser supports <code>let</code> just fine).</p>
+
+<div class="note">
+<p><strong>Note</strong>: We are currently in the process of updating the course to use <code>let</code> rather than <code>var</code>. Bear with us!</p>
+</div>
+
+<h2 id="Updating_a_variable">Updating a variable</h2>
+
+<p>Once a variable has been initialized with a value, you can change (or update) that value by simply giving it a different value. Try entering the following lines into your console:</p>
+
+<pre class="brush: js notranslate">myName = 'Bob';
+myAge = 40;</pre>
+
+<h3 id="變數命名規則悄悄話">變數命名規則悄悄話</h3>
+
+<p>You can call a variable pretty much anything you like, but there are limitations. Generally, you should stick to just using Latin characters (0-9, a-z, A-Z) and the underscore character.</p>
+
+<ul>
+ <li>You shouldn't use other characters because they may cause errors or be hard to understand for an international audience.</li>
+ <li>Don't use underscores at the start of variable names — this is used in certain JavaScript constructs to mean specific things, so may get confusing.</li>
+ <li>Don't use numbers at the start of variables. This isn't allowed and will cause an error.</li>
+ <li>A safe convention to stick to is so-called <a href="https://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms">"lower camel case"</a>, where you stick together multiple words, using lower case for the whole first word and then capitalize subsequent words. We've been using this for our variable names in the article so far.</li>
+ <li>Make variable names intuitive, so they describe the data they contain. Don't just use single letters/numbers, or big long phrases.</li>
+ <li>Variables are case sensitive — so <code>myage</code> is a different variable to <code>myAge</code>.</li>
+ <li>One last point — you also need to avoid using JavaScript reserved words as your variable names — by this, we mean the words that make up the actual syntax of JavaScript! So, you can't use words like <code>var</code>, <code>function</code>, <code>let</code>, and <code>for</code> as variable names. Browsers will recognize them as different code items, and so you'll get errors.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: You can find a fairly complete list of reserved keywords to avoid at <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">Lexical grammar — keywords</a>.</p>
+</div>
+
+<p>良好的命名範例:</p>
+
+<pre class="example-good notranslate">age
+myAge
+init
+initialColor
+finalOutputValue
+audio1
+audio2</pre>
+
+<p>不好的命名範例:</p>
+
+<pre class="example-bad notranslate">1
+a
+_12
+myage
+MYAGE
+var
+Document
+skjfndskjfnbdskjfb
+thisisareallylongstupidvariablenameman</pre>
+
+<p>Error-prone name examples:</p>
+
+<pre class="example-invalid notranslate">var
+Document
+</pre>
+
+<p>Try creating a few more variables now, with the above guidance in mind.</p>
+
+<h2 id="變數資料類型">變數資料類型</h2>
+
+<p>There are a few different types of data we can store in variables. In this section we'll describe these in brief, then in future articles, you'll learn about them in more detail.</p>
+
+<p>So far we've looked at the first two, but there are others.</p>
+
+<h3 id="Numbers_數字">Numbers 數字</h3>
+
+<p>You can store numbers in variables, either whole numbers like 30 (also called integers) or decimal numbers like 2.456 (also called floats or floating point numbers). You don't need to declare variable types in JavaScript, unlike some other programming languages. When you give a variable a number value, you don't include quotes:</p>
+
+<pre class="brush: js notranslate">let myAge = 17;</pre>
+
+<h3 id="Strings_字串">Strings 字串</h3>
+
+<p>Strings are pieces of text. When you give a variable a string value, you need to wrap it in single or double quote marks, otherwise, JavaScript will try to interpret it as another variable name.</p>
+
+<pre class="brush: js notranslate">let dolphinGoodbye = 'So long and thanks for all the fish';</pre>
+
+<h3 id="Booleans_布林值">Booleans 布林值</h3>
+
+<p>Booleans are true/false values — they can have two values, <code>true</code> or <code>false</code>. These are generally used to test a condition, after which code is run as appropriate. So for example, a simple case would be:</p>
+
+<pre class="brush: js notranslate">let iAmAlive = true;</pre>
+
+<p>Whereas in reality it would be used more like this:</p>
+
+<pre class="brush: js notranslate">let test = 6 &lt; 3;</pre>
+
+<p>This is using the "less than" operator (<code>&lt;</code>) to test whether 6 is less than 3. As you might expect, it will return <code>false</code>, because 6 is not less than 3! You will learn a lot more about such operators later on in the course.</p>
+
+<h3 id="Arrays_陣列">Arrays 陣列</h3>
+
+<p>An array is a single object that 它包含多個用方括號括起來並用逗號分隔的值。Try entering the following lines into your console:</p>
+
+<pre class="brush: js notranslate">let myNameArray = ['Chris', 'Bob', 'Jim'];
+let myNumberArray = [10, 15, 40];</pre>
+
+<p>Once these arrays are defined, you can access each value by their location within the array. Try these lines:</p>
+
+<pre class="brush: js notranslate">myNameArray[0]; // should return 'Chris'
+myNumberArray[2]; // should return 40</pre>
+
+<p>The square brackets specify an index value corresponding to the position of the value you want returned. You might have noticed that arrays in JavaScript are zero-indexed: the first element is at index 0.</p>
+
+<p>You'll learn a lot more about arrays in <a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">a future article</a>.</p>
+
+<h3 id="Objects_物件">Objects 物件</h3>
+
+<p>在編程中,物件是對真實生活物件進行建模的代碼結構。 您可以擁有一個代表停車場的簡單物件,其中包含有關其寬度和長度的信息,或者您可以擁有一個代表一個人的物件,並用物件紀錄其姓名、身高、體重、慣用語言,如何跟他打招呼等的資訊。</p>
+
+<p>請試著在你的console中輸入以下指令:</p>
+
+<pre class="brush: js notranslate">let dog = { name : 'Spot', breed : 'Dalmatian' };</pre>
+
+<p>取得物件中儲存的資料可以使用以下語法:</p>
+
+<pre class="brush: js notranslate">dog.name</pre>
+
+<p>We won't be looking at objects any more for now — you can learn more about those in <a href="/en-US/docs/Learn/JavaScript/Objects">a future module</a>.</p>
+
+<h2 id="動態型別">動態型別</h2>
+
+<p>JavaScript 是一個"動態型別語言",意思是不像其他強型別程式語言,在JavaScript 宣告變數時你不用指定指定資料類型(數字、字串或陣列等等)。</p>
+
+<p>For example, if you declare a variable and give it a value enclosed in quotes, the browser will treat the variable as a string:</p>
+
+<pre class="brush: js notranslate">let myString = 'Hello';</pre>
+
+<p>It will still be a string, even if it contains numbers, so be careful:</p>
+
+<pre class="brush: js notranslate">let myNumber = '500'; // oops, this is still a string
+typeof myNumber;
+myNumber = 500; // much better — now this is a number
+typeof myNumber;</pre>
+
+<p>Try entering the four lines above into your console one by one, and see what the results are. You'll notice that we are using a special operator called <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/typeof">typeof</a></code> — this returns the data type of the variable you pass into it. The first time it is called, it should return <code>string</code>, as at that point the <code>myNumber</code> variable contains a string, <code>'500'</code>. Have a look and see what it returns the second time you call it.</p>
+
+<h2 id="JavaScript中的常數">JavaScript中的常數</h2>
+
+<p>許多程式語言都有常數的概念:一經宣告就不改變的值。設定常數有許多原因,例如若引入第三方腳本而改動變數值,將會造成許多問題而且很難除錯。</p>
+
+<p>一開始JavaScript是沒有常數的,直到今日我們才有了關鍵字 <code>const</code>,讓我們儲存不能改變的值:</p>
+
+<pre class="brush: js notranslate">const daysInWeek = 7<span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-number">;
+const hoursInDay = 24;</span></span></span></span></pre>
+
+<p><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-number"><code>const</code> works in exactly the same way as <code>let</code>, except that you can't give a <code>const</code> a new value. In the following example, the second line would throw an error:</span></span></span></span></p>
+
+<pre class="brush: js notranslate">const daysInWeek = 7<span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-number">;
+daysInWeek = 8;</span></span></span></span></pre>
+
+<h2 id="Summary">Summary</h2>
+
+<p>By now you should know a reasonable amount about JavaScript variables and how to create them. In the next article, we'll focus on numbers in more detail, looking at how to do basic math in JavaScript.</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Maths", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是 JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">和 JavaScript 的第一次接觸</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html b/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html
new file mode 100644
index 0000000000..c610e17dd8
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/what_is_javascript/index.html
@@ -0,0 +1,425 @@
+---
+title: JavaScript 是什麼?
+slug: Learn/JavaScript/First_steps/What_is_JavaScript
+tags:
+ - API
+ - JavaScript
+ - 學習
+ - 撰寫程式
+ - 新手
+ - 核心觀念
+ - 瀏覽器
+ - 註解
+translation_of: Learn/JavaScript/First_steps/What_is_JavaScript
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">歡迎來到 MDN 的 JavaScript 初學者課程!我們將在這個章節綜觀 JavaScript ,回答一些像是「它什麼?」和「可以使用它作什麼?」之的問題,並確保你了解 JavaScript 的特性。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備條件:</th>
+ <td>基本的電腦知識,基本了解 HTML 和 CSS 技術。</td>
+ </tr>
+ <tr>
+ <th scope="row">學習目標:</th>
+ <td>了解 JavaScript 的本質、功能、以及它如何構成網站的一部分</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="高層次的定義">高層次的定義</h2>
+
+<p>JavaScript 是一種腳本,也能稱它為程式語言,可以讓你在網頁中實現出複雜的功能。當網頁不只呈現靜態的內容,另外提供了像是:內容即時更新、地圖交動、繪製 2D/3D 圖形,影片播放控制……等,你就可以大膽地認為 JavaScript 已經參與其中。它是標準網頁技術蛋糕的第三層,而其他兩層(<a href="/zh-TW/docs/Learn/HTML">HTML</a> 和 <a href="/zh-TW/docs/Learn/CSS">CSS</a>)我們在其他學習單元中有更多詳細的介紹。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13502/cake.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+ <li>{{glossary("HTML")}} 是一種標記語言,我們使用它組織網頁裡的內容並給予定義, 例如:定義段落、標題、資料表格,或是在頁面嵌入圖片和影片。.</li>
+ <li>{{glossary("CSS")}} 是一種樣式規則的語言,用來幫我們的 HTML 內容上套用樣式,例如:設置背景顏色、字型,或讓內容以多欄的方式呈現。</li>
+ <li>{{glossary("JavaScript")}} 是一種腳本語言,它使你能夠動態的更新內容、控制多媒體、動畫……幾乎所有事。(好吧,不是所有事情,但神奇的是你可以通過短短幾行 JavaScript 程式碼實現。)</li>
+</ul>
+
+<p>這三層很好的構建在一起。讓我們以一個簡單的文字為例。我們可以使用 HTML 標記來表示它的結構和意圖:</p>
+
+<pre class="brush: html notranslate">&lt;p&gt;Player 1: Chris&lt;/p&gt;</pre>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13422/just-html.png" style="height: 28px; width: 108px;"></p>
+
+<p>然後我們可以加一些 CSS ,讓它看起來更好:</p>
+
+<pre class="brush: css notranslate">p {
+ font-family: 'helvetica neue', helvetica, sans-serif;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ text-align: center;
+ border: 2px solid rgba(0,0,200,0.6);
+ background: rgba(0,0,200,0.3);
+ color: rgba(0,0,200,0.6);
+ box-shadow: 1px 1px 2px rgba(0,0,200,0.4);
+ border-radius: 10px;
+ padding: 3px 10px;
+ display: inline-block;
+ cursor:pointer;
+}</pre>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13424/html-and-css.png" style="height: 48px; width: 187px;"></p>
+
+<p>最後,我們可以加一些  JavaScript 來作出互動的行為:</p>
+
+<pre class="brush: js notranslate">const para = document.querySelector('p');
+
+para.addEventListener('click', updateName);
+
+function updateName() {
+ let name = prompt('輸入新的名字');
+ para.textContent = 'Player 1: ' + name;
+}
+</pre>
+
+<p>{{ EmbedLiveSample('高層次的定義', '100%', 80, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>試試點擊這最後版本的文字,看看會發生什麼事情(你同樣也可以在 GitHub 找到這個範例,來查看<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/javascript-label.html">原始碼</a>或<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/javascript-label.html">在線上執行</a>)!</p>
+
+<p>JavaScript 能做到更多,讓我們更深入地探索。</p>
+
+<h2 id="它究竟可以做什麼呢">它究竟可以做什麼呢?</h2>
+
+<p>JavaScript 語言的核心包含了很多常用的程式功能供你使用,如:</p>
+
+<ul>
+ <li>將有用的值存儲在變數中。例如上述例子,我們要求輸入一個新名字,然後將該名字存在名為<code>name</code>的變數裡。</li>
+ <li>對文本片段的操作(在程式裡稱作"字串")。在上述例子中,我們拿了字串 "Player 1: " 並將其與 <code>name</code> 變數連接來創造完整文本標籤,如:''Player 1: Chris"。</li>
+ <li>執行程式碼,回應網頁上發生的某些事件。在上述例子中,我們使用 {{Event("click")}} 事件,當按鈕被點擊時,便執行更新文本標籤的程式碼。 </li>
+ <li>以及其他更多更多的功能!</li>
+</ul>
+
+<p>然而,更令人興奮的是那些基於用戶端的 JavaScript 語言構建的功能。也就是所謂的 <strong>應用程式介面</strong>(<strong>API</strong>),提供 JavaScript 程式額外的超能力。</p>
+
+<p>API 是預先製作完成的程式模組,支援開發者實現困難或無法實現的功能。在程式設計中就如同在建築房子的時候使用系統傢俱,拿預先裁好的板子用螺絲鎖上來組合成書架,相比從頭自己設計,找合適木材,切成正確的形狀和尺寸,再找到合適的螺絲最後組裝書架而言更簡單。</p>
+
+<p>他們通常分為兩類。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p>
+
+<p><strong>瀏覽器 API(Browser APIs)</strong>內建在你的瀏覽器中,能夠依本地的電腦環境輸出資料或實現複雜的功能。舉例而言:</p>
+
+<ul>
+ <li>{{domxref("Document_Object_Model","DOM (文件物件模型) API")}} 讓你能操作 HTML和 CSS,像是建立、移除或改變 HTML 元素,或動態地將新樣式套用到頁面…等等。每當你看到彈出視窗,或有新的內容出現在畫面上(就像上面的範例所展示的),那就是 DOM 在動作。</li>
+ <li>{{domxref("Geolocation","Geolocations(地理位置) API")}} 可以取得位置資訊。這就是 <a href="https://www.google.com/maps">Google Maps</a> 取得你的位置並標示在地圖上所透過的方式。</li>
+ <li>{{domxref("Canvas_API","Canvas")}} 和 {{domxref("WebGL_API","WebGL")}} API 可以讓你在網頁創造 2D 動畫及 3D 圖像。人們正使用這些技術來作一些令人驚奇的事,參見 <a href="https://www.chromeexperiments.com/">Chrome Experiments</a> 及 <a href="http://webglsamples.org/">webglsamples</a>.</li>
+ <li><a href="https://developer.mozilla.org/zh-TW/Apps/Fundamentals/Audio_and_video_delivery">Audio 和 Video API</a> 像 {{domxref("HTMLMediaElement")}} 和  {{domxref("WebRTC API", "WebRTC")}} 一樣讓你可以使用多媒體做真正有趣的事情,例如在網頁中播放音樂或影片,或由網路攝影機頡取你的影像顯示在另一個人電腦裡(試試我們的<a href="http://chrisdavidmills.github.io/snapshot/">簡單例子</a>來了解)。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意</strong>:上面的許多範例無法在舊版的瀏覽器上運作。使用現代的瀏覽器像是 Firefox、Chrome、Edge 或 Opera 來嘗試執行你的程式總是比較好的。當你接近要交付作為產品的程式(也就是實際的用戶將要使用的時候),就需要思考關於<a href="/zn-TW/docs/Learn/Tools_and_testing/Cross_browser_testing">跨瀏覽器測試</a>的事情。</p>
+</div>
+
+<p><strong>第三方 API</strong> 預設不內建在瀏覽器裡,你通常由網路上取得他們的程式碼與資訊。例如:</p>
+
+<ul>
+ <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a> 能讓你做很多事,像是顯示最新的Twitter貼文在你的網站上。</li>
+ <li><a href="https://developers.google.com/maps/">Google Maps API</a> 能讓你在自己的網站中嵌入訂製的地圖或其他相關功能。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意</strong>: 我們不會在此涵蓋這些進階的APIs。你可以在我們的 <a href="/zh-TW/docs/Learn/JavaScript/Client-side_web_APIs">客戶端網頁 API 單元</a>找到更多資訊。</p>
+</div>
+
+<p>那裡也有很多的東西。然而不要一頭熱陷進去。你不會在學習 JavaScript 24 小時後,就能開發出下一個 Facebook、Google 地圖或 Instagram 之類的產品出來。有許多的基礎的東西得先了解,這也是你在這裡的原因,讓我們繼續吧!</p>
+
+<h2 id="JavaScript_在你的頁面做了些什麼?">JavaScript 在你的頁面做了些什麼?</h2>
+
+<p>這裡我們開始看一些程式碼,探索當 JavaScript 在你的頁面上執行時,發生了哪些事情。</p>
+
+<p>簡單回顧一下當瀏覽器載入一個網站時會發生的事情(第一次是在我們的<a href="/zh-TW/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_does_CSS_actually_work">CSS 如何工作</a>章節中提到)。當瀏覽器載入一個網頁,就是在執行環境(瀏覽器分頁)中執行程式碼(HTML,CSS 和 JavaScript)。就像是工廠收集原料(程式碼)並且產出商品(網頁呈現的結果)。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13504/execution.png" style="display: block; margin: 0 auto;"></p>
+
+<p>透過 DOM API (上面提到的)動態調整 HTML 與 CSS 進行改變網頁呈現,在 JavaScript 是很常見的使用方式。要注意的是,檔案中的程式碼通常會以出現在頁面上的順序來執行。如果 JavaScript 比準備操作的 HTML 、 CSS 更早被載入,就可能會發生錯誤。你將會在這個章節的後段學到一些解決問題的方法,它在<a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript#Script_loading_strategies">腳本載入策略</a>的部分。</p>
+
+<h3 id="瀏覽器安全性">瀏覽器安全性</h3>
+
+<p>瀏覽器的每個分頁有獨立的空間來執行程式碼(技術上稱「執行環境excution environments」),這表示在絕大部分的情形之下,每個分頁的程式碼是獨立運行的,不能直接影響其它分頁(或網站)裡的程式。這是一個好的安全措施,少了它,有心人會開始寫程式來偷取網站的資料,或是作其它不好的事情。</p>
+
+<div class="note">
+<p><strong>注意</strong>:是有一些安全的方式能在不同的網頁、分頁之間傳遞程式和資料,不過這些進階的技術不會在涵蓋在這個單元中。</p>
+</div>
+
+<h3 id="JavaScript_的執行順序">JavaScript 的執行順序</h3>
+
+<p>當瀏覽器遇到一段 JavaScript 程式碼,通常會由上到下執行。這意味著你需要注意東西擺放的順序。為了說明,讓我們回到我們曾看過的第一個範例:</p>
+
+<pre class="brush: js notranslate">const para = document.querySelector('p');
+
+para.addEventListener('click', updateName);
+
+function updateName() {
+ let name = prompt('輸入新的名字');
+ para.textContent = 'Player 1: ' + name;
+}</pre>
+
+<p>這裡我們選擇了一個文字段落(第 1 行),然後加上事件偵聽器,所以當段落被點擊的時候,<code>updateName()</code> 程式區塊(5 到 8 行 )會被執行。<code>updateName()</code> 程式區塊(這種可以重複使用的程式區塊被稱為「函數 function」)會向使用者要一個新的名字,然後將插到段落中,更新顯示的內容。</p>
+
+<p>如果你交換前兩行的程式碼,它將不再正常運作。取而代之的,<a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools">瀏覽器開發主控台</a>會回報一個錯誤訊息:「<code>TypeError: para is undefined</code>」,意思是 <code>para</code> 物件尚不存在,所以我們在它上頭增加事件偵聽器。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 這是一個很常見的錯誤,在你嘗試對物件進行操作之前,你需要注意它們已經存在。</p>
+</div>
+
+<h3 id="直譯式與編譯式程式語言">直譯式與編譯式程式語言</h3>
+
+<p>你可能在程式相關的文章中看過<strong>直譯式</strong> (<strong>interpreted</strong> )與<strong>編譯式 (compiled)</strong>這兩個詞。在直譯式程式語言中,程式碼由上到下執行,而且執行的結果是立即回應得到的。在瀏覽器執行前,你不需要將程式轉換為其它的形式。程式碼的內容是以對程式人員友善的形式並直接能夠運作。</p>
+
+<p>另一方面,編譯式程式語言需要在電腦執行之前轉換(編譯)成另一種形式。例如: C/C++ 在被電腦執行之前要編譯為組合語言。被執行的程式是一種二進位的格式,由程式原始碼產生出來。</p>
+
+<p>JavaScript 是一個輕量的直接程式語言。網頁瀏覽器收到文字格式的 JavaScript 程式碼,並直接執行。以技術的角度來看,大多數現代的 JavaScript 直譯器實際上會使用一種稱為<strong>即時編譯(just-in-time compiling)</strong>的技術來提升執行表現。 JavaScript 被使用時,原始程式會被編譯成更快的二進位格式,讓它們能更有效率的運行。然而, JavaScript 仍然被認為是一種直譯式的程式語言,因為編譯動作是在程式運作時,而不是事先完成。</p>
+
+<p>兩種語言都有各自的優點,但是我們不在此時討論這個議題。</p>
+
+<h3 id="伺服器端與用戶端程式">伺服器端與用戶端程式</h3>
+
+<p>你也有可能聽過<strong>伺服器端</strong>與<strong>客戶端</strong>程式,尤其在網站開發的領域。客戶端程式在使用者的電腦中運作,當瀏覽網頁的時候,頁面中的客戶端程式被下載,接著被瀏覽器執行與顯示結果。在這個單元中,我們只談論<strong>客戶端 JavaScript</strong>。</p>
+
+<p>另一方面,伺服器端的程式在伺服器上執行,接著產出的結果被瀏覽器下載後顯示。受歡迎的伺服器端網頁語言,包括 PHP、Python、Ruby 和 ASP.NET 以及… JavaScript!JavaScript 也能夠作為伺服器端程式語言,流行的 Node.js 環境就是一例。你可以在我們的<a href="/zh-TW/docs/Learn/Server-side">動態網站—伺服器端網站程式設計</a>主題中找到更多資訊。</p>
+
+<h3 id="動態與靜態程式">動態與靜態程式</h3>
+
+<p><strong>動態</strong>一詞被用於描述用戶端 JavaScript 和伺服器端程的式語言,用來描述具有在不同的狀況下更新網頁/網頁應用程式來顯示不同東西,依需要來產生新內容的能力。是根據要求生成新內容的能力。伺服器端程式在伺服器上動態產生的新內容,可能是來自資料庫中取出的數據,而用戶端 JavaScript 在收到由伺服器端要回來的資料,在瀏覽器內動態產生新的內容(如 HTML 表格)後加入頁面中呈現出來。在兩個情境中詞義稍微不同,但是相關的,兩種方法(伺服器端和用戶端)通常可以協同工作。</p>
+
+<p>一個沒有動態更新內容能力的網頁被稱為<strong>靜態</strong>,它在任何時候都只顯示一樣的內容。</p>
+
+<h2 id="如何在網頁中增加_JavaScript_?">如何在網頁中增加 JavaScript ?</h2>
+
+<p>在 HTML 頁面中使用 JavaScript 與 CSS 的方法類似。在 HTML 中 CSS 藉著{{htmlelement("link")}} 元素引入外部樣式(stylesheets)以及 {{htmlelement("style")}} 元素定義內部樣式。JavaScript 在 HTML中只需要一個朋友 — {{htmlelement("script")}} 元素。讓我們了解它是如何運作。</p>
+
+<h3 id="內部的_JavaScript">內部的 JavaScript</h3>
+
+<ol>
+ <li>首先,下載一份 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript.html">apply-javascript.html 範例</a>儲存在自己的電腦上合適的目錄裡。</li>
+ <li>用瀏覽器與文字編輯器打開範例。你會看到 HTML 建立了一個簡單的網頁,包含一個可點擊的按鈕。</li>
+ <li>接著,切換到文字編輯器,在標頭區加入下面的文字,就放在 <code>&lt;/head&gt;</code> 結尾標籤前:
+ <pre class="brush: html notranslate">&lt;script&gt;
+
+ // JavaScript 將放在這裡
+
+&lt;/script&gt;</pre>
+ </li>
+ <li>現在,我們將在我們的 {{htmlelement("script")}} 元素中加入一些 JavaScript 程式,讓網頁能做些有趣的事,接者在「// JavaScript 將放在這裡」那行後面:
+ <pre class="brush: js line-numbers language-js notranslate"><code class="language-js">document<span class="punctuation token">.</span><span class="function token">addEventListener</span><span class="punctuation token">(</span><span class="string token">"DOMContentLoaded"</span><span class="punctuation token">,</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">function</span> <span class="function token">createParagraph</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">let</span> para <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">createElement</span><span class="punctuation token">(</span><span class="string token">'p'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ para<span class="punctuation token">.</span>textContent <span class="operator token">=</span> <span class="string token">'You clicked the button!'</span><span class="punctuation token">;</span>
+ document<span class="punctuation token">.</span>body<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>para<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+
+ <span class="keyword token">const</span> buttons <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">querySelectorAll</span><span class="punctuation token">(</span><span class="string token">'button'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="keyword token">for</span><span class="punctuation token">(</span><span class="keyword token">let</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> i <span class="operator token">&lt;</span> buttons<span class="punctuation token">.</span>length <span class="punctuation token">;</span> i<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ buttons<span class="punctuation token">[</span>i<span class="punctuation token">]</span><span class="punctuation token">.</span><span class="function token">addEventListener</span><span class="punctuation token">(</span><span class="string token">'click'</span><span class="punctuation token">,</span> createParagraph<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+ </li>
+ <li>儲存你的檔案並且重新整理網頁,現在你會發現每次點擊按鈕,都會在下方產生一個新的文字段落。</li>
+</ol>
+
+<div class="note">
+<p><strong>注意</strong>: 如果你的版本不能正常運作,重新按照步驟再操作一次,檢查每一步都正確。你下載的範例是 <code>.html</code> 結尾的檔名?你加入的 {{htmlelement("script")}} 元素在 <code>&lt;/head&gt;</code> 標籤的前面?你輸入的 JavaScript 與上面提供的一模一樣? <strong>JavaScript 程式大小寫,而且很挑剔,所以你輸入的語法要一模一樣,不然可能會無法運作。</strong></p>
+</div>
+
+<div class="note">
+<p><strong>注意</strong>: GitHub上有完整版本的範例在 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">apply-javascript-internal.html</a>(<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">看線上版本</a>)。</p>
+</div>
+
+<h3 id="外部的_JavaScript">外部的 JavaScript</h3>
+
+<p>內部 JavaScript 目前運作得很好,但如果我們想把 JavaScript 放在外部檔案,應該怎麼做?讓我們現在來探索。</p>
+
+<ol>
+ <li>首先,建立一個新的檔案,和 HTML 檔案放在相同的目錄下,命名為 <code>script.js</code> ,確定這個檔案是以 .js 為副檔名, 因為這就是它被識別為 JavaScript 的原因。</li>
+ <li>將 {{htmlelement("script")}} 元素(包含裡面的程式)換成下面的樣子:
+ <pre class="brush: html notranslate">&lt;script src="script.js" async&gt;&lt;/script&gt;</pre>
+ </li>
+ <li>在 <code>script.js</code> 中,加入下面的程式碼:
+ <pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="keyword token">function</span> <span class="function token">createParagraph</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">let</span> para <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">createElement</span><span class="punctuation token">(</span><span class="string token">'p'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ para<span class="punctuation token">.</span>textContent <span class="operator token">=</span> <span class="string token">'You clicked the button!'</span><span class="punctuation token">;</span>
+ document<span class="punctuation token">.</span>body<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>para<span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="punctuation token">}</span>
+
+<span class="keyword token">const</span> buttons <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">querySelectorAll</span><span class="punctuation token">(</span><span class="string token">'button'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+<span class="keyword token">for</span><span class="punctuation token">(</span><span class="keyword token">let</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> i <span class="operator token">&lt;</span> buttons<span class="punctuation token">.</span>length <span class="punctuation token">;</span> i<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ buttons<span class="punctuation token">[</span>i<span class="punctuation token">]</span><span class="punctuation token">.</span><span class="function token">addEventListener</span><span class="punctuation token">(</span><span class="string token">'click'</span><span class="punctuation token">,</span> createParagraph<span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="punctuation token">}</span></code></pre>
+ </li>
+ <li>儲存檔案並在你的瀏覽器執行重新整理,你應該會看到一樣的結果!雖然是一樣的結果,但現在我們是由外部的檔案來引入 JavaScript 程式。就組織程式碼,讓程式可以在多個 HTML 間重複被使用而言,這通常是好的作法。另外,因為少了一大堆程式碼在裡頭,也能夠讓 HTML 檔案更容易被閱讀。</li>
+</ol>
+
+<div class="note">
+<p><strong>注意</strong>: 你可以在 GitHub 上找到這個版本的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">apply-javascript-external.html</a> 與 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/script.js">script.js</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">看線上版本</a>)。</p>
+</div>
+
+<h3 id="行內的_JavaScript">行內的 JavaScript</h3>
+
+<p>注意,有時候你會遇到一些 JavaScript 程式混在HTML語法之中。它可能會看起來像這樣:</p>
+
+<pre class="brush: js example-bad notranslate">function createParagraph() {
+ var para = document.createElement('p');
+ para.textContent = 'You clicked the button!';
+ document.body.appendChild(para);
+}</pre>
+
+<pre class="brush: html example-bad notranslate">&lt;button onclick="createParagraph()"&gt;Click me!&lt;/button&gt;</pre>
+
+<p>你可以在底下試試這個段程式的作用。</p>
+
+<p>{{ EmbedLiveSample('行內的_JavaScript', '100%', 150, "", "", "hide-codepen-jsfiddle") }}</p>
+
+<p>這個範例與前面兩個有完全相同的功能,除了 {{htmlelement("button")}} 元素中包含了一個行內 <code>onclick</code> 處理程序,當按鈕按下時執行。</p>
+
+<p><strong>然而,請不要這樣做。</strong>用 JavaScript 汙染你的 HTML 是一種不好的作法,而且沒有效率,因為你必須在每個你希望 JavaScript 作用的地方加入 <code>onclick="createParagraph()"</code> 屬性。</p>
+
+<p>使用單純 JavaScript 的結構,讓你可以用一個指令選擇所有的按鈕。在我們前面的範例中,使用下面的程式碼達到這個目的:</p>
+
+<pre class="notranslate">var buttons = document.querySelectorAll('button');
+
+for (var i = 0; i &lt; buttons.length ; i++) {
+ buttons[i].addEventListener('click', createParagraph);
+}</pre>
+
+<p>這或許看起來比 <code>onclick</code> 屬性還長一點,但是能套用在全部的按鈕上,無論頁面上有多少按鈕,也不管未來新增或移除多少個(按鈕)。這段 JavaScript 程式都不需要改變。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 試著編輯你自己版本的 <code>apply-javascript.html</code> ,在裡面多添加一點按鈕。當你重新載入網頁,你應該會發現所有按鈕,按下去的時候都會建立一的段落。很簡潔吧!</p>
+</div>
+
+<h3 id="腳本載入策略Script_loading_strategies">腳本載入策略(Script loading strategies)</h3>
+
+<p>在正確的時機載入腳本涉及一些要注意的東西。並不如它看起來的簡單!其中一個常見的問題是,所有的 HTML 是根據出現順序載入。假如你使用 JavaScript 操作頁面中的元素(精確地來說是 <a href="/zh-TW/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#The_document_object_model">DOM 元素</a>),如果 JavaScript 在這些 HTML 操作對象前被讀取及解析,你的程式將無法運作。</p>
+
+<p>上面的範例中,內部和外部 JavaScript 範例裡的程式碼都放在 HTML 的 head 區域,在 body 區被載入前就先被解析。這樣會造成一些問題,所以我們載入與執行在文件(HTML檔)的開頭,是HTML <code>body</code> 還沒解析之前。這可能會產生錯誤,所以我們使用一些模式來處理它。</p>
+
+<p>在內部程式的範例中,你可以看到以下這樣結構的程式碼:</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">document<span class="punctuation token">.</span><span class="function token">addEventListener</span><span class="punctuation token">(</span><span class="string token">"DOMContentLoaded"</span><span class="punctuation token">,</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="operator token">...</span>
+<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>這是一個事件偵聽器,它偵聽瀏覽器的「DOMContentLoaded」事件,它是在 HTML body 部分已經完全載入與解析發出。區塊內(... 的部分)的 JavaScript 直到事件被發出後才會執行,這樣子問題就被避開了。(你將會在這個課程中<a href="/zh-TW/docs/Learn/JavaScript/Building_blocks/Events">學習到什麼是事件</a>)</p>
+
+<p>在外部程式的範例中,我們使用比較現代的 JavaScript 特性來解決這個問題,<code>defer</code> 屬性,它告訴瀏覽器碰到這種 <code>&lt;script&gt;</code> 標籤時,繼續下載後面其他的 HTML 內容。</p>
+
+<pre class="brush: js line-numbers language-js notranslate"><code class="language-js"><span class="operator token">&lt;</span>script src<span class="operator token">=</span><span class="string token">"script.js"</span> defer<span class="operator token">&gt;</span><span class="operator token">&lt;</span><span class="operator token">/</span>script<span class="operator token">&gt;</span></code></pre>
+
+<p>在這個例子中,腳本(JavaScript 程式)與 HTML 會同時載入,所以程式將正確地執行。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 在外部程式的範例裡,我們不需要使用 <code>DOMContentLoaded</code> 事件因為 <code>defer</code> 為我們解決問題了。而在內部程式的範例裡我們沒用 <code>defer</code> 屬性,是因為 <code>defer</code> 屬性只能用於外部的腳本。</p>
+</div>
+
+<p>這個問題有另一個舊式的解決方法,就是將 <code>script</code> 元素放在 <code>body</code> 元素的底部(剛好在 <code>&lt;/body&gt;</code> 的前面),如此它就會在所有 HTML 被解析完之後才被載入。這個方法的問題在於腳本的載入與解析工作會被完成擋住,一直到所有 HTML 載入完成。在擁有許多 JavaScript 的大型網站中,這樣會導致嚴重的效能問題,拖慢你的網站。</p>
+
+<h4 id="async_和_defer">async 和 defer</h4>
+
+<p>實際上,有兩個方法可以閃過上述腳本被擋到的問題:<code>async</code> 與 <code>defer</code>(前面看到的)。來看看兩者的區別。</p>
+
+<p>使用 <code>async</code> 屬性(如下所示)所載入的腳本,在下載的同時不會讓網頁的渲染被阻塞(停住),並且在下載完成後馬上執行。它並不保證腳本會按照任何特定的順序執行,只保證不去妨礙網頁中其他部分顯示工作。<code>async</code> 的最佳使用情境,是當網頁中的腳本間彼此獨立,因而不依賴彼此運行的狀況下。</p>
+
+<p>例如你有以下的 <code>script</code> 元素</p>
+
+<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">async</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/vendor/jquery.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span>
+
+<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">async</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/script2.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span>
+
+<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">async</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/script3.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span></code></pre>
+
+<p>你不能將元素的順序視為腳本載入順序。 <code>jquery.js</code> 可能會在 <code>script2.js</code> 與 <code>script3.js</code> 的之前或之後載入,在這個情況下,在腳本中依賴 <code>jquery</code> 的函數將會發生錯誤,因為被執行到的時候 <code>jquery</code> 還沒被定義(載入且解析完畢)。</p>
+
+<p>當有許多非立即要使用的腳本,而你只希望它們能盡快被載入完畢,就應該使用 <code>async</code> 。例如:你有一些遊戲內容的檔案需要載入,它將在遊戲開始後被用到。但是現在你只是需要顯示遊戲介紹、一些選單以及遊戲大廳,不希望等到所有內容都下載完成之後才顯示。</p>
+
+<p>使用 <code>defer</code> 屬性(如下所示)所載入的腳本,會在腳本與內容都下載完成後,依照出現順序被執行。</p>
+
+<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">defer</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/vendor/jquery.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span>
+
+<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">defer</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/script2.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span>
+
+<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>script</span> <span class="attr-name token">defer</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>js/script3.js<span class="punctuation token">"</span></span><span class="punctuation token">&gt;</span></span><span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>script</span><span class="punctuation token">&gt;</span></span></code></pre>
+
+<p>全部具有 <code>defer</code> 屬性的腳本會依據出現的順序載入。因此在第二個範例中,我們可以肯定 <code>jquery.js</code> 會在 <code>script2.js</code> 與 <code>script3.js</code> 之前被載入, <code>script2.js</code> 會在 <code>script3.js</code> 之前載入。在網頁的所有內容被載入完成之前,它是不會被執行的。當你的程式依賴著某些元素存在時(如:要調整頁面上一到多個元素),這個屬性很有用。</p>
+
+<p>總結一下:</p>
+
+<ul>
+ <li><code>async</code> 和 <code>defer</code> 屬性都是用來告訴瀏覽器使用獨立線程(行程)來下載腳本,同一時間頁面的其它部分(如 DOM 元件之類)也在下載,因此頁面的載入不會因為腳本被影響。</li>
+ <li>如果你的腳本應該立即被執行,而且不依賴其它腳本先被載入,就用 <code>async</code> 。</li>
+ <li>如果你的腳本依賴其他腳本先被解析或 DOM 已經存在,就用 <code>defer</code> 來載入它們,並根據你想要瀏覽器執行的順序安排 <code>&lt;script&gt;</code> 元素的次序。</li>
+</ul>
+
+<h2 id="註解">註解</h2>
+
+<p>如同 HTML 和 CSS,在 JavaScript 的程式碼中也可以撰寫註解,它會被瀏覽器忽略,僅用來提供你的開發伙伴,說明程式是如何運作(或是自己,當六個月後回來看程式碼,忘記曾經做過了什麼)。註解非常有用,你應該常常使用它,尤其是在大型應用程式裡。註解有兩種形式:</p>
+
+<ul>
+ <li>單行註解,寫在兩個(正)斜線「//」之後,例如:
+ <pre class="brush: js notranslate">// 我是一個註解</pre>
+ </li>
+ <li>多行註解,寫在 /* 和 */ 之間的文字,例如:
+ <pre class="brush: js notranslate">/*
+ 我也是
+ 一個註解
+*/</pre>
+ </li>
+</ul>
+
+<p>舉例來說,我們可以在前面範例的 JavaScript 裡加入註解,像是:</p>
+
+<pre class="brush: js notranslate">// 函數:建立一個段落元素並加到 HTML body 的尾端
+
+function createParagraph() {
+ var para = document.createElement('p');
+ para.textContent = 'You clicked the button!';
+ document.body.appendChild(para);
+}
+
+/*
+ 1. 找出頁面上所有按鈕,並把它們放到陣列中
+ 2. 使用迴圈,對每個按鈕偵聽 click 事件
+
+ 當任何按鈕被按下,執行 createParagraph() 函數
+*/
+
+var buttons = document.querySelectorAll('button');
+
+for (var i = 0; i &lt; buttons.length ; i++) {
+ buttons[i].addEventListener('click', createParagraph);
+}</pre>
+
+<div class="blockIndicator note">
+<p><strong>注意:一般而言,多寫註解比少寫來得好。但是要注意,如果你發現加了許多註解在說明變數的用途(那麼你的變數命名可能需要更直觀,更帶有意義),或是解釋非常簡單的操作(也許你的程式碼太過於複雜)。</strong></p>
+</div>
+
+<h2 id="總結">總結</h2>
+
+<p>所以你已經踏出在 JavaScript 世界中的第一步。我們從理論開始,逐漸熟悉使用 JavaScript 的原因,以及你可以用它做些什麼。過程中你看到了一些程式碼範例,學到如何將 JavaScript 與你網站的其它東西放在一起。</p>
+
+<p>JavaScript 目前可能看起來有一點嚇人,然而不用擔心,在本課程我們會透過簡單的步驟,帶著你建立觀念並繼續向前。 在下一章節,我們將會<a href="/zh-TW/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">投入更實用的知識</a>,帶你直接入門並建立你自己的 JavaScript 作品。</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">初次接觸Javascript</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
+
+<p>{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}</p>
diff --git a/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html b/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html
new file mode 100644
index 0000000000..5eec96717b
--- /dev/null
+++ b/files/zh-tw/learn/javascript/first_steps/what_went_wrong/index.html
@@ -0,0 +1,253 @@
+---
+title: 出了什麼問題?JavaScript 疑難排解
+slug: Learn/JavaScript/First_steps/What_went_wrong
+translation_of: Learn/JavaScript/First_steps/What_went_wrong
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</div>
+
+<p class="summary">當你在練習撰寫上一節的"猜數字"遊戲時,你可能會發現它無法運作。不用擔心,本文將會把你從快被拔光的頭髮中拯救出來,並且給你一些小提示,讓你知道怎麼找出及修正 Javascript 的程式運行錯誤。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備:</th>
+ <td>基本電腦能力,基本html及css理解以及了解JavaScript是什麼</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>獲得開始解決簡單編碼問題的能力及信心</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="錯誤類型">錯誤類型</h2>
+
+<p>一般來說,當你的編碼有錯誤時,主要有兩種類型</p>
+
+<ul>
+ <li><strong>語法錯誤</strong>: 在編碼中有一些拼字錯誤導致程序完全或部分沒有正常運作。在這個狀況下,通常你會獲得一些錯誤訊息。只要對工具熟悉以及了解錯誤訊息的意思,這種錯誤通常很好修正!</li>
+ <li><strong>邏輯錯誤</strong>: 這種錯誤代表程式碼的語法正確,但程式完成的部分不是開發者想做的?,意即程式碼執行成功,但返回錯誤的結果。這種錯誤通常比<strong>語法錯誤</strong>還要難修正,因為並沒有錯誤訊息讓我們可以很直接地知道程式碼的問題。</li>
+</ul>
+
+<p>好的,但事情並沒有那麼單純——當你越深入,就會發現更多不同的因素。但上述的分類已經足夠應付初期的工程師職涯了。接著,我們將更深入來討論這兩個類型。</p>
+
+<h2 id="一個錯誤範例">一個錯誤範例</h2>
+
+<p>讓我們從剛剛的猜數字遊戲開始 — 在這個版本中,我們將故意引入一些錯誤以便從中學習。前往 Github 下載一份 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">number-game-errors.html</a> (或運行線上版 <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">running live here</a>).</p>
+
+<ol>
+ <li>首先,在編輯器與瀏覽器分別開啟你剛下載檔案。</li>
+ <li>試著玩遊戲——你會注意到當你按下按鈕「Submit guess」時,它沒有任何反應!</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 你也許是想修復你自己寫的遊戲中的錯誤!這是件好事,但我們還是建議你在學習這篇文章時先使用我們的版本,這樣你才可以學到我們接下來要教的技巧。在這之後再回去修正你自己的遊戲也不遲!</p>
+</div>
+
+<p>現在,先讓我們來看看開發者主控台有沒有提示我們任何錯誤,然後試著修正他們。你會在接下來的段落中學到如何修正這些錯誤。</p>
+
+<h2 id="修復語法錯誤">修復語法錯誤</h2>
+
+<p>在前篇文章中我們讓你在 <a href="/zh-TW/docs/Learn/Common_questions/What_are_browser_developer_tools" rel="nofollow">開發者工具 JavaScript console</a> 中輸入了一些JavaScript 指令(如果你不記得怎麼打開這個東西,點選前面的連結複習一下)。更重要的是,主控台在瀏覽器的 JavaScript引擎讀取到有語法錯誤的 JavaScript 時會提示一些錯誤訊息。現在讓我們來看看:</p>
+
+<ol>
+ <li>切換到你開啟了 <code>number-game-errors.html</code> 的分頁,然後打開你的 JavaScript 主控台。你應該會看到如下的幾行錯誤訊息:<img alt="" src="https://mdn.mozillademos.org/files/13496/not-a-function.png" style="display: block; margin: 0 auto;"></li>
+ <li>這是一個非常容易追尋的錯誤,而且瀏覽器還給你了不少有用的資訊來幫助你(這張截圖是 Firefox 的,但其他瀏覽器也會提示相似的錯誤訊息)。從左到右,我們可以看到:
+ <ul>
+ <li>一個紅色的 "X" 代表這是一個錯誤訊息。</li>
+ <li>一條錯誤訊息提示你什麼東西出錯了:"TypeError: guessSubmit.addeventListener is not a function(TypeError: guessSubmit.addeventListener 並不是一個函式)"</li>
+ <li>一個 "Learn More" 連結連向一個解釋這個錯誤並包含大量詳細資訊的 MDN 頁面。</li>
+ <li>出錯的 JavaScript 檔案名稱,連結連向開發者工具的除錯器。點下這個連結,你就能看到出錯的那行程式被高亮顯示出來。</li>
+ <li>在該 JavaScript 檔案中錯誤的行號,還有錯誤發生在該行第幾個字元。在這個例子中,是第 86 行的第 3 個字元。</li>
+ </ul>
+ </li>
+ <li>如果我們在編輯器中檢視第 86 行,我們會看到:
+ <pre class="brush: js notranslate">guessSubmit.addeventListener('click', checkGuess);</pre>
+ </li>
+ <li>主控台提示的錯誤訊息寫著 "guessSubmit.addeventListener is not a function(guessSubmit.addeventListener 並不是一個函式)",所以我們大概是哪裡拼錯字了。如果你並不確定一個函式的正確名稱如何拼寫,打開 MDN 確認看看是個不錯的選擇。最佳做法是在你喜歡的搜尋引擎搜尋 "mdn <em>關鍵字</em>"。為了節省時間,這裡提供你一個捷徑:<code><a href="/zh-TW/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>。</li>
+ <li>回來看看這個頁面,我們明顯是把函式名稱給拼錯了!記住,JavaScript 是會區分大小寫的,所以任何些微的拼寫錯誤甚至是大小寫錯誤都會造成錯誤發生。把<code>addeventListener</code> 改成<code>addEventListener</code> 問題就解決了。現在將你的程式碼修正吧。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 看看這個 <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_function">TypeError: "x" is not a function</a> 連結來了解更多有關這類錯誤的資訊。</p>
+</div>
+
+<h3 id="語法錯誤:第二回合">語法錯誤:第二回合</h3>
+
+<ol>
+ <li>將你的頁面存檔並重整,你現在應該會看到剛剛的錯誤消失了。</li>
+ <li>現在試著輸入一個猜測並按下 Submit guess 按鈕,你會發現... 另一個錯誤!<img alt="" src="https://mdn.mozillademos.org/files/13498/variable-is-null.png" style="display: block; margin: 0 auto;"></li>
+ <li>這次的錯誤是 "TypeError: lowOrHi is null(TypeError: lowOrHi 為 null)",在第 78 行的位置。
+ <div class="note"><strong>Note</strong>: <code><a href="/zh-TW/docs/Glossary/Null">Null</a></code> 是一個特別的值,代表著「空」、「什麼都沒有」。<code>lowOrHi</code> 被宣告為一個變數,但並沒有被賦予任何有意義的值 — 他既沒有變數型態,也沒有值。</div>
+
+ <div class="note"><strong>Note</strong>: 這個錯誤並沒有在頁面載入完成後就發生,因為這個錯誤發生在一個函式中(在 <code>checkGuess() { ... }</code> 區塊中)。在之後詳細介紹函式的文章中,你會學到在函式中的程式碼與在函式外的程式碼其實是執行在不同範疇中的。在我們的這個情況裡,有錯誤的程式碼在 <code>checkGuess()</code> 在 86 行被執行前都並沒有執行,也因此錯誤並沒有在頁面一載入就發生。</div>
+ </li>
+ <li>看看第 78 行,你會看到:
+ <pre class="brush: js notranslate">lowOrHi.textContent = 'Last guess was too high!';</pre>
+ </li>
+ <li>這行試著將 <code>lowOrHi</code> 的 <code>textContent</code> 屬性設為一個字串。但是這行沒有執行成功,因為 <code>lowOrHi</code> 並沒有存著它應該要存著的值。讓我們來看看為什麼 — 試試在程式碼中搜尋其他 <code>lowOrHi</code> 有出現的地方。在第 48 行你會看到:
+ <pre class="brush: js notranslate">var lowOrHi = document.querySelector('lowOrHi');</pre>
+ </li>
+ <li>這行程式碼試著將一個 HTML 元素的參照存起來。讓我們檢查一下在這行程式碼執行後,變數中的值是否為 <code>null</code>。在第 49 行加上:
+ <pre class="brush: js notranslate">console.log(lowOrHi);</pre>
+
+ <div class="note">
+ <p><strong>Note</strong>: <code><a href="/zh-TW/docs/Web/API/Console/log">console.log()</a></code> 是一個非常好用的除錯功能,它能夠將值印出至主控台中。所以這行程式碼會在第 48 行賦值給 <code>lowOrHi</code> 後,將它的值印出至主控台中。</p>
+ </div>
+ </li>
+ <li>存檔並重整,你應該會在主控台中看到 <code>console.log()</code> 輸出的結果。<img alt="" src="https://mdn.mozillademos.org/files/13494/console-log-output.png" style="display: block; margin: 0 auto;">在這個時間點,<code>lowOrHi</code> 的值是 <code>null</code>。所以很明顯的,第 48 行一定出了什麼問題。</li>
+ <li>讓我們思考一下發生了什麼問題。第 48 行呼叫了 <code><a href="/zh-TW/docs/Web/API/Document/querySelector">document.querySelector()</a></code> 方法來透過 CSS 選擇器取得一個 HTML 元素參照。打開我們的網頁看看我們想要取得的段落元素:
+ <pre class="brush: js notranslate">&lt;p class="lowOrHi"&gt;&lt;/p&gt;</pre>
+ </li>
+ <li>所以我們需要的是一個開頭是小數點 (.) 的 class 選擇器,但傳進第48 行 <code>querySelector()</code> 方法的選擇器並沒有開頭的小數點。這也許就是問題所在了!試著將第 48 行的 <code>lowOrHi</code> 改成 <code>.lowOrHi</code>。</li>
+ <li>再次存檔並重整,你的 <code>console.log()</code> 現在應該會輸出我們想要的 <code>&lt;p&gt;</code> 元素了。呼!又修好了另一個錯誤!你現在可以把你的 <code>console.log()</code> 那行移除了,或是你想要留著之後查看 — 取決於你。</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: 看看這個 <a href="/zh-TW/docs/Web/JavaScript/Reference/Errors/Unexpected_type">TypeError: "x" is (not) "y"</a> 連結來了解更多有關這類錯誤的資訊。</p>
+</div>
+
+<h3 id="語法錯誤:第三回合">語法錯誤:第三回合</h3>
+
+<ol>
+ <li>現在如果你試著再次玩這個遊戲應該會相當順利,直到該讓遊戲結束的時機點才會發生錯誤:無論是猜對還是10次用完。</li>
+ <li>此時console提供錯誤訊息跟一開始一樣: "TypeError: resetButton.addeventListener is not a function"! 然而此次錯誤來自第94行。查看第94行後,我們可以輕易發現依舊是屬性大小寫問題,一樣把<code>addeventListener</code> 改成 <code>.addEventListener</code>就沒問題了。</li>
+</ol>
+
+<h2 id="邏輯錯誤">邏輯錯誤</h2>
+
+<p>到這邊為止遊戲應該可以進行得很順利,然而玩幾次下來無疑地你會發現「隨機」數字總是0或1,這可不是我們想要的!</p>
+
+<ol>
+ <li>搜尋位於44行的變數<code>randomNumber</code>,其內容是設定遊戲一開始的隨機數字:
+
+ <pre class="brush: js notranslate">var randomNumber = Math.floor(Math.random()) + 1;</pre>
+ </li>
+ <li>另一個開始新回合時產生隨機數字的變數則在113行左右:
+ <pre class="brush: js notranslate">randomNumber = Math.floor(Math.random()) + 1;</pre>
+ </li>
+ <li>為了測試問題是否出在這兩段程式碼,我們需要再次邀請<code>console.log()</code> 好朋友,將之分別放到44、113行的程式碼下一行:
+ <pre class="brush: js notranslate">console.log(randomNumber);</pre>
+ </li>
+ <li>儲存程式碼並更新頁面,然後再試玩幾次,你會看到<code>randomNumber</code> 在console中總是等於1,這就是問題所在。</li>
+</ol>
+
+<h3 id="修正小錯誤">修正小錯誤</h3>
+
+<p>為了修正這個錯誤,我們得先了解它是怎麼運作的。首先,我們呼叫<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a></code>以產生一個介於0到1的隨機小數,例如: 0.5675493843</p>
+
+<pre class="brush: js notranslate">Math.random()</pre>
+
+<p>接著,我們將<code>Math.random()</code> 產生的隨機小數傳進<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a></code>,函式會回傳小於等於所給數字的最大整數,然後為這個整數值加1:</p>
+
+<pre class="notranslate">Math.floor(Math.random()) + 1</pre>
+
+<p><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">由於</span></font><code>Math.floor</code>是無條件捨去取整數(地板值),所以一個介於0到1的隨機小數永遠只會得到0,幫這個小數加1的話又會永遠只得到1。所以進位前我們先幫隨機小數乘上100 ,如此一來我們就能得到介於0到99的隨機數字了:</p>
+
+<pre class="brush: js notranslate">Math.floor(Math.random()*100);</pre>
+
+<p>別忘了還要加上1,數字範圍才能成功介於1到100:</p>
+
+<pre class="brush: js notranslate">Math.floor(Math.random()*100) + 1;</pre>
+
+<p>試著自己動手更新這兩行程式碼吧,儲存並更新頁面後你應該能看到遊戲如預期般進行!</p>
+
+<h2 id="其他常見錯誤">其他常見錯誤</h2>
+
+<p>還有些初學者非常容易忽略的小問題,這小節讓我們來概覽一下:</p>
+
+<h3 id="語法錯誤:語句缺少「_」_(SyntaxError_missing_before_statement)">語法錯誤:語句缺少「 ; 」<br>
+ (SyntaxError: missing ; before statement)</h3>
+
+<p>這個錯誤是指每行程式碼結束時必須加上英文輸入法的分號<code>;</code>(請注意不要打成中文輸入法),分號被遺忘的錯誤有時不太容易發現,此外另舉一例:如果我們改動下方變數<code>checkGuess()</code> 中的程式碼:</p>
+
+<pre class="brush: js notranslate">var userGuess = Number(guessField.value);</pre>
+
+<p>改成</p>
+
+<pre class="brush: js notranslate">var userGuess === Number(guessField.value);</pre>
+
+<p>此時程式碼會回報錯誤,因為瀏覽器會認為你想設定不同的東西;我們需要確保自己沒有誤用、混用指派運算子(<code>=</code>):用於賦予變數值跟嚴格比較運算子(<code>===</code>):用於比較兩個值是否完全相等,並回覆<code>true</code>/<code>false</code>布林值。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 更多細節請參考右方關於<em>缺少分號的語法錯誤</em>文章頁面: <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_semicolon_before_statement">SyntaxError: missing ; before statement</a> 。</p>
+</div>
+
+<h3 id="無論輸入什麼,程序總是顯示「你贏了」">無論輸入什麼,程序總是顯示「你贏了」</h3>
+
+<p>還有另一種混用指派運算子(<code>=</code>)與嚴格比較運算子(<code>===</code>)的狀況,舉例如果我們將變數 <code>checkGuess()</code>中的嚴格比較運算子(<code>===</code>)</p>
+
+<pre class="brush: js notranslate">if (userGuess === randomNumber) {</pre>
+
+<p>改成指派運算子(<code>=</code>)</p>
+
+<pre class="brush: js notranslate">if (userGuess = randomNumber) {</pre>
+
+<p>這個檢查就失效了,程式會永遠回傳 <code>true</code>而勝利並結束遊戲。請小心!</p>
+
+<h3 id="語法錯誤:參數列表後面缺少「」_(SyntaxError_missing_after_argument_list)">語法錯誤:參數列表後面缺少「)」 <br>
+ (SyntaxError: missing ) after argument list)</h3>
+
+<p>給完函數或方法參數時別忘了放上<code>)</code>右括號(請注意不要打成中文輸入法)。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 更多細節請參考右方關於<em>缺少右括號的語法錯誤</em>文章頁面:<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_parenthesis_after_argument_list">SyntaxError: missing ) after argument list</a> 。</p>
+</div>
+
+<h3 id="語法錯誤:屬性ID後缺少「」_SyntaxError_missing_after_property_id">語法錯誤:屬性ID後缺少「:」<br>
+ SyntaxError: missing : after property id</h3>
+
+<p>This error usually relates to an incorrectly formed JavaScript object, but in this case we managed to get it by changing</p>
+
+<pre class="brush: js notranslate">function checkGuess() {</pre>
+
+<p>to</p>
+
+<pre class="brush: js notranslate">function checkGuess( {</pre>
+
+<p>This has caused the browser to think that we are trying to pass the contents of the function into the function as an argument. Be careful with those parentheses!</p>
+
+<h3 id="語法錯誤:「」缺少SyntaxError_missing_after_function_body">語法錯誤:「}」缺少SyntaxError: missing } after function body</h3>
+
+<p>This is easy — it generally means that you've missed one of your curly braces from a function or conditional structure. We got this error by deleting one of the closing curly braces near the bottom of the <code>checkGuess()</code> function.</p>
+
+<h3 id="SyntaxError_expected_expression_got_string_or_SyntaxError_unterminated_string_literal">SyntaxError: expected expression, got '<em>string</em>' or SyntaxError: unterminated string literal</h3>
+
+<p>These errors generally mean that you've missed off a string value's opening or closing quote mark. In the first error above, <em>string</em> would be replaced with the unexpected character(s) that the browser found instead of a quote mark at the start of a string. The second error means that the string has not been ended with a quote mark.</p>
+
+<p>For all of these errors, think about how we tackled the examples we looked at in the walkthrough. When an error arises, look at the line number you are given, go to that line and see if you can spot what's wrong. Bear in mind that the error is not necessarily going to be on that line, and also that the error might not be caused by the exact same problem we cited above!</p>
+
+<div class="note">
+<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token">SyntaxError: Unexpected token</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unterminated_string_literal">SyntaxError: unterminated string literal</a> reference pages for more details about these errors.</p>
+</div>
+
+<h2 id="小結">小結</h2>
+
+<p>So there we have it, the basics of figuring out errors in simple JavaScript programs. It won't always be that simple to work out what's wrong in your code, but at least this will save you a few hours of sleep and allow you to progress a bit faster when things don't turn out right earlier on in your learning journey.</p>
+
+<h2 id="See_also">See also</h2>
+
+<div>
+<ul>
+ <li>There are many other types of errors that aren't listed here; we are compiling a reference that explains what they mean in detail — see the <a href="/en-US/docs/Web/JavaScript/Reference/Errors">JavaScript error reference</a>.</li>
+ <li>If you come across any errors in your code that you aren't sure how to fix after reading this article, you can get help! Ask on the <a class="external external-icon" href="https://discourse.mozilla-community.org/t/learning-web-development-marking-guides-and-questions/16294">Learning Area Discourse thread</a>, or in the <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC channel on <a class="external external-icon" href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Tell us what your error is, and we'll try to help you. A listing of your code would be useful as well.</li>
+</ul>
+</div>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</p>
+
+<h2 id="在這個學習模組中">在這個學習模組中</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_is_JavaScript">什麼是JavaScript?</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/A_first_splash">初次接觸Javascript</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/What_went_wrong">什麼出錯了? JavaScript 的疑難排解(除錯)</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Variables">儲存你需要的資訊 — 變數</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Math">JavaScript 的基本運算— 數字 與 運算子</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Strings">處理文字 — JavaScript 的字串</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Useful_string_methods">有用的字串方法</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Arrays">陣列</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/First_steps/Silly_story_generator">附錄:笑話產生器</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/howto/index.html b/files/zh-tw/learn/javascript/howto/index.html
new file mode 100644
index 0000000000..5e5f7257c2
--- /dev/null
+++ b/files/zh-tw/learn/javascript/howto/index.html
@@ -0,0 +1,294 @@
+---
+title: JavaScript 解決常見的問題
+slug: Learn/JavaScript/Howto
+translation_of: Learn/JavaScript/Howto
+---
+<div>{{LearnSidebar}}<br>
+以下鏈接針對您需要修復的常見問題的解決方案,以便讓您的JavaScript語法正確執行。</div>
+
+<h2 id="初學者常見的錯誤"><strong>初學者常見的錯誤</strong></h2>
+
+<h3 id="糾正語法和代碼">糾正語法和代碼</h3>
+
+<p><br>
+  </p>
+
+<p>如果您的代碼毫無反映或瀏覽器反饋某些內容「未定義」,請檢查您是否「正確輸入」所有變量名稱,函數名稱等。</p>
+
+<p>以下的常見造成問題的內置瀏覽器功能比對:</p>
+
+<p> </p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col"><strong>正確</strong></th>
+ <th scope="col"><strong><span style="display: none;"> </span>錯誤<span style="display: none;"> </span></strong></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>getElementsByTagName()</code></td>
+ <td><code>getElementbyTagName()</code></td>
+ </tr>
+ <tr>
+ <td><code>getElementsByName()</code></td>
+ <td><code>getElementByName()</code></td>
+ </tr>
+ <tr>
+ <td><code>getElementsByClassName()</code></td>
+ <td><code>getElementByClassName()</code></td>
+ </tr>
+ <tr>
+ <td><code>getElementById()</code></td>
+ <td><code>getElementsById()</code></td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="分號位置">分號位置</h3>
+
+<p>You need to make sure you don't place any semi-colons incorrectly. For example:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Correct</th>
+ <th scope="col">Wrong</th>
+ </tr>
+ <tr>
+ <td><code>elem.style.color = 'red';</code></td>
+ <td><code>elem.style.color = 'red;'</code></td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="功能內容">功能內容</h3>
+
+<p>There are a number of things that can go wrong with functions.</p>
+
+<p>One of the most common errors is to declare the function, but not call it anywhere. For example:</p>
+
+<pre class="brush: js">function myFunction() {
+ alert('This is my function.');
+};</pre>
+
+<p>This code won't do anything unless you call it, for example with</p>
+
+<pre class="brush: js">myFunction();</pre>
+
+<h4 id="功能範圍"><strong>功能範圍</strong></h4>
+
+<p>Remember that <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">functions have their own scope</a> — you can't access a variable value set inside a function from outside the function, unless you declared the variable globally (i.e. not inside any functions), or <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">return the value</a> out of the function.</p>
+
+<h4 id="在return語句後執行語法">在return語句後執行語法</h4>
+
+<p>Remember also that when you return a value out of a function, the JavaScript interpreter exits the function — no code declared after the return statement will run.</p>
+
+<p>In fact, some browsers (like Firefox) will give you an error message in the developer console if you have code after a return statement. Firefox gives you "unreachable code after return statement".</p>
+
+<h3 id="對象表示法與正確的指派">對象表示法與正確的指派</h3>
+
+<p>When you assign something normally in JavaScript, you use a single equals sign, e.g.:</p>
+
+<pre class="brush: js">const myNumber = 0;</pre>
+
+<p>This doesn't work in <a href="/en-US/docs/Learn/JavaScript/Objects">Objects</a>, however — with objects you need to separate member names from their values using colons, and separate each member with a comma, for example:</p>
+
+<pre class="brush: js">const myObject = {
+ name: 'Chris',
+ age: 38
+}</pre>
+
+<h2 id="基本定義"><strong>基本定義</strong></h2>
+
+<div class="column-container">
+<div class="column-half">
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#A_high-level_definition">What is JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#What_is_a_variable">What is a variable?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">What are strings?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#What_is_an_Array">What is an array?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">What is a loop?</a></li>
+</ul>
+</div>
+
+<div class="column-half">
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">What is a function?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">What is an event?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">What is an object?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#No_really_what_is_JSON">What is JSON?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#What_are_APIs">What is a web API?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#The_document_object_model">What is the DOM?</a></li>
+</ul>
+</div>
+</div>
+
+<h2 id="基本使用例子">基本使用例子</h2>
+
+<div class="column-container">
+<div class="column-half">
+<h3 id="概括">概括</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#How_do_you_add_JavaScript_to_your_page">How do you add JavaScript to your page?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#Comments">How do you add comments to JavaScript code?</a></li>
+</ul>
+
+<h3 id="變量">變量</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Declaring_a_variable">How do you declare a variable?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Initializing_a_variable">How do you initialize a variable with a value?</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Updating_a_variable">How do you update a variable's value?</a> (also see <a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Assignment_operators">Assignment operators</a>)</li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Variable_types">What data types can values have in JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Loose_typing">What does 'loosely typed' mean?</a></li>
+</ul>
+
+<h3 id="數學運算">數學運算</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Types_of_numbers">What types of number do you have to deal with in web development?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Arithmetic_operators">How do you do basic math in JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Operator_precedence">What is operator precedence, and how is it handled in JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Increment_and_decrement_operators">How do you increment and decrement values in JavaScript?</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Math#Comparison_operators">How do you compare values in JavaScript?</a> (e.g. to see which one is bigger, or to see if one value is equal to another).</li>
+</ul>
+
+<h3 id="字串">字串</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Creating_a_string">How do you create a string in JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Single_quotes_versus_double_quotes">Do you have to use single quotes or double quotes?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Escaping_characters_in_a_string">How do you escape characters in strings?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">How do you join strings together?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">Can you join strings and numbers together?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_the_length_of_a_string">How do you find the length of a string?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">How you find what character is at a certain position in a string?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_a_substring_inside_a_string_and_extracting_it">How do you find and extract a specific substring from a string?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Changing_case">How do you change the case of a string?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Updating_parts_of_a_string">How do you replace one specific substring with another?</a></li>
+</ul>
+</div>
+
+<div class="column-half">
+<h3 id="序列">序列</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Creating_an_array">How do you create an array?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Accessing_and_modifying_array_items">How do you access and modify the items in an array?</a> (this includes multidimensional arrays)</li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Finding_the_length_of_an_array">How do you find the length of an array?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Adding_and_removing_array_items">How you add and remove array items?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Converting_between_strings_and_arrays">How do you split a string into array items, or join array items into a string?</a></li>
+</ul>
+
+<h3 id="Debugging_JavaScript">Debugging JavaScript</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Types_of_error">What are the basic types of error?</a></li>
+ <li><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools, and how do you access them?</a></li>
+ <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#The_Console_API">How do you log a value to the JavaScript console?</a></li>
+ <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_the_JavaScript_debugger">How do you use breakpoints, and other JavaScript debugging features?</a></li>
+</ul>
+
+<p>For more information on JavaScript debugging, see <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a>; also see <a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Other_common_errors">Other common errors</a> for a description of common errors.</p>
+
+<h3 id="Making_decisions_in_code">Making decisions in code</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">How do you execute different blocks of code, depending on a variable's value or other condition?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">How do you use if ...else statements?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Nesting_if_..._else">How do nest one decision block inside another?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Logical_operators_AND_OR_and_NOT">How do you use AND, OR, and NOT operators in JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements">How do you conveniently handle a large number of choices for one condition?</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Ternary_operator">How do you use a ternary operator to make a quick choice between two options based on a true or false test?</a></li>
+</ul>
+
+<h3 id="Loopingiteration">Looping/iteration</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">How do you run the same bit of code over and over again?</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Exiting_loops_with_break">How do you exit a loop before the end if a certain condition is met?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Skipping_iterations_with_continue">How do you skip to the next iteration of a loop if a certain condition is met?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">How do you use while and do ... while loops?</a></li>
+ <li>How to iterate over the elements in an array</li>
+ <li>How to iterate over the elements in a multidimensional array</li>
+ <li>How to iterate over the members in an object</li>
+ <li>How to iterate over the members of an object nested inside an array</li>
+</ul>
+</div>
+</div>
+
+<h2 id="進階使用例子">進階使用例子</h2>
+
+<div class="column-container">
+<div class="column-half">
+<h3 id="Functions">Functions</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Built-in_browser_functions">How do you find functions in the browser?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Functions_versus_methods">What is the difference between a function and a method?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">How do you create your own functions?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Invoking_functions">How do you run (call, or invoke) a function?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Anonymous_functions">What is an anonymous function?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_parameters">How do you specify parameters (or arguments) when invoking a function?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">What is function scope?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">What are return values, and how do you use them?</a></li>
+</ul>
+
+<h3 id="對向">對向</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">How do you create an object?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Dot_notation">What is dot notation?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation">What is bracket notation?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Setting_object_members">How do you get and set the methods and properties of an object?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#What_is_this">What is <code>this</code>, in the context of an object?</a></li>
+ <li><a href="/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">What is object-oriented programming?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances">What are constructors and instances, and how do you create them?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Other_ways_to_create_object_instances">What different ways are there to create objects in JavaScript?</a></li>
+</ul>
+
+<h3 id="JSON">JSON</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#JSON_structure">How do you structure JSON data, and read it from JavaScript?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Loading_our_JSON">How can you load a JSON file into a page?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Converting_between_objects_and_text">How do you convert a JSON object to a text string, and back again?</a></li>
+</ul>
+</div>
+
+<div class="column-half">
+<h3 id="任務">任務</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_handler_properties">What are event handlers and how do you use them?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_%E2%80%94_don%27t_use_these">What are inline event handlers?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#addEventListener()_and_removeEventListener()">What does the <code>addEventListener()</code> function do, and how do you use it?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#What_mechanism_should_I_use">Which mechanism should I use to add event code to my web pages?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_objects">What are event objects, and how do you use them?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Preventing_default_behaviour">How do you prevent default event behaviour?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture">How do events fire on nested elements? (event propagation, also related — event bubbling and capturing)</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation">What is event delegation, and how does it work?</a></li>
+</ul>
+
+<h3 id="Object-oriented_JavaScript">Object-oriented JavaScript</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">What are object prototypes?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#The_constructor_property">What is the constructor property, and how can you use it?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#Modifying_prototypes">How do you add methods to the constructor?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">How do you create a new constructor that inherits its members from a parent constructor?</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#Object_member_summary">When should you use inheritance in JavaScript?</a></li>
+</ul>
+
+<h3 id="網頁Web_APIs">網頁Web APIs</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#Active_learning_Basic_DOM_manipulation">How do you manipulate the DOM (e.g. adding or removing elements) using JavaScript?</a></li>
+</ul>
+
+<p> </p>
+</div>
+</div>
diff --git a/files/zh-tw/learn/javascript/index.html b/files/zh-tw/learn/javascript/index.html
new file mode 100644
index 0000000000..17fed115be
--- /dev/null
+++ b/files/zh-tw/learn/javascript/index.html
@@ -0,0 +1,71 @@
+---
+title: JavaScript — 動態的客戶端指令
+slug: Learn/JavaScript
+tags:
+ - Beginner
+ - CodingScripting
+ - JavaScript
+ - Landing
+ - NeedsTranslation
+ - Topic
+ - TopicStub
+ - 初學者
+translation_of: Learn/JavaScript
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">{{Glossary("JavaScript")}} 程式語言可讓你在網頁上建構複雜的事物。當網頁不僅僅呆板呈現給你靜態的內容(像是即時的內容更新,互動式地圖、2D/3D 動畫、滑鼠操控影片播放…等等),你可以大膽猜測 JavaScript 已經參與其中。</p>
+
+<h2 id="學習途徑">學習途徑</h2>
+
+<p>JavaScript 相較於 <a href="/zh-TW/docs/Learn/HTML">HTML</a> 和 <a href="/zh-TW/docs/Learn/CSS">CSS</a> 這些技術可以說比較困難。開始嘗試學習 JavaScript 之前,強烈建議你起碼先熟悉上述兩項技術,或者了解其它的更好。可以透過以下單元開始:</p>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Getting_started_with_the_web">入門認識 Web</a></li>
+ <li><a href="/zh-TW/docs/Learn/HTML/Introduction_to_HTML">HTML 簡介</a>.</li>
+ <li><a href="/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 簡介</a>.</li>
+</ul>
+
+<p>若你之前有其他程式語言的撰寫經驗,也許會有幫助。</p>
+
+<p>當熟悉 JavaScript 的基本知識之後,你應該進入一些更進階的主題,像是:</p>
+
+<ul>
+ <li>深入 JavaScript,像是 <a href="/zh-TW/docs/Web/JavaScript/Guide">JavaScript 指南</a></li>
+ <li><a href="/zh-TW/docs/Web/API">Web <u>APIs</u></a></li>
+</ul>
+
+<h2 id="單元">單元</h2>
+
+<p>本主題涵蓋許多單元,建議你依下列順序閱讀。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/First_steps">JavaScript 初探</a></dt>
+ <dd>在我們的第一個 JavaScript 單元,在帶你初次實際撰寫 JavaScript 程式之前,我們先回答幾個基本的問題,像是「什麼是 JavaScript?」、「它看起來是什麼樣子?」、「它能做些什麼?」。接著,我們深入地討論幾個 JavaScript 關鍵的組成元素,例如:變數、字串、數字、陣列。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">JavaScript 構成元素</a></dt>
+ <dd>在這個單元,我們繼續含蓋 JavaScript 關鍵的基本元素,把焦點放在常見程式碼區塊的類型,像是條件陳述式、迴圈、函數以及事件。你已經在這個課程中看過這些東西,但只是匆匆一瞥,在這裡我們會明確地討論。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects">JavaScript 物件介紹</a></dt>
+ <dd>在 JavaScript 程式語言,絕大部分的東西都是物件,從核心的 JavaScript 元素像是字串(string)和陣列(array)到基於 JavaScript 建構的瀏覽器 API 都是。你甚至可以建立自己的物件,將相關的變數與函數封裝成能有效率操作的集合體。如果你想更深入了解這門程式語言的知識,並撰寫出更有效率的程式碼,了解 JavaScript 物件導向的本質是重要的,因此我們準備這個單元來幫助你。這裡我們教詳細的物件理論與語法,看看要如何建自你自己的物件,以及說明什麼是 JSON 資料和怎麼使用它。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous">非同步的 JavaScript</a></dt>
+ <dd>這個單元我們來討論非同步的 JavaScript,它為什麼重要,以及它能如何有效處理像是由伺服器抓取資料這種阻塞性操作(它會造成網頁停頓)。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Client-side_web_APIs">用戶端的 web API</a></dt>
+ <dd>當你走在用 JavaScript 撰寫用戶端程式,來建構網站或應用程式的路上,不利用 API 很難走很遠,介接在操控瀏覽器、作業系統的不同功能,或是接收來自其它網站、服務的資料。在這個單元中,我們將討索什麼是 API ,以及如何使用幾個在你開發過程中,十分頻繁被使用到的 API 。</dd>
+ <dt>
+ <h2 id="解決常見的_JavaScript_問題">解決常見的 JavaScript 問題</h2>
+
+ <p>在你寫網頁時,可參閱〈<a href="/zh-TW/docs/Learn/JavaScript/Howto">透過 JavaScript 解決常見的問題</a>〉內所提供的連結,解決許多常見問題。</p>
+ </dt>
+</dl>
+
+<h2 id="參考資源">參考資源</h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript on MDN</a></dt>
+ <dd>MDN 上連結到各篇 JavaScript 核心文件的主要,在這裡你可以找到關於 JavaScript 程式語言各方面廣泛的參考文件,還有一些進階的指引幫助你成為熟練的 JavaScript 使用者。</dd>
+ <dt><a href="https://learnjavascript.online/">Learn JavaScript</a></dt>
+ <dd>對於想成為網站開發者一個很好的資源,以互動的方式學習 JavaScript ,包含短課程、互動測驗,自動評估狀況給予指引。前 40 堂課是免費,完整的課程可以在一次付費買下。</dd>
+ <dt><a href="https://exlskills.com/learn-en/courses/javascript-fundamentals-basics_javascript">JavaScript Fundamentals on EXLskills</a></dt>
+ <dd>在免費的 EXLskills 開源課程中,介紹給你所有開始建構 JavaScript 應用程式所需要的東西。</dd>
+ <dt><a href="https://www.youtube.com/user/codingmath">Coding math</a></dt>
+ <dd>一系列優質的教學影片,教你需要了解哪些數學知識,來讓你成為有效率的程式設計師。(作者:<a href="https://twitter.com/bit101">Keith Peters</a>)</dd>
+</dl>
diff --git a/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html b/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html
new file mode 100644
index 0000000000..33cb338c8d
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/adding_bouncing_balls_features/index.html
@@ -0,0 +1,184 @@
+---
+title: 為彈跳彩球添增其他功能
+slug: Learn/JavaScript/Objects/Adding_bouncing_balls_features
+translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">在本文中,你將繼續使用前一篇文章的彈跳彩球展示程式,另外加入幾項有趣的新功能。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必備條件:</th>
+ <td>在開始本文所提的實作之前,應先看過先前的相關文章。</td>
+ </tr>
+ <tr>
+ <th scope="row">要點:</th>
+ <td>測試 JavaScript 物件與 OO 架構的完整性。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="開始">開始</h2>
+
+<p>在開始之前,請先複製先前文章所提供的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index-finished.html">index-finished.html</a>、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a>、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">main-finished.js</a> 等檔案,儲存於本端磁碟的新資料夾中。</p>
+
+<div class="note">
+<p><strong>注意:</strong>你也可透過如 <a class="external external-icon" href="http://jsbin.com/">JSBin</a> 或 <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> 等網站進行此一實作。你可將 HTML、CSS、JavaScript 貼入相關線上編輯器之一。如果你所用的線上編輯器並未提供獨立的 JavaScript/CSS 面板,則可將之放入 HTML 頁面內的行內 <code>&lt;script&gt;</code>/<code>&lt;style&gt;</code> 元素中。</p>
+</div>
+
+<h2 id="專案簡介">專案簡介</h2>
+
+<p>彈跳彩球很有趣,但接著我們要加入使用者可控制的「邪惡圈」,在碰到彩球之後隨即吃掉彩球,添加更多互動性。也希望透過邪惡圈與彩球所繼承的通用 <code>Shape()</code> 物件,測試你的物件技術。最後還要加上計分功能,顯示尚未吃掉的彩球數量。</p>
+
+<p>下方擷圖則讓你了解最終成品的樣子:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13875/bouncing-evil-circle.png" style="display: block; margin: 0 auto;"></p>
+
+<ul>
+</ul>
+
+<p>可先參考<a href="http://mdn.github.io/learning-area/javascript/oojs/assessment/">完成範例</a>讓心裡有個底 (別偷看原始碼啊!)</p>
+
+<h2 id="須進行的步驟">須進行的步驟</h2>
+
+<p>下列段落將逐步說明。</p>
+
+<h3 id="建立新物件">建立新物件</h3>
+
+<p>首先將現有的 <code>Ball()</code> 建構子變更為 <code>Shape()</code> 建構子,以及新的 <code>Ball()</code> 建構子:</p>
+
+<ol>
+ <li><code>Shape()</code> 建構子對 <code>x</code>、<code>y</code>、<code>velX</code>、<code>velY</code> 屬性的定義方式,就如同 <code>Ball()</code> 建構子所用的方式。</li>
+ <li>另須定義新的 <code>exists</code> 屬性,用以追蹤球體是否存在於程式之中 (也就是尚未遭邪惡圈所吃掉)。此屬性必為布林值 (Boolean),初始值為 <code>true</code>。</li>
+ <li><code>Ball()</code> 建構子應從 <code>Shape()</code> 建構子繼承 <code>x</code>、<code>y</code>、<code>velX</code>、<code>velY</code>、<code>exists</code> 等屬性。另必須將這些屬性定義為參數以利呼叫之。</li>
+ <li>必須定義 <code>color</code> 與 <code>size</code> 屬性各 1 組,且由於兩者均來自於原始的 <code>Ball()</code> 建構子之中,所以剛開始的隨機值亦須相同。</li>
+ <li>記得應正確設定 <code>Ball()</code> 建構子的 <code>prototype</code> 與 <code>constructor</code>。</li>
+</ol>
+
+<p>彩球的 <code>draw()</code>、<code>update()</code>、<code>collisionDetect()</code> 函式定義,均與之前完全相同。</p>
+
+<p>到此為止可重新載入程式碼,搭配重新設計的物件也應該運作無誤。</p>
+
+<h3 id="定義_EvilCircle()">定義 EvilCircle()</h3>
+
+<p>再來見見這個壞蛋 — <code>EvilCircle()</code>!這個遊戲要加入 1 個會吃球的邪惡圈,而且要透過繼承自 <code>Shape()</code> 的建構子來定義這個邪惡圈。你可能也想添增另個讓第二個玩家控制的圈圈,或許多加幾個由電腦控制的邪惡圈。當然,光一個邪惡圈並無法統治世界,但可為此遊戲增添不少樂趣。</p>
+
+<p><code>EvilCircle()</code> 建構子應繼承 <code>Shape()</code> 的 <code>x、</code><code>y、</code><code>exists。</code></p>
+
+<p>亦可定義自有的屬性如下:</p>
+
+<ul>
+ <li><code>color</code> — <code>'white'</code></li>
+ <li><code>size</code> — <code>10</code></li>
+ <li><code>velX</code> — <code>20</code></li>
+ <li><code>velY</code> — <code>20</code></li>
+</ul>
+
+<p>再次提醒,請記得要將所繼承的屬性在建構子中定義為參數,並應正確設定 <code>prototype</code> 與 <code>constructor</code> 屬性。</p>
+
+<h3 id="定義_EvilCircle()_的函式">定義 EvilCircle() 的函式</h3>
+
+<p><code>EvilCircle()</code> 應具備 4 個函式,如下:</p>
+
+<h4 id="draw()"><code>draw()</code></h4>
+
+<p>此函式的功能與 <code>Ball()</code> 的 <code>draw()</code> 函式相同,就是在 canvas 上繪製物件實體;且運作的方式也類似,所以你可以複製 <code>Ball.prototype.draw</code> 定義來開始。接著要完成下列改變:</p>
+
+<ul>
+ <li>我們要空心的邪惡圈,但不只是單純實心黑線畫成的圓而已 (要有邊框)。只要將 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> 與 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code> 更新成 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle">strokeStyle</a></code> 與 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/stroke">stroke()</a></code> 即可辦到。</li>
+ <li>還可以讓邊框更粗一點,有助你更容易看到邪惡圈。只要在 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code> 呼叫之後的某個地方設定 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth">lineWidth</a></code> 的值 (「3」就可以) 即可。</li>
+</ul>
+
+<h4 id="checkBounds()"><code>checkBounds()</code></h4>
+
+<p>此函式功能就與 <code>Ball()</code> 的 <code>update()</code> 函式第一部分相同,負責邪惡圈是否跳出螢幕邊界之外並適時阻止。同樣的,你還是可以複製 <code>Ball.prototype.update</code> 定義來用,但須更改下列:</p>
+
+<ul>
+ <li>Get rid of the last two lines — we don't want to automatically update the evil circle's position on every frame, because we will be moving it in some other way, as you'll see below.</li>
+ <li>Inside the <code>if()</code> statements, if the tests return true we don't want to update <code>velX</code>/<code>velY</code>; we want to instead change the value of <code>x</code>/<code>y</code> so the evil circle is bounced back onto the screen slightly. Adding or subtracting (as appropriate) the evil circle's <code>size</code> property would make sense.</li>
+</ul>
+
+<h4 id="setControls()"><code>setControls()</code></h4>
+
+<p>This method will add an <code>onkeydown</code> event listener to the <code>window</code> object so that when certain keyboard keys are pressed, we can move the evil circle around. The following code block should be put inside the method definition:</p>
+
+<pre class="brush: js">var _this = this;
+window.onkeydown = function(e) {
+ if(e.keyCode === 65) {
+ _this.x -= _this.velX;
+ } else if(e.keyCode === 68) {
+ _this.x += _this.velX;
+ } else if(e.keyCode === 87) {
+ _this.y -= _this.velY;
+ } else if(e.keyCode === 83) {
+ _this.y += _this.velY;
+ }
+ }</pre>
+
+<p>So when a key is pressed, the event object's <a href="/en-US/docs/Web/API/KeyboardEvent/keyCode">keyCode</a> property is consulted to see which key is pressed. If it is one of the four represented by the specified keycodes, then the evil circle will move left/right/up/down.</p>
+
+<ul>
+ <li>For a bonus point, let us know which keys the specified keycodes map to.</li>
+ <li>For another bonus point, can you tell us why we've had to set <code>var _this = this;</code> in the position it is in? It is something to do with function scope.</li>
+</ul>
+
+<h4 id="collisionDetect()"><code>collisionDetect()</code></h4>
+
+<p>This method will act in a very similar way to <code>Ball()</code>'s <code>collisionDetect()</code> method, so you can use a copy of that as the basis of this new method. But there are a couple of differences:</p>
+
+<ul>
+ <li>In the outer <code>if</code> statement, you no longer need to check whether the current ball in the iteration is the same as the ball that is doing the checking — because it is not longer a ball, it is the evil circle! Instead, you need to do a test to see if the ball being checked exists (with which property could you do this with?). If it doesn't exist, it has already been eaten by the evil circle, so there is no need to check it again.</li>
+ <li>In the inner <code>if</code> statement, you no longer want to make the objects change color when a collision is detected — instead, you want to set any balls that collide with the evil circle to not exist any more (again, how do you think you'd do that?).</li>
+</ul>
+
+<h3 id="Bringing_the_evil_circle_into_the_program">Bringing the evil circle into the program</h3>
+
+<p>Now we've defined the evil circle, we need to actually make it appear in our scene. To do this, you need to make some changes to the <code>loop()</code> function.</p>
+
+<ul>
+ <li>First of all, create a new evil circle object instance, then call its <code>setControls()</code> method. You only need to do these two things once, not on every iteration of the loop.</li>
+ <li>At the point where you loop through every ball and call the <code>draw()</code>, <code>update()</code>, and <code>collisionDetect()</code> functions for each one, make it so that these functions are only called if the current ball exists.</li>
+ <li>Call the evil ball instance's <code>draw()</code>, <code>checkBounds()</code>, and <code>collisionDetect()</code> methods on every iteration of the loop.</li>
+</ul>
+
+<h3 id="Implementing_the_score_counter">Implementing the score counter</h3>
+
+<p>To implement the score counter, follow the following steps:</p>
+
+<ol>
+ <li>In your HTML file, add a {{HTMLElement("p")}} element just below the {{HTMLElement("h1")}} element containing the text "Ball count: ".</li>
+ <li>In your CSS file, add the following rule at the bottom:
+ <pre class="brush: css">p {
+ position: absolute;
+ margin: 0;
+ top: 35px;
+ right: 5px;
+ color: #aaa;
+}</pre>
+ </li>
+ <li>In your JavaScript, make the following updates:
+ <ul>
+ <li>Create a variable that stores a reference to the paragraph.</li>
+ <li>Keep a count of the number of balls on screen in some way.</li>
+ <li>Increment the count and display the updated number of balls each time a ball is added to the scene.</li>
+ <li>Decrement the count and display the updated number of balls each time the evil circle eats a ball (causes it not to exist).</li>
+ </ul>
+ </li>
+</ol>
+
+<h2 id="Hints_and_tips">Hints and tips</h2>
+
+<ul>
+ <li>This assessment is quite challenging. Take each step slowly and carefully.</li>
+ <li>It might be an idea to keep a separate copy of the demo after you get each stage working, so you can refer back to it if you find yourself in trouble later on.</li>
+</ul>
+
+<h2 id="交作業">交作業</h2>
+
+<p>如果你是在某個課堂上操作這份作業,那麼請將成品交給您的老師 / 助教;如果您是自學者,在我們的<a href="https://discourse.mozilla-community.org/t/learning-web-development-marking-guides-and-questions/16294">專屬討論區</a>或 <a href="https://wiki.mozilla.org/IRC">Mozilla IRC </a>上的 <a href="irc://irc.mozilla.org/mdn">#mdn</a> 頻道都可以很輕鬆地找到人給予指教。記得先認真做一下習題,要怎麼收獲先那麼栽呀!</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/javascript/objects/basics/index.html b/files/zh-tw/learn/javascript/objects/basics/index.html
new file mode 100644
index 0000000000..3b70536656
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/basics/index.html
@@ -0,0 +1,243 @@
+---
+title: JavaScript 物件基礎概念
+slug: Learn/JavaScript/Objects/Basics
+translation_of: Learn/JavaScript/Objects/Basics
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">第一篇談到 JavaScript 物件的文章中,我們了解到基本的 JavaScript 物件語法,複習了某些先前提過的 JavaScript 功能,也再次強調你現正使用中的許多功能其實就是物件。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必要條件:</th>
+ <td>基本的電腦素養、對 HTML 與 CSS 已有初步認識、熟悉 JavaScript 基本概念 (參閱〈<a href="/zh-TW/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉)。</td>
+ </tr>
+ <tr>
+ <th scope="row">主旨:</th>
+ <td>了解「物件導向 (OO)」程式設計背後的基礎理論、其與 JavaScript (多屬於物件) 之間的關係、該如何使用 JavaScript 物件進行開發。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="物件基礎概念">物件基礎概念</h2>
+
+<p>物件是一批相關的數據以及/或者功能(通常包含了幾個變數及函式 — 當它們包含在物件中時被稱做「屬性」(properties)或「函式」(methods)),讓我們用一個範例來看看物件的長相。</p>
+
+<p>在開始之前,請先複製一份 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 檔案到你自己的本端硬碟中。此檔案內容物不多,就 1 組 {{HTMLElement("script")}} 元素可寫入我們的原始碼;在繪製頁面時,1 組元素可輸入簡易指令;幾個變數定義;1 組函式可針對輸入至 input 的程式碼,將之輸出到 {{HTMLElement("p")}} 元素。我們將透過此檔案說明基礎的物件語法。</p>
+
+<p>JavaScript 內的大多數東西,均是透過定義並初始設定變數來建立物件。</p>
+
+<p>現在, 請在自己的 oojs.html 檔案中、JavaScript 程式碼中加入下列程式碼,接著儲存並重新整理:</p>
+
+<pre class="brush: js">var person = {};</pre>
+
+<p>然後在瀏覽器中開啟 oojs.html, 再打開瀏覽器的開發者工具, 在 JavaScript 的控制台下, 輸入<code>person</code>, 並按下 Enter 鈕,就會得到下列結果:</p>
+
+<pre class="brush: js">[object Object]</pre>
+
+<p>恭喜, 你已經建立了自己的第一個物件。但這仍是空的物件,所以能做的事不多。接下來, 再如下所示, 幫 person 物件更新內容:</p>
+
+<pre class="brush: js">var person = {
+ name : ['Bob', 'Smith'],
+ age : 32,
+ gender : 'male',
+ interests : ['music', 'skiing'],
+ bio : function() {
+ alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
+ },
+ greeting: function() {
+ alert('Hi! I\'m ' + this.name[0] + '.');
+ }
+};
+</pre>
+
+<p>改完後同樣儲存 oojs.html、重新整理瀏覽器之後,再到控制台輸入 person, 將會看到新的結果:</p>
+
+<pre class="brush: js">person.name[0]
+person.age
+person.interests[1]
+person.bio()
+person.greeting()</pre>
+
+<p>現在你的物件裡面已經有了某些資料與功能,而且能透過某些簡易語法存取之。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法完成上述步驟,可先和我們的版本比較一下。參閱 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> (或觀看 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">實際執行</a>)。你最容易犯下的錯誤是在物件中的最後一個成員 (member)末端加上逗號,如此就會造成錯誤。</p>
+</div>
+
+<p>目前為止發生了什麼事呢?現在這個物件是由多個成員所構成,各個成員均有 1 個名稱 (如上述的 <code>name</code> 與 <code>age</code>) 以及 1 組數值 (如 <code>['Bob', 'Smith']</code> 與 <code>32</code>)。由名稱與數值構成的組合均以逗號區隔,而名稱與數值之間則以冒號隔開。語法應如下所示:</p>
+
+<pre class="brush: js">var objectName = {
+ member1Name : member1Value,
+ member2Name : member2Value,
+ member3Name : member3Value
+}</pre>
+
+<p>物件成員的數值可能是任何東西,像上述的範例物件就有 1 組字串、1 組數字、2 個陣列、2 組函式。前 4 組項目均為資料項目,可說是該物件的<strong>屬性</strong>。最後 2 組項目的功能則是用以指定物件對該筆資料所應進行的作業,可說是物件的<strong>函式 (Method)</strong>。</p>
+
+<p>類似這種物件即稱為「<strong>實字物件 (Object literal)</strong>」,按照字面上的意思寫出物件內容;與其相對的就是根據「類別」做出的物件實體。我們稍後會再說明。</p>
+
+<p>在傳送一系列結構化的相關資料項目時 (例如傳送請求至伺服器並置入資料庫中),就常常會透過實字物件的方式建立物件。另與「分別傳送多個項目」相較,送出單一物件當然效率更高,且當你想根據名稱找出各個項目時,更易於搭配陣列。</p>
+
+<h2 id="點記法_(Dot_notation)">點記法 (Dot notation)</h2>
+
+<p>你可透過點記法 (Dot notation) 存取物件的屬性與函式。物件名稱 (這裡是 person) 作為<strong>命名空間 (Namespace)</strong> —為了能存取物件所<strong>封裝</strong>的所有東西,這也是必須首先輸入的項目。接著你寫一個「點」以及你所想存取的項目,可能是簡單屬性的名稱、陣列屬性的項目,又或是針對物件函式之一的呼叫。舉例來說:</p>
+
+<pre class="brush: js">person.age
+person.interests[1]
+person.bio()</pre>
+
+<h3 id="子命名空間">子命名空間</h3>
+
+<p>甚至可以將物件成員的數值轉為另一個物件。舉例來說,你可將名稱成員從</p>
+
+<pre class="brush: js">name : ['Bob', 'Smith'],</pre>
+
+<p>改變為</p>
+
+<pre class="brush: js">name : {
+ first : 'Bob',
+ last : 'Smith'
+},</pre>
+
+<p>我們這裡以極高效率建立了子命名空間。看起來複雜但其實不然。若要存取這些項目,你只要透過另一個點,將 onto the end 的額外步驟串連起來即可。如下所示:</p>
+
+<pre class="brush: js">person.name.first
+person.name.last</pre>
+
+<p><strong>重要:</strong>現在你必須看過自己的函式碼,將實例</p>
+
+<pre class="brush: js">name[0]
+name[1]</pre>
+
+<p>改變為</p>
+
+<pre class="brush: js">name.first
+name.last</pre>
+
+<p>否則你的函式就不能運作了。</p>
+
+<h2 id="括弧記法_(Bracket_notation)">括弧記法 (Bracket notation)</h2>
+
+<p>括弧記法 (Bracket notation) 是另個存取物件屬性的方法。之前的:</p>
+
+<pre class="brush: js">person.age
+person.name.first</pre>
+
+<p>可寫成</p>
+
+<pre class="brush: js">person['age']
+person['name']['first']</pre>
+
+<p>這很像在陣列中存取項目的方法。其實基本上是一樣的東西 ─ 但前者是透過指數  (index number) 選擇項目;括弧記法則是透過各成員數值相關的名稱來選擇項目。因此物件有時亦稱作<strong>「相聯陣列 (Associative array)」</strong>;也就是說,其「將字串對應到數值」的方式,與陣列「將數字對應到數值」的方式相同。</p>
+
+<h2 id="設定物件成員">設定物件成員</h2>
+
+<p>到目前為止,我們只說明了檢索 (或<strong>取得</strong>) 物件成員。你也可以簡單宣告你所要設定的成員 (用點或括弧記法均可),設定 (<strong>更新</strong>) 物件成員的數值,如下:</p>
+
+<pre class="brush: js">person.age = 45
+person['name']['last'] = 'Cratchit'</pre>
+
+<p>試著輸入下列程式碼,再次取得成員之後看看變更的結果:</p>
+
+<pre class="brush: js">person.age
+person['name']['last']</pre>
+
+<p>設定成員不只是更新現有屬性與函式的數值,也可以建立全新的成員,如下:</p>
+
+<pre class="brush: js">person['eyes'] = 'hazel'
+person.farewell = function() { alert("Bye everybody!") }</pre>
+
+<p>現在可以測試自己的新成員了:</p>
+
+<pre class="brush: js">person['eyes']
+person.farewell()</pre>
+
+<p>此外,括弧記法不僅可動態設定成員數值,亦可設定成員名稱。假設使用者可在自己的人事資料中儲存自訂的數值類型,例如鍵入成員名稱與數值為 2 組文字輸入項,就會類似:</p>
+
+<pre class="brush: js">var myDataName = nameInput.value
+var myDataValue = nameValue.value</pre>
+
+<p>接著可將此新的成員名稱與數值加進 <code>person</code> 這個物件:</p>
+
+<pre class="brush: js">person[myDataName] = myDataValue</pre>
+
+<p>若要測試,可將下列程式碼加進自己的程式碼,加在宣告玩 <code>person</code> 物件的大括號後:</p>
+
+<pre class="brush: js">var myDataName = 'height'
+var myDataValue = '1.75m'
+person[myDataName] = myDataValue</pre>
+
+<p>現在儲存並重新整理,將下列輸入你的文字輸入項中:</p>
+
+<pre class="brush: js">person.height</pre>
+
+<p>因為點記法只接受字母表示的成員名稱,不能是指向名稱的變數值,所以並無法使用。</p>
+
+<h2 id="這個「this」是什麼?">這個「this」是什麼?</h2>
+
+<p>你可能注意到我們函式有怪怪的地方。看看以下範例:</p>
+
+<pre class="brush: js">greeting: function() {
+ alert('Hi! I\'m ' + this.name.first + '.');
+}</pre>
+
+<p>你可能會想這個「this」是幹嘛用的。「this」是指目前寫入程式碼的物件;所以此範例的 <code>this </code>就等於 <code>person</code>。那又為何不寫 <code>person</code> 就好呢?如同你在〈<a href="/zh-TW/docs/Learn/JavaScript/Objects/Object-oriented_JS">初學者的物件導向 JavaScript</a>〉一文中所看過的,當我們開始設定建構子等東西時,有用的「<code>this</code>」就可在成員內文改變時 (例如 2 個不同 <code>person</code> 物件實例可能具備不同的名稱,但打招呼時仍要使用自己的名稱),確保仍使用了正確的值。</p>
+
+<p>先用簡化的一對 person 物件說明:</p>
+
+<pre class="brush: js">var person1 = {
+ name : 'Chris',
+ greeting: function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+}
+
+var person2 = {
+ name : 'Brian',
+ greeting: function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+}</pre>
+
+<p>此範例中的函式碼雖然完全一樣,但 <code>person1.greeting()</code> 將輸出「Hi! I'm Chris.」;<code>person2.greeting()</code> 則會呈現「Hi! I'm Brian.」。如我們剛剛說過的,「<code>this」等於「已於內部放置程式碼」的物件</code>。如果你是依字面意義寫出物件,那可能沒什麼感覺,但如果你是用動態方式產生物件 (例如使用建構子) 的話,就能明顯感覺到方便之處了。再看下去你更清楚原因。</p>
+
+<h2 id="其實你一直在使用物件">其實你一直在使用物件</h2>
+
+<p>隨著你看完這些範例,你應該會覺得跟自己使用的點記法很類似。這是因為你整個課程都在使用點記法。每次我們透過內建的瀏覽器 API 或 JavaScript 物件寫出範例時,我們就是在用物件;因為這些功能也就是以本文提及完全相同的物件結構所寫成。即便是更複雜的範例也是一樣。</p>
+
+<p>所以當你使用字串函式如下:</p>
+
+<pre class="brush: js">myString.split(',');</pre>
+
+<p>你就是在使用 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> 類別實例可用的方法。每次只要你在程式碼中建立字串,該字串就會自動建立成為 <code>String</code> 的實例,並具備有多個常見的方法與屬性。</p>
+
+<p>若你透過下列程式碼存取文件物件模型 (DOM):</p>
+
+<pre class="brush: js">var myDiv = document.createElement('div');
+var myVideo = document.querySelector('video');</pre>
+
+<p>你也就在使用 <code><a href="/zh-TW/docs/Web/API/Document">Document</a></code> 類別實例上的函式。當載入網頁時,就會建立 <code>Document</code> 的實例,亦所謂的 <code>document</code>,將呈現整個網頁的架構、內容,以及其他功能 (如網址)。同樣的,這代表其上已有多個常見的函式\屬性。</p>
+
+<p>同理可證,目前你在使用的許多物件\API (如 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code><code>、<a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> 等) 也都是類似情形。</p>
+
+<p>另該注意的是,內建的物件\API 不見得會自動建立物件實例。像以 <a href="/zh-TW/docs/Web/API/Notifications_API">Notifications API</a>  (它可以幫助你使用現代瀏覽器向使用者發送通知 ) 為例,就需要你針對想要觸發的通知,使用建構子逐一建立新的物件實例。試著將下列程式碼丟進你的 JavaScript 主控台:</p>
+
+<pre class="brush: js">var myNotification = new Notification('Hello!');</pre>
+
+<p>我們會在後續文章中說明建構子 (Constructor)。</p>
+
+<div class="note">
+<p><strong>注意:</strong>可思考一下物件「訊息傳遞」的溝通方式。當某個物件需要其他物件執行其他作業時,往往會透過其函式之一傳送訊息給其他物件並等待回應。這也是我們所謂的回傳值。</p>
+</div>
+
+<h2 id="摘要">摘要</h2>
+
+<p>恭喜你已經快讀完我們第一篇 JS 物件的文章了。你應該已經知道該如何使用 JavaScript 中的物件,並建立自己的簡單物件了。你也應該了解物件在儲存相關資料的好用之處。如果你將 <code>person</code> 物件中的所有屬性與函式,當做個別的變數與函式並試著追蹤,肯定吃力不討好;且其他具備相同名稱的變數與函式也可能發生問題。「物件」讓我們能在其封包中安全的與資訊相互區隔。</p>
+
+<p>下一篇文章將說明「物件導向程式設計 (OOP)」理論,並了解相關技術是如何用於 JavaScript 之中。</p>
+
+<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/javascript/objects/index.html b/files/zh-tw/learn/javascript/objects/index.html
new file mode 100644
index 0000000000..aa4b296a95
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/index.html
@@ -0,0 +1,42 @@
+---
+title: JavaScript 物件介紹
+slug: Learn/JavaScript/Objects
+translation_of: Learn/JavaScript/Objects
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">在 JavaScript 裡面,從諸如字串與陣列的核心功能、到以 JavaScript 建構的瀏覽器 API,大部分的東西都可算是「物件 (Object)」。你甚至可建立自己的物件,將相關函式與變數封裝 (Encapsulate) 為有效封包,並可作為多樣的資料容器 (Data container)。如果你想更精進既有的程式語言知識,就必須了解 JavaScript 的「物件導向 (Object-Oriented;OO)」本質。為此,我們設計了相關文章來協助你更進一步。本文將先說明物件理論和語法的細節,再引導你建立自己的物件。</p>
+
+<h2 id="必備條件">必備條件</h2>
+
+<p>在開始閱讀本文之前,你應該已經對 HTML 與 CSS 有一定程度的認識。建議你先看過〈<a href="https://developer.mozilla.org/zh-TW/docs/Web/Guide/HTML/Introduction">HTML 介紹</a>〉以及〈<a href="https://developer.mozilla.org/zh-TW/docs/Learn/CSS/Introduction_to_CSS">CSS 介紹</a>〉,再開始了解 JavaScript。</p>
+
+<p>你也應該已經初步了解過 JavaScript 基本概念,再進一步閱讀 JavaScript 物件。所以另請先看過〈<a href="/zh-TW/docs/Learn/JavaScript/First_steps">JavaScript 的第一步</a>〉與〈<a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">JavaScript 基礎要件</a>〉。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你在使用的桌機\平板\其他裝置,無法讓你建立自己的檔案,則可透過如 <a href="http://jsbin.com/">JSBin</a> 或 <a href="https://thimble.mozilla.org/">Thimble</a> 的線上編碼程式,來體驗 (大多數的) 範例程式碼。</p>
+</div>
+
+<h2 id="指南">指南</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Basics">物件基本概念</a></dt>
+ <dd>第一篇主述 JavaScript 物件。我們將說明基本的 JavaScript 物件語法,並重新講解某些先前已經說過的 JavaScript 功能,也會再提及許多物件是你現正使用中的功能。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object-oriented_JS">適合初學者的 OO JaveScript</a></dt>
+ <dd>說明過基本概念之後,就會將重點放在物件導向的 JavaScript (OOJS) 本質上。本文會先介紹 OO 程式設計的基礎理論,再說明 JavaScript 是如何透過建構子 (Constructor) 函式模擬物件類別並建立物件實體 (Instance)。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object_prototypes">物件原型</a></dt>
+ <dd>原型 (Prototype) 是 JavaScript 物件用以互相繼承功能的機制,且其與典型 OO 程式語言中的繼承機制有所不同。本文將探討其中相異性、說明原型鏈的運作方式,並透過原型屬性將函式新增至現有建構子。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Inheritance">JavaScript 中的繼承</a></dt>
+ <dd>再說明了 JavaScript 大多數的 OO 特性之後,將說明應如何建立「子」物件類別 (建構子) 並繼承其「母」類別的功能。此外,我們將針對你可能使用 OOJS 的時機提供建言。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/JSON">利用 JSON 資料</a></dt>
+ <dd>JavaScript Object Notation (JSON) 為標準格式,用以將「結構化資料 (Structured data)」呈現為 JavaScript 物件,並常用於網站之間呈現\傳輸資料 (如從伺服器傳送資料到用戶端,以於網頁上顯示內容)。你一定會常接觸到類似情形,所以本文將提供用 JavaScript 搭配 JSON 開發時的所有資訊,包含在 JSON 物件中存取資料項目,以及撰寫你自己的 JSON。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object_building_practice">物件打造實例</a></dt>
+ <dd>前幾篇文章帶領你看過基本的 JavaScript 物件理論和語法細節,幫你打下厚實的基礎。而本文要讓你實際操作,透過更多實例自訂出 JavaScript 物件,讓你享受多采多姿的學習過程 (讓你寫出彩色的跳跳球喔)。</dd>
+</dl>
+
+<h2 id="評量">評量</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">為彩色跳跳球展示範例新增其他功能</a></dt>
+ <dd>在此評量中,你已經先寫出了跳跳球範例。接著要讓你新增其他有趣的功能。</dd>
+</dl>
diff --git a/files/zh-tw/learn/javascript/objects/inheritance/index.html b/files/zh-tw/learn/javascript/objects/inheritance/index.html
new file mode 100644
index 0000000000..f9db84dae8
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/inheritance/index.html
@@ -0,0 +1,210 @@
+---
+title: JavaScript 中的「繼承」
+slug: Learn/JavaScript/Objects/Inheritance
+translation_of: Learn/JavaScript/Objects/Inheritance
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">在解釋過大部分的 OOJS 細節之後,本文將說明該如何建立「子」物件類別 (建構子),並從其「母」類別繼承功能。此外,也將建議開發者應於何時、於何處使用 OOJS。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必備條件:</th>
+ <td>基本的電腦素養、已了解 HTML 與 CSS 基本概念、熟悉 JavaScript 基礎 (可參閱〈<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉) 與 OOJS 的基礎 (可參閱〈<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>〉)。</td>
+ </tr>
+ <tr>
+ <th scope="row">主旨:</th>
+ <td>了解應如何建構 JavaScript 中的繼承。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="原型繼承">原型繼承</h2>
+
+<p>目前為止,我們看過幾個繼承的實作範例:原型鍊的運作方式,以及繼承的成員如何形成原型鍊。但這些大部分都與內建的瀏覽器函式有關。那我們又該如何在 JavaScript 建立物件且由其他物件繼承而來呢?</p>
+
+<p>如稍早的系列文章中所述,某些人認為 JavaScript 並非真正的物件導向 (OO) 語言。在「典型 OO」中,你必須定義特定的類別物件,才能定義哪些類別所要繼承的類別 (可參閱〈<a href="http://www.tutorialspoint.com/cplusplus/cpp_inheritance.htm">C++ inheritance</a>〉了解簡易範例)。JavaScript 則使用不同的系統 —「繼承」的物件並不會一併複製功能過來,而是透過原型鍊連接其所繼承的功能,亦即所謂的原型繼承 (<strong>Prototypal inheritance</strong>)。</p>
+
+<p>就透過範例了解此一概念吧。</p>
+
+<h2 id="入門">入門</h2>
+
+<p>首先將 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">oojs-class-inheritance-start.html</a> 檔案 (亦可參考<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">實際執行</a>) 複製到本端磁碟。可在裡面找到本課程一直沿用的 <code>Person()</code> 建構子範例,但這裡有些許不同,也就是該建構子只定義了屬性:</p>
+
+<pre class="brush: js">function Person(first, last, age, gender, interests) {
+ this.name = {
+ first,
+ last
+ };
+ this.age = age;
+ this.gender = gender;
+ this.interests = interests;
+};</pre>
+
+<p>這些函式均已定義於建構子的原型之上,例如:</p>
+
+<pre class="brush: js">Person.prototype.greeting = function() {
+ alert('Hi! I\'m ' + this.name.first + '.');
+};</pre>
+
+<p>假設要建立一個像前面 OO 定義中說過的 <code>Teacher</code> 類別,且除了繼承 <code>Person</code> 的所有成員,還要包含:</p>
+
+<ol>
+ <li>新的 <code>subject</code> 屬性,可包含老師所傳授的科目。</li>
+ <li>更新過的 <code>greeting()</code> 函式,要比標準的 <code>greeting()</code> 函式更正式一點,更適合老師在校對學生使用。</li>
+</ol>
+
+<h2 id="定義_Teacher()_建構子函式">定義 Teacher() 建構子函式</h2>
+
+<p>首先必須建立 <code>Teacher()</code> 建構子,將下列程式碼加到現有程式碼之下:</p>
+
+<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) {
+ Person.call(this, first, last, age, gender, interests);
+
+ this.subject = subject;
+}</pre>
+
+<p>這看起來和 Person 建構子有許多地方類似,但比較奇怪的就是之前沒看過的 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a></code> 函式。此函式基本上可讓你呼叫在其他地方定義的函數,而非目前內文 (context) 中定義的函式。當執行函式時,第一個參數用來指定你要使用 <code>this</code> 值,其他參數則指定應該傳送到該函式的參數。</p>
+
+<div class="note">
+<p><strong>注意:</strong>我們此範例中建立新的物件實例時,會指定所要繼承的屬性。但必須注意的是,即使實例不需將屬性指定為參數,你還是必須在建構子中將屬性指定為參數  (在建立物件時,你可能獲得設定為隨意值的屬性)。</p>
+</div>
+
+<p>所以這裡可在 <code>Teacher()</code> 建構子函式之內有效執行 <code>Person() </code>建構子函式 (如上述),藉以在 <code>Teacher()</code> 之內定義相同的屬性,但使用的是傳送到 <code>Teacher()</code> 的屬性值,而非 <code>Person()</code> 的屬性值 (我們將 <code>this</code> 值設為簡單的「<code>this」並</code>傳送到 <code>call()</code>,代表這個 <code>this</code> 是 <code>Teacher()</code> 的函式)。</p>
+
+<p>建構子的最後一行則定義了新的 <code>subject</code> 屬性,代表只有老師具備,一般人不會有。</p>
+
+<p>我們也可以單純這樣做:</p>
+
+<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) {
+ this.name = {
+ first,
+ last
+ };
+ this.age = age;
+ this.gender = gender;
+ this.interests = interests;
+ this.subject = subject;
+}</pre>
+
+<p>但這樣只是重新定義了新的屬性,而不是繼承自 <code>Person() 而來,所以無法達到我們預設的目標,也需要更多程式碼才能達成。</code></p>
+
+<h2 id="設定_Teacher()_的原型與建構子參考">設定 Teacher() 的原型與建構子參考</h2>
+
+<p>到目前為止發現一個問題:我們定義了新的建構子,但預設只有 1 個空白的 <code>prototype</code> 屬性。接著要讓 <code>Teacher()</code> 繼承 <code>Person()</code> 原型中所定義的函式,該怎麼做呢?</p>
+
+<ol>
+ <li>繼續在現有程式碼下方加入:
+ <pre class="brush: js">Teacher.prototype = Object.create(Person.prototype);</pre>
+ 這裡再次用好朋友 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code> 解救。我們透過 <code>create()</code> 並搭配等同於 <code>Person.prototype</code> 的原型,建立新的 <code>prototype</code> 屬性值 (它本身就是物件,包含屬性與函式) ,並將之設定為 <code>Teacher.prototype</code> <code>的值。也就是說</code> <code>Teacher.prototype</code> 現在會繼承 <code>Person.prototype</code> 上的所有可用函式。</li>
+ <li>此外,基於我們的繼承方式,<code>Teacher()</code> <code>prototype</code> 的建構子屬性目前設定為 <code>Person()。可參閱</code> <a href="https://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor">Stack Overflow post</a> 進一步了解原因。可先儲存自己的程式碼、在瀏覽器中載入頁面,再將下列程式碼輸入至 JavaScript 主控台以驗證:
+ <pre class="brush: js">Teacher.prototype.constructor</pre>
+ </li>
+ <li>這樣可能會產生問題,所以要設定正確。你可回到自己的原始碼並在最下方加入下列程式碼:
+ <pre class="brush: js">Teacher.prototype.constructor = Teacher;</pre>
+ </li>
+ <li>如果儲存並重新整理之後,只要輸入 <code>Teacher.prototype.constructor</code> 應該就會回傳 <code>Teacher()</code>。</li>
+</ol>
+
+<h2 id="給_Teacher()_新的_greeting()_函式">給 Teacher() 新的 greeting() 函式</h2>
+
+<p>接著必須在 <code>Teacher()</code> 建構子上定義新的 <code>greeting()</code> 函式。</p>
+
+<p>最簡單的方法就是在 <code>Teacher()</code> 的原型上定義此函式。將下列加入程式碼最底部:</p>
+
+<pre class="brush: js">Teacher.prototype.greeting = function() {
+ var prefix;
+
+ if(this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
+ prefix = 'Mr.';
+ } else if(this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
+ prefix = 'Mrs.';
+ } else {
+ prefix = 'Mx.';
+ }
+
+ alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
+};</pre>
+
+<p>這樣就會顯示老師的問候語,也會針對老師的性別使用合適的稱呼,可用於條件陳述式。</p>
+
+<h2 id="簡易範例">簡易範例</h2>
+
+<p>現在你已經輸入所有程式碼了,可以試著用<code>Teacher()</code> 建立物件實例。將下列 (或是你想用的類似程式碼) 加入現有程式碼的底部:</p>
+
+<pre class="brush: js">var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre>
+
+<p>儲存並重新整理之後,試著存取新 <code>teacher1</code> 物件的屬性語函式,例如:</p>
+
+<pre class="brush: js">teacher1.name.first;
+teacher1.interests[0];
+teacher1.bio();
+teacher1.subject;
+teacher1.greeting();</pre>
+
+<p>這樣應該運作無虞。前 3 行的存取成員即繼承自一般 <code>Person()</code> 建構子 (類別)。最後 2 行的存取成員只能用於特定的 <code>Teacher()</code> 建構子 (類別) 之上。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法進行到現有進度,可比較自己與<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">完整版本</a> (亦可看<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">實際執行</a>的情形) 的程式碼。</p>
+</div>
+
+<p>這裡所提的技巧,當然不是在 JavaScript 建立繼承類別的唯一方法,但足以堪用。並可讓你了解應如何於 JavaScript 實作繼承。</p>
+
+<p>你可能也想看看某些新的 {{glossary("ECMAScript")}} 功能,可更簡潔的在 JavaScript 中繼承 (參閱 <a href="/en-US/docs/Web/JavaScript/Reference/Classes">Classes</a>)。但由於這些功能尚未廣泛支援其他瀏覽器,這裡先略過不提。本系列文章中提到的其他程式碼,均可回溯支援到 IE9 或更早版本。當然還是有辦法支援更舊的版本。</p>
+
+<p>一般方法就是使用 JavaScript 函式庫,且最常見的就是簡單集結可用的功能,更快、更輕鬆的完成繼承。例如 <a href="http://coffeescript.org/#classes">CoffeeScript</a> 即提供了 <code>class</code><code>、extends</code> 等等。</p>
+
+<h2 id="進階習題">進階習題</h2>
+
+<p>在<a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">〈OOP 理論〉段落</a>中,我們也納入了 <code>Student</code> 類別並繼承了 <code>Person</code> 的所有功能,此外也提供不同的 <code>greeting()</code> 函式,且較 <code>Teacher</code> 的問候語沒那麼正式。在看了該段落中的學生問候語之後,可試著實作自己的 <code>Student()</code> 建構子,並繼承 <code>Person()</code>, 的所有功能,再實作不同的 <code>greeting()</code> 函式。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法進行到現有進度,可參考<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-student.html">完成版本</a> (亦可看<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">實際執行</a>的情形)。</p>
+</div>
+
+<h2 id="物件成員摘要">物件成員摘要</h2>
+
+<p>簡單來說,你基本上需要考量 3 種類型的屬性\函式:</p>
+
+<ol>
+ <li>已於建構子函式中定義,會交給物件實體的屬性\函式。這應該很容易處理。在你自己的程式碼中,就是透過 <code>this.x = x</code> 類別行並在建構子中定義的成員;在瀏覽器程式碼中,就是僅限物件實體可用的成員 (一般是透過 <code>new</code> 關鍵字並呼叫建構子所建立,例如 <code>var myInstance = new myConstructor()</code>)。</li>
+ <li>直接在建構子上定義,並僅能用於該建構子的屬性\函式。這類屬性\函式往往只能用於內建瀏覽器物件之上,並直接「鍊接」至建構子 (而非實例) 以利識別,例如 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code>。</li>
+ <li>定義於建構子原型上的屬性\函式,交由所有的實例繼承,亦繼承了物件類別。這類屬性\函式包含建構子原型屬性之上定義的所有成員,例如 <code>myConstructor.prototype.x()</code>。</li>
+</ol>
+
+<p>如果你不確定到底屬於上述的哪一個,也別擔心。現在你還在學習階段,往後定會熟能生巧。</p>
+
+<h2 id="在_JavaScript_中使用繼承的時機?">在 JavaScript 中使用繼承的時機?</h2>
+
+<p>看到這裡,你心裡應該覺得很複雜。沒錯。「原型」與「繼承」可說是 JavaScript 最複雜的概念之二,但許多 JavaScript 的強大功能與彈性,均來自於其物件結構與繼承,也值得你了解運作方式。</p>
+
+<p>不論是使用 WebAPI 的多樣功能,或是你在字串、陣列等所呼叫的函式\屬性 (定義於內建瀏覽器物件之上),你都可以不斷繼承下去。</p>
+
+<p>在自己的程式碼裡,特別是剛接觸或小型專案時,你用繼承的頻率可能沒那麼高。若沒真正需要,只是「為使用而使用」繼承,老實說只是浪費時間。但隨著程式碼規模越來越大,你就會找到使用的時間。如果你發現自己開始建立類似功能的多個物件時,就可先建立通用的物件類型,來概括所有共用的功能,並在特定物件類型中繼承這些功能,既方便又有效率。</p>
+
+<div class="note">
+<p><strong>注意:</strong>基於 JavaScript 運作的方式 (如原型鍊等),物件之間的功能共享一般稱為<strong>「</strong><strong>委託 (Delegation)」</strong>,即特定物件將功能委託至通用物件類型。「委託」其實比繼承更精確一點。因為「所繼承的功能」並不會複製到「進行繼承的物件」之上,卻是保留在通用物件之中。</p>
+</div>
+
+<p>當使用繼承時,建議你不要設定太多層的繼承關係,並時時留意你所定義的函式與屬性。在開始寫程式碼時,你可能會暫時修改內建瀏覽器物件的原型,除非你真的需要,否則儘量別這麼做。太多繼承可能連你自己都搞混,而且一旦需要除錯就會痛苦萬分。</p>
+
+<p>最後,物件可說是另一種形式的程式碼再利用,如同函式或迴圈一般,且有其專屬的角色與優點。如果你正建立一堆相關變數與函式,並要全部一起追蹤、封裝,就可以透過物件。你也能以物件方式傳送整個資料集合。而且上述兩種情況均不需使用建構子或繼承就能夠達成。如果你只需要某一物件的單一實作,那麼單純使用物件就好,完全不需要繼承。</p>
+
+<h2 id="摘要">摘要</h2>
+
+<p>本文為大家溫習了 OOJS 核心理論和語法。現在你應該了解 JavaScript 物件與 OOP 的基本概念、原型及原型繼承、建立類別 (建構子) 與物件實例的方法、為類別新增功能、建立從其他類別繼承而來的子類別。</p>
+
+<p>下篇文章就要來看看該如何搭配 JavaScript Object Notation (JSON),使用 JavaScript 物件的常見資料交換格式。</p>
+
+<h2 id="另可參閱">另可參閱</h2>
+
+<ul>
+ <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — 互動式學習網站,讓你了解物件。</li>
+ <li><a href="https://www.amazon.com/gp/product/193398869X/">Secrets of the JavaScript Ninja</a> 的第六章 — 進階 JavaScript 概念與技術的好書。第六章講述了原型與繼承的概念。此書有紙本與線上版。</li>
+ <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&amp;%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes">You Don't Know JS: this &amp; Object Prototypes</a> — Kyle Simpson 絕佳 JavaScript 手冊系列的一部分。第五章特別深入講述了原型。我們透過本文為初學者提供簡易概念,但 Kyle 則說明得更深入、更精確。</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/javascript/objects/json/index.html b/files/zh-tw/learn/javascript/objects/json/index.html
new file mode 100644
index 0000000000..71a4a3776a
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/json/index.html
@@ -0,0 +1,325 @@
+---
+title: 使用 JSON 資料
+slug: Learn/JavaScript/Objects/JSON
+tags:
+ - JSON
+translation_of: Learn/JavaScript/Objects/JSON
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">JavaScript Object Notation (JSON) 為將結構化資料 (structured data) 呈現為 JavaScript 物件的標準格式,常用於網站上的資料呈現、傳輸 (例如將資料從伺服器送至用戶端,以利顯示網頁)。你應該會常常遇到,因此本文將說明 JavaScript 搭配 JSON 時所應知道的觀念,包含如何在 JSON 物件中存取資料項目,並寫出你自己的 JSON。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必要條件:</th>
+ <td>基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉) 與 OOJS 基本概念 (參閱〈<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>〉)。</td>
+ </tr>
+ <tr>
+ <th scope="row">主旨:</th>
+ <td>了解應如何使用 JSON 格式所儲存的資料,建立自己的 JSON 物件。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="說真的,到底什麼是_JSON?">說真的,到底什麼是 JSON?</h2>
+
+<p>{{glossary("JSON")}} 是依照 JavaScript 物件語法的資料格式,經 <a href="https://en.wikipedia.org/wiki/Douglas_Crockford">Douglas Crockford</a> 推廣普及。雖然 JSON 是以 JavaScript 語法為基礎,但可獨立使用,且許多程式設計環境亦可讀取 (剖析) 並產生 JSON。</p>
+
+<p>JSON 可能是物件或字串。當你想從 JSON中讀取資料時,JSON可作為物件;當要跨網路傳送 JSON 時,就會是字串。這不是什麼大問題 —  JavaScript 提供全域 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> 物件,其內的函式可進行切換。</p>
+
+<p>JSON 物件可儲存於其自有的檔案中,基本上就是副檔名為 <code>.json</code> 的文字檔案,以及 <code>application/json</code> 的 {{glossary("MIME type")}}。</p>
+
+<h3 id="JSON_的架構">JSON 的架構</h3>
+
+<p>我們剛提到「JSON 物件基本上就是 JavaScript 物件」,而這敘述在大多數情況下都對。如同標準的 JavaScript 物件,你當然可在 JSON 之內加入相同的基本資料類型,如字串、數字、陣列、布林值,以及其他物件,接著同樣能再建構出資料繼承,如:</p>
+
+<pre class="brush: json">{
+  "squadName" : "Super hero squad",
+  "homeTown" : "Metro City",
+  "formed" : 2016,
+  "secretBase" : "Super tower",
+ "active" : true,
+  "members" : [
+    {
+      "name" : "Molecule Man",
+      "age" : 29,
+      "secretIdentity" : "Dan Jukes",
+      "powers" : [
+        "Radiation resistance",
+        "Turning tiny",
+        "Radiation blast"
+      ]
+    },
+    {
+      "name" : "Madame Uppercut",
+      "age" : 39,
+      "secretIdentity" : "Jane Wilson",
+      "powers" : [
+        "Million tonne punch",
+        "Damage resistance",
+        "Superhuman reflexes"
+      ]
+    },
+    {
+      "name" : "Eternal Flame",
+      "age" : 1000000,
+      "secretIdentity" : "Unknown",
+      "powers" : [
+        "Immortality",
+        "Heat Immunity",
+        "Inferno",
+        "Teleportation",
+        "Interdimensional travel"
+      ]
+    }
+  ]
+}</pre>
+
+<p>舉例來說,如果將此物件載入至 JavaScript 程式並將之儲存為「<code>superHeroes</code>」變數,如同〈<a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript 物件基本概念</a>〉一文中提過的,接著能以相同的  存取其內部的資料,如下:</p>
+
+<pre class="brush: js">superHeroes.hometown
+superHeroes["active"]</pre>
+
+<p>若要順著繼承往下存取資料,只要將必要的屬性名稱與陣列索引「鍊」在一起即可。舉例來說,如果要存取成員列表中的第二位英雄的第三項超能力,你必須:</p>
+
+<pre class="brush: js">superHeroes["members"][1]["powers"][2]</pre>
+
+<ol>
+ <li>首先要有變數名稱 — <code>superHeroes</code>。</li>
+ <li>要在變數中存取 <code>members</code> 屬性,所以用 <code>["members"]</code>。</li>
+ <li><code>members</code> 包含由物件產生陣列。我們要存取陣列中的第二個物件,所以用 <code>[1]</code>。</li>
+ <li>在此物件中,我們要存取 <code>powers</code> 屬性,所以用 <code>["powers"]</code>。</li>
+ <li>在 <code>powers</code> 屬性中有 1 個陣列具備所選超級英雄的能力。我們要選第三種能力,所以用 <code>[2]</code>。</li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>我們在 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html">JSONText.html</a> 範例 (參閱<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/JSONTest.html">原始碼</a>) 的變數中,示範上述可用的 JSON。你可在自己瀏覽器的 JavaScript 主控台載入此程式碼,並存取變數中的資料。</p>
+</div>
+
+<h3 id="陣列作為_JSON">陣列作為 JSON</h3>
+
+<p>我們在上面提過「 JSON 物件基本上就是 JavaScript 物件,而這敘述在大多數情況下都對」。其中「在大多數情況下都對」的理由,就是因為陣列也可以是有效的 JSON 物件,例如:</p>
+
+<pre class="brush: json">[
+ {
+ "name" : "Molecule Man",
+ "age" : 29,
+ "secretIdentity" : "Dan Jukes",
+ "powers" : [
+ "Radiation resistance",
+ "Turning tiny",
+ "Radiation blast"
+ ]
+ },
+ {
+    "name" : "Madame Uppercut",
+    "age" : 39,
+    "secretIdentity" : "Jane Wilson",
+    "powers" : [
+      "Million tonne punch",
+      "Damage resistance",
+      "Superhuman reflexes"
+    ]
+  }
+]</pre>
+
+<p>上面程式碼絕對是有效的 JSON。你可用陣列指數為開頭來存取陣列項目,例如 <code>[0]["powers"][0]</code>。</p>
+
+<h3 id="其他附註">其他附註</h3>
+
+<ul>
+ <li>JSON 是純粹的資料格式 — 僅具備屬性,而無函式。</li>
+ <li>JSON 需要雙引號,才能使用\有效。所以最安全的方法就是以雙引號撰寫之。</li>
+ <li>單一個逗號或冒號放錯位置,也會讓 JSON 檔案出錯而無法運作。你應仔細檢視所有要使用的資料 (只要產生器程式能正確運作,由電腦產生的 JSON 也就不容易出錯)。你可透過如 <a href="http://jsonlint.com/">JSONLint</a> 的應用程式檢驗 JSON。</li>
+ <li>不限於陣列或物件,只要是符合標準 JSON 物件形式的任何資料,都可以夾帶進 JSON 檔案中。因此,單一字串或數字也可能是有效的 JSON 物件,但不一定有用就是了...</li>
+</ul>
+
+<h2 id="主動學習:完成_JSON_範例">主動學習:完成 JSON 範例</h2>
+
+<p>現在就試著在網站上,透過某些 JSON 資料完成範例吧。</p>
+
+<h3 id="入門">入門</h3>
+
+<p>在開始之前,先複製我們的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes.html">heroes.html</a> 與 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/style.css">style.css</a> 到你的本端硬碟中。後者包含某些簡易的 CSS 可塑造網頁風格;前者則提供極簡單主體 HTML:</p>
+
+<pre class="brush: html">&lt;header&gt;
+&lt;/header&gt;
+
+&lt;section&gt;
+&lt;/section&gt;</pre>
+
+<p>加上 {{HTMLElement("script")}} 元素,才能納入稍後會在此習題中寫出來的 JavaScript 程式碼。目前只有 2 行程式碼,用以取得 {{HTMLElement("header")}} 與 {{HTMLElement("section")}} 元素的參考,並將之儲存於變數之中:</p>
+
+<pre class="brush: js">var header = document.querySelector('header');
+var section = document.querySelector('section');</pre>
+
+<p>你可到 GitHub 上找到此 JSON 資料:<a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json</a>。</p>
+
+<p>接著載入到頁面之中,並使用某些有趣的 DOM 操控 (DOM manipulation) 來顯示,如下:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13857/json-superheroes.png" style="display: block; margin: 0 auto;"></p>
+
+<h3 id="載入我們的_JSON">載入我們的 JSON</h3>
+
+<p>若要將 JSON 載入至頁面,就要透過 {{domxref("XMLHttpRequest")}} API (通常稱為 <strong>XHR</strong>)。此是極好用的 JavaScript 物件,可讓網路請求透過 JavaScript (例如圖片、文字、JSON,甚至 HTML 片段) 來檢索伺幅器的資源,這也代表我們不需載入整個頁面,就能更新小部分的內容。如此可讓網頁反應速度更快;聽起來很棒吧?但可惜本文無法再深入講解更多細節。</p>
+
+<ol>
+ <li>一開始,我們先針對要在變數中檢索的 JSON 檔案,將其網址儲存起來。把下列程式碼加到你 JavaScript 程式碼的最下方:
+ <pre class="brush: js">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';</pre>
+ </li>
+ <li>為了建立請求,我們必須透過 <code>new</code> 關鍵字,先從 <code>XMLHttpRequest</code> 建構子建立新的請求物件實例。把下列加到最後一行:
+ <pre class="brush: js">var request = new XMLHttpRequest();</pre>
+ </li>
+ <li>現在用 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/open">open()</a></code> 函式開啟新的請求。加入下列程式碼:
+ <pre class="brush: js">request.open('GET', requestURL);</pre>
+
+ <p>這樣就顧到至少 2 個參數。當然也有其他參數可選擇。但這個簡易範例只需要 2 個強制參數:</p>
+
+ <ul>
+ <li>在設立網路請求時,應使用 HTTP 函式。因為這裡只要檢索簡單的資料,所以用 <code><a href="/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> 就可以。</li>
+ <li>URL 提供請求目的地 — 這也就是我們剛剛儲存的 JSON 檔案網址。</li>
+ </ul>
+ </li>
+ <li>接著加入下面 2 行程式碼。我們為 JSON 設定了 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/responseType">responseType</a></code>,告知伺服器應回傳 JSON 物件,再以 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/send">send()</a></code> 函式傳送請求:
+ <pre class="brush: js">request.responseType = 'json';
+request.send();</pre>
+ </li>
+ <li>最後就是等待由伺服器所回傳的反應,再接著處理。把下列程式碼加入現有程式碼的最下方:
+ <pre class="brush: js">request.onload = function() {
+ var superHeroes = request.response;
+ populateHeader(superHeroes);
+ showHeroes(superHeroes);
+}</pre>
+ </li>
+</ol>
+
+<p>在這裡,我們將所獲得的響應 (可到 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/response">response</a></code> 屬性中找到) 儲存到 <code>superHeroes</code> 變數之中。此變數現在會納入我們的 JSON。接著再把此 JSON 檔案送到 2 個函式呼叫。第一個函式呼叫會將正確資料填入 &lt;<code>header&gt;</code>;第二個函式呼叫則會為團隊中的各個英文建立資訊卡,再插入至 <code>&lt;section&gt;</code> 內。</p>
+
+<p>當於請求物件上觸發載入事件時,會執行一個事件處理器。我們就將程式碼包裹至此處理器之中 (參閱 <code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code>) — 只要成功回傳響應,就會觸發載入事件。之所以這樣做,是為了確保當我們要以 <code>request.response</code> 進行某件事時,此 <code>request.response</code> 絕對可用。</p>
+
+<h3 id="產生標頭">產生標頭</h3>
+
+<p>現在檢索過了 JSON 資料,接著就寫出上面參照過的 2 個函式來利用 JSON 資料吧。首先將下列函式定義加到先前的程式碼中:</p>
+
+<pre class="brush: js">function populateHeader(jsonObj) {
+ var myH1 = document.createElement('h1');
+ myH1.textContent = jsonObj['squadName'];
+ header.appendChild(myH1);
+
+ var myPara = document.createElement('p');
+ myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed'];
+ header.appendChild(myPara);
+}</pre>
+
+<p>我們已經將參數命名為 <code>jsonObj</code>,所以在這個函式之內就要用 jsonObj 呼叫此參數。這裡先以 <code><a href="/en-US/docs/Web/API/Document/createElement">createElement()</a></code> 建立 1 組 {{HTMLElement("h1")}} 元素、將其 <code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code> 指定為 JSON 的 <code>squadName</code> 屬性、透過 <code><a href="/en-US/docs/Web/API/Node/appendChild">appendChild()</a></code> 將之附加到標頭。接著 {{HTMLElement("p")}} 元素依樣畫葫蘆一遍:建立、設定其文字內容、附加到標頭。唯一不同之處,就是將該文字設定為 1 組串接字串 (Concatenated string),其內包含 JSON 的 <code>homeTown</code> 與 <code>formed</code> 屬性。</p>
+
+<h3 id="建立超級英雄的資訊卡片">建立超級英雄的資訊卡片</h3>
+
+<p>現在將下列函式加到程式碼底端,用以建立並顯示超級英雄的卡片:</p>
+
+<pre class="brush: js">function showHeroes(jsonObj) {
+ var heroes = jsonObj['members'];
+
+ for(i = 0; i &lt; heroes.length; i++) {
+ var myArticle = document.createElement('article');
+ var myH2 = document.createElement('h2');
+ var myPara1 = document.createElement('p');
+ var myPara2 = document.createElement('p');
+ var myPara3 = document.createElement('p');
+ var myList = document.createElement('ul');
+
+ myH2.textContent = heroes[i].name;
+ myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity;
+ myPara2.textContent = 'Age: ' + heroes[i].age;
+ myPara3.textContent = 'Superpowers:';
+
+ var superPowers = heroes[i].powers;
+ for(j = 0; j &lt; superPowers.length; j++) {
+ var listItem = document.createElement('li');
+ listItem.textContent = superPowers[j];
+ myList.appendChild(listItem);
+ }
+
+ myArticle.appendChild(myH2);
+ myArticle.appendChild(myPara1);
+ myArticle.appendChild(myPara2);
+ myArticle.appendChild(myPara3);
+ myArticle.appendChild(myList);
+
+ section.appendChild(myArticle);
+ }
+}</pre>
+
+<p>我們先把 JSON 的 <code>members</code> 屬性儲存到新的變數中。此陣列所具備的多個物件,均包含了各個超級英雄的資訊。</p>
+
+<p>接著我們以 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for 迴圈</a>循環陣列中的各個物件。針對每個物件都會:</p>
+
+<ol>
+ <li>建立數個新的元素:1 組 <code>&lt;article&gt;</code>、1 組 <code>&lt;h2&gt;、3 組</code> <code>&lt;p&gt;、1 組</code> <code>&lt;ul&gt;。</code></li>
+ <li>讓 &lt;h2&gt; 納入目前超級英雄的 <code>name</code>。</li>
+ <li>接著 3 個段落分別是英雄的 <code>secretIdentity</code>、<code>age、Superpowers</code>,在列表中帶出相關資訊。</li>
+ <li>另以新變數 <code>superPowers</code> 儲存 <code>powers</code> 屬性 — 其中包含 1 組陣列以列出目前英雄的超能力。</li>
+ <li>再用另一個 <code>for</code> 迴圈逐一巡過目前英雄的超能力。針對每一項超能力,我們再建立 1 組 <code>&lt;li&gt;</code> 元素,把超能力放進該元素之中,再透過 <code>appendChild()</code> 把 <code>listItem</code> 放入 <code>&lt;ul&gt;</code> 元素之內 (<code>myList</code>)。</li>
+ <li>最後就是在 <code>&lt;article&gt;</code> (<code>myArticle</code>) 之內附加 <code>&lt;h2&gt;、</code><code>&lt;p&gt;、</code><code>&lt;ul&gt;</code>;再把 <code>&lt;article&gt;</code> 附加於 <code>&lt;section&gt;</code> 之內。這附加的順序極為重要,因為這也會是 HTML 中的顯示順序。</li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法讓此範例運作,可參閱我們的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished.html">heroes-finished.html</a> 原始碼 (亦可看到<a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html">實際執行情況</a>。)</p>
+</div>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法用我們說過的點記法 (dot-)\括弧記法 (bracket notation) 來存取 JSON,則可用新分頁或自己的文字編輯器開啟 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">superheroes.json</a> 檔案並參考之。你也可再回去看看 <a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript 物件基礎概念</a> ,再次了解點\括弧記法。</p>
+</div>
+
+<h2 id="物件與文字交互轉換">物件與文字交互轉換</h2>
+
+<p>上述是存取 JSON 的簡易範例,因為我們設定要回傳響應的 XHR 已經是 JSON 格式。透過:</p>
+
+<pre class="brush: js">request.responseType = 'json';</pre>
+
+<p>但有時候沒這麼好運。我們有時會接收到文字字串格式的 JSON 資料,且必須將之轉換為物件。且當我們要以某種訊息傳送 JSON 資料時,也必須將之轉換為字串才能正確運作。還好,這 2 種問題在 Web 開發過程中甚為常見。內建的 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> 物件很早就新增到瀏覽器之中,且包含下列 2 種函式:</p>
+
+<ul>
+ <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">parse()</a></code>:接收文字字串形式的 JSON 物件作為參數,並回傳對應的物件。</li>
+ <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">stringify()</a></code>:接收 JSON 物件作為參數,並回傳對等的文字字串形式。</li>
+</ul>
+
+<p>你可到 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished-json-parse.html">heroes-finished-json-parse.html</a> 範例 (參閱<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished-json-parse.html">原始碼</a>) 中看到第一個函式的運作情形。這其實跟我們先前範例所進行的事情一模一樣,不同之處在於我們設定 XHR 要回傳 JSON 為文字,接著再使用 <code>parse()</code> 轉換為實際的 JSON 物件。關鍵程式碼片段如下:</p>
+
+<pre class="brush: js">request.open('GET', requestURL);
+request.responseType = 'text'; // now we're getting a string!
+request.send();
+
+request.onload = function() {
+ var superHeroesText = request.response; // get the string from the response
+ var superHeroes = JSON.parse(superHeroesText); // convert it to an object
+ populateHeader(superHeroes);
+ showHeroes(superHeroes);
+}</pre>
+
+<p>你可能會猜 <code>stringify()</code> 就是反過來運作了吧?可在瀏覽器的 JavaScript 主控台上輸入下列程式碼,看看其運作方式:</p>
+
+<pre class="brush: js">var myJSON = { "name" : "Chris", "age" : "38" };
+myJSON
+var myString = JSON.stringify(myJSON);
+myString</pre>
+
+<p>這樣就建立了 JSON 物件了。接著檢查內容物之後,就可透過 <code>stringify()</code> 將之轉換為字串。將回傳值儲存到新變數之中,再檢查一次即可。</p>
+
+<h2 id="摘要">摘要</h2>
+
+<p>我們透過本文簡單介紹了該如何在程式中使用 JSON、該如何建立\剖析 JSON、該如何存取其內的資料。接著就要說明物件導向 JavaScript (OOJS)。</p>
+
+<h2 id="另可參閱">另可參閱</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON 物件參考頁面</a></li>
+ <li><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest 物件參考頁面</a></li>
+ <li><a href="/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">使用 XMLHttpRequest</a></li>
+ <li><a href="/en-US/docs/Web/HTTP/Methods">HTTP 請求函式</a></li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html b/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html
new file mode 100644
index 0000000000..1504f5fc49
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/object-oriented_js/index.html
@@ -0,0 +1,277 @@
+---
+title: 初學者應知道的物件導向 JavaScript
+slug: Learn/JavaScript/Objects/Object-oriented_JS
+translation_of: Learn/JavaScript/Objects/Object-oriented_JS
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">在看完了基本概念之後,接著要說明物件導向 JavaScript (OOJS)。本文將概述物件導向程式設計 (OOP) 的理論,另說明 JavaScript 是如何透過建構子函式來模擬物件類別,又是如何建立物件實體 (Instance)。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必備條件:</th>
+ <td>基本的電腦素養、已初步了解 HTML 與 CSS、熟悉 JavaScript (參閱〈<a href="/zh-TW/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉以及 OOJS 基礎概念 (參閱〈<a href="/zh-TW/docs/Learn/JavaScript/Object-oriented/Introduction">物件基礎概念</a>〉。</td>
+ </tr>
+ <tr>
+ <th scope="row">主旨:</th>
+ <td>了解物件導向程式設計的基本理論、其與 JavaScript (幾乎所有東西都是物件) 之間的關係、應如何寫出建構子與物件實體。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="基本物件導向程式設計">基本物件導向程式設計</h2>
+
+<p>最先,讓我們從簡單、高層次的視角來看物件導向程式設計 (Object-oriented programming;OOP) 最基本的概念。我們說簡單是因為 OOP 很容易變得複雜,就算現在就設法完整解釋,也可能讓大家越來越混亂。OOP 基本概念是:採用物件(objects)來模塑真實的實物世界:也就是在程式中的呈現是透過 objects 來塑造其模型,且\或提供簡單方式存取其「難以或不可能採用的功能」。</p>
+
+<p>物件可裝載相關的資料與程式碼,資料部分是你塑造某個模型的資訊,而程式碼部分則用是操作行為(<strong>Method</strong>)實現。Object data  -- 函式部分通常也使用 ---可工整地儲存 (正式一點應該是<strong>封裝 Encapsulated</strong>) 在物件包裹(這個包裹有特定的稱呼方式,有時候即所謂的<strong>命名空間 Namespace</strong>) ,使其能輕鬆地建構性存取。物件也常作為「資料儲存 (Datastore),促成簡易實現跨網傳送。</p>
+
+<h3 id="定義物件範本">定義物件範本</h3>
+
+<p>我們先找個簡單程式,如同學校裡用來顯示師生資訊的程式。本文只是要了解一般的 OOP 理論,並非以特定程式語言為出發點。</p>
+
+<p>我們先拿<a href="/zh-TW/docs/Learn/JavaScript/Objects/Basics">第一篇物件文章</a>中的「Person」物件類型為範例,其中定義了一個人的一般資料與功能。其實有很多資訊可助你了解一個人 (像是住址、身高、鞋子尺寸、DNA、護照號碼、明顯的人格特質等......),但我們這裡只列出了姓名、年齡、性別、興趣。我們另希望根據這些資料寫出簡介,初步了解這個人。上述這些即所謂的「<strong>抽象 (Abstraction)」</strong>。為某個複雜東西建立簡單的模型,藉以代表其最重要的概念或特質,且該模型建立方式極易於搭配我們的程式設計用途。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p>
+
+<h3 id="建立實際物件">建立實際物件</h3>
+
+<p>我們可從這個「類別」建立<strong>物件實體 (Object instance)</strong> — 即該物件包含了類別中所定義的資料與功能。而「Person」類別可設定出幾個實際的人物:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p>
+
+<p>在根據類別建立物件實體時,就是執行類別的「<strong>建構子 (Constructor) 函式</strong>」所建立。而這個「根據類別來建立物件實體」的過程即稱為「<strong>實體化 (Instantiation)」</strong>。物件實體就是從類別實體化而來。</p>
+
+<h3 id="特殊類別">特殊類別</h3>
+
+<p>如果我們不要一般人物,而想建立老師與學生這類比較特定類型的人物。在 OOP 中,我們可根據其他類別建立新的類別。新的子類別則可<strong>繼承 (Inherit) </strong>其<strong>母類別</strong>的資料與程式碼特性。你可重複使用所有物件類型共有的功能,而不需再複製之。若功能需與類別有所差異,則可直接於其上定義特殊功能。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13881/MDN-Graphics-inherited-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p>
+
+<p>這樣很方便。因為老師與學生也同樣使用了如姓名、性別、年齡等的共通特性,所以只要定義這些特性 1 次即可。你也可以分別在不同的類別中定義相同特性,各個特性的定義就置於不同的命名空間中。舉例來說,學生的打招呼方式可以是「Yo, I'm [firstName]」;老師的招呼方式就正式一點,如「Hello, my name is [Prefix] [lastName]」。</p>
+
+<div class="note">
+<p><strong>注意:</strong>所謂的<strong>「多型 (Polymorphism)」</strong>,即是用多個物件類別建置相同功能。</p>
+</div>
+
+<p>現在你可根據子類別來建立物件實例了。例如:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13885/MDN-Graphics-instantiation-teacher-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p>
+
+<p>本文後面將講解應如何將 OOP 理論實際用於 JavaScript 中。</p>
+
+<h2 id="建構子與物件實例">建構子與物件實例</h2>
+
+<p>JavaScript 使用稱為建構子函式(<strong>constructor function</strong>)的特殊函式,定義物件與功能。開發者常常會不知道到底需建立多少物件,這時建構子可讓你高效率建立所需物件,並依需要為其添加資料與函式。</p>
+
+<p>在新的物件實例透過建構子函式產生後,其核心將透過一種稱為<strong>原型鏈</strong>(Prototype chain,由原型定義,可參閱 <a href="/zh-TW/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a>)的參照鏈連在一起。</p>
+
+<p>接著就在 JS 中,透過建構子建立類別及其物件實例。首先請你先在本端磁碟中再另外複製一份前面文章提過的 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 檔案。</p>
+
+<h3 id="簡易範例">簡易範例</h3>
+
+<ol>
+ <li>先看看該如何用一般函式定義一個人。將下列函式加到 <code>script</code> 元素裡面:
+
+ <pre class="brush: js">function createNewPerson(name) {
+ var obj = {};
+ obj.name = name;
+ obj.greeting = function () {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+ return obj;
+}</pre>
+ </li>
+ <li>呼叫此函式之後即可建立新的 1 個人,另在瀏覽器的 JavaScript 主控台中測試下列程式碼:
+ <pre class="brush: js">var salva = createNewPerson('salva');
+salva.name;
+salva.greeting();</pre>
+ 目前為止沒什麼問題,但有點囉嗦。如果早知道要建立物件的話,又何必要建立新的空白物件再回傳呢?幸好 JavaScript 透過建構子函式提供了方便的捷徑。現在就來試試看!</li>
+ <li>用下列程式碼替代之前的函式:
+ <pre class="brush: js">function Person(name) {
+ this.name = name;
+ this.greeting = function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ };
+}</pre>
+ </li>
+</ol>
+
+<p>建構子也就是 JavaScript 版本的「類別」之一。你可以注意到,除了無法回傳任何數值或明確建立物件之外,建構子其實已具備函式中的所有功能,並已基本定義了屬性與函式 (Method)。你也能看到這裡同樣用了「<code>this</code>」關鍵字,即不論何時建立了這裡的任一物件實例,物件的「<code>name</code>」屬性均同等於「傳送至建構子呼叫的名稱值」;且 <code>greeting()</code> 函式也會使用相同「傳送至建構子呼叫的名稱值」。</p>
+
+<div class="note">
+<p><strong>注意:</strong>建構子函式名稱往往以大寫字母起頭,如此可方便你在程式碼中找出建構子函式。</p>
+</div>
+
+<p>我們又該如何呼叫建構子以建立物件呢?</p>
+
+<ol>
+ <li>將下列程式碼加到目前的程式碼之下:
+ <pre class="brush: js">var person1 = new Person('Bob');
+var person2 = new Person('Sarah');</pre>
+ </li>
+ <li>儲存程式碼並在瀏覽器中重新載入,試著將下列程式碼輸入到文字輸入畫面中:
+ <pre class="brush: js">person1.name
+person1.greeting()
+person2.name
+person2.greeting()</pre>
+ </li>
+</ol>
+
+<p>現在你應該能在頁面上看到兩組新物件,且各自以不同的命名空間儲存。若要存取其屬性與函式,就要以 <code>person1</code> 或 <code>person2</code> 開始呼叫。這些物件均完整封包,不致與其他功能衝突;但仍具備相同的 <code>name</code> 屬性與 <code>greeting()</code> 函式。另請注意,物件均使用當初建立時所各自指派的 <code>name</code> 值;這也是「<code>this</code>」如此重要的原因之一,以確保物件可使用自己的值而不致混淆其他數值。</p>
+
+<p>再看一次建構子呼叫:</p>
+
+<pre class="brush: js">var person1 = new Person('Bob');
+var person2 = new Person('Sarah');</pre>
+
+<p>這裡用了「<code>new</code>」關鍵字告知瀏覽器「我們要建立新的物件實例」,並接著在函式名稱之後的括號內傳入函式所需要的參數,並將結果儲存於變數之中 — 相當類似普通函式被呼叫的方式 。各個實例均根據此定義所建立:</p>
+
+<pre class="brush: js">function Person(name) {
+ this.name = name;
+ this.greeting = function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ };
+}</pre>
+
+<p>在建立新的物件之後,<code>person1</code> 與 <code>person2</code> 的變數將有效率地納入下列物件:</p>
+
+<pre class="brush: js">{
+ name : 'Bob',
+ greeting : function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+}
+
+{
+ name : 'Sarah',
+ greeting : function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+}</pre>
+
+<p>剛剛說的「有效率」,是因為實際功能仍定義於類別中,而非物件實例之中。這情況與我們稍早談過的物件實字 (Object literal) 相反。</p>
+
+<h3 id="建立完整的建構子">建立完整的建構子</h3>
+
+<p>上面不過是入門的簡單範例。接著繼續建立最後的 <code>Person()</code> 建構子。</p>
+
+<ol>
+ <li>將截至目前為止的程式碼移除,加入下列取代用的建構子。原則上與簡易範例完全一樣,只是比較複雜一點:
+ <pre class="brush: js">function Person(first, last, age, gender, interests) {
+ this.name = {
+ first,
+ last
+ };
+ this.age = age;
+ this.gender = gender;
+ this.interests = interests;
+ this.bio = function() {
+ alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
+ };
+ this.greeting = function() {
+ alert('Hi! I\'m ' + this.name.first + '.');
+ };
+};</pre>
+ </li>
+ <li>再接著加入下列程式碼,就可建立物件實例:
+ <pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre>
+ </li>
+</ol>
+
+<p>現在可存取我們為第一個物件所定義的屬性與函式:</p>
+
+<pre class="brush: js">person1['age']
+person1.interests[1]
+person1.bio()
+// etc.</pre>
+
+<div class="note">
+<p><strong>注意:</strong>如果你到這裡有點吃力,請先比較自己與我們的程式碼。可參閱 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-finished.html">oojs-class-finished.html</a> (也可<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-finished.html">看實際執行的情況</a>)。</p>
+</div>
+
+<h3 id="進階習題">進階習題</h3>
+
+<p>在開始之前,先試著自己添加更多物件建立程式碼,再針對產生的物件實例取得並設定其成員。</p>
+
+<p>此外,原來的 <code>bio()</code> 函式其實有點問題。即使你的「人」是女性,其輸出一定會有「He」這個代名詞。而且即使 <code>interests</code> 陣列中列出超過 2 個以上的「興趣」,這個 bio 函式也只會有 2 個興趣。你能試著在類別定義 (建構子) 中修正這個問題嗎?你可在建構子中放入任何你喜歡的程式碼 (但可能會需要幾個 conditionals 搭配 1 個迴圈)。想想應如何根據性別以及列出的興趣 (1 或 2 個以上),建構出不同的程式碼。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你卡在這裡,我們也在 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">GitHub repo 上提供了解答</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">立刻觀看</a>)。先試著自己解決問題吧!</p>
+</div>
+
+<h2 id="建立物件實例的其他方法">建立物件實例的其他方法</h2>
+
+<p>目前解釋了 2 種建立物件實例的方法 — <a href="/zh-TW/docs/Learn/JavaScript/Objects/Basics#Object_basics">宣告物件實字</a>,以及使用建構子函式。</p>
+
+<p>當然還有別的方法,但我們希望你先熟悉此 2 種方法,以免你日後的 Web 旅程上會再遇到。</p>
+
+<h3 id="Object_建構子">Object() 建構子</h3>
+
+<p>首先可使用 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object">Object()</a></code> 建構子建立新的物件。沒錯,即使是泛型物件 (Generic object) 也具備建構子,可用以產生空白物件。</p>
+
+<ol>
+ <li>將下列輸入瀏覽器的 JavaScript 主控台內:
+ <pre class="brush: js">var person1 = new Object();</pre>
+ </li>
+ <li>如此會在 <code>person1</code> 變數中儲存 1 組空白物件。接著可透過點 (dot-) 或括弧記法 (bracket notation) 為此物件新增屬性與函式。如下列範例:
+ <pre class="brush: js">person1.name = 'Chris';
+person1['age'] = 38;
+person1.greeting = function() {
+ alert('Hi! I\'m ' + this.name + '.');
+}</pre>
+ </li>
+ <li>你可將一組物件實字傳送給 <code>Object()</code> 建構子作為參數,藉以預先填入屬性\函式。如下所示:
+ <pre class="brush: js">var person1 = new Object({
+ name : 'Chris',
+ age : 38,
+ greeting : function() {
+ alert('Hi! I\'m ' + this.name + '.');
+ }
+});</pre>
+ </li>
+</ol>
+
+<h3 id="使用_create_函式">使用 create() 函式</h3>
+
+<p>建構子可以幫助你保持程式的可讀性 — 你可以將建構子建立在同一個地方,並根據需求從這些建構子中建立物件實例,這樣做可以讓你清楚地得知它們的來源。</p>
+
+<p>不過,有些人偏好建立物件實例,而不先做建構子,尤其是他們的物件不會用很多實例時。JavaScript 有個稱作 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code> 的內建函式能讓你這麼做。有了它,你就能根據現有物件,建立新的物件。</p>
+
+<ol>
+ <li>在 JavaScript 主控台裡測試:
+ <pre class="brush: js">var person2 = Object.create(person1);</pre>
+ </li>
+ <li>再測試以下:
+ <pre class="brush: js">person2.name
+person2.greeting()</pre>
+ </li>
+</ol>
+
+<p>你會看到 <code>person2</code> 是根據 <code>person1</code> 所建立:它具備了相同的屬性以及可用的函式。</p>
+
+<p><code>create()</code> 的其中一個限制,就是 IE8 並不支援。因此,如果你需要支援舊版瀏覽器,建構子會比較有用。</p>
+
+<p>我們後續會再說明 <code>create()</code> 的效果。</p>
+
+<h2 id="總結">總結</h2>
+
+<p>本文簡略說明了 OO 理論,雖然還沒全部講完,至少也讓你初步了解到本文所要闡述的重點。此外,我們已經開始說明 JavaScript 與 OO 之間的關係、其與「傳統 OO」之間的差異、使用建構子於 JavaScript 中實作類別的方法,以及其他產生物件實例的方式。</p>
+
+<p>下一篇文章將說明 JavaScript 物件原型。</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li>
+ <li><a href="/zh-TW/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/objects/object_building_practice/index.html b/files/zh-tw/learn/javascript/objects/object_building_practice/index.html
new file mode 100644
index 0000000000..4a47aa39eb
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/object_building_practice/index.html
@@ -0,0 +1,283 @@
+---
+title: 物件建構實作
+slug: Learn/JavaScript/Objects/Object_building_practice
+tags:
+ - Canvas
+ - JavaScript
+translation_of: Learn/JavaScript/Objects/Object_building_practice
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">我們解說完必要的 JavaScript 物件理論以及語法細節,想先幫你把根紮好。接著就透過實作範例,讓你實際建立自己有趣又多彩的 JavaScript 物件。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必備條件:</th>
+ <td>基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉) 與 OOJS 基本概念 (參閱〈<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>〉)。</td>
+ </tr>
+ <tr>
+ <th scope="row">要點:</th>
+ <td>親手實作物件與物件導向 (OO) 技術。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="弄一些彈跳彩球">弄一些彈跳彩球</h2>
+
+<p>本文將帶領你實作經典的「彈跳球」展示網頁,讓你了解物件在 JavaScript 中的用處。這些小球會在畫面上四處彈跳,而且互相碰撞時變換顏色。範例成品如下:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13865/bouncing-balls.png" style="display: block; height: 614px; margin: 0px auto; width: 800px;"></p>
+
+<ol>
+</ol>
+
+<p>此範例將透過 <a href="/en-US/docs/Web/API/Canvas_API">Canvas API</a> 在畫面上繪製球體,<a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> API 則是繪製整個動畫;而且你不需先了解此兩個 API。但我們希望在看完本文之後,能引起大家深入探究此兩個 API 的興趣。整個過程會利用某些花俏的物件,並讓你看到幾項有趣技術,像是球體從牆上回彈,並檢查球體是否互相碰撞 (也就是碰撞偵測)。</p>
+
+<h2 id="著手開始">著手開始</h2>
+
+<p>先複製 <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index.html">index.html</a></code><code>、<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a></code>、<code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main.js">main.js</a></code> 檔案到你的本機磁碟中。這些檔案分別具備下列:</p>
+
+<ol>
+ <li>極簡的 HTML 文件,具備 1 個 {{HTMLElement("h1")}} 元素、1 個 {{HTMLElement("canvas")}} 元素可繪製彩球,以及其他元素可將 CSS 與 JavaScript 套用到 HTML 之上。</li>
+ <li>一些極簡單的樣式,主要可作為 <code>&lt;h1&gt; 的樣式風格與定位之用,並省去網頁邊緣的捲動棒或空白</code> (看起來更簡約)。</li>
+ <li>某些 JavaScript 可用以設定 <code>&lt;canvas&gt;</code> 元素,另有通用函式可供我們往後使用。</li>
+</ol>
+
+<p>指令碼第一部分就像:</p>
+
+<pre class="brush: js">var canvas = document.querySelector('canvas');
+
+var ctx = canvas.getContext('2d');
+
+var width = canvas.width = window.innerWidth;
+var height = canvas.height = window.innerHeight;</pre>
+
+<p>此指令碼將為 <code>&lt;canvas&gt;</code> 元素提供參照,接著於其上呼叫 <code><a href="/en-US/docs/Web/API/HTMLCanvasElement/getContext">getContext()</a></code> 函式,藉以提供能開始繪圖的內文 (Context)。所產生的變數 (<code>ctx</code>) 也就是物件,將直接呈現 canvas 的繪圖區域,讓我們繪製 2D 圖像。</p>
+
+<p>接著設定 <code>width</code> 與 <code>height</code> 共 2 個變數,也就是 canvas 元素的寬度與高度 (透過 <code>canvas.width</code> 與 <code>canvas.height</code> 屬性呈現) 即等於瀏覽器可視區的寬度與高度 (也就是網頁顯示的區域 — 可經由 {{domxref("Window.innerWidth")}} 與 {{domxref("Window.innerHeight")}} 屬性得知)。</p>
+
+<p>你會看到我們在這裡串連了多個指定式,以快速設定所有變數,而且運作無虞。</p>
+
+<p>剛開始的指令碼後半部如下:</p>
+
+<pre class="brush: js">function random(min, max) {
+ var num = Math.floor(Math.random()*(max-min)) + min;
+ return num;
+}</pre>
+
+<p>此函式共有 2 組參數 (argument),並會回傳此範圍之內的任意值。</p>
+
+<h2 id="在程式中設定球體的模型">在程式中設定球體的模型</h2>
+
+<p>我們的程式會讓一堆彩球在畫面中彈來彈去。因為這些球體的行動方式均相同,所以透過物件呈現這些彩球也合情合理。先在程式碼底部加入下列建構子:</p>
+
+<pre class="brush: js">function Ball() {
+ this.x = random(0,width);
+ this.y = random(0,height);
+ this.velX = random(-7,7);
+ this.velY = random(-7,7);
+ this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
+ this.size = random(10,20);
+}</pre>
+
+<p>這裡我們要定義某些屬性,以利彩球能在程式中動作:</p>
+
+<ul>
+ <li><code>x</code> 與 <code>y</code> 座標 — 每顆彩球都會先有位於畫面中的隨機水平\垂直座標。範圍從 0 (最左上角) 到瀏覽器可視區的寬\高度 (最右下角) 為止。</li>
+ <li>水平與垂直速度 (<code>velX</code> 與 <code>velY</code>) — 每顆彩球均具備隨機的速度值;在我們開始彩球動畫時,這些數值就會加上 <code>x</code>/<code>y</code> 座標值,以利在各畫格(frame)中移動彩球。</li>
+ <li><code>color</code> — 彩球的顏色是隨機產生。</li>
+ <li><code>size</code> — 各彩球大小亦為隨機,從 10 到 20 像素不等。</li>
+</ul>
+
+<p>屬性講完了,那函式呢?程式中的彩球要實際運作才行。</p>
+
+<h3 id="繪製球體">繪製球體</h3>
+
+<p>先將下列 <code>draw()</code> 函式加到 <code>Ball() 的</code> <code>prototype 之中:</code></p>
+
+<pre class="brush: js">Ball.prototype.draw = function() {
+ ctx.beginPath();
+ ctx.fillStyle = this.color;
+ ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+ ctx.fill();
+}</pre>
+
+<p>透過此函式,再呼叫我們之前定義在 2D canvas 內文(ctx)中的物件成員,就能讓球體自己在螢幕上畫出自己。此內文就像是白紙一樣,接著就用筆在紙上畫出點東西:</p>
+
+<ul>
+ <li>首先以 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code> 聲明我們要在紙上畫出來的形狀。</li>
+ <li>接著用 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> 定義該形狀所要呈現的顏色 — 設定為球體的 <code>color</code> 屬性。</li>
+ <li>再用 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/arc">arc()</a></code> 函式在紙上勾勒出弧形。相關參數為:
+ <ul>
+ <li>弧形中心的 <code>x</code> 與 <code>y</code> 位置 — 我們指定球體的 <code>x</code> 與 <code>y</code> 屬性。</li>
+ <li>弧形半徑 — 指定球體的 <code>size</code> 屬性。</li>
+ <li>最後 2 項參數則指定弧形繪製時的圓圈起、終點角度。我們這裡指定 0 度與 <code>2 * PI</code> 度,這也等於半徑繞了 360 度 (你必須在半徑中指定,有點煩)。如此構成完整的圓。如果你只設定了 <code>1 * PI,就會只有半球體</code> (即 180 度)。</li>
+ </ul>
+ </li>
+ <li>最後使用 <code><a href="/en-US/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code> 函式,基本上是用來聲稱「完成我們以 <code>beginPath()</code> 開始的繪圖路徑,再用 <code>fillStyle 中指定的色彩將之填滿</code>」。</li>
+</ul>
+
+<p>你已經可以開始測試自己的物件了。</p>
+
+<ol>
+ <li>儲存目前的程式碼,在瀏覽器中載入此 HTML 檔案。</li>
+ <li>開啟瀏覽器的 JavaScript 主控台,並在主控台開啟時重新整理網頁,讓 canvas 尺寸變更為左側較小型的可視區域。</li>
+ <li>鍵入下列程式碼以建立新的球體實例:
+ <pre class="brush: js">var testBall = new Ball();</pre>
+ </li>
+ <li>再呼叫其成員:
+ <pre class="brush: js">testBall.x
+testBall.size
+testBall.color
+testBall.draw()</pre>
+ </li>
+ <li>輸入最後一行之後,應該就能看到 canvas 上出現自己產生的球體。</li>
+</ol>
+
+<h3 id="更新球體的資料">更新球體的資料</h3>
+
+<p>現在可以繪製彩球了。但在讓球彈跳之前,我們必須先更新幾個函式。將下列程式碼加到 JavaScript 檔案底端,把 <code>update()</code> 函式加到 <code>Ball()</code> 的 <code>prototype</code> 之中:</p>
+
+<pre class="brush: js">Ball.prototype.update = function() {
+ if((this.x + this.size) &gt;= width) {
+ this.velX = -(this.velX);
+ }
+
+ if((this.x - this.size) &lt;= 0) {
+ this.velX = -(this.velX);
+ }
+
+ if((this.y + this.size) &gt;= height) {
+ this.velY = -(this.velY);
+ }
+
+ if((this.y - this.size) &lt;= 0) {
+ this.velY = -(this.velY);
+ }
+
+ this.x += this.velX;
+ this.y += this.velY;
+}</pre>
+
+<p>函式的前 4 個部分負責檢查球體是否碰到 canvas 邊緣。如果球體抵達邊緣,我們就反轉相對加速度的方向,讓球反方向行進。以球體向上 (正向 <code>velX</code>) 時為例,接著就會改變水平速度,球體也就反向運動。</p>
+
+<p>在這 4 個情境中,我們:</p>
+
+<ul>
+ <li>檢查 <code>x</code> 座標是否大於 canvas 的寬度 (球體抵達右側邊緣)。</li>
+ <li>檢查 <code>x</code> 座標是否小於 0 (球體抵達左側邊緣)。</li>
+ <li>檢查 <code>y</code> 座標是否大於 canvas 的高度 (球體抵達底部邊緣)。</li>
+ <li>檢查 <code>y</code> 座標是否小於 0 (球體抵達頂部邊緣)。</li>
+</ul>
+
+<p>在各情境中,因為 <code>x</code>/<code>y</code> 座標為球體的中心,所以我們把球體的 <code>size</code> 納入計算,但我們不要球體在回彈之前在半路上就跳出畫面之外。</p>
+
+<p>最後 2 行則是將 <code>velX</code> 與 <code>velY</code> 值分別加入 <code>x\y</code> 座標之中;每次只要呼叫此函式,球體就會依照應有的效果移動。</p>
+
+<p>到這裡沒有問題的話,就開始弄動畫吧!</p>
+
+<h2 id="球體動起來">球體動起來</h2>
+
+<p>接著來玩玩吧。我們要加更多球到 canvas 中並開始動畫效果。</p>
+
+<ol>
+ <li>首先要弄個地方儲存所有的彩球。將下方陣列加到現有程式碼底部即可:
+ <pre class="brush: js">var balls = [];</pre>
+
+ <p>所有可提供動畫效果的程式,一般都會採用動畫迴圈,可用以更新程式中的資訊,並接著在動畫的各個畫格上繪製產生的結果。這也是大部分遊戲或類似程式的基礎。</p>
+ </li>
+ <li>再將下列程式碼加到現有程式碼底部:
+ <pre class="brush: js">function loop() {
+ ctx.fillStyle = 'rgba(0,0,0,0.25)';
+ ctx.fillRect(0,0,width,height);
+
+ while(balls.length &lt; 25) {
+ var ball = new Ball();
+ balls.push(ball);
+ }
+
+ for(i = 0; i &lt; balls.length; i++) {
+ balls[i].draw();
+ balls[i].update();
+ }
+
+ requestAnimationFrame(loop);
+}</pre>
+
+ <p>我們的 <code>loop()</code> 函式可進行:</p>
+
+ <ul>
+ <li>設定 canvas 填滿色彩或是半透明的黑色。接著透<code>過 fillRect()</code> (共 4 個參數提供起始座標,以及繪製矩形的高度與寬度),跨 canvas 的寬度與高度繪製整個矩型的色彩。如此可在繪製下一個畫格之前,先覆蓋前一個已存在的畫格;否則會看到許多隻長長的蛇爬來爬去。填充顏色已設定為半透明狀態:<code>rgba(0,0,0,0.25)</code> 可讓先前的畫格微微發亮,製造出球體移動時的小尾巴效果。如果將 0.25 更改為 1,就會完全消除尾巴。你可自己測試不同的數值,找出自己喜歡的效果。</li>
+ <li>可對 <code>Ball()</code> 建立新的實作,接著將之 <code>push()</code> 到球體陣列的最後,且彩球數量必須少於 25 個。所以整個畫面最多顯示 25 個球。你可嘗試變更 <code>balls.length &lt; 25</code> 中的數值,畫面中的彩球數量也會隨著變化。依你所用電腦\瀏覽器處理效能的不同,若繪製上千個彩球就會拖慢整個動畫的速度。</li>
+ <li>迴圈將巡過 <code>balls</code> 陣列中的所有彩球,並執行各個彩球的 <code>draw()</code> 與 <code>update()</code> 函式,以於畫面中逐一繪製,接著對下個畫格的位置與速度執行必要更新。</li>
+ <li>再以 <code>requestAnimationFrame()</code> 函式執行過此函式 — 當此函式持續執行並傳送相同的函式名稱時,就會每秒執行此函式達特定次數,以產生流暢的動畫。接著重複執行此作業,也就是函式每次執行時均會呼叫自身 1 次,進而循環執行。</li>
+ </ul>
+ </li>
+ <li>最後將下列程式碼加入最底端,呼叫函式 1 次讓動畫開始運作。
+ <pre class="brush: js">loop();</pre>
+ </li>
+</ol>
+
+<p>基本就是這樣了。試著儲存並重新整理檔案,讓你的彩球開始跳動吧!</p>
+
+<h2 id="另增碰撞偵測">另增碰撞偵測</h2>
+
+<p>現在弄點有趣的東西,就把碰撞偵測 (Collision detection) 加進程式裡,讓彩球知道自己碰到其他球了。</p>
+
+<ol>
+ <li>首先將下列函式定義加進你自己定義 <code>update()</code> 函式中 (例如 <code>Ball.prototype.update</code> 區塊):
+
+ <pre class="brush: js">Ball.prototype.collisionDetect = function() {
+ for(j = 0; j &lt; balls.length; j++) {
+ if( (!(this.x === balls[j].x &amp;&amp; this.y === balls[j].y &amp;&amp; this.velX === balls[j].velX &amp;&amp; this.velY === balls[j].velY)) ) {
+ var dx = this.x - balls[j].x;
+ var dy = this.y - balls[j].y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+
+ if (distance &lt; this.size + balls[j].size) {
+ balls[j].color = this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
+ }
+ }
+ }
+}</pre>
+
+ <p>這函式有點複雜,所以現在不瞭解如何運作的也別擔心。解釋如下:</p>
+
+ <ul>
+ <li>對每個彩球來說,我們必須檢查是否碰撞到其他球。所以要設定另一個 <code>for</code> 迴圈以循環檢視 <code>balls[]</code> 陣列中的所有彩球。</li>
+ <li>在我們的 for 迴圈中,我們立刻使用 <code>if</code> 陳述式檢查「現正透過迴圈循環檢查中」的彩球,是否即為我們目前檢查中的同一彩球。我們不需要檢查彩球是否碰撞到自己!為了達到此效果,我們檢查彩球目前的 <code>x</code>/<code>y</code> 座標與速度,是否等同於迴圈檢查的彩球。接著透過「<code>!</code>」否定檢查,所以在 if 陳述式中的程式碼,只有在彩球相異時才會執行。</li>
+ <li>接著使用一般演算法檢查 2 個球體之間的碰撞。我們基本上會檢查任 2 個球體的範圍是否重疊。另將透過〈<a href="/en-US/docs/Games/Techniques/2D_collision_detection">2D 碰撞偵測</a>〉一文進一步解釋。</li>
+ <li>如果偵測到碰撞,則隨即執行內部 <code>if</code> 陳述式的程式碼。在本範例中,我們剛設定了 2 個球體的 <code>color</code> 屬性為新的隨機色彩。但當然可以更複雜點,像是讓彩球更逼真的互相反彈,但這實作起來就更複雜了。對這類的物理模擬,開發者就必須使用如 <a href="http://wellcaffeinated.net/PhysicsJS/">PhysicsJS</a>、<a href="http://brm.io/matter-js/">matter.js</a>、<a href="http://phaser.io/">Phaser</a> 等的遊戲\物理函式庫。</li>
+ </ul>
+ </li>
+ <li>你也可以在動畫的每一畫格中呼叫此一函式。在 <code>balls[i].update();</code> 這一行下方新增下列程式碼即可:
+ <pre class="brush: js">balls[i].collisionDetect();</pre>
+ </li>
+ <li>儲存並重新整理之後,就能看到球體在碰撞時變更其色彩了!</li>
+</ol>
+
+<div class="note">
+<p><strong>注意:</strong>如果你無法讓此範例順利運作,可比較我們的<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">最後版本</a> (另可參閱<a href="http://mdn.github.io/learning-area/javascript/oojs/bouncing-balls/index-finished.html">實際執行情形</a>)。</p>
+</div>
+
+<h2 id="摘要">摘要</h2>
+
+<p>希望你喜歡撰寫出隨機彩球碰撞範例,其內並包含我們前面說過的多樣物件與 OO 技術!本文應該已提供你有用的物件實作與絕佳的實際文本。</p>
+
+<p>物件實體就到這裡。接著就是你要磨練自己的物件技術了!</p>
+
+<h2 id="另可參閱">另可參閱</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/API/Canvas_API/Tutorial">Canvas 線上教學</a> — 2D canvas 初學者指南</li>
+ <li><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></li>
+ <li><a href="/en-US/docs/Games/Techniques/2D_collision_detection">2D 碰撞偵測</a></li>
+ <li><a href="/en-US/docs/Games/Techniques/3D_collision_detection">3D 碰撞偵測</a></li>
+ <li><a href="/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript">只使用 JavaScript 的 2D 打磚塊遊戲</a> — 2D 遊戲開發初學者的絕佳線上教學</li>
+ <li><a href="/en-US/docs/Games/Tutorials/2D_breakout_game_Phaser">剖析器 (Phaser) 的 2D 打磚塊遊戲</a> — 以 JavaScript 遊戲函式庫建構 2D 遊戲的基本概念</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/javascript/objects/object_prototypes/index.html b/files/zh-tw/learn/javascript/objects/object_prototypes/index.html
new file mode 100644
index 0000000000..9bfbc98fea
--- /dev/null
+++ b/files/zh-tw/learn/javascript/objects/object_prototypes/index.html
@@ -0,0 +1,236 @@
+---
+title: 物件原型
+slug: Learn/JavaScript/Objects/Object_prototypes
+translation_of: Learn/JavaScript/Objects/Object_prototypes
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</div>
+
+<p class="summary">JavaScript 的物件即透過原型 (Prototype) 機制相互繼承功能,且與典型的物件導向 (OO) 程式語言相較,其運作方式有所差異。我們將透過本文說明相異之處、解釋原型鍊 (Prototype chain) 運作的方式,並了解原型屬性是如何將函式新增至現有的建構子 (Constructor) 之中。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">必備條件:</th>
+ <td>基本的電腦素養、已初步了解 HTML 與 CSS、熟悉 JavaScript (參閱〈<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉以及 OOJS 基礎概念 (參閱〈<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>〉。</td>
+ </tr>
+ <tr>
+ <th scope="row">主旨:</th>
+ <td>了解 JavaScript 的物件原型、原型鍊的運作方式、應如何將新的函式加入原型屬性之中。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="「原型」架構的程式語言?">「原型」架構的程式語言?</h2>
+
+<p>常有人說 JavaScript 是<strong>原型架構的程式語言 </strong>— 各個物件均具備 1 組<strong>原型物件</strong>作為範本物件,用以繼承函式與屬性。物件的原型物件可能也具備原型物件,並繼承了其上的函式與屬性。這就是我們所謂的「<strong>原型鍊 (Prototype chain)</strong>」,同時正好說明為何 A 物件的屬性與函式是透過 B 物件的屬性與函式所定義。</p>
+
+<p>精確點說,這些屬性與函式都是透過物件的建構子函式所定義,並非物件實例本身。</p>
+
+<p>傳統的 OOP 都是先定義了類別,接著在建立物件實例之後,在類型上定義的所有屬性與函式均複製到此實例。但 JavaScript 不會複製這些屬性與函式,卻是在物件實例與其建構子之間設定連結 (原型鍊中的連結),只要順著原型鍊就能在建構子之中找到屬性與函式。</p>
+
+<p>先看個範例會比較清楚點。</p>
+
+<h2 id="了解原型物件">了解原型物件</h2>
+
+<p>先回到我們寫過的 <code>Person()</code> 建構子範例。在你的瀏覽器裡載入範例。如果你還沒看完前篇文章並製作出此範例,可先使用 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 這個範例 (可看到<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">原始碼</a>)。</p>
+
+<p>我們在此範例中定義了建構子函式:</p>
+
+<pre class="brush: js">function Person(first, last, age, gender, interests) {
+
+ // property and method definitions
+
+};</pre>
+
+<p>接著建立如下的物件實例:</p>
+
+<pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre>
+
+<p>如果你在自己的 JavaScript 主控台中鍵入「<code>person1.」,應該會看到瀏覽器根據此物件可用的成員名稱開始自動補完:</code></p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13853/object-available-members.png" style="display: block; margin: 0 auto;"></p>
+
+<p>在此列表中,可以看到 <code>person1</code> 原型物件上所定義的成員,也就是 <code>Person()</code> 建構子 — <code>name</code>、<code>age</code>、<code>gender</code>、<code>interests</code>、<code>bio</code>、<code>greeting</code>。你也會看到其他如 <code>watch</code>、<code>valueOf 等,同樣也是定義在</code> <code>Person()</code> 建構子原型物件之上的成員,如此構成 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>。下圖顯示原型鍊的運作方式。</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13891/MDN-Graphics-person-person-object-2.png" style="display: block; height: 150px; margin: 0px auto; width: 700px;"></p>
+
+<p>所以當你在 <code>person1 上呼叫了「實際上是定義於 Object 上的函式」,會發生什麼事呢?舉例來說:</code></p>
+
+<pre class="brush: js">person1.valueOf()</pre>
+
+<p>此函式僅回傳所呼叫的物件數值。此範例所將發生的是:</p>
+
+<ul>
+ <li>瀏覽器先檢查 <code>person1</code> 物件上是否有可用的 <code>valueOf()</code> 函式。</li>
+ <li>其實沒有,所以瀏覽器接著檢查 <code>person1</code> 物件的原型物件 (<code>Person</code>) 上是否有可用的 <code>valueOf()</code> 函式。</li>
+ <li>同樣沒有,所以瀏覽器再檢查 <code>Person()</code> 建構子的原型物件 (<code>Object</code>) 上是否有可用的 <code>valueOf()</code> 函式。這次有,所以就會呼叫。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意:</strong>再次重申,在原型鍊中的函式與屬性並<strong>不是</strong>從任一物件複製到另一個物件,而是如上述的,沿著該原型鍊向上存取而得。</p>
+</div>
+
+<div class="note">
+<p><strong>注意:</strong>直接存取物件的原型物件,並沒有一定的方式。原型鍊中,項目之間的「連結」均定義於內部屬性之內,即 JavaScript 規格中的 <code>[[prototype]]</code> (可參閱 {{glossary("ECMAScript")}})。新版瀏覽器均具備所謂的「<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code> (兩邊都是 2 個底線)」屬性,其中就包含了物件的原型物件。舉例來說,你可嘗試「<code>person1.__proto__」</code>與「<code>person1.__proto__.__proto__</code>」看看程式碼中的鍊會是什麼樣子!</p>
+</div>
+
+<h2 id="原型屬性也定義所要繼承的成員">原型屬性也定義所要繼承的成員</h2>
+
+<p>所以該在哪裡定義所要繼承的屬性與函式呢?若看一下 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code> 參考頁面,你就會看到左邊列出許多屬性與函式,遠超過上方擷圖所列 <code>person1</code> 物件所繼承的成員數量。有些繼承了,有些則無?為什麼呢?</p>
+
+<p>原因在於,繼承的成員就是在 <code>prototype</code> 屬性 (你也能稱之為子命名空間 sub namespace) 中定義的成員,也就是以「<code>Object.prototype.」開頭的成員;並非只以「</code><code>Object.」開頭的成員。</code><code>prototype</code> 屬性值就是 1 個物件,基本上儲存了許多我們想「讓原型鍊上的物件一路繼承下去」的屬性與函式。</p>
+
+<p>所以如 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch">Object.prototype.watch()</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a></code> 等等,均可用於繼承自 <code>Object()</code> 的任何物件類型,包含以建構子建立的新物件實例。</p>
+
+<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is()</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code>,及其他未於 <code>prototype</code> 內定義的成員,也就不會繼承至 1). 物件實例或 2). 從 <code>Object() 繼承而來的物件類型。</code>這些函式\屬性都只能用於 <code>Object()</code> 建構子本身。</p>
+
+<div class="note">
+<p><strong>注意:</strong>這看起來很奇怪:你怎麼能在建構子上定義函式 (Method),而且這建構子本身也是函式 (Function)?其實「Function」也屬於一個物件類型,可參閱 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code> 建構子參考以進一步了解。</p>
+</div>
+
+<ol>
+ <li>你可自行檢查現有的原型屬性。回到我們之前的範例,試著於 JavaScript 主控台中輸入:
+ <pre class="brush: js">Person.prototype</pre>
+ </li>
+ <li>輸出結果很平淡,畢竟我們並未在自定的建構子原型上定義任何東西。依預設值,建構子的 <code>prototype</code> 都是從空白開始。現在可嘗試下列:
+ <pre class="brush: js">Object.prototype</pre>
+ </li>
+</ol>
+
+<p>這樣就會看到 <code>Object</code> 的 <code>prototype</code> 屬性中所定義的許多函式,而繼承自 <code>Object</code> 的物件也能找到這些函式。</p>
+
+<p>只要試著尋找如 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code> 等全域物件的原型上定義的函式與屬性,就會看到 JavaScript 中的其他原型鍊繼承範例。這些物件都在其原型上定義了多個成員,因此可作為你建立字串時的範例:</p>
+
+<pre class="brush: js">var myString = 'This is my string.';</pre>
+
+<p><code>myString</code> 上立刻就有多個有用的函式,如 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split">split()</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">indexOf()</a></code>、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a></code> 等。</p>
+
+<div class="warning">
+<p><strong>重要:</strong><code>prototype</code> 這個屬性,是 JavaScript 中最讓人混淆的名稱之一。你可能會認為<code>this</code>屬性即指目前物件(current object)的原型物件(prototype object),但它其實不是原型 (應該是可透過 <code>__proto__</code> 存取的內部物件(internal object)才對,記得上面說過的嗎?)。<code>prototype</code>是一個物件(object),內含了你定義所應該繼承的成員。</p>
+</div>
+
+<h2 id="再次溫習_create()">再次溫習 create()</h2>
+
+<p>我們先前講過用 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create()</a></code> 函式建立新物件實例的方法。</p>
+
+<ol>
+ <li>舉例來說,你可先在前面的 JavaScript 主控台範例中試著輸入:
+ <pre class="brush: js">var person2 = Object.create(person1);</pre>
+ </li>
+ <li><code>create()</code> 實際上是透過特定的原型物件,來建立新的物件。我們在這裡將 <code>person1</code> 作為原型物件,建立了 <code>person2</code>。你可於主控台輸入下列以測試之:
+ <pre class="brush: js">person2.__proto__</pre>
+ </li>
+</ol>
+
+<p>如此將回傳 <code>person1</code> 物件。</p>
+
+<h2 id="建構子的屬性">建構子的屬性</h2>
+
+<p>每個物件實例都具備 1 個<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">建構子</a></code>屬性,指向「用以建立實例」的原始建構子函式。</p>
+
+<ol>
+ <li>舉例來說,若在主控台中輸入下列指令:
+ <pre class="brush: js">person1.constructor
+person2.constructor</pre>
+
+ <p>應該兩者都會回傳 <code>Person()</code> 建構子,因為此建構子包含這些實例的原始定義。</p>
+
+ <p>偷吃步的方法,是將圓括弧加到 <code>constructor</code> 屬性 (須包含任何必要參數) 末端,以從該建構子建立其他物件實例。畢竟建構子也是函式 (Function),所以可透過圓括弧將之觸發。你只要納入 <code>new</code> 這個關鍵字,即可將此函式作為建構子。</p>
+ </li>
+ <li>在主控台中輸入:
+ <pre class="brush: js">var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);</pre>
+ </li>
+ <li>現在可試著存取新物件的功能,例如:
+ <pre class="brush: js">person3.name.first
+person3.age
+person3.bio()</pre>
+ </li>
+</ol>
+
+<p>這樣運作得還不差。你不需常常用這方法,但當你要建立新的實例,又因為某些原因找不到原始建構子的參照,這就特別有用了。</p>
+
+<p>此外,<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> 屬性還有其他用處。舉例來說,如果你有個物件實例,並要回傳建構子 (本身就是實例) 的名稱,就透過:</p>
+
+<pre class="brush: js">instanceName.constructor.name</pre>
+
+<p>也可嘗試:</p>
+
+<pre class="brush: js">person1.constructor.name</pre>
+
+<h2 id="修改原型">修改原型</h2>
+
+<p>先看看建構子的 <code>prototype</code> 屬性的修改範例:</p>
+
+<ol>
+ <li>回到 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 範例,先在本機儲存 1 份<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">原始碼</a>的副本。在現成的 JavaScript 中加入下列程式碼,即是將新函式新增到建構子的 <code>prototype</code> 屬性:
+
+ <pre class="brush: js">Person.prototype.farewell = function() {
+ alert(this.name.first + ' has left the building. Bye for now!');
+}</pre>
+ </li>
+ <li>儲存程式碼並在瀏覽器中載入頁面,再輸入下列程式碼:
+ <pre class="brush: js">person1.farewell();</pre>
+ </li>
+</ol>
+
+<p>這時應該會看到警示訊息且內含了建構子所定義的人名。這樣很有用,但如果能動態更新整個繼承鍊,且從建構子分割出來的所有物件實例都能使用此新的函式,就會更有用!</p>
+
+<p>花個 1 分鐘想想,我們的程式碼中定義了建構子,然後根據建構子建立實例物件,接著將新函式添增到建構子的原型:</p>
+
+<pre class="brush: js">function Person(first, last, age, gender, interests) {
+
+ // property and method definitions
+
+};
+
+var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']);
+
+Person.prototype.farewell = function() {
+ alert(this.name.first + ' has left the building. Bye for now!');
+}</pre>
+
+<p>但是 <code>farewell()</code> 函式仍可用於 <code>person1</code> 物件實例,其可用的功能已自動更新過。如此證明了我們之前對原型鍊的說明,也代表瀏覽器會沿著鍊往上找「尚未於物件實例上定義的函式」,而非「複製到實例中的函式」。如此可建構強大且靈活的系統。</p>
+
+<div class="note">
+<p><strong>注意:</strong>如果你在讓此範例運作時感覺有點困難,可參閱 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-prototype.html">oojs-class-prototype.html</a> 範例 (也可看<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-prototype.html">即時運作</a>的情形)。</p>
+</div>
+
+<p>你很少會看到在 <code>prototype</code> 屬性上定義的屬性,因為照此範例定義的屬性彈性較低,舉例來說,你可新增如下的屬性:</p>
+
+<pre class="brush: js">Person.prototype.fullName = 'Bob Smith';</pre>
+
+<p>但因為幾乎不會有人取這名字,所以就沒什麼彈性。最好可以在 <code>name.first</code> 與 <code>name.last 之外建立 fullName:</code></p>
+
+<pre class="brush: js">Person.prototype.fullName = this.name.first + ' ' + this.name.last;</pre>
+
+<p>但因為這樣會參照全域範圍,而非函式範圍,所以也不適用。若呼叫此屬性,則將回傳 <code>undefined undefined</code>。這種模式適合我們先前於原型中定義的函式,因為該函式就是在功能範圍之內,且可成功轉移至物件實例的的範圍。因此你可能會在原型中定義常數屬性 (也就是永遠不需更改的屬性),但一般來說會比較適合在建構子中定義屬性。</p>
+
+<p>事實上,許多物件定義較常見的模式,就是在建構子中定義屬性,而在原型中定義函式。這樣一來,建構子只有屬性定義;函式則切分到不同的區塊,讓整個程式碼較清楚易讀。舉例來說:</p>
+
+<pre class="brush: js">// Constructor with property definitions
+
+function Test(a,b,c,d) {
+ // property definitions
+};
+
+// First method definition
+
+Test.prototype.x = function () { ... }
+
+// Second method definition
+
+Test.prototype.y = function () { ... }
+
+// etc.</pre>
+
+<p>你可在 Piotr Zalewa 的「<a href="https://github.com/zalun/school-plan-app/blob/master/stage9/js/index.js">school plan app</a>」範例中看到實際運作的範例。</p>
+
+<h2 id="摘要">摘要</h2>
+
+<p>本文說明了 JavaScript 物件原型,包含原型物件鍊是如何讓物件能互相繼承其特性、原型屬性的本質、原型屬性又是如何能將函式新增至建構子,以及其他相關概念。</p>
+
+<p>接著我們將讓你在自己的任 2 個自訂物件之間,實作功能的繼承。</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</p>
diff --git a/files/zh-tw/learn/performance/index.html b/files/zh-tw/learn/performance/index.html
new file mode 100644
index 0000000000..9cd34ae5a9
--- /dev/null
+++ b/files/zh-tw/learn/performance/index.html
@@ -0,0 +1,124 @@
+---
+title: Web performance
+slug: Learn/Performance
+tags:
+ - CSS
+ - HTML
+ - HTTP
+ - JavaScript
+ - Learn
+ - NeedsTranslation
+ - Performance
+ - TopicStub
+ - Web Performance
+translation_of: Learn/Performance
+---
+<p>{{LearnSidebar}}{{draft}}</p>
+
+<p class="summary">Building websites requires HTML, CSS, and JavaScript. To build websites and applications people want to use, which attract and retain users, you need to create a good user experience. Part of good user experience is ensuring the content is quick to load and responsive to user interaction. This is known as web performance, and in this module you'll learn all you need to build performant websites.</p>
+
+<p>Web performance is the objective measurement and the perceived user experience of load time and runtime. Web performance is how long a site takes to load, become interactive and responsive, and how smooth the content is during user interactions. Is the scrolling smooth? Are buttons clickable? Are pop-ups quick to open up, and do they animate smoothly as they do so? Web performance includes both objective measurements like time to load, frames per second, and <a href="/en-US/docs/Web/Performance/Time_to_interactive">time to interactive</a>, and subjective experiences of how long it felt like it took the content to load.</p>
+
+<p>Many features impact performance including latency, application size, the number of DOM nodes, the number of resource requests made, JavaScript performance, CPU load, and more.  It is important to minimize the loading and response times, and add additional features to conceal latency by making the experience as available and interactive as possible, as soon as possible, while asynchronously loading in the longer tail parts of the experience.</p>
+
+<p>Web performance involves measuring the actual and perceived speeds of an application, optimizing where possible, and then monitoring the performance, to ensure that what you've optimized stays optimized.</p>
+
+<p>There are tools, APIs, and best practices that help us measure, improve performance, and monitor performance. We'll look at these too in the course of this module.</p>
+
+<h2 id="Learning_pathway">Learning pathway</h2>
+
+<p>While knowing HTML, CSS, and JavaScript is needed for implementing many web performance improvement recommendations, knowing how to build applications is not a necessary pre-condition for understanding and measuring web performance.</p>
+
+<p>Several of the introductory modules below do not require programming knowledge, though an understanding of HTML is needed for the HTML and performance module, an understanding of CSS is needed for the CSS and performance module, etc. We recommend that you work through our introductory modules first, starting with <a href="/en-US/docs/Learn/Performance/What_is_web_performance">what is web performance</a> first. The introductory modules provide an overview of web performance. The first three should be considered required reading whether you are a developer or project manager. The tech topic focused modules are more appropriate for developers using these technologies.</p>
+
+<p>The advanced modules delve deeper into topics overviewed in the introductory modules and provide overviews of performance APIs, testing and analysis tools, and performance bottleneck gotchas.</p>
+
+<p>It is recommended that you work through <a href="/en-US/docs/Learn/Getting_started_with_the_web">Getting started with the web</a> before proceeding with this topic. However, doing so isn't absolutely necessary.</p>
+
+<h2 id="Introductory_modules">Introductory modules</h2>
+
+<p>This topic contains the following modules, in a suggested order for working through them. You should definitely start with the first one.</p>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/Performance/What_is_web_performance">What is web performance?</a></dt>
+ <dd>This article starts the module off with a good look at what performance actually is — this includes the tools, metrics, APIs, networks, and groups of people we need to consider when thinking about performance, and how we can make performance part of our web development workflow.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/Perceived_performance">How do users perceive performance?</a></dt>
+ <dd>
+ <p>More important than how fast your website is in milliseconds, is how fast your users perceive your site to be. These perceptions are impacted by actual p<span style="letter-spacing: -0.00278rem;">age load time, idling, responsiveness to user interaction, and the smoothness of scrolling and other animations. In this article, we discuss the various loading metrics, animation, and responsiveness metrics, along with best practices to improve user perception, if not the actual timings.</span></p>
+ </dd>
+ <dt><a href="/en-US/docs/Learn/Performance/Basics">Web performance basics</a></dt>
+ <dd>In addition to the front end components of HTML, CSS, JavaScript, and media files, there are features that can make applications slower and features that can make applications subjectively and objectively faster. There are many APIs, developer tools, best practices, and bad practices relating to web performance. Here we'll introduce many of these features ad the basic level and provide links to deeper dives to improve performance for each topic.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/HTML_Performance_Features">HTML performance features</a></dt>
+ <dd>Some attributes and the source order of your mark-up can impact the performance or your website. By minimizing the number of DOM nodes, making sure the best order and attributes are used for including content such as styles, scripts, media, and third-party scripts, you can drastically improve the user experience. This article looks in detail at how HTML can be used to ensure maximum performance.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/Multimedia">Multimedia: images and video</a></dt>
+ <dd>The lowest hanging fruit of web performance is often media optimization. Serving different media files based on each user agent's capability, size, and pixel density is possible. Additional tips like removing audio tracks from background videos can improve performance even further. In this article we discuss the impact video, audio, and image content has on performance, and the methods to ensure that impact is as minimal as possible.</dd>
+ <dt>Responsive Images</dt>
+ <dd>While optimizing images is vital to high-performance media-rich user experiences, ensuring that images are sized appropriately for the devices that download them is especially important. In this article, we'll discuss the role of native browser features such as the &lt;picture&gt; element and the srcset attribute in efficient image delivery, and how you can use them with confidence.</dd>
+ <dt>Alternative media formats</dt>
+ <dd>When it comes to images and videos, there are more formats than you're likely aware of. Some of these formats can take your highly optimized media-rich pages even further by offering additional reductions in file size. In this guide we'll discuss some alternative media formats, how to use them responsibly so that non-supporting browsers don't get left out in the cold, and some advanced guidance on transcoding your existing assets to them.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/CSS">CSS performance features</a></dt>
+ <dd>CSS may be a less important optimization focus for improved performance, but there are some CSS features that impact performance more than others. In this article we look at some CSS properties that impact performance and suggested ways of handling styles to ensure performance is not negatively impacted.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/JavaScript">JavaScript performance best practices</a></dt>
+ <dd>JavaScript, when used properly, can allow for interactive and immersive web experiences — or it can significantly harm download time, render time, in-app performance, battery life, and user experience. This article outlines some JavaScript best practices that should be considered to ensure even complex content is as performant as possible.</dd>
+ <dt>Web font performance</dt>
+ <dd>An often overlooked aspect of performance landscape are web fonts. Web fonts are more prominent in web design than ever, yet many developers simply embed them from a third party service and think nothing of it. In this article, we'll covers methods for getting your font files as small as possible with efficient file formats and sub setting. From there, we'll go on to talk about how browsers text, and how you can use CSS and JavaScript features to ensure your fonts render quickly, and with minimal disruption to the user experience.</dd>
+</dl>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/Performance/Mobile">Mobile performance</a></dt>
+ <dd>With web access on mobile devices being so popular, and all mobile platforms having fully-fledged web browsers, but possibly limited bandwidth, CPU and battery life, it is important to consider the performance of your web content on these platforms. This article looks at mobile-specific performance considerations.</dd>
+</dl>
+
+<h2 id="In_this_section">In this section</h2>
+
+<p>{{LandingPageListSubpages}}</p>
+
+<h2 id="Advanced_Modules">Advanced Modules</h2>
+
+<dl>
+ <dt>Populating the page</dt>
+ <dd>An HTTP request is made and, hopefully, a few seconds later, the site appears. Displaying the content involves executing JavaScript, possibly modifying the DOM, calculating styles, calculating layout, and finally rendering the content, which involves painting and compositing, and can involve GPU acceleration on a separate thread.</dd>
+ <dt>Performance bottlenecks</dt>
+ <dd></dd>
+ <dt><a href="/en-US/docs/Learn/Performance/Understanding_latency">Understanding latency</a></dt>
+ <dd>
+ <p>Latency is the amount of time it takes between the browser making a request for a resource, and the browser receiving back the first byte of the resource requested. This article explains what latency is, how it impacts performance, and how to measure and improve latency.</p>
+ </dd>
+ <dt>Understanding bandwidth</dt>
+ <dd>
+ <p>Bandwidth is the amount of data (measured in Mbps or Kbps) that can be sent per second. This article explains the role of bandwidth in media-rich internet applications, how it can be measured, and how you can optimize applications to make the best use of available bandwidth.</p>
+ </dd>
+ <dt>HTTP/2 and you</dt>
+ <dd>
+ <p>The transport layer—that is, HTTP—is utterly essential to the functioning of the web, and it has only been relatively recently that it has seen a major update in the form of HTTP/2. Out of the box, HTTP/2 provides many performance improvements and advantages over its predecessor, but it also changes the landscape. In this article, you'll learn what HTTP/2 does for you, and how to fine-tune your application to make it do go even further.</p>
+ </dd>
+ <dt>The role of TLS in performance</dt>
+ <dd>
+ <p>TLS—or HTTPS as we tend to call it—is crucial in creating secure and safe user experiences. While hardware has reduced the negative impacts TLS has had on server performance, it's still represents a substantial slice of the time we spend waiting for browsers to connect to servers. This article explains the TLS handshake process, and offers some tips for reducing this time, such as OCSP stapling, HSTS preload headers, and the potential role of resource hints in masking TLS latency for third parties.</p>
+ </dd>
+ <dt><a href="/en-US/docs/Performance/Profiling_with_the_Built-in_Profiler">Profiling with the built-in profiler</a></dt>
+ <dd>Learn how to profile app performance with Firefox's built-in profiler.</dd>
+ <dt>Reading performance charts</dt>
+ <dd>Developer tools provide information on performance, memory, and network requests. Knowing how to read  <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Waterfall">waterfall</a> charts, <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Call_Tree">call trees</a>, traces, <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Flame_Chart">flame charts</a> , and <a href="https://developer.mozilla.org/en-US/docs/Tools/Performance/Allocations">allocations</a> in your browser developer tools will help you understand waterfall and flame charts in other performance tools.</dd>
+ <dt><a href="/en-US/Apps/Build/Performance/CSS_JavaScript_animation_performance">CSS and JavaScript animation performance</a></dt>
+ <dd>Animations are critical for a pleasurable user experience. This article discusses the performance differences between CSS and JavaScript-based animations.</dd>
+ <dt>Analyzing JavaScript bundles</dt>
+ <dd>No doubt, JavaScript is a big part of modern web development. While you should always strive to reduce the amount of JavaScript you use in your applications, it can be difficult to know where to start. In this guide, we'll show you how to analyze your application's script bundles, so you know <em>what</em> you're using, as well how to detect if there are duplicated scripts between bundles in your app.</dd>
+ <dt>Lazy-loading JavaScript with dynamic imports</dt>
+ <dd>When developers hear the term "lazy loading", they immediately think of below-the-fold imagery that loads when it scrolls into the viewport. But did you know you can lazy load JavaScript as well? In this guide we'll talk about the dynamic import() statement, which is a feature in modern browsers that loads a JavaScript module on demand. Of course, since this feature isn't available everywhere, we'll also show you how you can configure your tooling to use this feature in a widely compatible fashion.</dd>
+</dl>
+
+<dl>
+ <dt>Controlling resource delivery with resource hints</dt>
+ <dd>Browsers often know better than we do when it comes to resource prioritization and delivery—but they're far from clairvoyant. Native browser features enable us to hint to the browser when it should connect to another server, or preload a resource before the browser knows it ever needs it. When used judiciously, this can make fast experience seem even faster. In this article, we cover native browser features like rel=preconnect, rel=dns-prefetch, rel=prefetch, and rel=preload, and how to use them to your advantage.</dd>
+ <dt><a href="/en-US/docs/Learn/Performance/dns-prefetch">DNS-Prefetch</a></dt>
+</dl>
+
+<h2 id="See_Also">See Also</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Web/Performance/Mobile_performance_checklist">Mobile performance checklist</a></li>
+ <li><a href="/en-US/docs/Web/Apps/Fundamentals/Performance/Optimizing_startup_performance">Optimizing Startup Performance</a><a href="/en-US/docs/Web/Apps/Fundamentals/Performance/Optimizing_startup_performance"> </a></li>
+</ul>
+
+<p>{{LandingPageListSubpages}}</p>
diff --git a/files/zh-tw/learn/performance/多媒體/index.html b/files/zh-tw/learn/performance/多媒體/index.html
new file mode 100644
index 0000000000..cbd3d8e23a
--- /dev/null
+++ b/files/zh-tw/learn/performance/多媒體/index.html
@@ -0,0 +1,130 @@
+---
+title: '多媒體: 圖像跟影片'
+slug: Learn/Performance/多媒體
+translation_of: Learn/Performance/Multimedia
+---
+<p>媒體,換句話說就是圖像跟影片,平均占了網站超過70%的下載流量。以下載的效能來考慮的話,減少媒體數量和檔案大小是一個簡單可以實現的目標。 <span class="seoSummary">這篇文章聚焦在優化圖像跟影片來改善網站的效能。</span></p>
+
+<div class="blockIndicator note">
+<p>這是一篇進階的在 web 上優化多媒體的介紹,包含基本的原則還有技巧,想了更多的話,可以看  <a href="https://images.guide">https://images.guide</a>。</p>
+</div>
+
+<h2 id="為什麼要優化你的多媒體">為什麼要優化你的多媒體</h2>
+
+<p>對於平均的網站, <a href="https://discuss.httparchive.org/t/state-of-the-web-top-image-optimization-strategies/1367">51% 的頻寬消耗來自圖像, 而影像則是 25%</a>,所以我們可以說處理和優化你的多媒體是很重要的。</p>
+
+<p>你必須考慮流量的使用. 很多的人都是使用流量有限制的上網方案, 或是用多少付多少的上網方案,也就是根據用了多少 MB 來付費。這樣的問題不是只發生在新興國家的市場. 在 2018 年, <a href="https://www.ofcom.org.uk/__data/assets/pdf_file/0021/113169/Technology-Tracker-H1-2018-data-tables.pdf" rel="noopener">英國仍有 24% 在使用「用多少付多少」的方案</a>。</p>
+
+<p>你還需要考慮記憶體的問題,因為許多移動設備的 RAM 都有限。有一件很重要的事你必須要記住,下載的圖像是被儲存在記憶體裡的。</p>
+
+<h2 id="優化圖像傳送">優化圖像傳送</h2>
+
+<p>儘管是頻寬的最大消耗者,但因為圖像是非同步載入的,所以訪問者可以在下載的同時看到頁面。因此,它們對<a href="/en-US/docs/Learn/Performance/perceived_performance">感知性能的影響</a>遠低於許多人的預期。 然而,圖像在內容中很常被使用,因此,重要的應該是讓訪問者盡快地看到它們,以獲得良好的體驗。</p>
+
+<h3 id="載入策略">載入策略</h3>
+
+<p>對於大多數網站來說,最大改進之一是將不在視窗裡的圖像做 lazy-loading ,而不是在初始頁面載入時就全部下載下來,不管訪問者是否之後會往下滾動查看它們。 許多 JavaScript 函式庫都可以為你實現這個功能,例如說 lazysize,並且瀏覽器的供應商也正在著手原生的 <code>lazyload</code> 屬性,然而目前還處於實驗階段。</p>
+
+<p>除了載入圖像的子集之外,接下來您還應該研究一下圖像本身的格式:</p>
+
+<ul>
+ <li>你是否正在載入最佳格式? (見下文)</li>
+ <li>你載入的尺寸正確嗎?</li>
+ <li>你已經壓縮圖像了嗎? (查看 <a href="https://imageoptim.com/" rel="noopener">ImageOptim</a>)</li>
+</ul>
+
+<h4 id="最佳格式">最佳格式</h4>
+
+<p>這非常值得用一個章節來介紹。因為為圖像選擇正確的格式可能很棘手。格式通常取決於圖像的用途:</p>
+
+<ul>
+ <li><strong>Progressive JPEG</strong>—不需要移動卷軸就能看到的網頁圖像。</li>
+ <li><strong>WebP / JPEG-XR / JPEG2000</strong>—往下移動卷軸才能看到網頁圖像。</li>
+ <li><strong>PNG / WebP</strong>—有透明度的圖像。 </li>
+ <li><strong>SVG</strong>—向量圖, 圖示 (備註: SVGs 比 icon fonts 還要好得多!).</li>
+</ul>
+
+<p>優先在不需要移動卷軸就能看到的網頁區域使用 Progressive JPEG 的原因是因為它們會逐漸地進行渲染(因此得名),這意味著用戶可以先看到低解析度的版本,然後再逐漸地變得清晰。而不是從頂部一行一行的以最高解析度來載入圖像,或甚至只有在完全下載好後才顯示。</p>
+
+<h4 id="控制下載圖像的優先級別(和順序)">控制下載圖像的優先級別(和順序)</h4>
+
+<p>將最重要的圖像更早地呈現在訪問者面前,可以改善感知性能。</p>
+
+<p>第一件要確認的事情是,你的前景圖像標籤 <code>&lt;img /&gt;</code> 跟你定義在 CSS 裡 <code>background-image</code> 的背景圖像 — 前景圖像比背景圖像被賦予更高的優先級別。</p>
+
+<p>其次,通過採用優先級別提示,你可以在圖像標籤中添加<code>importance</code> 屬性來進一步控制優先級別。輪播是一個在圖像上使用優先級別提示的例子,它的第一個圖像的優先級高於其他的圖像。</p>
+
+<h3 id="渲染策略">渲染策略</h3>
+
+<p>由於圖像是非同步載入的,並且會在第一次渲染後繼續載入,因此,如果在載入之前未定義尺寸的話,則可能會導致頁面內容的重新編排。比如說,當圖像載入時,文字內容可能會被擠壓到下面。所以, 很重要的是,定義 <code>width</code> 跟 <code>height</code> 或是新的 <code>intrinsicsize</code> 屬性。</p>
+
+<p>對於任何的背景圖像,設置 <code>background-color</code> 的值非常重要,因為在圖像下載之前,它能讓上面的內容是能夠被閱讀的。</p>
+
+<h2 id="優化影像傳送">優化影像傳送</h2>
+
+<p>為了確保您不會將不必要的大文件發送給用戶,最好<a href="#compress"> 壓縮所有你要傳輸的影像</a>,<a href="#omptimize">優化<code>&lt;source&gt;</code> 順序</a>, 設定 <a href="https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia#Video_autoplay">autoplay</a>, <a href="#muted">移除靜音影像的聲音</a>, <a href="https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia#Video_preload">優化影像預載</a>, 還有 <a href="https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia#Consider_streaming">考慮串流</a> 這部影像。</p>
+
+<h3 id="壓縮所有影像">壓縮所有影像</h3>
+
+<p>大多數的影像壓縮工作都包含,比較影像裡的相鄰幀,並刪除原始幀和後續幀中相同的細節。你想同時壓縮影像並將其匯出為多種影像格式, 包含 WebM,MPEG-4/H.264,以及 Ogg/Theora.</p>
+
+<p>你用來創建影像的軟體可能包含優化檔案大小的功能。如果沒有的話,那麼可以考慮幾種線上工具,像是之後篇章會討論的 <a href="https://www.ffmpeg.org/">FFmpeg</a>,他可以協助編碼,解碼,轉換,以及呈現其他神奇的功能。</p>
+
+<h3 id="優化_&lt;source>_順序">優化 <code>&lt;source&gt;</code> 順序</h3>
+
+<p>從最小到最大來排序影像的來源。例如說,給定三個壓縮影像,分別為 10 MB,12MB,以及13MB, 把最小的擺在第一個,最大的擺在最後一格。</p>
+
+<pre>&lt;video width="400" height="300" controls="controls"&gt;
+ &lt;!-- WebM: 10 MB --&gt;
+ &lt;source src="video.webm" type="video/webm" /&gt;
+ &lt;!-- MPEG-4/H.264: 12 MB --&gt;
+ &lt;source src="video.mp4" type="video/mp4" /&gt;
+ &lt;!-- Ogg/Theora: 13 MB --&gt;
+ &lt;source src="video.ogv" type="video/ogv" /&gt;
+&lt;/video&gt;</pre>
+
+<p>就順序的角度來說,瀏覽器會下載它看到的第一個影像來源,因此先讓他載入一個較小的影像。就"最小"的角度來說,要確認你的壓縮影響仍然看起來不會太糟。有幾個演算法可能會讓你的影像看起來像是個會動的 gif 。雖然 128 Kb 的影像可能在用戶體驗上會比 10 MB 的影像好,可是把看起來像是 gif 粒狀的影像放在內容後面,也可能會對你的品牌產生負面影響。</p>
+
+<p>查看 <a href="http://caniuse.com/#search=video">CanIUse.com</a> 來確認現今瀏覽器對於影像以及不同媒體格式的支持。  </p>
+
+<h3 id="影像自動播放">影像自動播放</h3>
+
+<p>為了確保循環播放背景影像,你需要向影像標籤裡添加多個屬性: <code>autoplay</code>, <code>muted</code>, 以及 <code>playsinline.</code></p>
+
+<pre>&lt;video autoplay="" loop="" muted="true" playsinline="" src="backgroundvideo.mp4"&gt;</pre>
+
+<p>雖然屬性 <code>loop</code> 和 <code>autoplay</code> 在對於影像的循環跟自動播放很合理,可是 <code>muted</code> 屬性在行動裝置的瀏覽器裡是必須添加的。</p>
+
+<p><code>Playsinline</code> 在行動裝置裡的 Safari 是必須的,他讓影像可以在不需要全螢幕的模式下被播放。</p>
+
+<h3 id="移除靜音影像的聲音">移除靜音影像的聲音</h3>
+
+<p>如果你有一個 <code>hero-video</code> 或是其他靜音影片, 請將聲音從影像中移除。 </p>
+
+<pre>&lt;video autoplay="" loop="" muted="true" playsinline="" id="hero-video"&gt;
+ &lt;source src="banner_video.webm"
+ type='video/webm; codecs="vp8, vorbis"'&gt;
+ &lt;source src="web_banner.mp4" type="video/mp4"&gt;
+&lt;/video&gt;</pre>
+
+<p>這段 <code>hero-video</code> 代碼, 常出現在許多研討會網站以及公司的主頁, 它是個包括自動播放,循環播放和靜音的影像。它不包含任何控制選單,因此無法收聽聲音。通常它是沒有聲音的,但仍然存在音軌,因此它仍會消耗頻寬。然而,我們沒有理由將頻寬分給靜音影像的聲音。移除聲音可以節省 20% 的頻寬。這代表,如果你的影像是 10 MB,則節省了 2 MB。</p>
+
+<p>根據您的影像創作軟體,你也許可以在匯出和壓縮過程中刪除聲音。 如果沒有,那麼有一個免費的工具 <a href="https://www.ffmpeg.org/">FFmpeg</a> ,可以使用以下指令來為你完成此任務</p>
+
+<pre><a href="https://www.ffmpeg.org/">ffmpeg</a> -i original.mp4 -an -c:v copy audioFreeVersion.mp4</pre>
+
+<p><code>FFmpeg</code> 稱自己為"用於記錄,轉換和串流音頻和影像的完整,跨平台解決方案"。</p>
+
+<h3 id="影像預載">影像預載</h3>
+
+<p>preload 屬性具有3個可用選項:<code>auto</code>|<code>metadata</code>|<code>none</code>。預設選項是 <code>metadata</code>.</p>
+
+<p>將選項更改為 <code>auto</code> 會告訴瀏覽器自動下載整個影像。僅有在極有可能播放時才應該執行此操作,否則會浪費大量的頻寬。</p>
+
+<p><code>preload="metadata"</code> 最多可讓 3% 的影像在頁面加載時被下載。 然後對於較大的影像來說,這可能或是大量的頻寬。</p>
+
+<p><code>preload="none"</code> 不會在播放之前下載任何的影像。 這會延遲影像的啟動時間,但能夠為播放可能性較低的影像保存大量的頻寬。</p>
+
+<h3 id="考慮串流">考慮串流</h3>
+
+<p><a href="https://www.smashingmagazine.com/2018/10/video-playback-on-the-web-part-2/">串流影像讓適當的影像大小和頻寬</a> (根據網路速度) 被傳遞給用戶。 就像使用響應式圖像一樣,正確大小的影像將被傳遞到瀏覽器,從而確保用戶的快速影像啟動、低緩衝以及優化的播放。</p>
diff --git a/files/zh-tw/learn/server-side/django/admin_site/index.html b/files/zh-tw/learn/server-side/django/admin_site/index.html
new file mode 100644
index 0000000000..2fce622972
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/admin_site/index.html
@@ -0,0 +1,354 @@
+---
+title: 'Django Tutorial Part 4: Django admin site'
+slug: Learn/Server-side/Django/Admin_site
+translation_of: Learn/Server-side/Django/Admin_site
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">現在,我們已經為本地圖書館網站 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 創建了模型,我們接下來使用 Django 管理網站,去添加 一些 “真實的“ 書本數據。首先,我們展示如何用管理網站註冊模型,然後展示如何登錄和創建一些數據。本文最後,我們介紹可以進一步改進管理網站的建議。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>先完成: <a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>
+ <p>了解 Django 管理站的優點與侷限,並使用它來為我們的模型新增一些資料。</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>Django 管理應用程序可以使用您的模型,自動構建可用於創建,查看,更新和刪除記錄的網站區域。這可以在開發過程中,節省大量的時間,從而很容易測試您的模型,並了解您是否擁有正確的數據。根據網站的類型,管理應用程序也可用於管理生產中的數據。 Django 項目建議僅用於內部數據管理(即僅供管理員或組織內部人員使用),因為以模型為中心的方法,不一定是所有用戶最好的界面,並且暴露了大量不必要的關於模型的細節。</p>
+
+<p>創建基礎項目時,自動完成所有的配置文件,包含您的網站中的管理應用程序在內(有關所需實際依賴關係的信息,如有需要請看 <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">Django docs here</a>)。其結果是,要將模型添加到管理應用程序,你必須做的,僅僅是註冊他們。在本文末尾,我們將簡要介紹,如何進一步配置管理區域,以更好地顯示我們的模型數據。</p>
+
+<p>註冊模型後,我們將展示,如何創建一個新的 “超級用戶”,登錄到該網站,並創建一些書籍,作者,書籍實例和書籍類別。這些將有助於測試我們將在下一個教程中,開始創建的視圖和模板。</p>
+
+<h2 id="註冊模型Registering_models">註冊模型(Registering models )</h2>
+
+<p>首先,我們從 catalog app 中打開 <strong>admin.py</strong> (<strong>/locallibrary/catalog/admin.py</strong>),目前它長的像下面區塊,注意它已經幫你導入 <code>django.contrib.admin</code>:</p>
+
+<pre class="brush: python">from django.contrib import admin
+
+# Register your models here.</pre>
+
+<p>將下方的程式碼複製貼在 <strong>admin.py</strong> 文件下方以註冊所有模型,這段程式碼簡單來說就是先將模型導入,再呼叫 <code>admin.site.register</code> 函式來註冊每個模型。</p>
+
+<pre class="brush: python">from .models import Author, Genre, Book, BookInstance
+
+admin.site.register(Book)
+admin.site.register(Author)
+admin.site.register(Genre)
+admin.site.register(BookInstance)</pre>
+
+<div class="note"><strong>注意</strong>:如果你在上一章節最後有接受挑戰並建立一個書本的「語言模型」 (<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/Models">查看模型教學文章</a>),你必需也要導入並註冊該模型!</div>
+
+<p>這是<strong>註冊模型</strong>最簡單的方式。</p>
+
+<p>而管理站則是高度用戶化的,我們會在接下來繼續說明其它註冊你的模型的方式。</p>
+
+<h2 id="創建超級用戶Creating_a_superuser">創建超級用戶(Creating a superuser)</h2>
+
+<p>為了能夠登入管理站,我們需要一個有啟用員工狀態(<em>Staff</em> status)的使用者帳號,另外為了要能檢視與產生資料,我們也需要讓這個使用者帳號擁有管理所有物件的權限,因此,你可以透過 <strong>manage.py</strong> 來創建一個擁有所有網站存取權限的超級用戶(superuser)。</p>
+
+<p>在與 <strong>manage.py</strong> 同一個資料夾中執行下方指令,建立一個超級用戶,你會被提示要輸入「使用者名稱」、「使用者 e-mail」和「強度夠高的密碼」。</p>
+
+<pre class="brush: bash">python3 manage.py createsuperuser</pre>
+
+<p>當完成指令輸入後,一個新的超級用戶就會被加進資料庫中,再來只要重新啟動開發用 server ,你便可以進行登入測試:</p>
+
+<pre class="brush: bash">python3 manage.py runserver
+</pre>
+
+<h2 id="登入並開始使用網站">登入並開始使用網站</h2>
+
+<p>要登入網站,必須先連上  <em>/admin</em> URL (e.g. <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin</a>) 並且輸入你的超級用戶的使用者名稱與密碼(你會被重新導向登入頁面,輸入你的帳密後會再回到  <em>/admin</em> URL)。</p>
+
+<p>網站中的這部分羅列了所有以我們安裝的 app 分組的模型,你可以點擊模型名稱進入陳列所有與其相關連資料的頁面,而你可以進一步編輯它們,或者你也可以直接點擊模型名稱旁邊的 <strong>Add</strong> 連結來開始創建該類型的資料。</p>
+
+<p><img alt="Admin Site - Home page" src="https://mdn.mozillademos.org/files/13975/admin_home.png" style="display: block; height: 634px; margin: 0px auto; width: 998px;"></p>
+
+<p>點擊 Books 右邊的 <strong>Add</strong> 連結來新增一本新書(會產生如下方的對話方塊),可以去觀察每個字段(field)、小部件、提示文字(如果有的話)是如何對應到你的模型的。</p>
+
+<p>在字段中輸入值,你可以透過各個字段旁邊的 <strong>+</strong> 按鈕來新增「作者」或「書籍類別」(或者從列表中選擇你已經新增的值),當你完成後可以點選 <strong>SAVE</strong>, <strong>Save and add another</strong>, 或 <strong>Save and continue editing</strong> 來儲存該筆資料。</p>
+
+<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p>
+
+<div class="note">
+<p><strong>注意:在這邊我們希望你花點時間在你的 app 中新增一些書本、作者和書及類型(例如:奇幻等)。請確保每位作者與每種書籍類型都分別關聯了一本以上的書(這在文章稍後的實作的時候,會讓你的列表與細節視圖更加豐富有趣)</strong>。</p>
+</div>
+
+<p>當你新增完書本後,點擊上方書籤的 <strong>Home</strong> 連結回到主要管理頁面,接著點擊 <strong>Books</strong> 連結來展示目前的書本清單(你也可以點及其他連結看看其他模型的列表),現在你已經加了幾本書,畫面應該會與下方截圖類似,你可以看到下方陳列了每本書的標題,這是我們在上一篇文章所提到的 Book 模型中的 <code>__str__()</code> 方法所回傳的值。</p>
+
+<p><img alt="Admin Site - List of book objects" src="https://mdn.mozillademos.org/files/13935/admin_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 407px; margin: 0px auto; width: 1000px;"></p>
+
+<p>在列表中,如果要刪掉你不想要的書,只需要先勾選欲刪除書本的勾選方框,從動作下拉選單選擇刪除動作(delete action),接著點選 <strong>GO</strong> 按鈕即可,另外你也可以點選 <strong>ADD BOOK</strong> 按鈕來新增一本書。</p>
+
+<p>你可以點擊書名來編輯它,下方顯示的書本編輯頁面幾乎與 <strong>Add</strong> 頁面相同,主要差異在於頁面的標題(Change book)以及增加了 <strong>Delete</strong>, <strong>HISTORY</strong> 和 <strong>VIEW ON SITE </strong>按鈕(會有這個按鈕出現是因為我們之前在模型中有定義了 <code>get_absolute_url()</code> 的方法)</p>
+
+<p><img alt="Admin Site - Book Edit" src="https://mdn.mozillademos.org/files/13977/admin_book_modify.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p>
+
+<p>現在透過頁面上方的索引連結回到 <strong>Home</strong> 頁面,然後看看 <strong>Author</strong> 和 <strong>Genre</strong> 列表,你在新增書本的時候應該已經新增了一些資料,不過你還可以再新增更多。</p>
+
+<p>你還沒有任何書本實例(Book Instances),因為這不會在建立書本時就產生(但你可以在新增 <code>BookInstance</code> 資料時新增 <code>Book</code>  ,這是 <code>ForeignKey</code> 字段的性質)。現在回到 Home 頁面然後點擊 Book instances 的 <strong>Add</strong> 按鈕,畫面會呈現如下圖的頁面,注意第一列有個很長、全域唯一的 id 編碼,它可以用來區分每本書在圖書館裡的每個副本。</p>
+
+<p><img alt="Admin Site - BookInstance Add" src="https://mdn.mozillademos.org/files/13981/admin_bookinstance_add.png" style="border-style: solid; border-width: 1px; display: block; height: 514px; margin: 0px auto; width: 863px;"></p>
+
+<p>幫你的每本書都新增幾筆不同的資料,有些資料的狀態(Status)請設成 <em>Available ,有些則設成 On loan,如果狀態為 </em><strong>not</strong> <em>Available,那記得需要設定到期日(Due back</em> date<em>)。</em></p>
+
+<p>就是這樣!你現在已經學會了如何建立與使用管理站(administration site),你也為你的 <code>Book</code>, <code>BookInstance</code>, <code>Genre</code>, 和 <code>Author</code> 模型建立了幾筆資料,再來當我們建立好視圖(Views)以及模板(Templates)後,就會開始來使用它們。</p>
+
+<h2 id="進階組態Advanced_configuration">進階組態(Advanced configuration)</h2>
+
+<p>Django 在「透過註冊模型的資訊建立管理站」這方面做得非常好:</p>
+
+<ul>
+ <li>每個模型都有各自的資料列表,每筆資料都藉由模型的 <code>__str__()</code> 方法來做分辨,而且會連結到更詳細的視圖/表格以便後續編輯,而且在預設情況下,這個視圖(View)的上方有一個「動作清單(action menu)」,你可以使用裡面的 delete 功能來執行資料的刪除作業。</li>
+ <li>用於編輯和新增紀錄的模型詳細紀錄表單包含了模型中的所有字段,並依照宣告順序垂直排列。</li>
+</ul>
+
+<p>你可以進一步訂製介面讓它更好用,以下是你可以進一步做的:</p>
+
+<ul>
+ <li>列表視圖(List views):
+ <ul>
+ <li>為每一筆紀錄增加額外的字段/資訊陳列。</li>
+ <li>為這些紀錄列表增加篩選器(例如:使用日期、使用狀態進行過濾)</li>
+ <li>為動作選單(action menu)添加額外的動作,並選擇是否要讓此選單在表格中呈現。</li>
+ </ul>
+ </li>
+ <li>細節視圖(Detail views):
+ <ul>
+ <li>選擇那些字段要隨著「順序、分組、可否編輯、是否被模組使用、取向」而陳列(或排除)。</li>
+ <li>添加相關的字段來允許內聯編輯(inline editing)(例如:添加一個功能讓你可以在新增一個作者的時候也順便能夠新增或編輯他的書本記錄)。</li>
+ </ul>
+ </li>
+</ul>
+
+<p>這部分我們將要來看幾個有助於改善 <em>LocalLibrary 介面的小變化,包含了添加更多資訊到 </em><code>Book</code> 和 <code>Author</code> 模型列表,以及改善編輯視圖的排版。我們不會改變 <code>Language</code> 和 <code>Genre</code> 的模型外貌因為他們都各只有1個字段,這樣做沒好處!</p>
+
+<p>你可以在 <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">The Django Admin site</a> (Django Docs) 找到關於管理站訂製選擇的完整參考。</p>
+
+<h3 id="註冊一個_模型管理_類別_ModelAdmin_class">註冊一個 模型管理 類別 (ModelAdmin class)</h3>
+
+<p>為了要改變模型在管理站的陳列方式,你需要定義一個模型管理(<a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-objects">ModelAdmin</a>)類別 (他是用來描述排版的),並且將它與其他模型一起註冊。</p>
+
+<p>我們現在先從 <code>Author</code> 模型開始。打開 catalog app 中的 <strong>admin.py</strong> 檔案(<strong>/locallibrary/catalog/admin.py</strong>),並將先前註冊 <code>Author</code> 模型的程式碼註解(在程式碼前面加一個 # 前綴):</p>
+
+<pre class="brush: js"># admin.site.register(Author)</pre>
+
+<p>現在加上一個新的 <code>AuthorAdmin</code> 類別與註冊函式,如下方所示:</p>
+
+<pre class="brush: python"># Define the admin class
+class AuthorAdmin(admin.ModelAdmin):
+ pass
+
+# Register the admin class with the associated model
+admin.site.register(Author, AuthorAdmin)
+</pre>
+
+<p>現在我們要為 <code>Book</code> 以及 <code>BookInstance</code> 模型添加 <code>ModelAdmin</code> 類別,我們一樣要先把原本的註冊程式碼註解:</p>
+
+<pre class="brush: js">#admin.site.register(Book)
+#admin.site.register(BookInstance)</pre>
+
+<p>現在我們要創造並註冊新的模型;為了達到示範的目的,我們會使用 <code>@register</code> 裝飾器替代先前做法來註冊模型(這跟 <code>admin.site.register()</code> 的語法做的事情完全一樣):</p>
+
+<pre class="brush: python"># Register the Admin classes for Book using the decorator
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+ pass
+
+# Register the Admin classes for BookInstance using the decorator
+@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+ pass</pre>
+
+<p>目前為止我們的管理類別都是空的(可以看到 "<code>pass"</code>),所以我們的管理行為都不會改變!現在我們可以來進一步定義我們的「特定模型的管理行為」。</p>
+
+<h3 id="配置列表視圖Configure_list_views">配置列表視圖(Configure list views)</h3>
+
+<p>我們的 <em>LocalLibrary 目前條列出所有作者,而他們都是使用以模型的 </em><code>__str__()</code><em> 方法產生的物件名稱。如過你只有少數幾個作者,那倒還好,但如果作者很多,你最後可能會有非常多副本。因此為了區別他們,或者你只是想呈現更多作者的有趣訊息,你可以使用「列表展示」(</em><a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display">list_display</a><em>)來位視圖添加額外的字段。</em></p>
+
+<p>將你的 <code>AuthorAdmin</code> 類別以下方程式碼取代。下方程式碼可以看出來,列表中被展示出來的字段名稱會被以需要的排序宣告為元組(tuple)形式。</p>
+
+<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin):
+ list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')</pre>
+
+<p>現在把網站導向作者列表,上方所設定的字段應該會被陳列出來,如下:</p>
+
+<p><img alt="Admin Site - Improved Author List" src="https://mdn.mozillademos.org/files/14023/admin_improved_author_list.png" style="border-style: solid; border-width: 1px; display: block; height: 302px; margin: 0px auto; width: 941px;"></p>
+
+<p>至於我們的 <code>Book</code> 模型,我們將額外添加 <code>author</code> 和 <code>genre</code> 兩樣。<code>author</code> 是一個<code>ForeignKey</code> 外鍵字段(一對一)關係,因此他將會透過關聯紀錄的 <code>__str__()</code> 值來表示。</p>
+
+<p>將 <code>BookAdmin</code> 類別以下方區段程式碼取代:</p>
+
+<pre class="brush: python">class BookAdmin(admin.ModelAdmin):
+ list_display = ('title', 'author', 'display_genre')</pre>
+
+<p>很不幸地,我們無法直接在 <code>list_display</code> 中指定「書籍類別」(<font face="Consolas, Liberation Mono, Courier, monospace">genre </font>field)字段,因為它是一個 <code>ManyToManyField</code> (多對多字段),因為如果這樣做會造成很大的資料庫讀寫「成本」,所以 Django 會預防這樣的狀況發生,因此,取而代之,我們將定義一個 <code>display_genre</code> 函式以「字串」形式得到書籍類別。(下方有定義此函式)</p>
+
+<div class="note">
+<p><strong>Note</strong>: Getting the <code>genre</code> may not be a good idea here, because of the "cost" of the database operation. We're showing you how because calling functions in your models can be very useful for other reasons — for example to add a <em>Delete </em>link next to every item in the list.</p>
+</div>
+
+<p>將以下程式碼添加到<code>Book</code>模型(<strong>models.py</strong>)。 這會從<code>genre</code>記錄的的頭三個值(如果有的話)創建一個字符串, 和創建一個在管理者網站中出現的<code>short_description</code>標題。</p>
+
+<pre class="brush: python">    def display_genre(self):
+ """Create a string for the Genre. This is required to display genre in Admin."""
+ return ', '.join(genre.name for genre in self.genre.all()[:3])
+
+ display_genre.short_description = 'Genre'
+</pre>
+
+<p>保存模型並更新管理員後,打開您的網站並轉到“Books”列表頁面; 您應該會看到類似以下的書籍清單:</p>
+
+<p><img alt="Admin Site - Improved Book List" src="https://mdn.mozillademos.org/files/14025/admin_improved_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 337px; margin: 0px auto; width: 947px;"></p>
+
+<p><code>Genre</code> 模型(如果定義了語言模型,則還有 <code>Language</code> 模型)都有一個欄位,因此沒有必要為它們創建其他模型以顯示欄位。</p>
+
+<div class="note">
+<p>注意: 更新 <code>BookInstance</code> 模型列表用來顯示狀態和預期的返回日期是有價值的。 我們在本文結尾處添加了一個挑戰!</p>
+</div>
+
+<h3 id="加入列表過濾器_List_Filter">加入列表過濾器 (List Filter)</h3>
+
+<p>當你的列表有很多個記錄時, 加入列表過濾器可以幫助你過濾想顯示的記錄。加入<code>list_filter</code>這個屬性就可以。請用以下的程式碼來取代原本的 <code style="font-style: normal; font-weight: normal;">BookInstanceAdmin</code> 類別</p>
+
+<pre class="brush: python">class BookInstanceAdmin(admin.ModelAdmin):
+<strong> list_filter = ('status', 'due_back')</strong>
+</pre>
+
+<p>現在的列表視圖右邊會多了一個過濾器。你可以選擇 dates 和 status 來做過濾:</p>
+
+<p><img alt="Admin Site - BookInstance List Filters" src="https://mdn.mozillademos.org/files/14037/admin_improved_bookinstance_list_filters.png" style="height: 528px; width: 960px;"></p>
+
+<h3 id="組織詳細視圖佈局">組織詳細視圖佈局</h3>
+
+<p>默認情況下,局部視圖按照模型中聲明的順序垂直排列所有字段。 您可以更改聲明的順序,顯示(或排除)哪些字段,使用分段來組織資訊,水平顯示還是垂直顯示字段,甚至管理表單中使用哪些編輯小部件。</p>
+
+<div class="note">
+<p>注意:  <em>LocalLibrary</em> 模型相對簡單,因此我們無須更改佈局。 但我們仍然會進行一些更改,向您展示如何進行。</p>
+</div>
+
+<h4 id="控制那些欄位顯示並佈置">控制那些欄位顯示並佈置</h4>
+
+<p>更新你的 <code>AuthorAdmin</code> 類別用來新增 <code>fields</code> 這行,如同下列所示 (粗體):</p>
+
+<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin):
+ list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+<strong> fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]</strong>
+</pre>
+
+<p><code>fields</code> 屬性僅按順序列出了要在表單上顯示的那些欄位。 默認情況下,字段是垂直顯示的,但是如果您進一步將它們分組到一個元組中,它們將水平顯示(如上面的“日期”字段中所示)。</p>
+
+<p>在您的網站上,轉到作者詳細信息視圖-現在應如下所示:</p>
+
+<p><img alt="Admin Site - Improved Author Detail" src="https://mdn.mozillademos.org/files/14027/admin_improved_author_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 282px; margin: 0px auto; width: 928px;"></p>
+
+<div class="note">
+<p><strong>注意</strong>: 您還可以使用 <code>exclude</code> 屬性來聲明要從表單中排除的屬性列表(將顯示模型中的所有其他屬性)。</p>
+</div>
+
+<h4 id="Sectioning_the_detail_view">Sectioning the detail view</h4>
+
+<p>You can add "sections" to group related model information within the detail form, using the <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a> attribute.</p>
+
+<p>In the <code>BookInstance</code> model we have information related to what the book is (i.e. <code>name</code>, <code>imprint</code>, and <code>id</code>) and when it will be available (<code>status</code>, <code>due_back</code>). We can add these in different sections by adding the text in bold to our <code>BookInstanceAdmin</code> class. </p>
+
+<pre class="brush: python">@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+ list_filter = ('status', 'due_back')
+
+<strong> fieldsets = (
+ (None, {
+ 'fields': ('book', 'imprint', 'id')
+ }),
+ ('Availability', {
+ 'fields': ('status', 'due_back')
+ }),
+ )</strong></pre>
+
+<p>Each section has its own title (or <code>None</code>, if you don't want a title) and an associated tuple of fields in a dictionary — the format is complicated to describe, but fairly easy to understand if you look at the code fragment immediately above.</p>
+
+<p>Now navigate to a book instance view in your website; the form should appear as shown below:</p>
+
+<p><img alt="Admin Site - Improved BookInstance Detail with sections" src="https://mdn.mozillademos.org/files/14029/admin_improved_bookinstance_detail_sections.png" style="border-style: solid; border-width: 1px; display: block; height: 580px; margin: 0px auto; width: 947px;"></p>
+
+<h3 id="Inline_editing_of_associated_records">Inline editing of associated records</h3>
+
+<p>Sometimes it can make sense to be able to add associated records at the same time. For example, it may make sense to have both the book information and information about the specific copies you've got on the same detail page.</p>
+
+<p>You can do this by declaring <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines">inlines</a>, of type <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> (horizonal layout) or <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.StackedInline">StackedInline</a> (vertical layout, just like the default model layout). You can add the <code>BookInstance</code> information inline to our <code>Book</code> detail by adding the lines below in bold near your <code>BookAdmin</code>:</p>
+
+<pre class="brush: python"><strong>class BooksInstanceInline(admin.TabularInline):
+    model = BookInstance</strong>
+
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+<strong>    inlines = [BooksInstanceInline]</strong>
+</pre>
+
+<p>Now navigate to a view for a <code>Book</code> in your website — at the bottom you should now see the book instances relating to this book (immediately below the book's genre fields):</p>
+
+<p><img alt="Admin Site - Book with Inlines" src="https://mdn.mozillademos.org/files/14033/admin_improved_book_detail_inlines.png" style="border-style: solid; border-width: 1px; display: block; height: 889px; margin: 0px auto; width: 937px;"></p>
+
+<p>In this case all we've done is declare our tabular inline class, which just adds all fields from the <em>inlined</em> model. You can specify all sorts of additional information for the layout, including the fields to display, their order, whether they are read only or not,  etc. (see <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> for more information). </p>
+
+<div class="note">
+<p><strong>Note</strong>: There are some painful limits in this functionality! In the screenshot above we have three existing book instances, followed by three placeholders for new book instances (which look very similar!). It would be better to have NO spare book instances by default and just add them with the <strong>Add another Book instance</strong> link, or to be able to just list the <code>BookInstance</code>s as non-readable links from here. The first option can be done by setting the <code>extra</code> attribute to 0 in <code>BooksInstanceInline</code> model, try it by yourself.</p>
+</div>
+
+<h2 id="自我挑戰">自我挑戰</h2>
+
+<p>在本節中我們學到了很多東西,所以現在該您嘗試一些事情了。</p>
+
+<ol>
+ <li>對於<code>BookInstance</code>列表視圖(list view),添加代碼以顯示<code>books</code>,<code>status</code>,<code>due back date</code> 和 <code>id</code>(而不是默認的__str __()文本)。</li>
+ <li>使用與<code>Book/BookInstance</code>相同的方法將<code>Book</code>項目的內聯列表添加到<code>Author</code> 的詳細視圖(detail view)中。</li>
+</ol>
+
+<ul>
+</ul>
+
+<h2 id="小結">小結</h2>
+
+<p>就是這樣! 您現在已經了解瞭如何以最簡單和改進的形式設置管理者網站,如何創建超級用戶,以及如何瀏覽管理者網站,查看,刪除和更新記錄。 在此過程中,您已經創建了許多Books,BookInstances,Genres和Authors,一旦我們創建了自己的view和templates,便可以列出和顯示這些記錄。</p>
+
+<h2 id="延伸閱讀">延伸閱讀</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial02/#introducing-the-django-admin">Writing your first Django app, part 2: Introducing the Django Admin</a>  (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">The Django Admin site</a> (Django Docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/authentication/index.html b/files/zh-tw/learn/server-side/django/authentication/index.html
new file mode 100644
index 0000000000..ec15ddeffd
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/authentication/index.html
@@ -0,0 +1,698 @@
+---
+title: 'Django Tutorial Part 8: User authentication and permissions'
+slug: Learn/Server-side/Django/Authentication
+translation_of: Learn/Server-side/Django/Authentication
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">在本教程中,我們將會展示如何允許用戶使用自己的帳戶登入到您的網站,以及如何根據用戶是否已登入和權限的不同來控制他們可以執行和查看的內容。作為展示的一部分,我們會擴展 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站,添加登入頁面和登出頁面,以及用來查看已借閱的圖書的頁面 - 分為用戶與員工兩種不同頁面。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>完成至 <a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django 線上教學 7: 會話(Sessions)框架</a>為止的所有主題。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解如何設定與運用使用者驗證與權限機制。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="大綱">大綱</h2>
+
+<p>Django提供認證和授權(“ permission”)系統,該系統建立在<a href="/zh-TW/docs/Learn/Server-side/Django/Sessions">上一教程</a>中討論的會話框架的基礎上。透過它可以驗證用戶憑證並定義個別用戶能夠執行的操作。 該框架包括用於<code>Users</code> 和<code>Groups</code> 的內置模型(一般常用來一次性套用權限於一群用戶上的方式),用於指定用戶是否可以執行任務的權限/旗標,用於登入用戶的表單和視圖,以及 查看用於限制內容的工具。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 從Django角度而言,身份驗證系統需要做到非常通用,因此不提供其他網頁身份驗證系統中提供的某些功能。 需要解決一些常見問題的話可以透過第三方軟件包。 例如,限制登錄嘗試和透過第三方進行身份驗證(例如OAuth)。</p>
+</div>
+
+<p>在本教程中,我們將會展示如何在<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>網站中啟用用戶身份驗證,並建立自己的登入和登出頁面,為模型添加權限以及控制對頁面的訪問。 我們將根據身份驗證/權限顯示為用戶或是圖書館員設計的已借出書籍列表。</p>
+
+<p>身份驗證系統非常有彈性,您可以根據需要從頭開始構建URL,表單,視圖和模板,只透過提供的API來登入用戶。 但是,在本文中,我們將為登入與登出頁面使用Django的“ stock”身份驗證視圖和表單。 我們仍然需要建立一些模板,但這很簡單。</p>
+
+<p>我們還將向您展示如何建立權限,並在視圖和模板中檢查登入狀態和權限。</p>
+
+<h2 id="Enabling_authentication">Enabling authentication</h2>
+
+<p>當我們<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/skeleton_website">創建框架網站</a>時(在教程2中),身份驗證已自動啟用,因此您此時無需執行任何其他操作。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 當我們使用<code>django-admin startproject</code>命令創建應用程序時,所有必要的配置都為我們完成了。 用戶和模型權限的數據庫表是在我們首次調用<code>python manage.py migrate</code>時創建的。</p>
+</div>
+
+<p>該配置是在項目文件(<strong>locallibrary/locallibrary/settings.py</strong>)的<code>INSTALLED_APPS</code> 和<code>MIDDLEWARE</code> 部分中設置的,如下所示:</p>
+
+<pre class="brush: python notranslate">INSTALLED_APPS = [
+ ...
+<strong>    'django.contrib.auth', </strong>#Core authentication framework and its default models.
+<strong>    'django.contrib.contenttypes', #</strong>Django content type system (allows permissions to be associated with models).
+ ....
+
+MIDDLEWARE = [
+ ...
+<strong>    'django.contrib.sessions.middleware.SessionMiddleware',</strong> #Manages sessions across requests
+ ...
+<strong>    'django.contrib.auth.middleware.AuthenticationMiddleware',</strong> #Associates users with requests using sessions.
+ ....
+</pre>
+
+<h2 id="Creating_users_and_groups">Creating users and groups</h2>
+
+<p>當我們在教程4中查看<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/Admin_site">Django管理站</a>點時,您已經創建了第一個用戶(這是一個超級用戶,使用命令p<code>python manage.py createsuperuser</code>創建)。 我們的超級用戶已經通過身份驗證,並且具有所有權限,因此我們需要創建一個測試用戶來代表普通站點用戶。 我們將使用管理站點來創建本地圖書館組和網站登錄名,因為這是最快的方法之一。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 您還可以通過編程方式創建用戶,如下所示。 例如,如果要開發一個界面以允許用戶創建自己的登錄名,則必須這樣做(您不應授予用戶訪問管理站點的權限)。</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.models import User
+
+# Create user and save to the database
+user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')
+
+# Update fields and then save again
+user.first_name = 'John'
+user.last_name = 'Citizen'
+user.save()
+</pre>
+</div>
+
+<p>在下面,我們將首先創建一個組,然後創建一個用戶。 即使我們還沒有添加庫成員的任何權限,但是如果以後需要添加,將它們一次添加到組中要比分別添加到每個成員要容易得多。</p>
+
+<p>啟動開發服務器,然後在本地Web瀏覽器(<a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>)中導航到管理站點。 使用您的超級用戶帳戶的憑據登錄到該站點。 管理站點的頂層顯示所有模型,按“ django應用程序”排序。 在“<strong>Authentication and Authorisation</strong>”部分,您可以單擊<strong>Users</strong> 或<strong>Groups</strong>鏈接以查看其現有記錄。</p>
+
+<p><img alt="Admin site - add groups or users" src="https://mdn.mozillademos.org/files/14091/admin_authentication_add.png" style="border-style: solid; border-width: 1px; display: block; height: 364px; margin: 0px auto; width: 661px;"></p>
+
+<p>首先,讓我們為圖書館成員創建一個新組。</p>
+
+<ol>
+ <li>單擊<strong>Add</strong>按鈕(在組旁邊)以創建一個新組; 輸入該組的名稱“Library Members”。<br>
+ <img alt="Admin site - add group" src="https://mdn.mozillademos.org/files/14093/admin_authentication_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 561px; margin: 0px auto; width: 800px;"></li>
+ <li>我們不需要該組的任何權限,因此只需按<strong>SAVE</strong> (您將被帶到組列表)。</li>
+</ol>
+
+<p>現在讓我們創建一個用戶:</p>
+
+<ol>
+ <li>導航回到管理站點的主頁</li>
+ <li>單擊“用戶”旁邊的“添加”按鈕以打開“添加用戶”對話框。<br>
+ <img alt="Admin site - add user pt1" src="https://mdn.mozillademos.org/files/14095/admin_authentication_add_user_prt1.png" style="border-style: solid; border-width: 1px; display: block; height: 409px; margin: 0px auto; width: 800px;"></li>
+ <li>輸入適合您的測試用戶的用戶名和密碼/密碼確認</li>
+ <li>按<strong>SAVE</strong>創建用戶。<br>
+ 管理站點將創建新用戶,並立即將您帶到“更改用戶”視窗,您可以在其中更改用戶名並為用戶模型的可選字段添加信息。 這些字段包括名字,姓氏,電子郵件地址,用戶狀態和權限(僅應設置“活動”標誌)。 在更下方的位置,您可以指定用戶的組和權限,並查看與該用戶相關的重要日期(例如,他們的加入日期和上次登錄日期)。<br>
+ <img alt="Admin site - add user pt2" src="https://mdn.mozillademos.org/files/14097/admin_authentication_add_user_prt2.png" style="border-style: solid; border-width: 1px; display: block; height: 635px; margin: 0px auto; width: 800px;"></li>
+ <li>在“組”部分中,從“可用組”列表中選擇“<strong>Library Member</strong>”組,然後按框之間的右箭頭將其移至“選擇的組”框中。<img alt="Admin site - add user to group" src="https://mdn.mozillademos.org/files/14099/admin_authentication_user_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 414px; margin: 0px auto; width: 933px;"></li>
+ <li>我們在這裡不需要執行任何其他操作,因此只需再次選擇<strong>SAVE</strong> 即可進入用戶列表。</li>
+</ol>
+
+<p>就是這樣而已! 現在,您將擁有一個“普通庫成員”帳戶,您將可以使用該帳戶進行測試(一旦我們實現了頁面以使其能夠登錄)。</p>
+
+<div class="note">
+<p><strong>注意</strong>:您應該嘗試創建另一個庫成員用戶。 另外,為圖書館員創建一個組,並為其添加用戶!</p>
+</div>
+
+<h2 id="Setting_up_your_authentication_views">Setting up your authentication views</h2>
+
+<p>Django提供了創建身份驗證頁面所需的幾乎所有內容,以處理“開箱即用”的登錄,註銷和密碼管理。 這包括URL映射器,視圖和表單,但不包括模板-我們必須創建自己的模板!</p>
+
+<p>在本節中,我們顯示如何將默認系統集成到LocalLibrary網站中並創建模板。 我們將它們放在主項目URL中。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 您不必使用任何代碼,但是您可能想要使用它,因為它使事情變得容易得多。 如果您更改用戶模型(一個高級主題!),幾乎可以肯定需要更改表單處理代碼,但是即使如此,您仍然可以使用庫存視圖功能。</p>
+</div>
+
+<div class="note">
+<p><strong>注意: </strong>在這種情況下,我們可以合理地將身份驗證頁面(包括URL和模板)放入目錄應用程序中。 但是,如果我們有多個應用程序,最好將這種共享的登錄行為分開,並使其在整個站點中都可用,這就是我們在此處顯示的內容!</p>
+</div>
+
+<h3 id="Project_URLs">Project URLs</h3>
+
+<p>將以下內容添加到項目urls.py文件(<strong>locallibrary/locallibrary/urls.py</strong>)文件的底部:</p>
+
+<pre class="brush: python notranslate">#Add Django site authentication urls (for login, logout, password management)
+urlpatterns += [
+ path('accounts/', include('django.contrib.auth.urls')),
+]
+</pre>
+
+<p>導航到<a href="http://127.0.0.1:8000/accounts/">http://127.0.0.1:8000/accounts/</a> URL(注意尾隨斜杠!),然後Django將顯示一個錯誤,指出找不到此URL,並列出了它嘗試的所有URL。 從中您可以看到將起作用的URL,例如:</p>
+
+<div class="note">
+<p><strong>注意: </strong>使用上述方法會在方括號中添加以下網址,這些網址可用於反轉網址映射。 您無需執行其他任何操作-上面的url映射會自動映射以下提到的URL。</p>
+</div>
+
+<div class="note">
+<pre class="brush: python notranslate">accounts/ login/ [name='login']
+accounts/ logout/ [name='logout']
+accounts/ password_change/ [name='password_change']
+accounts/ password_change/done/ [name='password_change_done']
+accounts/ password_reset/ [name='password_reset']
+accounts/ password_reset/done/ [name='password_reset_done']
+accounts/ reset/&lt;uidb64&gt;/&lt;token&gt;/ [name='password_reset_confirm']
+accounts/ reset/done/ [name='password_reset_complete']</pre>
+</div>
+
+<p>現在嘗試導航到登錄URL(<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>)。 這將再次失敗,但是會顯示一條錯誤消息,告訴您我們在模板搜索路徑上缺少必需的模板(<strong>registration/login.html</strong>)。 您會在頂部黃色部分看到以下幾行:</p>
+
+<pre class="brush: python notranslate">Exception Type: TemplateDoesNotExist
+Exception Value: <strong>registration/login.html</strong></pre>
+
+<p>下一步是在搜索路徑上創建註冊目錄,然後添加<strong>login.html</strong>文件。</p>
+
+<h3 id="Template_directory">Template directory</h3>
+
+<p>我們剛剛添加的url(和隱式視圖)期望在模板搜索路徑中某個目錄<strong>/registration/</strong> 中找到它們的關聯模板。</p>
+
+<p>對於這個網站,我們將HTML頁面放在<strong>templates/registration/</strong>目錄中。 此目錄應位於您的項目根目錄中,即與<strong>catalog</strong> 和<strong>locallibrary</strong> 文件夾相同的目錄中)。 請立即創建這些文件夾。</p>
+
+<div class="note">
+<p><strong>Note:</strong> Your folder structure should now look like the below:<br>
+ locallibrary (django project folder)<br>
+    |_catalog<br>
+    |_locallibrary<br>
+    |_templates <strong>(new)</strong><br>
+                 |_registration</p>
+</div>
+
+<p>為了使這些目錄對模板加載器可見(即將該目錄放置在模板搜索路徑中),請打開項目設置(<strong>/locallibrary/locallibrary/settings.py</strong>),並更新<code>TEMPLATES</code> 部分的<code>DIRS</code>行,如圖所示。</p>
+
+<pre class="brush: python notranslate">TEMPLATES = [
+ {
+ ...
+<strong> 'DIRS': ['./templates',],</strong>
+ 'APP_DIRS': True,
+ ...
+</pre>
+
+<h3 id="Login_template">Login template</h3>
+
+<div class="warning">
+<p><strong>重要信息</strong>:本文提供的身份驗證模板是Django演示登錄模板的非常基本/稍作修改的版本。 您可能需要自定義它們以供自己使用!</p>
+</div>
+
+<p>創建一個名為/<strong>locallibrary/templates/registration/login.html</strong>的新HTML文件。 為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+
+{% if form.errors %}
+ &lt;p&gt;Your username and password didn't match. Please try again.&lt;/p&gt;
+{% endif %}
+
+{% if next %}
+ {% if user.is_authenticated %}
+    &lt;p&gt;Your account doesn't have access to this page. To proceed,
+    please login with an account that has access.&lt;/p&gt;
+  {% else %}
+    &lt;p&gt;Please login to see this page.&lt;/p&gt;
+  {% endif %}
+{% endif %}
+
+&lt;form method="post" action="{% url 'login' %}"&gt;
+{% csrf_token %}
+
+&lt;div&gt;
+  &lt;td&gt;\{{ form.username.label_tag }}&lt;/td&gt;
+  &lt;td&gt;\{{ form.username }}&lt;/td&gt;
+&lt;/div&gt;
+&lt;div&gt;
+  &lt;td&gt;\{{ form.password.label_tag }}&lt;/td&gt;
+  &lt;td&gt;\{{ form.password }}&lt;/td&gt;
+&lt;/div&gt;
+
+&lt;div&gt;
+  &lt;input type="submit" value="login" /&gt;
+  &lt;input type="hidden" name="next" value="\{{ next }}" /&gt;
+&lt;/div&gt;
+&lt;/form&gt;
+
+{# Assumes you setup the password_reset view in your URLconf #}
+&lt;p&gt;&lt;a href="{% url 'password_reset' %}"&gt;Lost password?&lt;/a&gt;&lt;/p&gt;
+
+{% endblock %}</pre>
+
+<p>該模板與我們之前看到的模板有一些相似之處-它擴展了我們的基本模板並覆蓋了內容塊。 其餘代碼是相當標準的表單處理代碼,我們將在以後的教程中進行討論。 現在您只需要知道的是,這將顯示一個表格,您可以在其中輸入用戶名和密碼,並且如果輸入無效的值,則在頁面刷新時會提示您輸入正確的值。</p>
+
+<p>保存模板後,導航回到登錄頁面(<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>),您應該看到類似以下內容:</p>
+
+<p><img alt="Library login page v1" src="https://mdn.mozillademos.org/files/14101/library_login.png" style="border-style: solid; border-width: 1px; display: block; height: 173px; margin: 0px auto; width: 441px;"></p>
+
+<p>如果嘗試登錄將成功,並且您將被重定向到另一個頁面(默認情況下為<a href="http://127.0.0.1:8000/accounts/profile/">http://127.0.0.1:8000/accounts/profile/</a>)。 這裡的問題是,默認情況下,Django期望登錄後將您帶到個人資料頁面,情況可能與否。 由於您尚未定義此頁面,因此會出現另一個錯誤!</p>
+
+<p>打開項目設置(<strong>/locallibrary/locallibrary/settings.py</strong>) ,然後將下面的文本添加到底部。 現在,當您登錄時,默認情況下應將您重定向到網站主頁。</p>
+
+<pre class="brush: python notranslate"># Redirect to home URL after login (Default redirects to /accounts/profile/)
+LOGIN_REDIRECT_URL = '/'
+</pre>
+
+<h3 id="Logout_template">Logout template</h3>
+
+<p>如果您導航到登出URL (<a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a>) ,則會看到一些奇怪的行為-您的用戶將被確定地註銷,但是您將被帶到<strong>Admin</strong> 註銷頁面。 那不是您想要的,僅僅是因為該頁面上的登錄鏈接將您帶到<strong>Admin</strong> 登錄屏幕(並且僅對具有<code>is_staff</code> 權限的用戶可用)。</p>
+
+<p>創建並打開 /<strong>locallibrary/templates/registration/logged_out.html</strong>。 複製以下文本:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;p&gt;Logged out!&lt;/p&gt;
+ &lt;a href="{% url 'login'%}"&gt;Click here to login again.&lt;/a&gt;
+{% endblock %}</pre>
+
+<p>這個模板非常簡單。 它僅顯示一條消息,通知您已註銷,並提供一個鏈接,您可以按此鏈接返回登錄屏幕。 如果再次進入註銷URL,您應該看到以下頁面:</p>
+
+<p><img alt="Library logout page v1" src="https://mdn.mozillademos.org/files/14103/library_logout.png" style="border-style: solid; border-width: 1px; display: block; height: 169px; margin: 0px auto; width: 385px;"></p>
+
+<h3 id="Password_reset_templates">Password reset templates</h3>
+
+<p>默認的密碼重置系統使用電子郵件向用戶發送重置鏈接。 您需要創建表格以獲取用戶的電子郵件地址,發送電子郵件,允許他們輸入新密碼並在整個過程完成時註明。</p>
+
+<p>以下模板可以用作起點。</p>
+
+<h4 id="密碼重設表格">密碼重設表格</h4>
+
+<p>這是用於獲取用戶電子郵件地址(用於發送密碼重置電子郵件)的表格。 創建<strong>/locallibrary/templates/registration/password_reset_form.html</strong>,並為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;form action="" method="post"&gt;
+ {% csrf_token %}
+ {% if form.email.errors %}
+ {{ form.email.errors }}
+ {% endif %}
+ &lt;p&gt;\{{ form.email }}&lt;/p&gt;
+ &lt;input type="submit" class="btn btn-default btn-lg" value="Reset password"&gt;
+ &lt;/form&gt;
+{% endblock %}
+</pre>
+
+<h4 id="密碼重置完成">密碼重置完成</h4>
+
+<p>收集您的電子郵件地址後,將顯示此表單。創建 <strong>/locallibrary/templates/registration/password_reset_done.html</strong>,並為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;p&gt;We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.&lt;/p&gt;
+{% endblock %}
+</pre>
+
+<h4 id="密碼重置電子郵件">密碼重置電子郵件</h4>
+
+<p>該模板提供了HTML電子郵件的文本,其中包含我們將發送給用戶的重置鏈接。 創建<strong>/locallibrary/templates/registration/password_reset_email.html</strong>,並為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">Someone asked for password reset for email \{{ email }}. Follow the link below:
+\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
+</pre>
+
+<h4 id="密碼重置確認">密碼重置確認</h4>
+
+<p>單擊密碼重置電子郵件中的鏈接後,即可在此頁面輸入新密碼。 創建 <strong>/locallibrary/templates/registration/password_reset_confirm.html</strong>,並為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ {% if validlink %}
+ &lt;p&gt;Please enter (and confirm) your new password.&lt;/p&gt;
+ &lt;form action="" method="post"&gt;
+ &lt;div style="display:none"&gt;
+ &lt;input type="hidden" value="\{{ csrf_token }}" name="csrfmiddlewaretoken"&gt;
+ &lt;/div&gt;
+ &lt;table&gt;
+ &lt;tr&gt;
+ &lt;td&gt;\{{ form.new_password1.errors }}
+ &lt;label for="id_new_password1"&gt;New password:&lt;/label&gt;&lt;/td&gt;
+ &lt;td&gt;\{{ form.new_password1 }}&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;\{{ form.new_password2.errors }}
+ &lt;label for="id_new_password2"&gt;Confirm password:&lt;/label&gt;&lt;/td&gt;
+ &lt;td&gt;\{{ form.new_password2 }}&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;&lt;/td&gt;
+ &lt;td&gt;&lt;input type="submit" value="Change my password" /&gt;&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;/table&gt;
+ &lt;/form&gt;
+ {% else %}
+ &lt;h1&gt;Password reset failed&lt;/h1&gt;
+ &lt;p&gt;The password reset link was invalid, possibly because it has already been used. Please request a new password reset.&lt;/p&gt;
+ {% endif %}
+{% endblock %}
+</pre>
+
+<h4 id="密碼重置完成_2">密碼重置完成</h4>
+
+<p>這是最後一個密碼重設模板,密碼重設成功後將顯示此模板以通知您。 創建<strong>/locallibrary/templates/registration/password_reset_complete.html</strong>,並為其提供以下內容:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;The password has been changed!&lt;/h1&gt;
+ &lt;p&gt;&lt;a href="{% url 'login' %}"&gt;log in again?&lt;/a&gt;&lt;/p&gt;
+{% endblock %}</pre>
+
+<h3 id="Testing_the_new_authentication_pages">Testing the new authentication pages</h3>
+
+<p>現在您已經添加了URL配置並創建了所有這些模板,身份驗證頁面現在應該可以正常工作了!</p>
+
+<p>您可以通過嘗試使用以下URL登錄然後註銷超級用戶帳戶來測試新的身份驗證頁面:</p>
+
+<ul>
+ <li><a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a></li>
+ <li><a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a></li>
+</ul>
+
+<p>您可以通過登錄頁面中的鏈接測試密碼重置功能。 <strong>請注意,Django只會將重置電子郵件發送到已經存儲在其數據庫中的地址(用戶)!</strong></p>
+
+<div class="note">
+<p><strong>筆記</strong>:密碼重設系統要求您的網站支持電子郵件,這不在本文的討論範圍之內,因此該部分尚無法使用。 要進行測試,請將以下行放在settings.py文件的末尾。 這將記錄發送到控制台的所有電子郵件(因此您可以從控制台複製密碼重置鏈接)。</p>
+
+<pre class="brush: python notranslate">EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+</pre>
+
+<p>有關更多信息,請參閱發送電子郵件(<a href="https://docs.djangoproject.com/en/2.0/topics/email/">Sending email</a>Django文檔)。</p>
+</div>
+
+<h2 id="針對經過身份驗證的用戶進行測試">針對經過身份驗證的用戶進行測試</h2>
+
+<p>本節介紹如何根據用戶是否登錄來有選擇地控制用戶看到的內容。</p>
+
+<h3 id="在模板中測試">在模板中測試</h3>
+
+<p>您可以使用 <code>\{{ user }}</code>模板變量在模板中獲取有關當前登錄用戶的信息(默認情況下,就像我們在框架中一樣設置項目時,該信息會添加到模板上下文中)。</p>
+
+<p>通常,您將首先針對 <code>\{{ user.is_authenticated }}</code>模板變量進行測試,以確定該用戶是否有資格查看特定內容。 為了演示這一點,接下來,我們將更新邊欄,以在用戶註銷時顯示“登錄”鏈接,在用戶登錄時顯示“註銷”鏈接。</p>
+
+<p>打開基礎模板。 (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) ,然後將以下文本複製到<code>sidebar</code> 塊中,緊接在<code>endblock</code> 模板標籤之前。</p>
+
+<pre class="brush: html notranslate"> &lt;ul class="sidebar-nav"&gt;
+
+ ...
+
+ <strong>{% if user.is_authenticated %}</strong>
+ &lt;li&gt;User: <strong>\{{ user.get_username }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;a href="{% url 'logout'%}?next=\{{request.path}}"&gt;Logout&lt;/a&gt;&lt;/li&gt;
+ <strong>{% else %}</strong>
+ &lt;li&gt;&lt;a href="{% url 'login'%}?next=\{{request.path}}"&gt;Login&lt;/a&gt;&lt;/li&gt;
+ <strong>{% endif %} </strong>
+ &lt;/ul&gt;</pre>
+
+<p>如您所見,我們使用 <code>if</code>-<code>else</code>-<code>endif</code> 模板標籤根據 <code>\{{ user.is_authenticated }}</code> \ {{user.is_authenticated}}是否為真來有條件地顯示文本。 如果用戶通過了身份驗證,那麼我們知道我們有一個有效的用戶,因此我們調用 <strong>\{{ user.get_username }} </strong>來顯示其名稱。</p>
+
+<p>我們使用<code>url</code> 模板標記和相應URL配置的名稱來創建登錄和註銷鏈接URL。 還要注意我們如何將<code>?next=\{{request.path}}</code>附加到URL的末尾。 這是在鏈接的URL的末尾添加一個URL參數,其中包含當前頁面的地址(URL)。 用戶成功登錄/註銷後,視圖將使用此``<code>next</code>''值將用戶重定向到他們首先單擊 login/logout 鏈接的頁面。</p>
+
+<div class="note">
+<p><strong>注意</strong>:試試看! 如果您在主頁上,然後單擊側欄中的“Login/Logout”,那麼在操作完成後,您應該回到同一頁面。</p>
+</div>
+
+<h3 id="在視圖中測試">在視圖中測試</h3>
+
+<p>如果您使用的是基於函數的視圖,則限制訪問函數的最簡單方法是將<code>login_required</code> 裝飾器應用於視圖函數,如下所示。 如果用戶已登錄,則您的視圖代碼將正常執行。 如果用戶未登錄,它將重定向到項目設置(<code>settings.LOGIN_URL</code>)中定義的登錄URL,並將當前的絕對路徑作為<code>next</code> URL參數傳遞。 如果用戶成功登錄,則他們將返回此頁面,但這次已通過身份驗證。</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.decorators import login_required
+
+@login_required
+def my_view(request):
+ ...</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 您可以通過在<code>request.user.is_authenticated</code>上進行測試來手動執行相同的操作,但是裝飾器要方便得多!</p>
+</div>
+
+<p>同樣,在基於類的視圖中限制對登錄用戶的訪問權限的最簡單方法是從 <code>LoginRequiredMixin</code>. 派生。 您需要首先在父類列表中,在主視圖類之前聲明此混合。</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin
+
+class MyView(LoginRequiredMixin, View):
+ ...</pre>
+
+<p>它具有與 <code>login_required</code> 裝飾器完全相同的重定向行為。 如果用戶未通過身份驗證,也可以指定其他位置來重定向用戶 (<code>login_url</code>),並使用URL參數名稱代替“ next”來插入當前的絕對路徑(<code>redirect_field_name</code>).。</p>
+
+<pre class="brush: python notranslate">class MyView(LoginRequiredMixin, View):
+ login_url = '/login/'
+ redirect_field_name = 'redirect_to'
+</pre>
+
+<p>有關更多詳細信息,請在此處查看<a href="https://docs.djangoproject.com/en/2.0/topics/auth/default/#limiting-access-to-logged-in-users">Django文檔</a>。</p>
+
+<h2 id="範例—列出當前用戶的書籍">範例—列出當前用戶的書籍</h2>
+
+<p>現在,我們知道瞭如何將頁面限制為特定用戶,讓我們創建當前用戶借閱的書籍的視圖。</p>
+
+<p>不幸的是,我們還沒有任何方式讓用戶借書! 因此,在創建圖書清單之前,我們將首先擴展<code>BookInstance</code> 模型以支持借用的概念,並使用Django Admin應用程序將大量圖書借給我們的測試用戶。</p>
+
+<h3 id="模型">模型</h3>
+
+<p>首先,我們將必須使用戶可以藉用<code>BookInstance</code> (我們已經具有<code>status</code> 和<code>due_back</code> ,但是在該模型和User之間還沒有任何關聯。我們將創建 一個使用<code>ForeignKey</code> (一對多)字段的方法,我們還需要一種簡單的機制來測試借出的書是否過期。<br>
+ <br>
+ 打開<strong>catalog/models.py</strong>,然後從 <code>django.contrib.auth.models</code>導入<code>User</code> 模型(將其添加到文件頂部的前一個導入行下面,因此<code>User</code> 可供使用它的後續代碼使用):</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.models import User
+</pre>
+
+<p>Ne接下來,將<code>borrower</code> 字段添加到<code>BookInstance</code> 模型中:</p>
+
+<pre class="notranslate">borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
+</pre>
+
+<p>當我們在這裡時,讓我們添加一個屬性,我們可以從模板中調用該屬性,以告知特定的圖書實例是否過期。 儘管我們可以在模板本身中進行計算,但是使用如下所示的<a href="https://docs.python.org/3/library/functions.html#property">屬性</a>會更加高效。</p>
+
+<p>將此添加到文件頂部附近:</p>
+
+<pre class="brush: python notranslate">from datetime import date</pre>
+
+<p class="brush: python">現在,在<code>BookInstance</code>類中添加以下屬性定義:</p>
+
+<pre class="brush: python notranslate">@property
+def is_overdue(self):
+ if self.due_back and date.today() &gt; self.due_back:
+ return True
+ return False</pre>
+
+<div class="note">
+<p><strong>Note</strong>: 在進行比較之前,我們首先要驗證<code>due_back</code>是否為空。 空的 <code>due_back</code>字段將導致Django拋出錯誤而不是顯示頁面:空值不可比。 這不是我們希望用戶體驗的東西!</p>
+</div>
+
+<p>現在,我們已經更新了模型,我們需要在項目上進行新的遷移,然後應用這些遷移:</p>
+
+<pre class="brush: bash notranslate">python3 manage.py makemigrations
+python3 manage.py migrate
+</pre>
+
+<h3 id="Admin">Admin</h3>
+
+<p>現在打開<strong>catalog/admin.py</strong>,然後將<code>list_display</code> 和<code>fieldsets</code> 中的<code>borrower</code> 字段添加到<code>BookInstanceAdmin</code> 類中,如下所示。 這將使該字段在“管理”部分中可見,以便我們可以在需要時將<code>User</code> 分配給<code>BookInstance</code> 。</p>
+
+<pre class="brush: python notranslate">@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_display = ('book', 'status'<strong>, 'borrower'</strong>, 'due_back', 'id')
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book','imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back'<strong>,'borrower'</strong>)
+        }),
+    )</pre>
+
+<h3 id="Loan_a_few_books">Loan a few books</h3>
+
+<p>現在可以將書借給特定用戶了,然後借出許多<code>BookInstance</code> 記錄。 將他們的<code>borrowed</code> 字段設置為測試用戶,<code>status</code> 為“借用”,並設置將來和將來的到期日。</p>
+
+<div class="note">
+<p><strong>注意</strong>:我們不會詳細說明該過程,因為您已經知道如何使用管理網站!</p>
+</div>
+
+<h3 id="On_loan_view">On loan view</h3>
+
+<p>現在,我們將添加一個視圖,以獲取已借給當前用戶的所有書籍的列表。 我們將使用我們熟悉的相同的通用的基於類的列表視圖,但是這次我們還將導入並從<code>LoginRequiredMixin</code>派生,以便只有登錄的用戶才能調用此視圖。 我們還將選擇聲明<code>template_name</code>,而不使用默認值,因為我們最終可能會擁有一些不同的BookInstance記錄列表,並具有不同的視圖和模板。<br>
+ <br>
+ 將以下內容添加到<strong>catalog / views.py</strong>:</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin
+
+class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
+ """Generic class-based view listing books on loan to current user."""
+ model = BookInstance
+ template_name ='catalog/bookinstance_list_borrowed_user.html'
+ paginate_by = 10
+
+ def get_queryset(self):
+ return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre>
+
+<p>為了將查詢限制為僅針對當前用戶的<code>BookInstance</code> 對象,我們重新實現了 <code>get_queryset()</code>,如上所示。 請注意,“ o”是“借出”的存儲代碼,我們在<code>due_back</code> 日期之前訂購,以便最先顯示最早的項目。</p>
+
+<h3 id="URL_conf_for_on_loan_books">URL conf for on loan books</h3>
+
+<p>現在打開<strong>/catalog/urls.py</strong>並添加指向上面視圖的<code>path()</code>(您可以將下面的文本複製到文件末尾)。</p>
+
+<pre class="brush: python notranslate">urlpatterns += [
+ path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
+]</pre>
+
+<h3 id="Template_for_on_loan_books">Template for on loan books</h3>
+
+<p>現在,我們需要為此頁面添加模板。 首先,創建模板文件 <strong>/catalog/templates/catalog/bookinstance_list_borrowed_user.html</strong> 並為其提供以下內容:</p>
+
+<pre class="brush: python notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Borrowed books&lt;/h1&gt;
+
+ {% if bookinstance_list %}
+ &lt;ul&gt;
+
+ {% for bookinst in bookinstance_list %}
+ &lt;li class="{% if bookinst.is_overdue %}text-danger{% endif %}"&gt;
+ &lt;a href="{% url 'book-detail' bookinst.book.pk %}"&gt;\{{bookinst.book.title}}&lt;/a&gt; (\{{ bookinst.due_back }})
+ &lt;/li&gt;
+ {% endfor %}
+ &lt;/ul&gt;
+
+ {% else %}
+ &lt;p&gt;There are no books borrowed.&lt;/p&gt;
+ {% endif %}
+{% endblock %}</pre>
+
+<p>該模板與我們先前為<code>Book</code> 和<code>Author</code> 物件創建的模板非常相似。 這裡唯一的“新內容”是我們檢查在模型中添加的方法(<code>bookinst.is_overdue</code>),並使用它來更改過期項目的顏色。</p>
+
+<p>開發服務器運行時,現在應該可以在瀏覽器中的 <a href="http://127.0.0.1:8000/catalog/mybooks/">http://127.0.0.1:8000/catalog/mybooks/</a> 上查看已登錄用戶的列表。 在您的用戶登錄和註銷後進行嘗試(在第二種情況下,應將您重定向到登錄頁面)。</p>
+
+<h3 id="Add_the_list_to_the_sidebar">Add the list to the sidebar</h3>
+
+<p>最後一步是將此新頁面的鏈接添加到側欄中。 我們將其放在同一部分中,在該部分中為登錄用戶顯示其他信息。</p>
+
+<p>打開基本模板 (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) 並將粗體顯示的行添加到側邊欄中,如圖所示。</p>
+
+<pre class="brush: python notranslate"> &lt;ul class="sidebar-nav"&gt;
+ {% if user.is_authenticated %}
+ &lt;li&gt;User: \{{ user.get_username }}&lt;/li&gt;
+<strong> &lt;li&gt;&lt;a href="{% url 'my-borrowed' %}"&gt;My Borrowed&lt;/a&gt;&lt;/li&gt;</strong>
+ &lt;li&gt;&lt;a href="{% url 'logout'%}?next=\{{request.path}}"&gt;Logout&lt;/a&gt;&lt;/li&gt;
+ {% else %}
+ &lt;li&gt;&lt;a href="{% url 'login'%}?next=\{{request.path}}"&gt;Login&lt;/a&gt;&lt;/li&gt;
+ {% endif %}
+ &lt;/ul&gt;
+</pre>
+
+<h3 id="What_does_it_look_like">What does it look like?</h3>
+
+<p>當任何用戶登錄後,他們將在邊欄中看到“<em>My Borrowed</em> ”,並且書的列表顯示如下(第一本書沒有截止日期,這是我們希望在以後的教程中解決的錯誤!) 。</p>
+
+<p><img alt="Library - borrowed books by user" src="https://mdn.mozillademos.org/files/14105/library_borrowed_by_user.png" style="border-style: solid; border-width: 1px; display: block; height: 215px; margin: 0px auto; width: 530px;"></p>
+
+<h2 id="Permissions">Permissions</h2>
+
+<p>權限與模型相關聯,並定義了具有權限的用戶可以在模型實例上執行的操作。 默認情況下,Django會自動為所有模型賦予添加,更改和刪除權限,從而允許具有權限的用戶通過管理站點執行關聯的操作。 您可以定義自己的模型權限,並將其授予特定用戶。 您還可以更改與同一模型的不同實例關聯的權限。</p>
+
+<p>這樣,對視圖和模板中的權限進行的測試就非常類似於對身份驗證狀態的測試(實際上,對權限的測試也對身份驗證進行了測試)。</p>
+
+<h3 id="Models">Models</h3>
+
+<p>使用<code>permissions</code> 字段在模型“<code>class Meta</code>”部分中完成權限的定義。 您可以在元組中根據需要指定任意數量的權限,每個權限本身都在嵌套的元組中定義,其中包含權限名稱和權限顯示值。 例如,我們可以定義一個權限,以允許用戶標記已退回一本書,如下所示:</p>
+
+<pre class="brush: python notranslate">class BookInstance(models.Model):
+ ...
+  class Meta:
+  ...
+<strong> permissions = (("can_mark_returned", "Set book as returned"),) </strong> </pre>
+
+<p>然後,我們可以將權限分配給管理站點中的“圖書管理員”組。</p>
+
+<p>打開<strong>catalog/models.py,</strong>然後添加權限,如上所示。 您將需要重新運行遷移(調用 <code>python3 manage.py makemigrations</code> 和<code>python3 manage.py migrate</code>)以適當地更新數據庫。</p>
+
+<h3 id="模板">模板</h3>
+
+<p>當前用戶的權限存儲在名為 <code>\{{ perms }}</code>. 的模板變量中。 您可以使用關聯的Django "app"“應用”中的特定變量名稱來檢查當前用戶是否具有特定權限,例如 如果用戶具有此權限,則 <code>\{{ perms.catalog.can_mark_returned }}</code> 將為 <code>True</code> ,否則為<code>False</code>。 我們通常使用模板 <code>{% if %}</code> 標籤測試權限,如下所示:</p>
+
+<pre class="brush: python notranslate">{% if perms.catalog.<code>can_mark_returned</code> %}
+ &lt;!-- We can mark a BookInstance as returned. --&gt;
+  &lt;!-- Perhaps add code to link to a "book return" view here. --&gt;
+{% endif %}
+</pre>
+
+<h3 id="視圖">視圖</h3>
+
+<p>可以在功能視圖中使用<code>permission_required</code> 裝飾器來測試權限,或者在基於類的視圖中使用<code>PermissionRequiredMixin</code>. 來測試權限。 模式和行為與登錄身份驗證的模式和行為相同,儘管當然您可能必須合理地添加多個權限。</p>
+
+<p>視圖裝飾器函數:</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.decorators import permission_required
+
+@permission_required('catalog.<code>can_mark_returned</code>')
+@permission_required('catalog.<code>can_edit</code>')
+def my_view(request):
+ ...</pre>
+
+<p>基於類的視圖需要權限的混合。</p>
+
+<pre class="brush: python notranslate">from django.contrib.auth.mixins import PermissionRequiredMixin
+
+class MyView(PermissionRequiredMixin, View):
+ permission_required = 'catalog.<code>can_mark_returned</code>'
+ # Or multiple permissions
+ permission_required = ('catalog.<code>can_mark_returned</code>', 'catalog.can_edit')
+ # Note that 'catalog.can_edit' is just an example
+ # the catalog application doesn't have such permission!</pre>
+
+<h3 id="範例">範例</h3>
+
+<p>我們不會在這裡更新LocalLibrary; 也許在下一個教程中!</p>
+
+<h2 id="挑戰自己">挑戰自己</h2>
+
+<p>在本文的前面,我們向您展示瞭如何為當前用戶創建一個頁面,列出他們所借用的書。 現在的挑戰是創建一個僅對圖書館員可見的相似頁面,該頁面顯示所有已借書的書,其中包括每個借書人的名字。</p>
+
+<p>您應該能夠遵循與其他視圖相同的模式。 主要區別在於您只需要將視圖限制為圖書館員即可。 您可以根據用戶是否是工作人員來執行此操作(函數裝飾器:<code>staff_member_required</code>,模板變量: <code>user.is_staff</code>),但是我們建議您改用<code>can_mark_returned</code> 權限和<code>PermissionRequiredMixin</code>,如上一節所述。</p>
+
+<div class="warning">
+<p><strong>重要</strong>:請記住不要將您的超級用戶用於基於權限的測試(即使尚未定義權限,權限檢查也始終對超級用戶返回true!)。 而是創建一個圖書管理員用戶,並添加所需的功能。</p>
+</div>
+
+<p>完成後,您的頁面應類似於以下屏幕截圖。<img alt="All borrowed books, restricted to librarian" src="https://mdn.mozillademos.org/files/14115/library_borrowed_all.png" style="border-style: solid; border-width: 1px; display: block; height: 283px; margin: 0px auto; width: 500px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>出色的工作-您現在已經創建了一個網站,圖書館成員可以登錄並查看他們自己的內容,館員(具有正確的權限)可以用來查看所有借出的書及其借書人。 目前,我們仍在查看內容,但是當您要開始修改和添加數據時,將使用相同的原理和技術。</p>
+
+<p>在下一篇文章中,我們將研究如何使用Django表單來收集用戶輸入,然後開始修改一些存儲的數據。</p>
+
+<h2 id="也可以看看">也可以看看</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/">User authentication in Django</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/default//">Using the (default) Django authentication system</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/#decorating-class-based-views">Introduction to class-based views &gt; Decorating class-based views</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/deployment/index.html b/files/zh-tw/learn/server-side/django/deployment/index.html
new file mode 100644
index 0000000000..752714dabb
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/deployment/index.html
@@ -0,0 +1,675 @@
+---
+title: 'Django Tutorial Part 11: Deploying Django to production'
+slug: Learn/Server-side/Django/Deployment
+translation_of: Learn/Server-side/Django/Deployment
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">現在,您已經創建(並測試)了一個令人敬畏的 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站,如果您希望將其安裝在公共 Web 服務器上,以便圖書館工作人員、和成員,可以通過 Internet 訪問它。本文概述如何找到主機來部署您的網站,以及您需要做什麼,才能讓您的網站準備好生產環境。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To learn where and how you can deploy a Django app to production.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Overview">Overview</h2>
+
+<p>Once your site is finished (or finished "enough" to start public testing) you're going to need to host it somewhere more public and accessible than your personal development computer.</p>
+
+<p>Up to now you've been working in a development environment, using the Django development web server to share your site to the local browser/network, and running your website with (insecure) development settings that expose debug and other private information. Before you can host a website externally you're first going to have to:</p>
+
+<ul>
+ <li>Make a few changes to your project settings.</li>
+ <li>Choose an environment for hosting the Django app.</li>
+ <li>Choose an environment for hosting any static files.</li>
+ <li>Set up a production-level infrastructure for serving your website.</li>
+</ul>
+
+<p>This tutorial provides some guidance on your options for choosing a hosting site, a brief overview of what you need to do in order to get your Django app ready for production, and a worked example of how to install the LocalLibrary website onto the <a href="https://www.heroku.com/">Heroku</a> cloud hosting service.</p>
+
+<h2 id="What_is_a_production_environment">What is a production environment?</h2>
+
+<p>The production environment is the environment provided by the server computer where you will run your website for external consumption. The environment includes:</p>
+
+<ul>
+ <li>Computer hardware on which the website runs.</li>
+ <li>Operating system (e.g. Linux, Windows).</li>
+ <li>Programming language runtime and framework libraries on top of which your website is written.</li>
+ <li>Web server used to serve pages and other content (e.g. Nginx, Apache).</li>
+ <li>Application server that passes "dynamic" requests between your Django website and the webserver.</li>
+ <li>Databases on which your website is dependent.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Depending on how your production is configured you might also have a reverse proxy, load balancer, etc.</p>
+</div>
+
+<p>The server computer could be located on your premises and connected to the Internet by a fast link, but it is far more common to use a computer that is hosted "in the cloud". What this actually means is that your code is run on some remote computer (or possibly a "virtual" computer) in your hosting company's data center(s). The remote server will usually offer some guaranteed level of computing resources (e.g. CPU, RAM, storage memory, etc.) and Internet connectivity for a certain price.</p>
+
+<p>This sort of remotely accessible computing/networking hardware is referred to as <em>Infrastructure as a Service (IaaS)</em>. Many IaaS vendors provide options to preinstall a particular operating system, onto which you must install the other components of your production environment. Other vendors allow you to select more fully-featured environments, perhaps including a complete Django and web-server setup.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Pre-built environments can make setting up your website very easy because they reduce the configuration, but the available options may limit you to an unfamiliar server (or other components) and may be based on an older version of the OS. Often it is better to install components yourself, so that you get the ones that you want, and when you need to upgrade parts of the system, you have some idea where to start!</p>
+</div>
+
+<p>Other hosting providers support Django as part of a <em>Platform as a Service</em> (PaaS) offering. In this sort of hosting you don't need to worry about most of your production environment (web server, application server, load balancers) as the host platform takes care of those for you (along with most of what you need to do in order to scale your application). That makes deployment quite easy, because you just need to concentrate on your web application and not all the other server infrastructure.</p>
+
+<p>Some developers will choose the increased flexibility provided by IaaS over PaaS, while others will appreciate the reduced maintenance overhead and easier scaling of PaaS. When you're getting started, setting up your website on a PaaS system is much easier, and so that is what we'll do in this tutorial.</p>
+
+<div class="note">
+<p><strong>Tip:</strong> If you choose a Python/Django-friendly hosting provider they should provide instructions on how to set up a Django website using different configurations of webserver, application server, reverse proxy, etc (this won't be relevant if you choose a PaaS). For example, there are many step-by-step guides for various configurations in the <a href="https://www.digitalocean.com/community/tutorials?q=django">Digital Ocean Django community docs</a>.</p>
+</div>
+
+<h2 id="Choosing_a_hosting_provider">Choosing a hosting provider</h2>
+
+<p>There are well over 100 hosting providers that are known to either actively support or work well with Django (you can find a fairly extensive list at <a href="http://djangofriendly.com/hosts/">Djangofriendly hosts</a>). These vendors provide different types of environments (IaaS, PaaS), and different levels of computing and network resources at different prices.</p>
+
+<p>Some of the things to consider when choosing a host:</p>
+
+<ul>
+ <li>How busy your site is likely to be and the cost of data and computing resources required to meet that demand.</li>
+ <li>Level of support for scaling horizontally (adding more machines) and vertically (upgrading to more powerful machines) and the costs of doing so.</li>
+ <li>Where the supplier has data centres, and hence where access is likely to be fastest.</li>
+ <li>The host's historical uptime and downtime performance.</li>
+ <li>Tools provided for managing the site — are they easy to use and are they secure (e.g. SFTP vs FTP).</li>
+ <li>Inbuilt frameworks for monitoring your server.</li>
+ <li>Known limitations. Some hosts will deliberately block certain services (e.g. email) . Others offer only a certain number of hours of "live time" in some price tiers, or only offer a small amount of storage.</li>
+ <li>Additional benefits. Some providers will offer free domain names and support for SSL certificates that you would otherwise have to pay for.</li>
+ <li>Whether the "free" tier you're relying on expires over time, and whether the cost of migrating to a more expensive tier means you would have been better off using some other service in the first place!</li>
+</ul>
+
+<p>The good news when you're starting out is that there are quite a few sites that provide "evaluation", "developer", or "hobbyist" computing environments for "free". These are always fairly resource constrained/limited environments, and you do need to be aware that they may expire after some introductory period. They are however great for testing low traffic sites in a real environment, and can provide an easy migration to paying for more resources when your site gets busier. Popular choices in this category include <a href="https://www.heroku.com/">Heroku</a>, <a href="https://www.pythonanywhere.com/">Python Anywhere</a>, <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/">Microsoft Azure</a>, etc.</p>
+
+<p>Many providers also have a "basic" tier that provides more useful levels of computing power and fewer limitations. <a href="https://www.digitalocean.com/">Digital Ocean</a> and <a href="https://www.pythonanywhere.com/">Python Anywhere</a> are examples of popular hosting providers that offer a relatively inexpensive basic computing tier (in the $5 to $10USD per month range).</p>
+
+<div class="note">
+<p><strong>Note:</strong> Remember that price is not the only selection criteria. If your website is successful, it may turn out that scalability is the most important consideration.</p>
+</div>
+
+<h2 id="Getting_your_website_ready_to_publish">Getting your website ready to publish</h2>
+
+<p>The <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django skeleton website</a> created using the <em>django-admin</em> and <em>manage.py</em> tools are configured to make development easier. Many of the Django project settings (specified in <strong>settings.py</strong>) should be different for production, either for security or performance reasons.</p>
+
+<div class="note">
+<p><strong>Tip:</strong> It is common to have a separate <strong>settings.py</strong> file for production, and to import sensitive settings from a separate file or an environment variable. This file should then be protected, even if the rest of the source code is available on a public repository.</p>
+</div>
+
+<p>The critical settings that you must check are:</p>
+
+<ul>
+ <li><code>DEBUG</code>. This should be set as <code>False</code> in production (<code>DEBUG = False</code>). This stops the sensitive/confidential debug trace and variable information from being displayed.</li>
+ <li><code>SECRET_KEY</code>. This is a large random value used for CSRF protection etc. It is important that the key used in production is not in source control or accessible outside the production server. The Django documents suggest that this might best be loaded from an environment variable or read from a serve-only file.
+ <pre># Read SECRET_KEY from an environment variable
+import os
+SECRET_KEY = os.environ['SECRET_KEY']
+
+#OR
+
+#Read secret key from a file
+with open('/etc/secret_key.txt') as f:
+ SECRET_KEY = f.read().strip()</pre>
+ </li>
+</ul>
+
+<p>Let's change the <em>LocalLibrary</em> application so that we read our <code>SECRET_KEY</code> and <code>DEBUG</code> variables from environment variables if they are defined, but otherwise use the default values in the configuration file.</p>
+
+<p>Open <strong>/locallibrary/settings.py</strong>, disable the original <code>SECRET_KEY</code> configuration and add the new lines as shown below in <strong>bold</strong>. During development no environment variable will be specified for the key, so the default value will be used (it shouldn't matter what key you use here, or if the key "leaks", because you won't use it in production).</p>
+
+<pre class="brush: python"># SECURITY WARNING: keep the secret key used in production secret!
+# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&amp;k3q+pmu)5%asj6yjpkag'
+<strong>import os</strong>
+<strong>SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&amp;k3q+pmu)5%asj6yjpkag')</strong>
+</pre>
+
+<p>Then comment out the existing <code>DEBUG</code> setting and add the new line shown below.</p>
+
+<pre class="brush: python"># SECURITY WARNING: don't run with debug turned on in production!
+# DEBUG = True
+<strong>DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) )</strong>
+</pre>
+
+<p>The value of the <code>DEBUG</code> will be <code>True</code> by default, but will be <code>False</code> if the value of the <code>DJANGO_DEBUG</code> environment variable is set to an empty string, e.g. <code>DJANGO_DEBUG=''</code>.</p>
+
+<div class="note">
+<p><strong>Note</strong>: It would be more intuitive if we could just set and unset the <code>DJANGO_DEBUG</code> environment variable to <code>True</code> and <code>False</code> directly, rather than using "any string" or "empty string" (respectively). Unfortunately environment variable values are stored as Python strings, and the only string that evaluates as <code>False</code> is the empty string (e.g. <code>bool('')==False</code>).</p>
+</div>
+
+<p>A full checklist of settings you might want to change is provided in <a href="https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/">Deployment checklist</a> (Django docs). You can also list a number of these using the terminal command below:</p>
+
+<pre class="brush: python">python3 manage.py check --deploy
+</pre>
+
+<h2 id="Example_Installing_LocalLibrary_on_Heroku">Example: Installing LocalLibrary on Heroku</h2>
+
+<p>This section provides a practical demonstration of how to install <em>LocalLibrary</em> on the <a href="http://heroku.com">Heroku PaaS cloud</a>.</p>
+
+<h3 id="Why_Heroku">Why Heroku?</h3>
+
+<p>Heroku is one of the longest running and popular cloud-based PaaS services. It originally supported only Ruby apps, but now can be used to host apps from many programming environments, including Django!</p>
+
+<p>We are choosing to use Heroku for several reasons:</p>
+
+<ul>
+ <li>Heroku has a <a href="https://www.heroku.com/pricing">free tier</a> that is <em>really</em> free (albeit with some limitations).</li>
+ <li>As a PaaS, Heroku takes care of a lot of the web infrastructure for us. This makes it much easier to get started, because you don't worry about servers, load balancers, reverse proxies, or any of the other web infrastructure that Heroku provides for us under the hood.</li>
+ <li>While it does have some limitations these will not affect this particular application. For example:
+ <ul>
+ <li>Heroku provides only short-lived storage so user-uploaded files cannot safely be stored on Heroku itself.</li>
+ <li>The free tier will sleep an inactive web app if there are no requests within a half hour period. The site may then take several seconds to respond when it is woken up.</li>
+ <li>The free tier limits the time that your site is running to a certain amount of hours every month (not including the time that the site is "asleep"). This is fine for a low use/demonstration site, but will not be suitable if 100% uptime is required.</li>
+ <li>Other limitations are listed in <a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs).</li>
+ </ul>
+ </li>
+ <li>Mostly it just works, and if you end up loving it, scaling your app is very easy.</li>
+</ul>
+
+<p>While Heroku is perfect for hosting this demonstration it may not be perfect for your real website. Heroku makes things easy to set up and scale, at the cost of being less flexible, and potentially a lot more expensive once you get out of the free tier.</p>
+
+<h3 id="How_does_Heroku_work">How does Heroku work?</h3>
+
+<p>Heroku runs Django websites within one or more "<a href="https://devcenter.heroku.com/articles/dynos">Dynos</a>", which are isolated, virtualized Unix containers that provide the environment required to run an application. The dynos are completely isolated and have an <em>ephemeral</em> file system (a short-lived file system that is cleaned/emptied every time the dyno restarts). The only thing that dynos share by default are application <a href="https://devcenter.heroku.com/articles/config-vars">configuration variables</a>. Heroku internally uses a load balancer to distribute web traffic to all "web" dynos. Since nothing is shared between them, Heroku can scale an app horizontally simply by adding more dynos (though of course you may also need to scale your database to accept additional connections).</p>
+
+<p>Because the file system is ephemeral you can't install services required by your application directly (e.g. databases, queues, caching systems, storage, email services, etc). Instead Heroku web applications use backing services provided as independent "add-ons" by Heroku or 3rd parties. Once attached to your web application, the dynos access the services using information contained in application configuration variables.</p>
+
+<p>In order to execute your application Heroku needs to be able to set up the appropriate environment and dependencies, and also understand how it is launched. For Django apps we provide this information in a number of text files:</p>
+
+<ul>
+ <li><strong>runtime.txt</strong>:<strong> </strong>the programming language and version to use.</li>
+ <li><strong>requirements.txt</strong>: the Python component dependencies, including Django.</li>
+ <li><strong>Procfile</strong>: A list of processes to be executed to start the web application. For Django this will usually be the Gunicorn web application server (with a <code>.wsgi</code> script).</li>
+ <li><strong>wsgi.py</strong>: <a href="http://wsgi.readthedocs.io/en/latest/what.html">WSGI</a> configuration to call our Django application in the Heroku environment.</li>
+</ul>
+
+<p>Developers interact with Heroku using a special client app/terminal, which is much like a Unix bash script. This allows you to upload code that is stored in a git repository, inspect the running processes, see logs, set configuration variables and much more!</p>
+
+<p>In order to get our application to work on Heroku we'll need to put our Django web application into a git repository, add the files above, integrate with a database add-on, and make changes to properly handle static files.</p>
+
+<p>Once we've done all that we can set up a Heroku account, get the Heroku client, and use it to install our website.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The instructions below reflect how to work with Heroku at time of writing. If Heroku significantly change their processes, you may wish to instead check their setup documents: <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a>.</p>
+</div>
+
+<p>That's all the overview you need in order to get started (see <a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> for a more comprehensive guide).</p>
+
+<h3 id="Creating_an_application_repository_in_Github">Creating an application repository in Github</h3>
+
+<p>Heroku is closely integrated with the <strong>git</strong> source code version control system, using it to upload/synchronise any changes you make to the live system. It does this by adding a new heroku "remote" repository named <em>heroku</em> pointing to a repository for your source on the Heroku cloud. During development you use git to store changes on your "master" repository. When you want to deploy your site, you sync your changes to the Heroku repository.</p>
+
+<div class="note">
+<p><strong>Note:</strong> If you're used to following good software development practices you are probably already using git or some other SCM system. If you already have a git repository, then you can skip this step.</p>
+</div>
+
+<p>There are a lot of ways of to work with git, but one of the easiest is to first set up an account on <a href="https://github.com/">Github</a>, create the repository there, and then sync to it locally:</p>
+
+<ol>
+ <li>Visit <a href="https://github.com/">https://github.com/</a> and create an account.</li>
+ <li>Once you are logged in, click the <strong>+</strong> link in the top toolbar and select <strong>New repository</strong>.</li>
+ <li>Fill in all the fields on this form. While these are not compulsory, they are strongly recommended.
+ <ul>
+ <li>Enter a new repository name (e.g. <em>django_local_library</em>), and description (e.g. "Local Library website written in Django".</li>
+ <li>Choose <strong>Python</strong> in the <em>Add .gitignore</em> selection list.</li>
+ <li>Choose your preferred license in the <em>Add license</em> selection list.</li>
+ <li>Check <strong>Initialize this repository with a README</strong>.</li>
+ </ul>
+ </li>
+ <li>Press <strong>Create repository</strong>.</li>
+ <li>Click the green "<strong>Clone or download</strong>" button on your new repo page.</li>
+ <li>Copy the URL value from the text field inside the dialog box that appears (it should be something like: <strong>https://github.com/<em>&lt;your_git_user_id&gt;</em>/django_local_library.git</strong>).</li>
+</ol>
+
+<p>Now the repository ("repo") is created we are going to want to clone it on our local computer:</p>
+
+<ol>
+ <li>Install <em>git</em> for your local computer (you can find versions for different platforms <a href="https://git-scm.com/downloads">here</a>).</li>
+ <li>Open a command prompt/terminal and clone your repository using the URL you copied above:
+ <pre class="brush: bash">git clone https://github.com/<strong><em>&lt;your_git_user_id&gt;</em></strong>/django_local_library.git
+</pre>
+ This will create the repository below the current point.</li>
+ <li>Navigate into the new repo.
+ <pre class="brush: bash">cd django_local_library.git</pre>
+ </li>
+</ol>
+
+<p>The final step is to copy in your application and then add the files to your repo using git:</p>
+
+<ol>
+ <li>Copy your Django application into this folder (all the files at the same level as <strong>manage.py</strong> and below, <strong>not</strong> their containing locallibrary folder).</li>
+ <li>Open the <strong>.gitignore</strong> file, copy the following lines into the bottom of it, and then save (this file is used to identify files that should not be uploaded to git by default).
+ <pre># Text backup files
+*.bak
+
+#Database
+*.sqlite3</pre>
+ </li>
+ <li>Open a command prompt/terminal and use the <code>add</code> command to add all files to git.
+ <pre class="brush: bash">git add -A
+</pre>
+ </li>
+ <li>Use the status command to check all files that you are about to add are correct (you want to include source files, not binaries, temporary files etc.). It should look a bit like the listing below.
+ <pre>&gt; git status
+On branch master
+Your branch is up-to-date with 'origin/master'.
+Changes to be committed:
+  (use "git reset HEAD &lt;file&gt;..." to unstage)
+
+        modified:   .gitignore
+        new file:   catalog/__init__.py
+ ...
+        new file:   catalog/migrations/0001_initial.py
+ ...
+        new file:   templates/registration/password_reset_form.html</pre>
+ </li>
+ <li>When you're satisfied commit the files to your local repository:
+ <pre class="brush: bash">git commit -m "First version of application moved into github"</pre>
+ </li>
+ <li>Then synchronise your local repository to the Github website, using the following:
+ <pre>git push origin master</pre>
+ </li>
+</ol>
+
+<p>When this operation completes, you should be able to go back to the page on Github where you created your repo, refresh the page, and see that your whole application has now been uploaded. You can continue to update your repository as files change using this add/commit/push cycle.</p>
+
+<div class="note">
+<p><strong>Tip:</strong> This is a good point to make a backup of your "vanilla" project — while some of the changes we're going to be making in the following sections might be useful for deployment on any platform (or development) others might not.</p>
+
+<p>The <em>best</em> way to do this is to use <em>git</em> to manage your revisions. With <em>git</em> you can not only go back to a particular old version, but you can maintain this in a separate "branch" from your production changes and cherry-pick any changes to move between production and development branches. <a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">Learning Git</a> is well worth the effort, but is beyond the scope of this topic.</p>
+
+<p>The <em>easiest</em> way to do this is to just copy your files into another location. Use whichever approach best matches your knowledge of git!</p>
+</div>
+
+<h3 id="Update_the_app_for_Heroku">Update the app for Heroku</h3>
+
+<p>This section explains the changes you'll need to make to our <em>LocalLibrary</em> application to get it to work on Heroku. While Heroku's <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a> instructions assume you will use the Heroku client to also run your local development environment, our changes here are compatible with the existing Django development server and ways of working we've already learned.</p>
+
+<h4 id="Procfile">Procfile</h4>
+
+<p>Create the file <code>Procfile</code> (no extension) in the root of your GitHub repository to declare the application's process types and entry points. Copy the following text into it:</p>
+
+<pre>web: gunicorn locallibrary.wsgi --log-file -</pre>
+
+<p>The "<code>web:</code>" tells Heroku that this is a web dyno and can be sent HTTP traffic. The process to start in this dyno is <em>gunicorn</em>, which is a popular web application server that Heroku recommends. We start Gunicorn using the configuration information in the module <code>locallibrary.wsgi</code> (created with our application skeleton: <strong>/locallibrary/wsgi.py</strong>).</p>
+
+<h4 id="Gunicorn">Gunicorn</h4>
+
+<p><a href="http://gunicorn.org/">Gunicorn</a> is the recommended HTTP server for use with Django on Heroku (as referenced in the Procfile above). It is a pure-Python HTTP server for WSGI applications that can run multiple Python concurrent processes within a single dyno (see <a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> for more information).</p>
+
+<p>While we won't need <em>Gunicorn</em> to serve our LocalLibrary application during development, we'll install it so that it becomes part of our <a href="#requirements">requirements</a> for Heroku to set up on the remote server.</p>
+
+<p>Install <em>Gunicorn</em> locally on the command line using <em>pip</em> (which we installed when <a href="/en-US/docs/Learn/Server-side/Django/development_environment">setting up the development environment</a>):</p>
+
+<pre class="brush: bash">pip3 install gunicorn
+</pre>
+
+<h4 id="Database_configuration">Database configuration</h4>
+
+<p>We can't use the default SQLite database on Heroku because it is file-based, and it would be deleted from the <em>ephemeral</em> file system every time the application restarts (typically once a day, and every time the application or its configuration variables are changed).</p>
+
+<p>The Heroku mechanism for handling this situation is to use a <a href="https://elements.heroku.com/addons#data-stores">database add-on</a> and configure the web application using information from an environment <a href="https://devcenter.heroku.com/articles/config-vars">configuration variable</a>, set by the add-on. There are quite a lot of database options, but we'll use the <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#plan-tiers">hobby tier</a> of the <em>Heroku postgres</em> database as this is free, supported by Django, and automatically added to our new Heroku apps when using the free hobby dyno plan tier.</p>
+
+<p>The database connection information is supplied to the web dyno using a configuration variable named <code>DATABASE_URL</code>. Rather than hard-coding this information into Django, Heroku recommends that developers use the <a href="https://warehouse.python.org/project/dj-database-url/">dj-database-url</a> package to parse the <code>DATABASE_URL</code> environment variable and automatically convert it to Django’s desired configuration format. In addition to installing the <em>dj-database-url</em> package we'll also need to install <a href="http://initd.org/psycopg/">psycopg2</a>, as Django needs this to interact with Postgres databases.</p>
+
+<h5 id="dj-database-url_(Django_database_configuration_from_environment_variable)">dj-database-url (Django database configuration from environment variable)</h5>
+
+<p>Install <em>dj-database-url</em> locally so that it becomes part of our <a href="#requirements">requirements</a> for Heroku to set up on the remote server:</p>
+
+<pre>$ pip3 install dj-database-url
+</pre>
+
+<h5 id="settings.py">settings.py</h5>
+
+<p>Open <strong>/locallibrary/settings.py</strong> and copy the following configuration into the bottom of the file:</p>
+
+<pre># Heroku: Update database configuration from $DATABASE_URL.
+import dj_database_url
+db_from_env = dj_database_url.config(conn_max_age=500)
+DATABASES['default'].update(db_from_env)</pre>
+
+<div class="note">
+<p><strong>Note:</strong></p>
+
+<ul>
+ <li>We'll still be using SQLite during development because the <code>DATABASE_URL</code> environment variable will not be set on our development computer.</li>
+ <li>The value <code>conn_max_age=500</code> makes the connection persistent, which is far more efficient than recreating the connection on every request cycle. However, this is optional and can be removed if needed.</li>
+</ul>
+</div>
+
+<h5 id="psycopg2_(Python_Postgres_database_support)">psycopg2 (Python Postgres database support)</h5>
+
+<p>Django needs <em>psycopg2</em> to work with Postgres databases and you will need to add this to the <a href="#requirements">requirements.txt</a> for Heroku to set this up on the remote server (as discussed in the requirements section below).</p>
+
+<p>Django will use our SQLite database locally by default, because the <code>DATABASE_URL</code> environment variable isn't set in our local environment. If you want to switch to Postgres completely and use our Heroku free tier database for both development and production then you can. For example, to install psycopg2 and its dependencies locally on a Linux-based system you would use the following bash/terminal commands:</p>
+
+<pre class="brush: bash"><code>sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib</code>
+pip3 install psycopg2
+</pre>
+
+<p>Installation instructions for the other platforms can be found on the <a href="http://initd.org/psycopg/docs/install.html">psycopg2 website here</a>.</p>
+
+<p>However, you don't need to do this — you don't need PostGreSQL active on the local computer, as long as you give it to Heroku as a requirement, in <code>requirements.txt</code> (see below).</p>
+
+<h4 id="Serving_static_files_in_production">Serving static files in production</h4>
+
+<p>During development we used Django and the Django development web server to serve our static files (CSS, JavaScript, etc.). In a production environment we instead typically serve static files from a content delivery network (CDN) or the web server.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Serving static files via Django/web application is inefficient because the requests have to pass through unnecessary additional code (Django) rather than being handled directly by the web server or a completely separate CDN. While this doesn't matter for local use during development, it would have a significant performance impact if we were to use the same approach in production. </p>
+</div>
+
+<p>To make it easy to host static files separately from the Django web application, Django provides the <em>collectstatic</em> tool to collect these files for deployment (there is a settings variable that defines where the files should be collected when <em>collectstatic</em> is run). Django templates refer to the hosting location of the static files relative to a settings variable (<code>STATIC_URL</code>), so that this can be changed if the static files are moved to another host/server.</p>
+
+<p>The relevant setting variables are:</p>
+
+<ul>
+ <li><code>STATIC_URL</code>: This is the base URL location from which static files will be served, for example on a CDN. This is used for the static template variable that is accessed in our base template (see <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>).</li>
+ <li><code>STATIC_ROOT</code>: This is the absolute path to a directory where Django's "collectstatic" tool will gather any static files referenced in our templates. Once collected, these can then be uploaded as a group to wherever the files are to be hosted.</li>
+ <li><code>STATICFILES_DIRS</code>: This lists additional directories that Django's collectstatic tool should search for static files.</li>
+</ul>
+
+<h5 id="settings.py_2">settings.py</h5>
+
+<p>Open <strong>/locallibrary/settings.py</strong> and copy the following configuration into the bottom of the file. The <code>BASE_DIR</code> should already have been defined in your file (the <code>STATIC_URL</code> may already have been defined within the file when it was created. While it will cause no harm, you might as well delete the duplicate previous reference).</p>
+
+<pre># Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.0/howto/static-files/
+
+# The absolute path to the directory where collectstatic will collect static files for deployment.
+STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
+
+# The URL to use when referring to static files (where they will be served from)
+STATIC_URL = '/static/'
+</pre>
+
+<p>We'll actually do the file serving using a library called <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a>, which we install and configure in the next section.</p>
+
+<p>For more information, see <a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs).</p>
+
+<h4 id="Whitenoise">Whitenoise</h4>
+
+<p>There are many ways to serve static files in production (we saw the relevant Django settings in the previous sections). Heroku recommends using the <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> project for serving of static assets directly from Gunicorn in production.</p>
+
+<div class="note">
+<p><strong>Note: </strong>Heroku automatically calls <em>collectstatic</em> and prepares your static files for use by WhiteNoise after it uploads your application. Check out <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> documentation for an explanation of how it works and why the implementation is a relatively efficient method for serving these files.</p>
+</div>
+
+<p>The steps to set up <em>WhiteNoise</em> to use with the project are:</p>
+
+<h5 id="WhiteNoise">WhiteNoise</h5>
+
+<p>Install whitenoise locally using the following command:</p>
+
+<pre>$ pip3 install whitenoise
+</pre>
+
+<h5 id="settings.py_3">settings.py</h5>
+
+<p>To install <em>WhiteNoise</em> into your Django application, open <strong>/locallibrary/settings.py</strong>, find the <code>MIDDLEWARE</code> setting and add the <code>WhiteNoiseMiddleware</code> near the top of the list, just below the <code>SecurityMiddleware</code>:</p>
+
+<pre>MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+ <strong>'whitenoise.middleware.WhiteNoiseMiddleware',</strong>
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+</pre>
+
+<p>Optionally, you can reduce the size of the static files when they are served (this is more efficient). Just add the following to the bottom of <strong>/locallibrary/settings.py</strong>:</p>
+
+<pre># Simplified static file serving.
+# https://warehouse.python.org/project/whitenoise/
+STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
+</pre>
+
+<h4 id="Requirements">Requirements</h4>
+
+<p>The Python requirements of your web application must be stored in a file <strong>requirements.txt</strong> in the root of your repository. Heroku will then install these automatically when it rebuilds your environment. You can create this file using <em>pip</em> on the command line (run the following in the repo root):</p>
+
+<pre class="brush: bash">pip3 freeze &gt; requirements.txt</pre>
+
+<p>After installing all the different dependencies above, your <strong>requirements.txt</strong> file should have <em>at least</em> these items listed (though the version numbers may be different). Please delete any other dependencies not listed below, unless you've explicitly added them for this application.</p>
+
+<pre>dj-database-url==0.4.1
+Django==2.0
+gunicorn==19.6.0
+<strong>psycopg2==2.6.2</strong>
+whitenoise==3.2.2
+</pre>
+
+<div class="note">
+<p>Make sure that a <strong>psycopg2</strong> line like the one above is present! Even iIf you didn't install this locally then you should still add this to the <strong>requirements.txt</strong>.</p>
+</div>
+
+<h4 id="Runtime">Runtime</h4>
+
+<p>The <strong>runtime.txt</strong> file, if defined, tells Heroku which programming language to use. Create the file in the root of the repo and add the following text:</p>
+
+<pre>python-3.6.4</pre>
+
+<div class="note">
+<p><strong>Note:</strong> Heroku only supports a small number of <a href="https://devcenter.heroku.com/articles/python-support#supported-python-runtimes">Python runtimes</a> (at time of writing, this includes the one above). Heroku will use a supported runtime irrespective of the value specified in this file.</p>
+</div>
+
+<h4 id="Save_changes_to_Github_and_re-test">Save changes to Github and re-test</h4>
+
+<p>Next lets save all our changes to Github. In the terminal (whist inside our repository), enter the following commands:</p>
+
+<pre class="brush: python">git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master</pre>
+
+<p>Before we proceed, lets test the site again locally and make sure it wasn't affected by any of our changes above. Run the development web server as usual and then check the site still works as you expect on your browser.</p>
+
+<pre class="brush: bash">python3 manage.py runserver</pre>
+
+<p>We should now be ready to start deploying LocalLibrary on Heroku.</p>
+
+<h3 id="Get_a_Heroku_account">Get a Heroku account</h3>
+
+<p>To start using Heroku you will first need to create an account:</p>
+
+<ul>
+ <li>Go to <a href="https://www.heroku.com/">www.heroku.com</a> and click the <strong>SIGN UP FOR FREE</strong> button.</li>
+ <li>Enter your details and then press <strong>CREATE FREE ACCOUNT</strong>. You'll be asked to check your account for a sign-up email.</li>
+ <li>Click the account activation link in the signup email. You'll be taken back to your account on the web browser.</li>
+ <li>Enter your password and click <strong>SET PASSWORD AND LOGIN</strong>.</li>
+ <li>You'll then be logged in and taken to the Heroku dashboard: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li>
+</ul>
+
+<h3 id="Install_the_client">Install the client</h3>
+
+<p>Download and install the Heroku client by following the <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">instructions on Heroku here</a>.</p>
+
+<p>After the client is installed you will be able run commands. For example to get help on the client:</p>
+
+<pre class="brush: bash">heroku help
+</pre>
+
+<h3 id="Create_and_upload_the_website">Create and upload the website</h3>
+
+<p>To create the app we run the "create" command in the root directory of our repository. This creates a git remote ("pointer to a remote repository") named <em>heroku</em> in our local git environment.</p>
+
+<pre class="brush: bash">heroku create</pre>
+
+<div class="note">
+<p><strong>Note:</strong> You can name the remote if you like by specifying a value after "create". If you don't then you'll get a random name. The name is used in the default URL.</p>
+</div>
+
+<p>We can then push our app to the Heroku repository as shown below. This will upload the app, package it in a dyno, run collectstatic, and start the site.</p>
+
+<pre class="brush: bash">git push heroku master</pre>
+
+<p>If we're lucky, the app is now "running" on the site, but it won't be working properly because we haven't set up the database tables for use by our application. To do this we need to use the <code>heroku run</code> command and start a "<a href="https://devcenter.heroku.com/articles/deploying-python#one-off-dynos">one off dyno</a>" to perform a migrate operation. Enter the following command in your terminal:</p>
+
+<pre class="brush: bash">heroku run python manage.py migrate</pre>
+
+<p>We're also going to need to be able to add books and authors, so lets also create our administration superuser, again using a one-off dyno:</p>
+
+<pre class="brush: bash">heroku run python manage.py createsuperuser</pre>
+
+<p>Once this is complete, we can look at the site. It should work, although it won't have any books in it yet. To open your browser to the new website, use the command:</p>
+
+<pre class="brush: bash">heroku open</pre>
+
+<p>Create some books in the admin site, and check out whether the site is behaving as you expect.</p>
+
+<h3 id="Managing_addons">Managing addons</h3>
+
+<p>You can check out the add-ons to your app using the <code>heroku addons</code> command. This will list all addons, and their price tier and state.</p>
+
+<pre class="brush: bash">&gt;heroku addons
+
+Add-on Plan Price State
+───────────────────────────────────────── ───────── ───── ───────
+heroku-postgresql (postgresql-flat-26536) hobby-dev free created
+ └─ as DATABASE</pre>
+
+<p>Here we see that we have just one add-on, the postgres SQL database. This is free, and was created automatically when we created the app. You can open a web page to examine the database add-on (or any other add-on) in more detail using the following command:</p>
+
+<pre class="brush: bash">heroku addons:open heroku-postgresql
+</pre>
+
+<p>Other commands allow you to create, destroy, upgrade and downgrade addons (using a similar syntax to opening). For more information see <a href="https://devcenter.heroku.com/articles/managing-add-ons">Managing Add-ons</a> (Heroku docs).</p>
+
+<h3 id="Setting_configuration_variables">Setting configuration variables</h3>
+
+<p>You can check out the configuration variables for the site using the <code>heroku config</code> command. Below you can see that we have just one variable, the <code>DATABASE_URL</code> used to configure our database.</p>
+
+<pre class="brush: bash">&gt;heroku config
+
+=== locallibrary Config Vars
+DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3</pre>
+
+<p>If you recall from the section on <a href="#Getting_your_website_ready_to_publish">getting the website ready to publish</a>, we have to set environment variables for <code>DJANGO_SECRET_KEY</code> and <code>DJANGO_DEBUG</code>. Let's do this now.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The secret key needs to be really secret! One way to generate a new key is to create a new Django project (<code>django-admin startproject someprojectname</code>) and then get the key that is generated for you from its <strong>settings.py</strong>.</p>
+</div>
+
+<p>We set <code>DJANGO_SECRET_KEY</code> using the <code>config:set</code> command (as shown below). Remember to use your own secret key!</p>
+
+<pre class="brush: bash">&gt;heroku config:set DJANGO_SECRET_KEY=eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh&amp;=
+
+Setting DJANGO_SECRET_KEY and restarting locallibrary... done, v7
+DJANGO_SECRET_KEY: eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh
+</pre>
+
+<p>We similarly set <code>DJANGO_DEBUG</code>:</p>
+
+<pre class="brush: bash">&gt;heroku config:set <code>DJANGO_DEBUG=
+
+Setting DJANGO_DEBUG and restarting locallibrary... done, v8</code></pre>
+
+<p>If you visit the site now you'll get a "Bad request" error, because the <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#allowed-hosts">ALLOWED_HOSTS</a> setting is <em>required</em> if you have <code>DEBUG=False</code> (as a security measure). Open <strong>/locallibrary/settings.py</strong> and change the <code>ALLOWED_HOSTS</code> setting to include your base app url (e.g. 'locallibrary1234.herokuapp.com') and the URL you normally use on your local development server.</p>
+
+<pre class="brush: python">ALLOWED_HOSTS = ['&lt;your app URL without the https:// prefix&gt;.herokuapp.com','127.0.0.1']
+# For example:
+# ALLOWED_HOSTS = ['fathomless-scrubland-30645.herokuapp.com','127.0.0.1']
+</pre>
+
+<p>Then save your settings and commit them to your Github repo and to Heroku:</p>
+
+<pre class="brush: bash">git add -A
+git commit -m 'Update ALLOWED_HOSTS with site and development server URL'
+git push origin master
+git push heroku master</pre>
+
+<div class="note">
+<p>After the site update to Heroku completes, enter an URL that does not exist (e.g. <strong>/catalog/doesnotexist/</strong>). Previously this would have displayed a detailed debug page, but now you should just see a simple "Not Found" page.</p>
+</div>
+
+<h3 id="Debugging">Debugging</h3>
+
+<p>The Heroku client provides a few tools for debugging:</p>
+
+<pre class="brush: bash">heroku logs # Show current logs
+heroku logs --tail # Show current logs and keep updating with any new results
+heroku config:set DEBUG_COLLECTSTATIC=1 # Add additional logging for collectstatic (this tool is run automatically during a build)
+heroku ps #Display dyno status
+</pre>
+
+<p>If you need more information than these can provide you will need to start looking into <a href="https://docs.djangoproject.com/en/2.0/topics/logging/">Django Logging</a>.</p>
+
+<ul>
+</ul>
+
+<h2 id="Summary">Summary</h2>
+
+<p>That's the end of this tutorial on setting up Django apps in production, and also the series of tutorials on working with Django. We hope you've found them useful. You can check out a fully worked-through version of the <a href="https://github.com/mdn/django-locallibrary-tutorial">source code on Github here</a>.<br>
+ <br>
+ The next step is to read our last few articles, and then complete the assessment task.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/">Deploying Django</a> (Django docs)
+
+ <ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/">Deployment checklist</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/static-files/deployment/">Deploying static files</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/">How to deploy with WSGI</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/modwsgi/">How to use Django with Apache and mod_wsgi</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/gunicorn/">How to use Django with Gunicorn</a> (Django docs)</li>
+ </ul>
+ </li>
+ <li>Heroku
+ <ul>
+ <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Configuring Django apps for Heroku</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/python-concurrency-and-database-connections">Concurrency and Database Connections in Django</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/config-vars">Configuration and Config Vars</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/deploying-python">Deploying Python and Django apps on Heroku</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/search?q=django">Other Heroku Django docs</a></li>
+ </ul>
+ </li>
+ <li>Digital Ocean
+ <ul>
+ <li><a href="https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-uwsgi-and-nginx-on-ubuntu-16-04">How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04</a></li>
+ <li><a href="https://www.digitalocean.com/community/tutorials?q=django">Other Digital Ocean Django community docs</a></li>
+ </ul>
+ </li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/django/development_environment/index.html b/files/zh-tw/learn/server-side/django/development_environment/index.html
new file mode 100644
index 0000000000..c3d4c5c823
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/development_environment/index.html
@@ -0,0 +1,429 @@
+---
+title: 架設 Django 開發環境
+slug: Learn/Server-side/Django/development_environment
+translation_of: Learn/Server-side/Django/development_environment
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</div>
+
+<p class="summary"><font><font>現在,你知道什麼是Django。</font></font><font><font>那麼我們將向你展示如何在Windows,Linux(Ubuntu)和Mac OSX上設置和測試Django開發環境—無論你常用哪種操作系統,本文應該都能讓你開始開發Django應用程序。</font></font></p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td><font>知道如何打開終端或命令行。</font><font>了解如何在計算機的操作系統上安裝軟件包。</font></td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td><span style='background-color: #ffe8d4; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>在你的計算機操作系統上運行Django(2.0)開發環境。</span></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Django_開發環境概覽">Django 開發環境概覽</h2>
+
+<p>Django 使你輕鬆設置自己的電腦,以便開始開發網絡應用。這部分介紹在開發環境可以取得什麼,並概述了部分設置和配置選項。本文的其餘部分,介紹了在Ubuntu,Mac OS X 和 Windows 上,安裝 Django 開發環境的<em>推薦方法</em>,以及如何測試。</p>
+
+<h3 id="什麼是_Django_開發環境">什麼是 Django 開發環境?</h3>
+
+<p>開發環境是在本地計算機上安裝 Django,你可以在將 Django 部署到生產環境之前,用於開發和測試 Django 應用程序。</p>
+
+<p>Django 本身提供的主要工具,是一組用於創建和使用 Django 項目的 Python 腳本,以及可用於在你的計算機的瀏覽器上,測試本地(即,你的計算機,而不是外部 Web 服務器)Django 網絡應用程序的簡單開發網路服務器 。</p>
+
+<p>還有其他外部工具, 它們構成了開發環境的一部分, 我們將不再贅述。這些包括 文本編輯器 <a href="/en-US/docs/Learn/Common_questions/Available_text_editors">text editor</a> 或編輯代碼的 IDE,以及像 <a href="https://git-scm.com/">Git </a>這樣的源代碼控制管理工具,用於安全地管理不同版本的代碼。我們假設你已經安裝了一個文本編輯器。</p>
+
+<h3 id="什麼是Django設置選項"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>什麼是Django設置選項?</font></font></span></h3>
+
+<p><font>Django 如何在安裝和配置方面非常靈活。</font><font>Django可以:</font></p>
+
+<ul>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>安裝在不同的操作系統上。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>可以一起使用Python 3 和Python 2.</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>通過Python包索引(PyPi)安裝,和在許多情況下主機的包管理器應用程序。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>配置為使用幾個數據庫之一,可能需要單獨安裝和配置。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>運行在主系統Python環境中或在單獨的Python虛擬環境中運行。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>每個選項都需要略微不同的配置和設置。</font><font>以下小節解釋了你的一些選擇。</font><font>對於本文的其餘部分,我們將介紹Django在少見的操作系統上的設置,考量該模塊的其餘部分。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font>: 其他可能的安裝選項在官方Django文檔中介紹。</font></font><a href="https://developer.mozilla.org/zh-CN/docs/learn/Server-side/Django/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83#furtherreading" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 243, 212);'><font><font>相應文件點擊這裡</font></font></a><font><font>。</font></font></p>
+</div>
+
+<h4 id="支持哪些操作系統" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>支持哪些操作系統?</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>幾乎任何可以運行Python編程語言的機器可以運行Django 網絡應用程序:Windows,Mac OSX,Linux/Unix,Solaris,僅舉幾例。</font><font>幾乎任何計算機都應該在開發過程中運行Django所需的性能。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在本文中。</font><font>我們將提供Windows,Mac OS X 和Linux/Unix的說明。</font></font></p>
+
+<h4 id="你應該使用什麼版本的Python" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你應該使用什麼版本的Python?</font></font></h4>
+
+<p>我們建議您使用最新版本 - 在編寫本文時,這是Python 3.7。</p>
+
+<p>如果需要,可以使用Python 3.4或更高版本(將來的版本中將刪除Python 3.4支持)。</p>
+
+<div class="note">
+<p><strong>注意</strong>: Python 2.7不能與Django 2.0一起使用(Django 1.11.x系列是最後一個支持Python 2.7的系列)。</p>
+</div>
+
+<h4 id="我們在哪裡下載Django" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們在哪裡下載Django?</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>有三個地方可以下載Django:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>Python包含庫(PyPi),使用</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>pip</font></font></strong><font><font>工具.這是獲取最新穩定版本的Django的最佳方式.</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>使用計算機軟件包管理器中的版本。</font><font>與操作系統捆綁在一起的Django的分發提供了一種熟悉的安裝機制。</font><font>請注意,打包版本可能相當舊,只能安裝到系統Python 環境中(可能不是你想要的)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>可以從源代碼獲取並安裝的最新版本的Python。</font><font>這不是推薦給初學者,但是當你準備好開始貢獻給Django本身的時候,它是必需的。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>本文介紹如何從PyPi安裝Django,從獲得最新的穩定版本。</font></font></p>
+
+<h4 id="哪個數據庫" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>哪個數據庫?</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>Django支持四個主要數據庫(PostgreSQL,MySQL,Oracle和SQLite),還有一些社區庫,可以為其他流行的SQL和NOSQL數據庫,提供不同級別的支持。</font><font>我們建議你為生產和開發,選擇相同的數據庫(儘管Django使用其對象關係映射器(ORM)抽像出許多數據庫差異,但是仍然存在可以避免的</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/databases/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>潛在問題</font></font></a><font><font><span> </span>).</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>對於本文(和本模塊的大部分),我們將使用將數據存放在文件中的SQLite數據庫。</font><font>SQLite旨在用作輕量級數據庫,不能支持高級並發。</font><font>然而,這確實是唯讀的應用程序的絕佳選擇。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>:當你使用標準工具(django-admin)啟動你的網站項目時,Django將默認配置為使用SQLite。</font><font>用來入門,這是一個很好的選擇,因為它不需要額外的配置和設置。</font></font></p>
+</div>
+
+<h4 id="安裝到整個本機系統還是Python虛擬環境中" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>安裝到整個本機系統還是Python虛擬環境中?</font></font></h4>
+
+<p>安裝Python3時,您將獲得一個由所有Python3代碼共享的單一全局環境。雖然您可以在環境中,安裝任何您喜歡的Python軟件包,但您一次只能安裝每個軟件包的一個特定版本。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 安裝到全局環境中的Python應用程序可能會相互衝突(即,如果它們依賴於同一程序包的不同版本)。</p>
+</div>
+
+<p>如果您將Django安裝到默認/全局環境中,那麼您將只能在計算機上,定位一個版本的Django。如果您想要創建新網站(使用最新版本的Django)同時仍然維護依賴舊版本的網站,這可能是一個問題。</p>
+
+<p>因此,經驗豐富的Python / Django開發人員,通常在獨立的Python虛擬環境中,運行Python應用程序。這樣可以在一台計算機上,實現多個不同的Django環境。 Django開發團隊本身建議您使用Python虛擬環境!</p>
+
+<p>本模塊假設您已將Django安裝到虛擬環境中,我們將向您展示如何做。</p>
+
+<h2 id="安裝_Python_3">安裝 Python 3</h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>為了使用Django,你需要安裝Python3.同樣你需要</font></font><a class="external external-icon" href="https://pypi.python.org/pypi" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Python包管理工具</font></font></a><font><font><span> </span>  —<span> </span></font></font><em><font><font>pip3</font></font></em><font><font><span> </span>—用來管理(安裝,更新和刪除)Django和其他Python應用程序使用的Python軟件包/庫。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>本書簡要說明如何根據需要檢查什麼版本,並根據需要安裝新版本,適用於</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Ubuntu Linux 16.04, Mac OS X, and Windows 10。</font></font></strong></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>:根據你的平台,您還可以從操作系統自己的軟件包管理器或其他機制安裝Python / pip。</font><font>對於大多數平台,您可以從</font></font><a class="external external-icon" href="https://www.python.org/downloads/" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>https://www.python.org/downloads/</font></font></a><font><font>下載所需的安裝文件,並使用適當的平台特定方法進行安裝。</font></font></p>
+</div>
+
+<h3 id="Ubuntu_18.04">Ubuntu 18.04</h3>
+
+<p>Ubuntu Linux 18.04 LTS默認包含Python 3.6.5。您可以通過在bash終端中運行以下命令來確認:</p>
+
+<pre class="brush: bash"><span style="line-height: 1.5;">python3 -V
+ Python 3.6.5</span></pre>
+
+<p><font><font>然而,在默認情況下,為Python 3(包括Django)安裝軟件包的Python包管理工具</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>不可用。</font><font>你</font></font></strong><font><font>可以使用以下方式將</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>pip3</font></font></strong><font><font>安裝在</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>bash</font></font></strong><font><font>終端</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>:</font></font></strong></p>
+
+<pre class="brush: bash">sudo apt install python3-pip
+</pre>
+
+<h3 id="macOS_X">macOS X</h3>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>Mac OS X "El Capitan" 不包括Python 3.你可以通過在bash終端中運行一下命令來確認:</span></p>
+
+<pre class="brush: bash"><span style="line-height: 1.5;">python3 -V
+ </span>-bash: python3: command not found</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你可以輕鬆從</font></font><a class="external external-icon" href="https://www.python.org/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>python.org</font></font></a><font><font>安裝Python 3(以及pip3工具):</font></font></p>
+
+<ol style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; list-style-type: decimal; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>下載所需的安裝程序:</font></font>
+
+ <ol style="font-style: normal !important; margin: 0px; padding: 6px 0px 0px 40px; border: 0px; list-style-type: decimal; max-width: 42rem;">
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>點擊</font></font><a class="external external-icon" href="https://www.python.org/downloads/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>https://www.python.org/downloads/</font></font></a></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>選擇</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Download Python 3.7.0</font></font></strong><font><font>按鈕(確切的版本號可能不同).</font></font></li>
+ </ol>
+ </li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>使用Finder找到文件,然後雙擊包文件。</font><font>遵循安裝提示。</font></font><br>
+ <font><font>(一般能拖拽就拖拽)</font></font></li>
+</ol>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你現在可以檢查Pyhon 3來確認成功安裝,如下所示:</font></font></p>
+
+<pre class="brush: bash"><span style="line-height: 1.5;">python3 -V
+ Python 3.7.0</span>
+</pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>你也可以通過列出可用的軟件包來檢查pip3是否安裝:</span></p>
+
+<pre class="brush: bash">pip3 list</pre>
+
+<h3 id="Windows_10">Windows 10</h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>windows默認不安裝,但你可以從</font></font><a class="external external-icon" href="https://www.python.org/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>python.org</font></font></a><font><font>輕鬆安裝它(以及pip3工具):</font></font></p>
+
+<ol style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; list-style-type: decimal; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>下載所需版本:</font></font>
+
+ <ol style="font-style: normal !important; margin: 0px; padding: 6px 0px 0px 40px; border: 0px; list-style-type: decimal; max-width: 42rem;">
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>點擊</font></font><a class="external external-icon" href="https://www.python.org/downloads/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>https://www.python.org/downloads/</font></font></a></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>選擇</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Download Python 3.7.0 </font></font></strong><font><font>按鈕(確切的版本號可能不同).</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>通過雙擊下載的文件並按照提示安裝Python</font></font></li>
+ </ol>
+ </li>
+</ol>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你可以通過在命令提示符中輸入以下文本來驗證是否安裝了Python:</font></font></p>
+
+<pre class="brush: bash"><span style="line-height: 1.5;">py -3 -V
+ Python 3.7.0</span>
+</pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>默認情況下,Windows安裝程序包含pip3(python包管理器,你可以列出安裝的軟件包):</span></p>
+
+<pre class="brush: bash"><span style="line-height: 1.5;">pip3 list</span>
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 安裝程序應設置上述命令工作所需的一切。但是,如果您收到無法找到Python 的消息,則可能忘記將其添加到系統路徑中。您可以通過再次運行安裝程序,選擇“修改”"Modify",然後選中第二頁上標有“將Python添加到環境變量”"Add Python to environment variables"的框來執行此操作。</p>
+</div>
+
+<h2 id="在Python虛擬環境中使​​用Django"><a id="Using_a_virtual_environment" name="Using_a_virtual_environment"></a>在Python虛擬環境中使​​用Django</h2>
+
+<p>我們將用於創建虛擬環境的庫是 <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenvwrapper</a>(Linux和macOS X)和 <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> (Windows),後者又使用 <a href="https://developer.mozilla.org/en-US/docs/Python/Virtualenv">virtualenv</a>工具。包裝工具為所有平台上的接口管理創建了一致的界面。</p>
+
+<h3 id="安裝虛擬環境軟體">安裝虛擬環境軟體</h3>
+
+<h4 id="Ubuntu虛擬環境設置">Ubuntu虛擬環境設置</h4>
+
+<p>安裝Python和pip之後,你可以安裝 virtualenvwrapper(包括virtualenv)。可在<a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">此處</a>找到官方安裝指南,或按照以下說明操作。</p>
+
+<p>使用pip3安裝該工具:</p>
+
+<pre class="brush: bash"><code>sudo pip3 install virtualenvwrapper</code></pre>
+
+<p>然後將以下行添加到shell啟動文件的末尾(這是主目錄中的隱藏文件名<strong>.bashrc</strong>)。這些設置了虛擬環境應該存在的位置,開發項目目錄的位置以及使用此軟件包安裝的腳本的位置 :</p>
+
+<pre class="brush: bash"><code>export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 '
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh</code>
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: <code>VIRTUALENVWRAPPER_PYTHON</code> 和 <code>VIRTUALENVWRAPPER_VIRTUALENV_ARGS </code>變量指向Python3的正常安裝位置,<code>source /usr/local/bin/virtualenvwrapper.sh</code>指向<code>virtualenvwrapper.sh</code>腳本的正常位置。如果virtualenv在測試時不起作用,那麼要檢查的一件事是Python和腳本位於預期的位置(然後適當地更改啟動文件)。</p>
+
+<p>您可以使用<code>which virtualenvwrapper.sh</code> 和 <code>which python3</code>.的命令找到系統的正確位置。</p>
+</div>
+
+<p>然後在終端中運行以下命令重新加載啟動文件:</p>
+
+<pre class="brush: bash"><code>source ~/.bashrc</code></pre>
+
+<p>此時您應該看到一堆腳本正在運行,如下所示:</p>
+
+<pre class="brush: bash"><code>virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject
+...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details</code>
+</pre>
+
+<p>現在,您可以使用<code>mkvirtualenv</code>命令創建新的虛擬環境。</p>
+
+<h4 id="macOS_X_虛擬環境設置">macOS X 虛擬環境設置</h4>
+
+<p>在 macOS X上設置 virtualenvwrapper 與在 Ubuntu上幾乎完全相同(同樣,您可以按照<a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">官方安裝指南</a>或下面的說明進行操作。</p>
+
+<p>使用 pip 安裝 virtualenvwrapper(並捆綁 virtualenv),如圖所示。</p>
+
+<pre class="brush: bash"><code>sudo pip3 install virtualenvwrapper</code></pre>
+
+<p>然後將以下幾行添加到 shell 啟動文件的末尾。</p>
+
+<pre class="brush: bash"><code>export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh</code></pre>
+
+<div class="note">
+<p><strong>注意</strong>: <code>VIRTUALENVWRAPPER_PYTHON</code>變量指向Python3的正常安裝位置,<code>source /usr/local/bin/virtualenvwrapper.sh</code>指向<code>virtualenvwrapper.sh</code>腳本的正常位置。如果virtualenv在測試時不起作用,那麼要檢查的一件事,是Python和腳本位於預期的位置(然後適當地更改啟動文件)。</p>
+
+<p>例如,對macOS進行的一次安裝測試,最終在啟動文件中需要以下幾行:</p>
+
+<pre class="brush: bash">export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh</pre>
+
+<p>您可以使用<code>which virtualenvwrapper.sh</code> 和 <code>which python3</code>的命令找到系統的正確位置。</p>
+</div>
+
+<p>這幾行與Ubuntu相同,但啟動文件是主目錄中、名稱不同的隱藏文件<strong>.bash_profile</strong>。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 如果在查找程序中找不到要編輯的<strong>.bash-profile</strong>,也可以使用nano在終端中打開它。</p>
+
+<p>命令看起來像這樣:</p>
+
+<pre><code>cd ~ # Navigate to my home directory
+ls -la #List the content of the directory. YOu should see .bash_profile
+nano .bash_profile # Open the file in the nano text editor, within the terminal
+# Scroll to the end of the file, and copy in the lines above
+# Use Ctrl+X to exit nano, Choose Y to save the file.</code>
+</pre>
+
+<p> </p>
+</div>
+
+<p>然後通過在終端中,進行以下調用,來重新加載啟動文件:</p>
+
+<pre class="brush: bash"><code>source ~/.bash_profile</code></pre>
+
+<p>此時,您可能會看到一堆腳本正在運行(與Ubuntu安裝相同的腳本)。您現在應該能夠使用<code>mkvirtualenv</code>命令,創建新的虛擬環境。</p>
+
+<h4 id="Windows_10_虛擬環境設置">Windows 10 虛擬環境設置</h4>
+
+<p>安裝<a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a>比設置virtualenvwrapper更簡單,因為您不需要配置工具存放虛擬環境信息的位置(有默認值)。您需要做的就是,在命令提示符中運行以下命令:</p>
+
+<pre><code>pip3 install virtualenvwrapper-win</code></pre>
+
+<p>現在,您可以使用<code>mkvirtualenv</code>命令創建新的虛擬環境</p>
+
+<h3 id="創建虛擬環境">創建虛擬環境</h3>
+
+<p>一旦你安裝了virtualenvwrapper或virtualenvwrapper-win,那麼在所有平台上使用虛擬環境都非常相似。</p>
+
+<p>現在,您可以使用<code>mkvirtualenv</code>命令創建新的虛擬環境。當此命令運行時,您將看到正在設置的環境(您看到的是略微特定​​於平台的)。當命令完成時,新的虛擬環境,將處於活動狀態 - 您可以看到這一點,因為提示的開頭,將是括號中環境的名稱(如下所示)。</p>
+
+<pre><code>$ mkvirtualenv my_django_environment
+
+Running virtualenv with interpreter /usr/bin/python3
+...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details
+(my_django_environment) ubuntu@ubuntu:~$</code>
+</pre>
+
+<p>現在,您可以在虛擬環境中,安裝Django,並開始開發。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 從本文開始(實際上是本系列教學),請假設任何命令都在Python虛擬環境中運行,就像我們在上面設置的那樣。</p>
+</div>
+
+<h3 id="使用虛擬環境">使用虛擬環境</h3>
+
+<p>您應該知道其他一些有用的命令(工具文檔中有更多,但這些是您經常使用的命令):</p>
+
+<ul>
+ <li><code>deactivate</code> — 退出當前的Python虛擬環境</li>
+ <li><code>workon</code> — 列出可用的虛擬環境</li>
+ <li><code>workon name_of_environment</code> — 激活指定的Python虛擬環境</li>
+ <li><code>rmvirtualenv name_of_environment</code> — 刪除指定的環境</li>
+</ul>
+
+<h2 id="安裝_Django">安裝 Django</h2>
+
+<p>一旦你創建了一個虛擬環境,並調用了<code>workon</code>來輸入它,就可以使用pip3來安裝Django。</p>
+
+<pre class="brush: bash">pip3 install django
+</pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>您可以通過運行以下命令來測試Django是否安裝(這只是測試Python可以找到Django模塊):</span></p>
+
+<pre class="brush: bash"># Linux/macOS X
+python3 -m django --version
+ 2.0
+
+# Windows
+py -3 -m django --version
+ 2.0
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 如果上面的Windows命令沒有顯示django模塊,請嘗試:</p>
+
+<pre class="brush: bash">py -m django --version</pre>
+在Windows中,Python 3腳本通過在命令前面加上<code>py -3</code>來啟動,儘管這可能會因具體安裝而異。如果遇到任何命令問題,請嘗試省略<code>-3</code>修飾符。在Linux / macOS X中,命令是<code>python3</code>。</div>
+
+<div class="warning">
+<p><font>重要提示:本教程的其餘部分,使用Linux命令來調用Python 3(python3)。</font><font>如果您在Windows上工作,只需將此前綴替換為:<code> py -3</code></font></p>
+</div>
+
+<h2 id="測試你的安裝"><font><font>測試你的安裝</font></font></h2>
+
+<p><font><font>上面的測試可以工作,但它不是很有趣。</font><font>一個更有趣的測試是創建一個骨架項目並看到它工作。</font><font>要做到這一點,先在你的命令提示符/終端導航到你想存儲你</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Django</font></font></strong><font><font>應用程序的位置。</font><font>為您的測試站點創建一個文件夾並瀏覽它。</font></font></p>
+
+<pre class="brush: bash">mkdir django_test
+cd django_test
+</pre>
+
+<p><font><font>然後,您可以使用<strong>django-admin</strong>工具創建一個名為“<span> </span></font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>mytestsite</font></font></strong><font><font><span> </span>”的新骨架站點,如圖所示。</font><font>創建網站後,您可以導航到文件夾,您將在其中找到管理項目的主要腳本,名為</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>manage.py</font></font></strong><font><font>。</font></font></p>
+
+<pre class="brush: bash">django-admin startproject mytestsite
+cd mytestsite</pre>
+
+<p><font><font>我們可以使用</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>manage.py</font></font></strong><font><font>和 </font></font><code>runserver </code><font><font>命令,從此文件夾內運行開發Web服務器,如圖所示。</font></font></p>
+
+<pre class="brush: bash">$ python3 manage.py runserver
+Performing system checks...
+
+System check identified no issues (0 silenced).
+
+You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
+Run 'python manage.py migrate' to apply them.
+
+December 29, 2017 - 03:03:47
+Django version 2.0, using settings 'mytestsite.settings'
+Starting development server at http://127.0.0.1:8000/
+Quit the server with CONTROL-C.
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 以上命令顯示Linux / macOS X命令。此時您可以忽略有關“14個未應用的遷移”的警告!("14 unapplied migration(s)" )</p>
+</div>
+
+<p><font>一旦服務器運行,您可以通過導航到本地Web瀏覽器上的以下URL來查看該站點:<code>http://127.0.0.1:8000/</code>。</font><font>你應該看到一個如下所示的網站:</font></p>
+
+<p><img alt="Django Skeleton App Homepage" src="https://mdn.mozillademos.org/files/15728/Django_Skeleton_Website_Homepage.png"></p>
+
+<ul>
+</ul>
+
+<h2 id="總結Summary">總結Summary</h2>
+
+<p>您現在已在計算機上啟動並運行Django開發環境。</p>
+
+<p>在測試部分,您還簡要了解了,我們如何使用<code>django-admin startproject</code>,創建一個新的Django網站,並使用開發Web服務器(<code>python3 manage.py runserver</code>)在瀏覽器中運行它。在下一篇文章中,我們將擴展此過程,構建一個簡單、但完整的Web應用程序。</p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/install/">Quick Install Guide</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/install/">How to install Django — Complete guide</a> (Django docs) - includes information on how to remove Django</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/windows/">How to install Django on Windows</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</p>
+
+<h2 id="本教程連結">本教程連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html b/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html
new file mode 100644
index 0000000000..d584b8259c
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/django_assessment_blog/index.html
@@ -0,0 +1,316 @@
+---
+title: 'Assessment: DIY Django mini blog'
+slug: Learn/Server-side/Django/django_assessment_blog
+tags:
+ - django
+ - 初學者
+ - 部落格
+translation_of: Learn/Server-side/Django/django_assessment_blog
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">在這個評估中,您將使用您在 <a href="/en-US/docs/Learn/Server-side/Django">Django Web Framework (Python)</a> 模組中獲得的知識,來創建一個非常基本的部落格。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">
+ <p>前提:</p>
+ </th>
+ <td>在開始時做這章節的任務之前,你應該已經看完這個模組的所有文章了。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>
+ <p>測試Django基礎的綜合應用,包含URL設定、模型、視圖、表單和模板。</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="專案簡介">專案簡介</h2>
+
+<p>需要顯示的頁面與對應的URLs和需求提列於下表:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">頁面</th>
+ <th scope="col">URL</th>
+ <th scope="col">需求</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>首頁</td>
+ <td><code>/</code> 和 <code>/blog/</code></td>
+ <td>關於此站的說明。</td>
+ </tr>
+ <tr>
+ <td>所有部落格文章的清單</td>
+ <td><code>/blog/blogs/</code></td>
+ <td>
+ <p>所有部落格文章的清單。</p>
+
+ <ul>
+ <li>所有使用者都能從側邊選單進入此頁。</li>
+ <li>清單按發布日期排序(新至舊)。</li>
+ <li>清單依照每頁5筆文章分頁。</li>
+ <li>清單內的每一筆項目顯示文章標題、發布日期與作者的名字。</li>
+ <li>文章標題連結至該至文章的詳細頁面。</li>
+ <li>作者的名字連結至該作者的詳細頁面。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>部落格作者(blogger) 詳細頁面</td>
+ <td><code>/blog/blogger/<em>&lt;author-id&gt;</em></code></td>
+ <td>
+ <p>特定作者(由id指定)的資訊與他所發布的部落格文章。</p>
+
+ <ul>
+ <li>所有使用者都能從作者連結進入此頁(例如文章內的作者連結)。</li>
+ <li>包含一些關於作者本身的資訊。</li>
+ <li>文章清單按發布日期排序(新至舊)。</li>
+ <li>不用分頁。</li>
+ <li>文章清單只顯示文章標題與發佈日期。</li>
+ <li>文章標題連結至文章詳細頁面。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>部落格文章詳細頁面</td>
+ <td><code>/blog/<em>&lt;blog-id&gt;</em></code></td>
+ <td>
+ <p>部落格文章詳細內容。</p>
+
+ <ul>
+ <li>任何使用者都能從部落格文章的清單進入此頁。</li>
+ <li>包含文章標題、作者、發布日期與內容。</li>
+ <li>文章的回覆必須呈現於底部。</li>
+ <li>文章的回覆必須按回覆時間排序(舊至新)。</li>
+ <li>已登入的使用者能看見新增回覆的連結。</li>
+ <li>文章與回覆需以純文字的方式顯示。不需要支援任何markup(例如連結、圖片、粗體/斜體等)。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>部落格作者清單</td>
+ <td><code>/blog/bloggers/</code></td>
+ <td>
+ <p>系統內的部落格作者清單。</p>
+
+ <ul>
+ <li>任何使用者都可以從側邊選單進入此頁。</li>
+ <li>作者名字連結至該作者的詳細頁面。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>回覆表單頁</td>
+ <td><code>/blog/<em>&lt;blog-id&gt;</em>/create</code></td>
+ <td>
+ <p>新增回覆於特定文章。</p>
+
+ <ul>
+ <li>只有登入的使用者可以由文章詳細頁面底部連結進入此頁。</li>
+ <li>提供能輸入回覆的表單(發布日期和文章標題不可被編輯)。</li>
+ <li>回覆被發表之後,頁面會轉址回該文章詳細頁。</li>
+ <li>使用者無法修改或是刪除他發表的回覆。</li>
+ <li>未登入的使用者會先被導至登入頁,登入之後才能發表回覆。一旦登入之後,他們便會被導至他們想發表回覆的文章頁。</li>
+ <li>回覆表單頁必須包含該文章的標題與連結。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>使用者身分認證頁</td>
+ <td><code>/accounts/<em>&lt;standard urls&gt;</em></code></td>
+ <td>
+ <p>標準的Django身分驗證頁面,用來登入、登出及修改密碼。</p>
+
+ <ul>
+ <li>使用者能從側欄連結進入登入/登出頁面。</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>管理者網頁</td>
+ <td><code>/admin/<em>&lt;standard urls&gt;</em></code></td>
+ <td>
+ <p>管理者網頁必須能新增/編輯/刪除部落格文章、作者及回覆。</p>
+
+ <ul>
+ <li>管理者網頁的每筆文章記錄必須一併於其底下陳列出相關的回覆。</li>
+ <li>管理者網頁的每一筆回覆都要以75字的回覆內容作為顯示名稱。</li>
+ <li>其餘的紀錄使用基本的註冊即可。</li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>另外您應該要寫一些基本的測試來驗證:</p>
+
+<ul>
+ <li>所有的模型欄位都有正確的標示和長度。</li>
+ <li>所有的模型都有期望的物件名稱(例如<code> __str__()</code> 回傳期望的值)。</li>
+ <li>模型有期望的URL給每篇文章與回覆。(例如<code>get_absolute_url()</code> 回傳期望的URL)。</li>
+ <li>BlogListView (所有文章的頁面) 可以從期望的位址進入(例如/blog/blogs)。</li>
+ <li>BlogListView (所有文章的頁面) 可以從期望的位址名稱進入(例如'blogs')。</li>
+ <li>BlogListView (所有文章的頁面) 使用期望的模板(例如預設值)。</li>
+ <li>BlogListView 以每頁5筆項目分頁(至少第一頁是如此)。</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: 當然你也可以跑很多其他的測試。但是我們會希望您至少實作以上列出的測試項目。</p>
+</div>
+
+<p>下一區塊顯示符合以上需求的網頁<a href="#Screenshots">截圖</a>。</p>
+
+<h2 id="截圖">截圖</h2>
+
+<p>The following screenshot provide an example of what the finished program should output.</p>
+
+<h3 id="列出所有的部落格文章">列出所有的部落格文章</h3>
+
+<p>這個頁面會列出所有部落格內的文章(可以從側邊選單的“所有文章”連結進入)。<br>
+ 幾項提醒:</p>
+
+<ul>
+ <li>側邊選單也要列出目前登入的使用者。</li>
+ <li>每篇文章與部落客都能透過連結的方式進入。</li>
+ <li>必須要有分頁(每頁5筆資料)。</li>
+ <li>文章排列順序由最新至最舊。</li>
+</ul>
+
+<p><img alt="List of all blogs" src="https://mdn.mozillademos.org/files/14319/diyblog_allblogs.png" style="border-style: solid; border-width: 1px; display: block; height: 363px; margin: 0px auto; width: 986px;"></p>
+
+<h3 id="列出所有部落客(文章作者)">列出所有部落客(文章作者)</h3>
+
+<p>可以由側邊選單的“所有部落客”進入此頁面,並於頁面上提供連結至每一位部落客。<br>
+ 從截圖可以發現到,並沒有任何一位使用者登入。</p>
+
+<p><img alt="List of all bloggers" src="https://mdn.mozillademos.org/files/14321/diyblog_blog_allbloggers.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 493px;"></p>
+
+<h3 id="部落格詳細頁">部落格詳細頁</h3>
+
+<p>顯示某篇特定部落格文章的詳細內容。</p>
+
+<p><img alt="Blog detail with add comment link" src="https://mdn.mozillademos.org/files/14323/diyblog_blog_detail_add_comment.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 986px;"></p>
+
+<p>請注意每個評論都有日期與時間,並且由最後至最新排列(與部落格文章相反)。<br>
+ 我們可以看見最底下有個連結連到新增評論的表單。當使用者沒有登入時,我們改以要求登入的連結代替。</p>
+
+<p><img alt="Comment link when not logged in" src="https://mdn.mozillademos.org/files/14325/diyblog_blog_detail_not_logged_in.png" style="border-style: solid; border-width: 1px; display: block; height: 129px; margin: 0px auto; width: 646px;"></p>
+
+<h3 id="新增評論表單">新增評論表單</h3>
+
+<p>這張表單用來新增評論,且使用者必須是登入狀態。當表單送出成功之後,我們必須回到相對應的部落格文章內容頁。</p>
+
+<p><img alt="Add comment form" src="https://mdn.mozillademos.org/files/14329/diyblog_comment_form.png" style="border-style: solid; border-width: 1px; display: block; height: 385px; margin: 0px auto; width: 778px;"></p>
+
+<h3 id="作者資料">作者資料</h3>
+
+<p>這頁顯示部落客的介紹資料以及列出他們所發表的部落格文章。</p>
+
+<p><img alt="Blogger detail page" src="https://mdn.mozillademos.org/files/14327/diyblog_blogger_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 379px; margin: 0px auto; width: 982px;"></p>
+
+<h2 id="一步一腳印Steps_to_complete">一步一腳印Steps to complete</h2>
+
+<p>以下說明實作的步驟。</p>
+
+<ol>
+ <li>建立一個此網站的專案及app骨架(可以參考<a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django 教學2 : 建立一個網站骨架</a>)。你也許會用'diyblog'作為專案名稱,‘blog'作為app的名稱。</li>
+ <li>建立部落格文章、評論與其他任何所需物件的模型。當你在思考怎麼設計的時候,請記得:
+ <ul>
+ <li>每一個評論都只屬於一篇部落格文章,但每一個部落格文章可以有很多筆評論。</li>
+ <li>部落格文章必須要依照發布時間排序(新至舊),評論要依照發布排序(舊至新)。</li>
+ <li>不是每位使用者都是部落客,但是每一位使用者都可以留下評論。</li>
+ <li>部落客必須有介紹資訊。</li>
+ </ul>
+ </li>
+ <li>跑migrations以及創建一個新的超級使用者(superuser)。</li>
+ <li>透過admin網站新稱一些部落格文章和評論。</li>
+ <li>幫部落格文章列表頁與部落客列表頁建立視圖、模板及設定URL。</li>
+ <li>幫部落格文章詳細頁與部落客詳細頁建立視圖、模板及設定URL。</li>
+ <li>建立一個頁面包含可以新增評論的表單(記得只有已登入的使用者可以進入此頁!)</li>
+</ol>
+
+<h2 id="提示與小技巧">提示與小技巧</h2>
+
+<p>This project is very similar to the <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> tutorial. You will be able to set up the skeleton, user login/logout behaviour, support for static files, views, URLs, forms, base templates and admin site configuration using almost all the same approaches.</p>
+
+<p>Some general hints:</p>
+
+<ol>
+ <li>The index page can be implemented as a basic function view and template (just like for the locallibrary).</li>
+ <li>The list view for blog posts and bloggers, and the detail view for blog posts can be created using the <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">generic list and detail views</a>.</li>
+ <li>The list of blog posts for a particular author can be created by using a generic list Blog list view and filtering for blog object that match the specified author.
+ <ul>
+ <li>You will have to implement <code>get_queryset(self)</code> to do the filtering (much like in our library class <code>LoanedBooksAllListView</code>) and get the author information from the URL.</li>
+ <li>You will also need to pass the name of the author to the page in the context. To do this in a class-based view you need to implement <code>get_context_data()</code> (discussed below).</li>
+ </ul>
+ </li>
+ <li>The <em>add comment</em> form can be created using a function-based view (and associated model and form) or using a generic <code>CreateView</code>. If you use a <code>CreateView</code> (recommended) then:
+ <ul>
+ <li>You will also need to pass the name of the blog post to the comment page in the context (implement <code>get_context_data()</code> as discussed below).</li>
+ <li>The form should only display the comment "description" for user entry (date and associated blog post should not be editable). Since they won't be in the form itself, your code will need to set the comment's author in the<code> form_valid()</code> function so it can be saved into the model (<a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user">as described here</a> — Django docs). In that same function we set the associated blog. A possible implementation is shown below (<code>pk</code> is a blog id passed in from the URL/URL configuration).
+ <pre class="brush: python"> def form_valid(self, form):
+ """
+ Add author and associated blog to form data before setting it as valid (so it is saved to model)
+ """
+ #Add logged-in user as author of comment
+ form.instance.author = self.request.user
+ #Associate comment with blog based on passed id
+ form.instance.blog=get_object_or_404(Blog, pk = self.kwargs['pk'])
+ # Call super-class form validation behaviour
+ return super(BlogCommentCreate, self).form_valid(form)
+</pre>
+ </li>
+ <li>You will need to provide a success URL to redirect to after the form validates; this should be the original blog. To do this you will need to override <code>get_success_url()</code> and "reverse" the URL for the original blog. You can get the required blog ID using the <code>self.kwargs</code> attribute, as shown in the <code>form_valid()</code> method above.</li>
+ </ul>
+ </li>
+</ol>
+
+<p>We briefly talked about passing a context to the template in a class-based view in the <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views#Overriding_methods_in_class-based_views">Django Tutorial Part 6: Generic list and detail views</a> topic. To do this you need to override <code>get_context_data()</code> (first getting the existing context, updating it with whatever additional variables you want to pass to the template, and then returning the updated context). For example, the code fragment below shows how you can add a blogger object to the context based on their <code>BlogAuthor</code> id.</p>
+
+<pre class="brush: python">class SomeView(generic.ListView):
+ ...
+
+ def get_context_data(self, **kwargs):
+        # Call the base implementation first to get a context
+        context = super(SomeView, self).get_context_data(**kwargs)
+        # Get the blogger object from the "pk" URL parameter and add it to the context
+        context['blogger'] = get_object_or_404(BlogAuthor, pk = self.kwargs['pk'])
+        return context
+</pre>
+
+<h2 id="Assessment">Assessment</h2>
+
+<p>The assessment for this task is <a href="https://github.com/mdn/django-diy-blog/blob/master/MarkingGuide.md">available on Github here</a>. This assessment is primarily based on how well your application meets the requirements we listed above, though there are some parts of the assessment that check your code uses appropriate models, and that you have written at least some test code. When you're done, you can check out our <a href="https://github.com/mdn/django-diy-blog">the finished example</a> which reflects a "full marks" project.</p>
+
+<p>Once you've completed this module you've also finished all the MDN content for learning basic Django server-side website programming! We hope you enjoyed this module and feel you have a good grasp of the basics!</p>
+
+<p>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/forms/index.html b/files/zh-tw/learn/server-side/django/forms/index.html
new file mode 100644
index 0000000000..a4553d2d73
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/forms/index.html
@@ -0,0 +1,661 @@
+---
+title: 'Django Tutorial Part 9: Working with forms'
+slug: Learn/Server-side/Django/Forms
+translation_of: Learn/Server-side/Django/Forms
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">在本教程中,我們將向您展示,如何在 Django 中使用 HTML 表單,特別是編寫表單以創建,更新和刪除模型實例的最簡單方法。作為本演示的一部分,我們將擴展 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary </a>網站,以便圖書館員,可以使用我們自己的表單(而不是使用管理員應用程序)更新圖書,創建,更新和刪除作者。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row"> 前提:</th>
+ <td>完成先前所有的教程, 包含 <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions">Django Tutorial Part 8: User authentication and permissions</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">目的:</th>
+ <td>了解如何製作表單來向用戶取得資訊並更新資料庫。了解<strong>通用類別表單編輯視圖 </strong>( generic class-based form editing views ) 能夠大幅簡化用於單一模型的表單製作。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概述">概述</h2>
+
+<p><a href="/en-US/docs/Web/Guide/HTML/Forms">HTML表單</a>是網頁上的一組一個或多個字段/小組件,可用於從用戶收集信息以提交到服務器。 表單是一種用於收集用戶輸入的靈活機制,因為有合適的小部件可以輸入許多不同類型的數據,包括文本框,複選框,單選按鈕,日期選擇器等。表單也是與服務器共享數據的相對安全的方式, 因為它們允許我們在具有跨站點請求偽造保護的<code>POST</code> 請求中發送數據。</p>
+
+<p>儘管到目前為止,本教程中尚未創建任何表單,但我們已經在Django Admin網站中遇到過這些表單-例如,下面的屏幕截圖顯示了一種用於編輯我們的<a href="/en-US/docs/Learn/Server-side/Django/Models">Book</a> 模型的表單,該表單由許多選擇列表和 文字編輯器。</p>
+
+<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>使用表單可能會很複雜!開發人員需要為表單編寫HTML,在服務器上(也可能在瀏覽器中)驗證並正確清理輸入的數據,使用錯誤消息重新發布表單以通知用戶任何無效字段,並在成功提交數據後處理數據,最後以某種方式回應用戶以表示成功。 Django表單通過提供一個框架使您能夠以編程方式定義表單及其字段,然後使用這些對像生成表單HTML代碼並處理許多驗證和用戶交互,從而完成了所有這些步驟中的大量工作。</p>
+
+<p>在本教程中,我們將向您展示創建和使用表單的幾種方法,尤其是通用編輯表單視圖如何顯著減少創建表單來操縱表單所需的工作量。楷模。在此過程中,我們將擴展本地圖書館應用程序,方法是添加一個允許圖書館員續訂圖書的表格,並創建頁面以創建,編輯和刪除圖書和作者(複製上面顯示的表格的基本版本以編輯圖書) )。</p>
+
+<h2 id="HTML_表單">HTML 表單</h2>
+
+<p>首先簡要介紹一下 <a href="/en-US/docs/Learn/HTML/Forms">HTML Forms</a>。 考慮一個簡單的 HTML 表單,其中有一個用於輸入某些“團隊”名稱的文本字段及其相關標籤:</p>
+
+<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p>
+
+<p>表單在HTML中定義為 <code>&lt;form&gt;...&lt;/form&gt;</code> 標記內元素的集合,其中至少包含<code>type="submit"</code>.的<code>input</code>元素。</p>
+
+<pre class="brush: html notranslate">&lt;form action="/team_name_url/" method="post"&gt;
+    &lt;label for="team_name"&gt;Enter name: &lt;/label&gt;
+    &lt;input id="team_name" type="text" name="name_field" value="Default name for team."&gt;
+    &lt;input type="submit" value="OK"&gt;
+&lt;/form&gt;</pre>
+
+<p>雖然這裡只有一個用於輸入團隊名稱的文本字段,但是表單可以具有任意數量的其他輸入元素及其關聯的標籤。字段的<code>type</code> 屬性定義將顯示哪種小部件。字段的 <code>name</code> 和<code>id</code> 用於標識JavaScript / CSS / HTML中的字段,而 <code>value</code>定義該字段在首次顯示時的初始值。匹配的團隊標籤是使用<code style="font-style: normal; font-weight: normal;">label</code> 標籤指定的(請參見上面的“輸入名稱”),其中的  <code style="font-style: normal; font-weight: normal;">for</code> 字段包含相關<code style="font-style: normal; font-weight: normal;">input</code>的<code style="font-style: normal; font-weight: normal;">id</code> 值。</p>
+
+<p><code>submit</code> 輸入將顯示為一個按鈕(默認情況下),用戶可以按下該按鈕以將表單中所有其他輸入元素中的數據上載到服務器(在這種情況下,僅是<code>team_name</code>)。表單屬性定義用於發送數據的HTTP<code>method</code> 以及服務器上數據的目的地(<code>action</code>):<br>
+  </p>
+
+<ul>
+ <li><code>action</code>: 提交表單時,將數據發送到該資源/ URL進行處理。如果未設置(或設置為空字符串),則表單將被提交回當前頁面URL。</li>
+ <li><code>method</code>: 用於發送數據的HTTP方法:post或get。
+ <ul>
+ <li>如果數據將導致服務器數據庫的更改,則應始終使用<code>POST</code> 方法,因為這樣可以使它更能抵抗跨站點的偽造請求攻擊。</li>
+ <li><code>GET</code> 方法應僅用於不更改用戶數據的表單(例如搜索表單)。建議您在希望添加書籤或共享URL時使用。</li>
+ </ul>
+ </li>
+</ul>
+
+<p>服務器的角色是首先呈現初始表單狀態-包含空白字段,或預填充初始值。用戶按下“提交”按鈕後,服務器將從Web瀏覽器接收帶有值的表單數據,並且必須驗證信息。如果表單包含無效數據,則服務器應再次顯示該表單,這一次將在“有效”字段中顯示用戶輸入的數據,並顯示描述無效字段問題的消息。服務器收到包含所有有效表單數據的請求後,便可以執行適當的操作(例如,保存數據,返回搜索結果,上傳文件等),然後通知用戶。</p>
+
+<p>可以想像,創建HTML,驗證返回的數據,在需要時使用錯誤報告重新顯示輸入的數據以及對有效數據執行所需的操作都需要花費大量精力才能“正確”。 Django通過刪除一些繁瑣且重複的代碼,使此操作變得更加容易!</p>
+
+<h2 id="Django表單處理流程">Django表單處理流程</h2>
+
+<p>Django的表單處理使用了我們在以前的教程中學到的所有相同技術(用於顯示有關模型的信息):視圖獲取請求,執行所需的任何操作,包括從模型中讀取數據,然後生成並返回HTML頁面( 從模板中,我們傳遞一個包含要顯示的數據的上下文)。 使事情變得更加複雜的是,服務器還需要能夠處理用戶提供的數據,並在出現任何錯誤時重新顯示頁面。</p>
+
+<p>下面顯示了Django處理表單請求的過程流程圖,該流程圖從對包含表單的頁面的請求(以綠色顯示)開始。<br>
+ <img alt="Updated form handling process doc." src="https://mdn.mozillademos.org/files/14205/Form%20Handling%20-%20Standard.png" style="display: block; height: 569px; margin: 0px auto; width: 800px;"></p>
+
+<p>根據上圖,Django表單處理的主要功能是:</p>
+
+<ol>
+ <li>在用戶第一次請求時顯示默認表單。
+ <ul>
+ <li>該表單可能包含空白字段(例如,如果您正在創建新記錄),或者可能會預先填充有初始值(例如,如果您正在更改記錄或具有有用的默認初始值)。</li>
+ <li>由於此表單與任何用戶輸入的數據均不相關(儘管它可能具有初始值),因此在這一點上被稱為未綁定。</li>
+ </ul>
+ </li>
+ <li>從提交請求中接收數據並將其綁定到表單。
+ <ul>
+ <li>將數據綁定到表單意味著當我們需要重新顯示表單時,用戶輸入的數據和任何錯誤均可用。</li>
+ </ul>
+ </li>
+ <li>清理並驗證數據。
+ <ul>
+ <li>清理數據會對輸入執行清理操作(例如,刪除可能用於向服務器發送惡意內容的無效字符),並將其轉換為一致的Python類型。</li>
+ <li>驗證會檢查該值是否適合該字段(例如,日期範圍正確,時間不要太短或太長等)</li>
+ </ul>
+ </li>
+ <li>如果任何數據無效,則這次重新顯示該表單,其中包含用戶填充的所有值和問題字段的錯誤消息。</li>
+ <li>如果所有數據均有效,請執行所需的操作(例如,保存數據,發送和發送電子郵件,返回搜索結果,上傳文件等)</li>
+ <li>完成所有操作後,將用戶重定向到另一個頁面。</li>
+</ol>
+
+<p>Django提供了許多工具和方法來幫助您完成上述任務。 最基本的是 <code>Form</code>類,它簡化了表單HTML的生成和數據清除/驗證的過程。 在下一節中,我們將使用頁面的實際示例描述表單如何工作,以使圖書館員可以續訂書籍。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 當我們討論Django的更多“高級”表單框架類時,了解<code>Form</code>的使用方式將對您有所幫助。</p>
+</div>
+
+<h2 id="使用表單和功能視圖續訂表單">使用表單和功能視圖續訂表單</h2>
+
+<p>接下來,我們將添加一個頁面,以使圖書館員可以續借借來的書。 為此,我們將創建一個允許用戶輸入日期值的表單。 我們將從當前日期(正常藉閱期)起3週內為該字段提供初始值,並添加一些驗證以確保館員不能輸入過去的日期或將來的日期。 輸入有效日期後,我們會將其寫入當前記錄的<code>BookInstance.due_back</code> 字段中。</p>
+
+<p>該示例將使用基於函數的視圖和<code>Form</code> 類。 以下各節說明表單的工作方式,以及您需要對正在進行的LocalLibrary項目進行的更改。</p>
+
+<h3 id="Form">Form</h3>
+
+<p><code>Form</code>類是Django表單處理系統的核心。 它指定表單中的字段,其佈局,顯示小部件,標籤,初始值,有效值,以及(一旦驗證)與無效字段關聯的錯誤消息。 該類還提供了使用預定義格式(表,列表等)在模板中呈現自身的方法,或用於獲取任何元素的值(啟用細粒度手動呈現)的方法。</p>
+
+<h4 id="申報表格">申報表格</h4>
+
+<p><code>Form</code> 的聲明語法與聲明<code>Model</code>的語法非常相似,並且具有相同的字段類型(和一些相似的參數)。 這是有道理的,因為在兩種情況下,我們都需要確保每個字段都處理正確的數據類型,被限制為有效數據並具有顯示/文檔描述。</p>
+
+<p>要創建一個表單,我們導入<code>Form</code> 庫,從<code>Form</code> 類派生,並聲明表單的字段。 下面顯示了我們的圖書館圖書續訂表格的一個非常基本的表格類:</p>
+
+<pre class="brush: python notranslate">from django import forms
+
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+</pre>
+
+<h4 id="Form_fields">Form fields</h4>
+
+<p>In this case we have a single <code><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datefield">DateField</a></code> for entering the renewal date that will render in HTML with a blank value, the default label "<em>Renewal date:</em>", and some helpful usage text: "<em>Enter a date between now and 4 weeks (default 3 weeks).</em>" As none of the other optional arguments are specified the field will accept dates using the <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#django.forms.DateField.input_formats">input_formats</a>: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16), and will be rendered using the default <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#widget">widget</a>: <a href="https://docs.djangoproject.com/en/2.0/ref/forms/widgets/#django.forms.DateInput">DateInput</a>.</p>
+
+<p>There are many other types of form fields, which you will largely recognise from their similarity to the equivalent model field classes: <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#booleanfield"><code>BooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#charfield"><code>CharField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#choicefield"><code>ChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#typedchoicefield"><code>TypedChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datefield"><code>DateField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datetimefield"><code>DateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#decimalfield"><code>DecimalField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#durationfield"><code>DurationField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#emailfield"><code>EmailField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#filefield"><code>FileField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#filepathfield"><code>FilePathField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#floatfield"><code>FloatField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#imagefield"><code>ImageField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#integerfield"><code>IntegerField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#genericipaddressfield"><code>GenericIPAddressField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#multiplechoicefield"><code>MultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#typedmultiplechoicefield"><code>TypedMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#nullbooleanfield"><code>NullBooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#regexfield"><code>RegexField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#slugfield"><code>SlugField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#timefield"><code>TimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#urlfield"><code>URLField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#uuidfield"><code>UUIDField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#combofield"><code>ComboField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#multivaluefield"><code>MultiValueField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#splitdatetimefield"><code>SplitDateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#modelmultiplechoicefield"><code>ModelMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#modelchoicefield"><code>ModelChoiceField</code></a>​​​​.</p>
+
+<p>The arguments that are common to most fields are listed below (these have sensible default values):</p>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#required">required</a>: If <code>True</code>, the field may not be left blank or given a <code>None</code> value. Fields are required by default, so you would set <code>required=False</code> to allow blank values in the form.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label">label</a>: The label to use when rendering the field in HTML. If <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label">label</a> is not specified then Django would create one from the field name by capitalising the first letter and replacing underscores with spaces (e.g. <em>Renewal date</em>).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label-suffix">label_suffix</a>: By default a colon is displayed after the label (e.g. Renewal date<strong>:</strong>). This argument allows you to specify a different suffix containing other character(s).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#initial">initial</a>: The initial value for the field when the form is displayed.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#widget">widget</a>: The display widget to use.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#help-text">help_text</a> (as seen in the example above): Additional text that can be displayed in forms to explain how to use the field.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#error-messages">error_messages</a>: A list of error messages for the field. You can override these with your own messages if needed.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#validators">validators</a>: A list of functions that will be called on the field when it is validated.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#localize">localize</a>: Enables the localisation of form data input (see link for more information).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled">disabled</a>: The field is displayed but its value cannot be edited if this is <code>True</code>. The default is <code>False</code>.</li>
+</ul>
+
+<h4 id="Validation">Validation</h4>
+
+<p>Django provides numerous places where you can validate your data. The easiest way to validate a single field is to override the method <code>clean_<strong>&lt;fieldname&gt;</strong>()</code> for the field you want to check. So for example, we can validate that entered <code>renewal_date</code> values are between now and 4 weeks by implementing <code>clean_<strong>renewal_date</strong>() </code>as shown below.</p>
+
+<pre class="brush: python notranslate">from django import forms
+
+<strong>from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext_lazy as _
+import datetime #for checking renewal date range.
+</strong>
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+<strong>    def clean_renewal_date(self):
+        data = self.cleaned_data['renewal_date']
+
+        #Check date is not in past.
+        if data &lt; datetime.date.today():
+            raise ValidationError(_('Invalid date - renewal in past'))
+
+        #Check date is in range librarian allowed to change (+4 weeks).
+        if data &gt; datetime.date.today() + datetime.timedelta(weeks=4):
+            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+        # Remember to always return the cleaned data.
+        return data</strong></pre>
+
+<p>There are two important things to note. The first is that we get our data using <code>self.cleaned_data['renewal_date']</code> and that we return this data whether or not we change it at the end of the function. This step gets us the data "cleaned" and sanitised of potentially unsafe input using the default validators, and converted into the correct standard type for the data (in this case a Python <code>datetime.datetime</code> object).</p>
+
+<p>The second point is that if a value falls outside our range we raise a <code>ValidationError</code>, specifying the error text that we want to display in the form if an invalid value is entered. The example above also wraps this text in one of <a href="https://docs.djangoproject.com/en/2.0/topics/i18n/translation/">Django's translation functions</a> <code>ugettext_lazy()</code> (imported as <code>_()</code>), which is good practice if you want to translate your site later.</p>
+
+<div class="note">
+<p><strong>Note:</strong> There are numerious other methods and examples for validating forms in <a href="https://docs.djangoproject.com/en/2.0/ref/forms/validation/">Form and field validation</a> (Django docs). For example, in cases where you have multiple fields that depend on each other, you can override the <a href="https://docs.djangoproject.com/en/2.0/ref/forms/api/#django.forms.Form.clean">Form.clean()</a> function and again raise a <code>ValidationError</code>.</p>
+</div>
+
+<p>That's all we need for the form in this example!</p>
+
+<h4 id="Copy_the_Form">Copy the Form</h4>
+
+<p>Create and open the file <strong>locallibrary/catalog/forms.py</strong> and copy the entire code listing from the previous block into it.</p>
+
+<h3 id="URL_Configuration">URL Configuration</h3>
+
+<p>Before we create our view, let's add a URL configuration for the <em>renew-books</em> page. Copy the following configuration to the bottom of <strong>locallibrary/catalog/urls.py</strong>.</p>
+
+<pre class="brush: python notranslate">urlpatterns += [
+ path('book/&lt;uuid:pk&gt;/renew/', views.renew_book_librarian, name='renew-book-librarian'),
+]</pre>
+
+<p>The URL configuration will redirect URLs with the format <strong>/catalog/book/<em>&lt;bookinstance id&gt;</em>/renew/</strong> to the function named <code>renew_book_librarian()</code> in <strong>views.py</strong>, and send the <code>BookInstance</code> id as the parameter named <code>pk</code>. The pattern only matches if <code>pk</code> is a correctly formatted <code>uuid</code>.</p>
+
+<div class="note">
+<p><strong>Note</strong>: We can name our captured URL data "<code>pk</code>" anything we like, because we have complete control over the view function (we're not using a generic detail view class that expects parameters with a certain name). However <code>pk</code>, short for "primary key", is a reasonable convention to use!</p>
+</div>
+
+<h3 id="View">View</h3>
+
+<p>As discussed in the <a href="#django_form_handling_process">Django form handling process</a> above, the view has to render the default form when it is first called and then either re-render it with error messages if the data is invalid, or process the data and redirect to a new page if the data is valid. In order to perform these different actions, the view has to be able to know whether it is being called for the first time to render the default form, or a subsequent time to validate data. </p>
+
+<p>For forms that use a <code>POST</code> request to submit information to the server, the most common pattern is for the view to test against the <code>POST</code> request type (<code>if request.method == 'POST':</code>) to identify form validation requests and <code>GET</code> (using an <code>else</code> condition) to identify the initial form creation request. If you want to submit your data using a <code>GET</code> request then a typical approach for identifying whether this is the first or subsequent view invocation is to read the form data (e.g. to read a hidden value in the form).</p>
+
+<p>The book renewal process will be writing to our database, so by convention we use the <code>POST</code> request approach. The code fragment below shows the (very standard) pattern for this sort of function view. </p>
+
+<pre class="brush: python notranslate">from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+def renew_book_librarian(request, pk):
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+<strong>    if request.method == 'POST':</strong>
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        <strong>if form.is_valid():</strong>
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form.
+<strong>    else:</strong>
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>First we import our form (<code>RenewBookForm</code>) and a number of other useful objects/methods used in the body of the view function:</p>
+
+<ul>
+ <li><code><a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#get-object-or-404">get_object_or_404()</a></code>: Returns a specified object from a model based on its primary key value, and raises an <code>Http404</code> exception (not found) if the record does not exist. </li>
+ <li><code><a href="https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.HttpResponseRedirect">HttpResponseRedirect</a></code>: This creates a redirect to a specified URL (HTTP status code 302). </li>
+ <li><code><a href="https://docs.djangoproject.com/en/2.0/ref/urlresolvers/#django.urls.reverse">reverse()</a></code>: This generates a URL from a URL configuration name and a set of arguments. It is the Python equivalent of the <code>url</code> tag that we've been using in our templates.</li>
+ <li><code><a href="https://docs.python.org/3/library/datetime.html">datetime</a></code>: A Python library for manipulating dates and times. </li>
+</ul>
+
+<p>In the view we first use the <code>pk</code> argument in <code>get_object_or_404()</code> to get the current <code>BookInstance</code> (if this does not exist, the view will immediately exit and the page will display a "not found" error). If this is <em>not </em>a <code>POST</code> request (handled by the <code>else</code> clause) then we create the default form passing in an <code>initial</code> value for the <code>renewal_date</code> field (as shown in bold below, this is 3 weeks from the current date). </p>
+
+<pre class="brush: python notranslate"> book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a GET (or any other method) create the default form
+    <strong>else:</strong>
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(<strong>weeks=3</strong>)
+        <strong>form = RenewBookForm(initial={'</strong>renewal_date<strong>': </strong>proposed_renewal_date<strong>,})</strong>
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>After creating the form, we call <code>render()</code> to create the HTML page, specifying the template and a context that contains our form. In this case the context also contains our <code>BookInstance</code>, which we'll use in the template to provide information about the book we're renewing.</p>
+
+<p>If however this is a <code>POST</code> request, then we create our <code>form</code> object and populate it with data from the request. This process is called "binding" and allows us to validate the form. We then check if the form is valid, which runs all the validation code on all of the fields — including both the generic code to check that our date field is actually a valid date and our specific form's <code>clean_renewal_date()</code> function to check the date is in the right range. </p>
+
+<pre class="brush: python notranslate">    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+<strong>        form = RenewBookForm(request.POST)</strong>
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>If the form is not valid we call <code>render()</code> again, but this time the form value passed in the context will include error messages. </p>
+
+<p>If the form is valid, then we can start to use the data, accessing it through the <code>form.cleaned_data</code> attribute (e.g. <code>data = form.cleaned_data['renewal_date']</code>). Here we just save the data into the <code>due_back</code> value of the associated <code>BookInstance</code> object.</p>
+
+<div class="warning">
+<p><strong>Important</strong>: While you can also access the form data directly through the request (for example <code>request.POST['renewal_date']</code> or <code>request.GET['renewal_date']</code> (if using a GET request) this is NOT recommended. The cleaned data is sanitised, validated, and converted into Python-friendly types.</p>
+</div>
+
+<p>The final step in the form-handling part of the view is to redirect to another page, usually a "success" page. In this case we use <code>HttpResponseRedirect</code> and <code>reverse()</code> to redirect to the view named <code>'all-borrowed'</code> (this was created as the "challenge" in <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django Tutorial Part 8: User authentication and permissions</a>). If you didn't create that page consider redirecting to the home page at URL '/').</p>
+
+<p>That's everything needed for the form handling itself, but we still need to restrict access to the view to librarians. We should probably create a new permission in <code>BookInstance</code> ("<code>can_renew</code>"), but to keep things simple here we just use the <code>@permission_required</code> function decorator with our existing <code>can_mark_returned</code> permission.</p>
+
+<p>The final view is therefore as shown below. Please copy this into the bottom of <strong>locallibrary/catalog/views.py</strong>.</p>
+
+<pre class="notranslate"><strong>from django.contrib.auth.decorators import permission_required</strong>
+
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+<strong>@permission_required('catalog.<code>can_mark_returned</code>')</strong>
+def renew_book_librarian(request, pk):
+    """
+    View function for renewing a specific BookInstance by librarian
+    """
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form.
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+</pre>
+
+<h3 id="The_template">The template</h3>
+
+<p>Create the template referenced in the view (<strong>/catalog/templates/catalog/book_renew_librarian.html</strong>) and copy the code below into it:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+{% block content %}
+
+ &lt;h1&gt;Renew: \{{bookinst.book.title}}&lt;/h1&gt;
+ &lt;p&gt;Borrower: \{{bookinst.borrower}}&lt;/p&gt;
+ &lt;p{% if bookinst.is_overdue %} class="text-danger"{% endif %}&gt;Due date: \{{bookinst.due_back}}&lt;/p&gt;
+
+<strong> &lt;form action="" method="post"&gt;
+ {% csrf_token %}
+ &lt;table&gt;
+ \{{ form }}
+  &lt;/table&gt;
+ &lt;input type="submit" value="Submit" /&gt;
+ &lt;/form&gt;</strong>
+
+{% endblock %}</pre>
+
+<p>Most of this will be completely familiar from previous tutorials. We extend the base template and then redefine the content block. We are able to reference <code>\{{bookinst}}</code> (and its variables) because it was passed into the context object in the <code>render()</code> function, and we use these to list the book title, borrower and the original due date.</p>
+
+<p>The form code is relatively simple. First we declare the <code>form</code> tags, specifying where the form is to be submitted (<code>action</code>) and the <code>method</code> for submitting the data (in this case an "HTTP POST") — if you recall the <a href="#HTML_forms">HTML Forms</a> overview at the top of the page, an empty <code>action</code> as shown, means that the form data will be posted back to the current URL of the page (which is what we want!). Inside the tags we define the <code>submit</code> input, which a user can press to submit the data. The <code>{% csrf_token %}</code> added just inside the form tags is part of Django's cross-site forgery protection.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Add the <code>{% csrf_token %}</code> to every Django template you create that uses <code>POST</code> to submit data. This will reduce the chance of forms being hijacked by malicious users.</p>
+</div>
+
+<p>All that's left is the <code>\{{form}}</code> template variable, which we passed to the template in the context dictionary. Perhaps unsurprisingly, when used as shown this provides the default rendering of all the form fields, including their labels, widgets, and help text — the rendering is as shown below:</p>
+
+<pre class="brush: html notranslate">&lt;tr&gt;
+  &lt;th&gt;&lt;label for="id_renewal_date"&gt;Renewal date:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+  &lt;input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required /&gt;
+  &lt;br /&gt;
+  &lt;span class="helptext"&gt;Enter date between now and 4 weeks (default 3 weeks).&lt;/span&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+</pre>
+
+<div class="note">
+<p><strong>Note:</strong> It is perhaps not obvious because we only have one field, but by default every field is defined in its own table row (which is why the variable is inside <code>table </code>tags above).​​​​​​ This same rendering is provided if you reference the template variable <code>\{{ form.as_table }}</code>.</p>
+</div>
+
+<p>If you were to enter an invalid date, you'd additionally get a list of the errors rendered in the page (shown in bold below).</p>
+
+<pre class="brush: html notranslate">&lt;tr&gt;
+  &lt;th&gt;&lt;label for="id_renewal_date"&gt;Renewal date:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+<strong>  &lt;ul class="errorlist"&gt;
+  &lt;li&gt;Invalid date - renewal in past&lt;/li&gt;
+  &lt;/ul&gt;</strong>
+  &lt;input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required /&gt;
+  &lt;br /&gt;
+  &lt;span class="helptext"&gt;Enter date between now and 4 weeks (default 3 weeks).&lt;/span&gt;
+ &lt;/td&gt;
+&lt;/tr&gt;</pre>
+
+<h4 id="Other_ways_of_using_form_template_variable">Other ways of using form template variable</h4>
+
+<p>Using <code>\{{form}}</code> as shown above, each field is rendered as a table row. You can also render each field as a list item (using <code>\{{form.as_ul}}</code> ) or as a paragraph (using <code>\{{form.as_p}}</code>).</p>
+
+<p>What is even more cool is that you can have complete control over the rendering of each part of the form, by indexing its properties using dot notation. So for example we can access a number of separate items for our <code>renewal_date</code> field:</p>
+
+<ul>
+ <li><code>\{{form.renewal_date}}:</code> The whole field.</li>
+ <li><code>\{{form.renewal_date.errors}}</code>: The list of errors.</li>
+ <li><code>\{{form.renewal_date.id_for_label}}</code>: The id of the label.</li>
+ <li><code>\{{form.renewal_date.help_text}}</code>: The field help text.</li>
+ <li>etc!</li>
+</ul>
+
+<p>For more examples of how to manually render forms in templates and dynamically loop over template fields, see <a href="https://docs.djangoproject.com/en/2.0/topics/forms/#rendering-fields-manually">Working with forms &gt; Rendering fields manually</a> (Django docs).</p>
+
+<h3 id="Testing_the_page">Testing the page</h3>
+
+<p>If you accepted the "challenge" in <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django Tutorial Part 8: User authentication and permissions</a> you'll have a list of all books on loan in the library, which is only visible to library staff. We can add a link to our renew page next to each item using the template code below.</p>
+
+<pre class="brush: html notranslate">{% if perms.catalog.can_mark_returned %}- &lt;a href="{% url 'renew-book-librarian' bookinst.id %}"&gt;Renew&lt;/a&gt; {% endif %}</pre>
+
+<div class="note">
+<p><strong>Note</strong>: Remember that your test login will need to have the permission "<code>catalog.can_mark_returned</code>" in order to access the renew book page (perhaps use your superuser account).</p>
+</div>
+
+<p>You can alternatively manually construct a test URL like this — <a href="http://127.0.0.1:8000/catalog/book/&lt;bookinstance id>/renew/">http://127.0.0.1:8000/catalog/book/<em>&lt;bookinstance_id&gt;</em>/renew/</a> (a valid bookinstance id can be obtained by navigating to a book detail page in your library, and copying the <code>id</code> field).</p>
+
+<h3 id="What_does_it_look_like">What does it look like?</h3>
+
+<p>If you are successful, the default form will look like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14209/forms_example_renew_default.png" style="border-style: solid; border-width: 1px; display: block; height: 292px; margin: 0px auto; width: 680px;"></p>
+
+<p>The form with an invalid value entered, will look like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14211/forms_example_renew_invalid.png" style="border-style: solid; border-width: 1px; display: block; height: 290px; margin: 0px auto; width: 658px;"></p>
+
+<p>The list of all books with renew links will look like this:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14207/forms_example_renew_allbooks.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 613px;"></p>
+
+<h2 id="ModelForms">ModelForms</h2>
+
+<p>Creating a <code>Form</code> class using the approach described above is very flexible, allowing you to create whatever sort of form page you like and associate it with any model or models.</p>
+
+<p>However if you just need a form to map the fields of a <em>single</em> model then your model will already define most of the information that you need in your form: fields, labels, help text, etc. Rather than recreating the model definitions in your form, it is easier to use the <a href="https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/">ModelForm</a> helper class to create the form from your model. This <code>ModelForm</code> can then be used within your views in exactly the same way as an ordinary <code>Form</code>.</p>
+
+<p>A basic <code>ModelForm</code> containing the same field as our original <code>RenewBookForm</code> is shown below. All you need to do to create the form is add <code>class Meta</code> with the associated <code>model</code> (<code>BookInstance</code>) and a list of the model <code>fields</code> to include in the form (you can include all fields using <code>fields = '__all__'</code>, or you can use <code>exclude</code> (instead of <code>fields</code>) to specify the fields <em>not </em>to include from the model).</p>
+
+<pre class="brush: python notranslate">from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+<strong> class Meta:
+ model = BookInstance
+ fields = ['due_back',]</strong>
+</pre>
+
+<div class="note">
+<p><strong>Note</strong>: This might not look like all that much simpler than just using a <code>Form</code> (and it isn't in this case, because we just have one field). However if you have a lot of fields, it can reduce the amount of code quite significantly!</p>
+</div>
+
+<p>The rest of the information comes from the model field definitions (e.g. labels, widgets, help text, error messages). If these aren't quite right, then we can override them in our <code>class Meta</code>, specifying a dictionary containing the field to change and its new value. For example, in this form we might want a label for our field of "<em>Renewal date</em>" (rather than the default based on the field name: <em>Due date</em>), and we also want our help text to be specific to this use case. The <code>Meta</code> below shows you how to override these fields, and you can similarly set <code>widgets</code> and <code>error_messages</code> if the defaults aren't sufficient.</p>
+
+<pre class="brush: python notranslate">class Meta:
+ model = BookInstance
+ fields = ['due_back',]
+<strong> labels = { 'due_back': _('Renewal date'), }
+ help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } </strong>
+</pre>
+
+<p>To add validation you can use the same approach as for a normal <code>Form</code> — you define a function named <code>clean_<em>field_name</em>()</code> and raise <code>ValidationError</code> exceptions for invalid values. The only difference with respect to our original form is that the model field is named <code>due_back</code> and not "<code>renewal_date</code>".</p>
+
+<pre class="brush: python notranslate">from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+<strong>    def clean_due_back(self):
+       data = self.cleaned_data['due_back']
+
+  #Check date is not in past.
+       if data &lt; datetime.date.today():
+           raise ValidationError(_('Invalid date - renewal in past'))
+
+       #Check date is in range librarian allowed to change (+4 weeks)
+       if data &gt; datetime.date.today() + datetime.timedelta(weeks=4):
+           raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+       # Remember to always return the cleaned data.
+       return data
+</strong>
+ class Meta:
+ model = BookInstance
+ fields = ['due_back',]
+ labels = { 'due_back': _('Renewal date'), }
+ help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), }
+</pre>
+
+<p>The class <code>RenewBookModelForm</code> below is now functionally equivalent to our original <code>RenewBookForm</code>. You could import and use it wherever you currently use <code>RenewBookForm</code>.</p>
+
+<h2 id="Generic_editing_views">Generic editing views</h2>
+
+<p>The form handling algorithm we used in our function view example above represents an extremely common pattern in form editing views. Django abstracts much of this "boilerplate" for you, by creating <a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/">generic editing views</a> for creating, editing, and deleting views based on models. Not only do these handle the "view" behaviour, but they automatically create the form class (a <code>ModelForm</code>) for you from the model.</p>
+
+<div class="note">
+<p><strong>Note: </strong>In addition to the editing views described here, there is also a <a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/#formview">FormView</a> class, which lies somewhere between our function view and the other generic views in terms of "flexibility" vs "coding effort". Using <code>FormView</code> you still need to create your <code>Form</code>, but you don't have to implement all of the standard form-handling pattern. Instead you just have to provide an implementation of the function that will be called once the submitted is known to be be valid.</p>
+</div>
+
+<p>In this section we're going to use generic editing views to create pages to add functionality to create, edit, and delete <code>Author</code> records from our library — effectively providing a basic reimplementation of parts of the Admin site (this could be useful if you need to offer admin functionality in a more flexible way that can be provided by the admin site).</p>
+
+<h3 id="Views">Views</h3>
+
+<p>Open the views file (<strong>locallibrary/catalog/views.py</strong>) and append the following code block to the bottom of it:</p>
+
+<pre class="brush: python notranslate">from django.views.generic.edit import CreateView, UpdateView, DeleteView
+from django.urls import reverse_lazy
+from .models import Author
+
+class AuthorCreate(CreateView):
+ model = Author
+ fields = '__all__'
+ initial={'date_of_death':'05/01/2018',}
+
+class AuthorUpdate(UpdateView):
+ model = Author
+ fields = ['first_name','last_name','date_of_birth','date_of_death']
+
+class AuthorDelete(DeleteView):
+ model = Author
+ success_url = reverse_lazy('authors')</pre>
+
+<p>As you can see, to create the views you need to derive from <code>CreateView</code>, <code>UpdateView</code>, and <code>DeleteView</code> (respectively) and then define the associated model.</p>
+
+<p>For the "create" and "update" cases you also need to specify the fields to display in the form (using in same syntax as for <code>ModelForm</code>). In this case we show both the syntax to display "all" fields, and how you can list them individually. You can also specify initial values for each of the fields using a dictionary of <em>field_name</em>/<em>value</em> pairs (here we arbitrarily set the date of death for demonstration purposes — you might want to remove that!). By default these views will redirect on success to a page displaying the newly created/edited model item, which in our case will be the author detail view we created in a previous tutorial. You can specify an alternative redirect location by explicitly declaring parameter <code>success_url</code> (as done for the <code>AuthorDelete</code> class).</p>
+
+<p>The <code>AuthorDelete</code> class doesn't need to display any of the fields, so these don't need to be specified. You do however need to specify the <code>success_url</code>, because there is no obvious default value for Django to use. In this case we use the <code><a href="https://docs.djangoproject.com/en/2.0/ref/urlresolvers/#reverse-lazy">reverse_lazy()</a></code> function to redirect to our author list after an author has been deleted — <code>reverse_lazy()</code> is a lazily executed version of <code>reverse()</code>, used here because we're providing a URL to a class-based view attribute.</p>
+
+<h3 id="Templates">Templates</h3>
+
+<p>The "create" and "update" views use the same template by default, which will be named after your model: <em>model_name</em><strong>_form.html</strong> (you can change the suffix to something other than <strong>_form</strong> using the <code>template_name_suffix</code> field in your view, e.g. <code>template_name_suffix = '_other_suffix'</code>)</p>
+
+<p>Create the template file <strong>locallibrary/catalog/templates/catalog/author_form.html</strong> and copy in the text below.</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+
+&lt;form action="" method="post"&gt;
+ {% csrf_token %}
+ &lt;table&gt;
+ \{{ form.as_table }}
+ &lt;/table&gt;
+ &lt;input type="submit" value="Submit" /&gt;
+
+&lt;/form&gt;
+{% endblock %}</pre>
+
+<p>This is similar to our previous forms, and renders the fields using a table. Note also how again we declare the <code>{% csrf_token %}</code> to ensure that our forms are resistant to CSRF attacks.</p>
+
+<p>The "delete" view expects to find a template named with the format <em>model_name</em><strong>_confirm_delete.html</strong> (again, you can change the suffix using <code>template_name_suffix</code> in your view). Create the template file <strong>locallibrary/catalog/templates/catalog/author_confirm_delete</strong><strong>.html</strong> and copy in the text below.</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+
+&lt;h1&gt;Delete Author&lt;/h1&gt;
+
+&lt;p&gt;Are you sure you want to delete the author: \{{ author }}?&lt;/p&gt;
+
+&lt;form action="" method="POST"&gt;
+ {% csrf_token %}
+ &lt;input type="submit" action="" value="Yes, delete." /&gt;
+&lt;/form&gt;
+
+{% endblock %}
+</pre>
+
+<h3 id="URL_configurations">URL configurations</h3>
+
+<p>Open your URL configuration file (<strong>locallibrary/catalog/urls.py</strong>) and add the following configuration to the bottom of the file:</p>
+
+<pre class="brush: python notranslate">urlpatterns += [
+    path('author/create/', views.AuthorCreate.as_view(), name='author_create'),
+    path('author/&lt;int:pk&gt;/update/', views.AuthorUpdate.as_view(), name='author_update'),
+    path('author/&lt;int:pk&gt;/delete/', views.AuthorDelete.as_view(), name='author_delete'),
+]</pre>
+
+<p>There is nothing particularly new here! You can see that the views are classes, and must hence be called via <code>.as_view()</code>, and you should be able to recognise the URL patterns in each case. We must use <code>pk</code> as the name for our captured primary key value, as this is the parameter name expected by the view classes.</p>
+
+<p>The author create, update, and delete pages are now ready to test (we won't bother hooking them into the site sidebar in this case, although you can do so if you wish).</p>
+
+<div class="note">
+<p><strong>Note</strong>: Observant users will have noticed that we didn't do anything to prevent unauthorised users from accessing the pages! We leave that as an exercise for you (hint: you could use the <code>PermissionRequiredMixin</code> and either create a new permission or reuse our <code>can_mark_returned</code> permission).</p>
+</div>
+
+<h3 id="Testing_the_page_2">Testing the page</h3>
+
+<p>First login to the site with an account that has whatever permissions you decided are needed to access the author editing pages.</p>
+
+<p>Then navigate to the author create page: <a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a>, which should look like the screenshot below.</p>
+
+<p><img alt="Form Example: Create Author" src="https://mdn.mozillademos.org/files/14223/forms_example_create_author.png" style="border-style: solid; border-width: 1px; display: block; height: 184px; margin: 0px auto; width: 645px;"></p>
+
+<p>Enter values for the fields and then press <strong>Submit</strong> to save the author record. You should now be taken to a detail view for your new author, with a URL of something like <em>http://127.0.0.1:8000/catalog/author/10</em>.</p>
+
+<p>You can test editing records by appending <em>/update/</em> to the end of the detail view URL (e.g. <em>http://127.0.0.1:8000/catalog/author/10/update/</em>) — we don't show a screenshot, because it looks just like the "create" page!</p>
+
+<p>Last of all we can delete the page, by appending delete to the end of the author detail-view URL (e.g. <em>http://127.0.0.1:8000/catalog/author/10/delete/</em>). Django should display the delete page shown below. Press <strong>Yes, delete.</strong> to remove the record and be taken to the list of all authors.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14221/forms_example_delete_author.png" style="border-style: solid; border-width: 1px; display: block; height: 194px; margin: 0px auto; width: 561px;"></p>
+
+<h2 id="Challenge_yourself">Challenge yourself</h2>
+
+<p>Create some forms to create, edit and delete <code>Book</code> records. You can use exactly the same structure as for <code>Authors</code>. If your <strong>book_form.html</strong> template is just a copy-renamed version of the <strong>author_form.html</strong> template, then the new "create book" page will look like the screenshot below:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14225/forms_example_create_book.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 595px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="Summary">Summary</h2>
+
+<p>Creating and handling forms can be a complicated process! Django makes it much easier by providing programmatic mechanisms to declare, render and validate forms. Furthermore, Django provides generic form editing views that can do <em>almost all</em> the work to define pages that can create, edit, and delete records associated with a single model instance.</p>
+
+<p>There is a lot more that can be done with forms (check out our See also list below), but you should now understand how to add basic forms and form-handling code to your own websites.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/forms/">Working with forms</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial04/#write-a-simple-form">Writing your first Django app, part 4 &gt; Writing a simple form</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/api/">The Forms API</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/">Form fields</a> (Django docs) </li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/validation/">Form and field validation</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/">Form handling with class-based views</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/">Creating forms from models</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/">Generic editing views</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/generic_views/index.html b/files/zh-tw/learn/server-side/django/generic_views/index.html
new file mode 100644
index 0000000000..240354cd6b
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/generic_views/index.html
@@ -0,0 +1,612 @@
+---
+title: 'Django Tutorial Part 6: Generic list and detail views'
+slug: Learn/Server-side/Django/Generic_views
+translation_of: Learn/Server-side/Django/Generic_views
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">本教程擴充了 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站,為書本與作者增加列表與細節頁面。此處我們將學到通用類別視圖,並演示如何降低你必須為一般使用案例撰寫的程式碼數量。我們也會更加深入 URL 處理細節,演示如何實施基本模式匹配。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">目的:</th>
+ <td>To understand where and how to use generic class-based views, and how to extract patterns from URLs and pass the information to views.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Overview">Overview</h2>
+
+<p>本教程中,通過為書本和作者添加列表和詳細信息頁面,我們將完成第一個版本的 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站(或者更準確地說,我們將向您展示如何實現書頁,並讓您自己創建作者頁面!) )</p>
+
+<p>該過程在創建索引頁面,我們在上一個教程中展示了該頁面。我們仍然需要創建URL地圖,視圖和模板。主要區別在於,對於詳細信息頁面,我們還有一個額外的挑戰,即從URL對於這些頁面,我們將演示一種完全不同的視圖類型:基於類別的通用列表和詳細視圖。這些可以顯著減少所需的視圖代碼量,有助於更容易編寫和維護。</p>
+
+<p>本教程的最後一部分,將演示在使用基於類別的通用列表視圖時,如何對數據進行分頁。</p>
+
+<h2 id="Book_list_page">Book list page</h2>
+
+<p>該書將顯示每條記錄的標題和作者,標題是指向相關圖書詳細信息頁面的超鏈接。該頁面將具有與站點中,所有其他頁面相同的結構和導航,因此,我們可以擴展在上一個教程中創建的基本模板 (<strong>base_generic.html</strong>)。</p>
+
+<h3 id="URL_mapping">URL mapping</h3>
+
+<p>開啟/catalog/urls.py,並複製加入下面粗體顯示的代碼。就像索引頁面的方式,這個path()函數,定義了一個與URL匹配的模式('books /'),如果URL匹配,將調用視圖函數(views.BookListView.as_view())和一個對應的特定映射的名稱。</p>
+
+<pre class="brush: python notranslate">urlpatterns = [
+ path('', views.index, name='index'),
+<strong>  </strong>path<strong>('books/', views.BookListView.as_view(), name='books'),</strong>
+]</pre>
+
+<p>正如前一個教程中所討論的,URL必須已經先匹配了/ catalog,因此實際上將為URL調用的視圖是:/ catalog / books /。</p>
+
+<p>我們將繼承現有的泛型視圖函數,該函數已經完成了我們希望此視圖函數執行的大部分工作,而不是從頭開始編寫自己的函數。對於基於Django類的視圖,我們通過調用類方法as_view(),來訪問適當的視圖函數。由此可以創建類的實例,並確保為HTTP請求正確的處理程序方法。</p>
+
+<h3 id="View_class-based">View (class-based)</h3>
+
+<p>我們可以很容易地,將書本列表列表編寫為常規函數(就像我們之前的索引視圖一樣),進入查詢數據庫中的所有書本,然後調用render(),將列表傳遞給指定的模板。然而,我們用另一種方​​法取代,我們將使用基於類的通用列表視圖(ListView)-一個繼承自現有視圖的類。因為通用視圖,已經實現了我們需要的大部分功能,並且遵循Django最佳實踐,我們將能夠創建更強大的列表視圖,代碼更多,重複次數最多,最終維護所需。</p>
+
+<p>開啟catalog / views.py,將以下代碼複製到文件的底部:</p>
+
+<pre class="brush: python notranslate">from django.views import generic
+
+class BookListView(generic.ListView):
+ model = Book</pre>
+
+<p>就是這樣!通用view將查詢數據庫,以獲取指定模型(Book)的所有記錄,然後呈現/locallibrary/catalog/templates/catalog/book_list.html的模板(我們將在下面創建)。在模板中,您可以使用所謂的object_list或book_list的模板變量(即通常為“ the_model_name_list”),以訪問書本列表。</p>
+
+<div class="note">
+<p><strong>Note</strong>: This awkward path for the template location isn't a misprint — the generic views look for templates in <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code> (<code>catalog/book_list.html</code> in this case) inside the application's <code>/<em>application_name</em>/templates/</code> directory (<code>/catalog/templates/)</code>.</p>
+</div>
+
+<p>您可以添加屬性,以更改上面的某種行為。例如,如果需要使用同一模型的多個視圖,則可以指定另一個模板文件,或者如果book_list對於特定模板用例不直觀,則可能需要使用不同的模板變量名稱。可能最有用的變更,是更改/過濾返回的結果子集-因此,您可能會列出其他用戶閱讀的前5本書,而不是列出所有書本。</p>
+
+<pre class="brush: python notranslate">class BookListView(generic.ListView):
+ model = Book
+ context_object_name = 'my_book_list' # your own name for the list as a template variable
+ queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
+ template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location</pre>
+
+<h4 id="Overriding_methods_in_class-based_views">Overriding methods in class-based views</h4>
+
+<p>雖然我們不需要在這裡執行此操作,但您也可以覆寫某些類別方法。</p>
+
+<p>例如,我們可以覆寫get_queryset()方法,來更改返回的記錄列表。這比單獨設置queryset屬性更靈活,就像我們在前面的代碼片段中進行的那樣(儘管在這案例中沒有太大用處):</p>
+
+<pre class="brush: python notranslate">class BookListView(generic.ListView):
+ model = Book
+
+    def get_queryset(self):
+        return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
+</pre>
+
+<p>我們還可以重寫<code>get_context_data()</code> 以便將其他上下文變數傳遞給模組 (例如,默認情況下傳遞書籍列表). 下面的片段顯示瞭如何向上下文添加名為"<code>some_data</code>" 的變數(然後它將用作模組變數)</p>
+
+<pre class="brush: python notranslate">class BookListView(generic.ListView):
+ model = Book
+
+    def get_context_data(self, **kwargs):
+        # Call the base implementation first to get the context
+        context = super(BookListView, self).get_context_data(**kwargs)
+        # Create any data and add it to the context
+        context['some_data'] = 'This is just some data'
+        return context</pre>
+
+<p>執行此操作時,務必遵循上面使用的模式:</p>
+
+<ul>
+ <li>首先從我們的superclass中獲取現有內文。</li>
+ <li>然後添加新的內文信息。</li>
+ <li>然後返回新的(更新後)內文。</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Check out <a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs) for many more examples of what you can do.</p>
+</div>
+
+<h3 id="Creating_the_List_View_template">Creating the List View template</h3>
+
+<p>建立HTML及複製以下文字串到<strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> , 這是基於通用類的列表視圖所期望的默認模板文件 (默認在<code>catalog中名稱為Book</code> 的模組).</p>
+
+<p>通用的views模板跟其他的模板沒有不同 (儘管傳遞給模板的內文/訊息當然可以不同). 與index模板一樣,我們在第一行中擴展了基本模板,然後更替名為 <code>content</code>的區塊。</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Book List&lt;/h1&gt;
+  <strong>{% if book_list %}</strong>
+  &lt;ul&gt;
+  {% for book in book_list %}
+      &lt;li&gt;
+        &lt;a href="\{{ book.get_absolute_url }}"&gt;\{{ book.title }}&lt;/a&gt; (\{{book.author}})
+      &lt;/li&gt;
+  {% endfor %}
+  &lt;/ul&gt;
+  <strong>{% else %}</strong>
+  &lt;p&gt;There are no books in the library.&lt;/p&gt;
+  <strong>{% endif %} </strong>
+{% endblock %}</pre>
+
+<p>該視圖默認將上下文(書籍列表)作為<code>object_list</code> 和 <code>book_list</code> 別名傳遞;兩者都會起作用.</p>
+
+<h4 id="Conditional_execution">Conditional execution</h4>
+
+<p>我們使用 <code><a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#if">if</a></code>, <code>else</code> 和 <code>endif</code> 模組標籤,以檢查<code>book_list</code> 是否已定義並且不為空。 如果 <code>book_list</code> 為空值, 則 <code>else</code> 子句回傳text 說明沒有書可以列出. 如果<code>book_list</code>不是空值, 然後我們遍曆書籍清單。</p>
+
+<pre class="brush: html notranslate"><strong>{% if book_list %}</strong>
+ &lt;!-- code here to list the books --&gt;
+<strong>{% else %}</strong>
+ &lt;p&gt;There are no books in the library.&lt;/p&gt;
+<strong>{% endif %}</strong>
+</pre>
+
+<p>The condition above only checks for one case, but you can test on additional conditions using the <code>elif</code> template tag (e.g. <code>{% elif var2 %}</code> ). For more information about conditional operators see: <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a>, and <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#ifchanged">ifchanged</a> in <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins">Built-in template tags and filters</a> (Django Docs).</p>
+
+<h4 id="For_loops">For loops</h4>
+
+<p>The template uses the <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#for">for</a> and <code>endfor</code> template tags to loop through the book list, as shown below. Each iteration populates the <code>book</code> template variable with information for the current list item.</p>
+
+<pre class="brush: html notranslate">{% for <strong>book</strong> in book_list %}
+ &lt;li&gt; &lt;!-- code here get information from each <strong>book</strong> item --&gt; &lt;/li&gt;
+{% endfor %}
+</pre>
+
+<p>While not used here, within the loop Django will also create other variables that you can use to track the iteration. For example, you can test the <code>forloop.last</code> variable to perform conditional processing the last time that the loop is run.</p>
+
+<h4 id="Accessing_variables">Accessing variables</h4>
+
+<p>The code inside the loop creates a list item for each book that shows both the title (as a link to the yet-to-be-created detail view) and the author.</p>
+
+<pre class="brush: html notranslate">&lt;a href="\{{ book.get_absolute_url }}"&gt;\{{ book.title }}&lt;/a&gt; (\{{book.author}})
+</pre>
+
+<p>We access the <em>fields</em> of the associated book record using the "dot notation" (e.g. <code>book.title</code> and <code>book.author</code>), where the text following the <code>book</code> item is the field name (as defined in the model).</p>
+
+<p>We can also call <em>functions</em> in the model from within our template — in this case we call <code>Book.get_absolute_url()</code> to get an URL you could use to display the associated detail record. This works provided the function does not have any arguments (there is no way to pass arguments!)</p>
+
+<div class="note">
+<p><strong>Note</strong>: We have to be a little careful of "side effects" when calling functions in templates. Here we just get a URL to display, but a function can do pretty much anything — we wouldn't want to delete our database (for example) just by rendering our template!</p>
+</div>
+
+<h4 id="Update_the_base_template">Update the base template</h4>
+
+<p>Open the base template (<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>) and insert <strong>{% url 'books' %} </strong>into the URL link for <strong>All books</strong>, as shown below. This will enable the link in all pages (we can successfully put this in place now that we've created the "books" url mapper).</p>
+
+<pre class="brush: python notranslate">&lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+<strong>&lt;li&gt;&lt;a href="{% url 'books' %}"&gt;All books&lt;/a&gt;&lt;/li&gt;</strong>
+&lt;li&gt;&lt;a href=""&gt;All authors&lt;/a&gt;&lt;/li&gt;</pre>
+
+<h3 id="What_does_it_look_like">What does it look like?</h3>
+
+<p>You won't be able to build book list yet, because we're still missing a dependency — the URL map for the book detail pages, which is needed to create hyperlinks to individual books. We'll show both list and detail views after the next section.</p>
+
+<h2 id="Book_detail_page">Book detail page</h2>
+
+<p>The book detail page will display information about a specific book, accessed using the URL <code>catalog/book/<em>&lt;id&gt;</em></code> (where <code><em>&lt;id&gt;</em></code> is the primary key for the book). In addition to fields in the <code>Book</code> model (author, summary, ISBN, language, and genre), we'll also list the details of the available copies (<code>BookInstances</code>) including the status, expected return date, imprint, and id. This will allow our readers not just to learn about the book, but also to confirm whether/when it is available.</p>
+
+<h3 id="URL_mapping_2">URL mapping</h3>
+
+<p>Open <strong>/catalog/urls.py</strong> and add the '<strong>book-detail</strong>' URL mapper shown in bold below. This <code>path()</code> function defines a pattern, associated generic class-based detail view, and a name.</p>
+
+<pre class="brush: python notranslate">urlpatterns = [
+ path('', views.index, name='index'),
+    path('books/', views.BookListView.as_view(), name='books'),
+<strong>  path('book/&lt;int:pk&gt;', views.BookDetailView.as_view(), name='book-detail'),</strong>
+]</pre>
+
+<p>For the <em>book-detail</em> path the URL pattern uses a special syntax to capture the specific id of the book that we want to see. The syntax is very simple: angle brackets define the part of the URL to be captured, enclosing the name of the variable that the view can use to access the captured data. For example, <strong>&lt;something&gt;</strong> , will capture the marked pattern and pass the value to the view as a variable "something". You can optionally precede the variable name with a <a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters">converter specification</a> that defines the type of data (int, str, slug, uuid, path).</p>
+
+<p>In this case we use <code>'&lt;int:pk&gt;'</code><strong> </strong> to capture the book id, which must be an integer, and pass it to the view as a parameter named <code>pk</code> (short for primary key).</p>
+
+<div class="note">
+<p><strong>Note</strong>: As discussed previously, our matched URL is actually <code>catalog/book/&lt;digits&gt;</code> (because we are in the <strong>catalog</strong> application, <code>/catalog/</code> is assumed).</p>
+</div>
+
+<div class="warning">
+<p><strong>Important</strong>: The generic class-based detail view <em>expects</em> to be passed a parameter named <strong>pk</strong>. If you're writing your own function view you can use whatever parameter name you like, or indeed pass the information in an unnamed argument.</p>
+</div>
+
+<h4 id="Advanced_path_matchingregular_expression_primer">Advanced path matching/regular expression primer</h4>
+
+<div class="note">
+<p><strong>Note</strong>: You won't need this section to complete the tutorial! We provide it because knowing this option is likely to be useful in your Django-centric future.</p>
+</div>
+
+<p>The pattern matching provided by <code>path()</code> is simple and useful for the (very common) cases where you just want to capture <em>any</em> string or integer. If you need more refined filtering (for example, to filter only strings that have a certain number of characters) then you can use the <a href="https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.re_path">re_path()</a> method.</p>
+
+<p>This method is used just like <code>path()</code> except that it allows you to specify a pattern using a <a href="https://docs.python.org/3/library/re.html">Regular expression</a>. For example, the previous path could have been written as shown below:</p>
+
+<pre class="brush: python notranslate"><strong>re_path(r'^book/(?P&lt;pk&gt;\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong>
+</pre>
+
+<p><em>Regular expressions</em> are an incredibly powerful pattern mapping tool. They are, frankly, quite unintuitive and scary for beginners. Below is a very short primer!</p>
+
+<p>The first thing to know is that regular expressions should usually be declared using the raw string literal syntax (i.e. they are enclosed as shown: <strong>r'&lt;your regular expression text goes here&gt;'</strong>).</p>
+
+<p>The main parts of the syntax you will need to know for declaring the pattern matches are:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Symbol</th>
+ <th scope="col">Meaning</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>^</td>
+ <td>Match the beginning of the text</td>
+ </tr>
+ <tr>
+ <td>$</td>
+ <td>Match the end of the text</td>
+ </tr>
+ <tr>
+ <td>\d</td>
+ <td>Match a digit (0, 1, 2, ... 9)</td>
+ </tr>
+ <tr>
+ <td>\w</td>
+ <td>Match a word character, e.g. any upper- or lower-case character in the alphabet, digit or the underscore character (_)</td>
+ </tr>
+ <tr>
+ <td>+</td>
+ <td>Match one or more of the preceding character. For example, to match one or more digits you would use <code>\d+</code>. To match one or more "a" characters, you could use <code>a+</code></td>
+ </tr>
+ <tr>
+ <td>*</td>
+ <td>Match zero or more of the preceding character. For example, to match nothing or a word you could use <code>\w*</code></td>
+ </tr>
+ <tr>
+ <td>( )</td>
+ <td>Capture the part of the pattern inside the brackets. Any captured values will be passed to the view as unnamed parameters (if multiple patterns are captured, the associated parameters will be supplied in the order that the captures were declared).</td>
+ </tr>
+ <tr>
+ <td>(?P&lt;<em>name</em>&gt;...)</td>
+ <td>Capture the pattern (indicated by ...) as a named variable (in this case "name"). The captured values are passed to the view with the name specified. Your view must therefore declare an argument with the same name!</td>
+ </tr>
+ <tr>
+ <td>[  ]</td>
+ <td>Match against one character in the set. For example, [abc] will match on 'a' or 'b' or 'c'. [-\w] will match on the '-' character or any word character.</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Most other characters can be taken literally!</p>
+
+<p>Lets consider a few real examples of patterns:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Pattern</th>
+ <th scope="col">Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><strong>r'^book/(?P&lt;pk&gt;\d+)$'</strong></td>
+ <td>
+ <p>This is the RE used in our url mapper. It matches a string that has <code>book/</code> at the start of the line (<strong>^book/</strong>), then has one or more digits (<code>\d+</code>), and then ends (with no non-digit characters before the end of line marker).</p>
+
+ <p>It also captures all the digits <strong>(?P&lt;pk&gt;\d+)</strong> and passes them to the view in a parameter named 'pk'. <strong>The captured values are always passed as a string!</strong></p>
+
+ <p>For example, this would match <code>book/1234</code> , and send a variable <code>pk='1234'</code> to the view.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>r'^book/(\d+)$'</strong></td>
+ <td>This matches the same URLs as the preceding case. The captured information would be sent as an unnamed argument to the view.</td>
+ </tr>
+ <tr>
+ <td><strong>r'^book/(?P&lt;stub&gt;[-\w]+)$'</strong></td>
+ <td>
+ <p>This matches a string that has <code>book/</code> at the start of the line (<strong>^book/</strong>), then has one or more characters that are <em>either</em> a '-' or a word character (<strong>[-\w]+</strong>), and then ends. It also captures this set of characters and passes them to the view in a parameter named 'stub'.</p>
+
+ <p>This is a fairly typical pattern for a "stub". Stubs are URL-friendly word-based primary keys for data. You might use a stub if you wanted your book URL to be more informative. For example <code>/catalog/book/the-secret-garden</code> rather than <code>/catalog/book/33</code>.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>You can capture multiple patterns in the one match, and hence encode lots of different information in a URL.</p>
+
+<div class="note">
+<p><strong>Note</strong>: As a challenge, consider how you might encode an url to list all books released in a particular year, month, day, and the RE that could be used to match it.</p>
+</div>
+
+<h4 id="Passing_additional_options_in_your_URL_maps">Passing additional options in your URL maps</h4>
+
+<p>One feature that we haven't used here, but which you may find valuable, is that you can declare and pass <a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/#views-extra-options">additional options</a> to the view. The options are declared as a dictionary that you pass as the third un-named argument to the <code>path()</code> function. This approach can be useful if you want to use the same view for multiple resources, and pass data to configure its behaviour in each case (below we supply a different template in each case).</p>
+
+<pre class="brush: python notranslate">path('url/', views.my_reused_view, <strong>{'my_template_name': 'some_path'}</strong>, name='aurl'),
+path('anotherurl/', views.my_reused_view, <strong>{'my_template_name': 'another_path'}</strong>, name='anotherurl'),
+</pre>
+
+<div class="note">
+<p><strong>Note:</strong> Both extra options and named captured patterns are passed to the view as <em>named</em> arguments. If you use the <strong>same name</strong> for both a captured pattern and an extra option then only the captured pattern value will be sent to the view (the value specified in the additional option will be dropped). </p>
+</div>
+
+<h3 id="View_class-based_2">View (class-based)</h3>
+
+<p>Open <strong>catalog/views.py</strong>, and copy the following code into the bottom of the file:</p>
+
+<pre class="brush: python notranslate">class BookDetailView(generic.DetailView):
+    model = Book</pre>
+
+<p>That's it! All you need to do now is create a template called <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>, and the view will pass it the database information for the specific <code>Book</code> record extracted by the URL mapper. Within the template you can access the list of books with the template variable named <code>object</code> OR <code>book</code> (i.e. generically "<code><em>the_model_name</em></code>").</p>
+
+<p>If you need to, you can change the template used and the name of the context object used to reference the book in the template. You can also override methods to, for example, add additional information to the context.</p>
+
+<h4 id="What_happens_if_the_record_doesnt_exist">What happens if the record doesn't exist?</h4>
+
+<p>If a requested record does not exist then the generic class-based detail view will raise an <code>Http404</code> exception for you automatically — in production this will automatically display an appropriate "resource not found" page, which you can customise if desired.</p>
+
+<p>Just to give you some idea of how this works, the code fragment below demonstrates how you would implement the class-based view as a function, if you were <strong>not</strong> using the generic class-based detail view.</p>
+
+<pre class="brush: python notranslate">def book_detail_view(request, primary_key):
+ try:
+ book = Book.objects.get(pk=primary_key)
+ except Book.DoesNotExist:
+ raise Http404('Book does not exist')
+
+ # from django.shortcuts import get_object_or_404
+  # book = get_object_or_404(Book, pk=primary_key)
+
+ return render(request, 'catalog/book_detail.html', context={'book': book})
+</pre>
+
+<p>The view first tries to get the specific book record from the model. If this fails the view should raise an <code>Http404</code> exception to indicate that the book is "not found". The final step is then, as usual, to call <code>render()</code> with the template name and the book data in the <code>context</code> parameter (as a dictionary).</p>
+
+<div class="note">
+<p><strong>Note</strong>: The <code>get_object_or_404()</code> (shown commented out above) is a convenient shortcut to raise an <code>Http404</code> exception if the record is not found.</p>
+</div>
+
+<h3 id="Creating_the_Detail_View_template">Creating the Detail View template</h3>
+
+<p>Create the HTML file <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong> and give it the below content. As discussed above, this is the default template file name expected by the generic class-based <em>detail</em> view (for a model named <code>Book</code> in an application named <code>catalog</code>).</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Title: \{{ book.title }}&lt;/h1&gt;
+
+ &lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href=""&gt;\{{ book.author }}&lt;/a&gt;&lt;/p&gt; &lt;!-- author detail link not yet defined --&gt;
+ &lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; \{{ book.summary }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;ISBN:&lt;/strong&gt; \{{ book.isbn }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;Language:&lt;/strong&gt; \{{ book.language }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;Genre:&lt;/strong&gt; {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}&lt;/p&gt;
+
+ &lt;div style="margin-left:20px;margin-top:20px"&gt;
+ &lt;h4&gt;Copies&lt;/h4&gt;
+
+ {% for copy in book.bookinstance_set.all %}
+ &lt;hr&gt;
+ &lt;p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}"&gt;\{{ copy.get_status_display }}&lt;/p&gt;
+ {% if copy.status != 'a' %}&lt;p&gt;&lt;strong&gt;Due to be returned:&lt;/strong&gt; \{{copy.due_back}}&lt;/p&gt;{% endif %}
+ &lt;p&gt;&lt;strong&gt;Imprint:&lt;/strong&gt; \{{copy.imprint}}&lt;/p&gt;
+ &lt;p class="text-muted"&gt;&lt;strong&gt;Id:&lt;/strong&gt; \{{copy.id}}&lt;/p&gt;
+ {% endfor %}
+ &lt;/div&gt;
+{% endblock %}</pre>
+
+<ul>
+</ul>
+
+<div class="note">
+<p>The author link in the template above has an empty URL because we've not yet created an author detail page. Once that exists, you should update the URL like this:</p>
+
+<pre class="notranslate">&lt;a href="<strong>{% url 'author-detail' book.author.pk %}</strong>"&gt;\{{ book.author }}&lt;/a&gt;
+</pre>
+</div>
+
+<p>Though a little larger, almost everything in this template has been described previously:</p>
+
+<ul>
+ <li>We extend our base template and override the "content" block.</li>
+ <li>We use conditional processing to determine whether or not to display specific content.</li>
+ <li>We use <code>for</code> loops to loop through lists of objects.</li>
+ <li>We access the context fields using the dot notation (because we've used the detail generic view, the context is named <code>book</code>; we could also use "<code>object</code>")</li>
+</ul>
+
+<p>The one interesting thing we haven't seen before is the function <code>book.bookinstance_set.all()</code>. This method is "automagically" constructed by Django in order to return the set of <code>BookInstance</code> records associated with a particular <code>Book</code>.</p>
+
+<pre class="brush: python notranslate">{% for copy in book.bookinstance_set.all %}
+&lt;!-- code to iterate across each copy/instance of a book --&gt;
+{% endfor %}</pre>
+
+<p>需要這方法是因為我們僅在“一”那側model(Book)定義一個<code>ForeignKey</code> (一對多)字段的關聯,也因為沒有任何的關聯被定義在“多”那側model(BookInstance),故無法透過字段來取得相關的紀錄。為了克服這個問題,Django建立一個function取名為“reverse lookup”供使用。function的名字以一對多關係中該 <code>ForeignKey</code> 被定義在的那個模型名稱小寫,再在字尾加上<code>_set</code>(因此在 <code>Book</code> 創建的function名是 <code>bookinstance_set()</code>)。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 在這我們使用 <code>all()</code> 取得所有紀錄 (預設),你無法直接在template做是因為你無法指定引數到function,但你可用 <code>filter()</code> 方法取得一個紀錄的子集 。</p>
+
+<p>順帶一提,若你不再基於類的view或model定義順序(order),開發伺服器會將會報錯類似的訊息:</p>
+
+<pre class="notranslate">[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637
+/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: &lt;QuerySet [&lt;Author: Ortiz, David&gt;, &lt;Author: H. McRaven, William&gt;, &lt;Author: Leigh, Melinda&gt;]&gt;
+ allow_empty_first_page=allow_empty_first_page, **kwargs)
+</pre>
+
+<p>That happens because the <a href="https://docs.djangoproject.com/en/2.0/topics/pagination/#paginator-objects">paginator object</a> expects to see some ORDER BY being executed on your underlying database. Without it, it can't be sure the records being returned are actually in the right order!<strong> </strong></p>
+
+<p>This tutorial didn't reach <strong>Pagination</strong> (yet, but soon enough), but since you can't use <code>sort_by()</code> and pass a parameter (the same with <code>filter()</code> described above) you will have to choose between three choices:</p>
+
+<ol>
+ <li>Add a <code>ordering</code> inside a <code>class Meta</code> declaration on your model.</li>
+ <li>Add a <code>queryset</code> attribute in your custom class-based view, specifying a <code>order_by()</code>.</li>
+ <li>Adding a <code>get_queryset</code> method to your custom class-based view and also specify the <code>order_by()</code>.</li>
+</ol>
+
+<p>If you decide to go with a <code>class Meta</code> for the <code>Author</code> model (probably not as flexible as customizing the class-based view, but easy enough), you will end up with something like this:</p>
+
+<pre class="notranslate">class Author(models.Model):
+ first_name = models.CharField(max_length=100)
+ last_name = models.CharField(max_length=100)
+ date_of_birth = models.DateField(null=True, blank=True)
+ date_of_death = models.DateField('Died', null=True, blank=True)
+
+ def get_absolute_url(self):
+ return reverse('author-detail', args=[str(self.id)])
+
+ def __str__(self):
+ return f'{self.last_name}, {self.first_name}'
+
+<strong> class Meta:
+ ordering = ['last_name']</strong></pre>
+
+<p>Of course, the field doesn't need to be <code>last_name</code>: it could be any other.</p>
+
+<p>And last, but not least, you should sort by an attribute/column that actually has a index (unique or not) on your database to avoid performance issues. Of course, this will not be necessary here (and we are probably getting ourselves too much ahead) if such small amount of books (and users!), but it is something to keep in mind for future projects.</p>
+</div>
+
+<h2 id="What_does_it_look_like_2">What does it look like?</h2>
+
+<p>At this point we should have created everything needed to display both the book list and book detail pages. Run the server (<code>python3 manage.py runserver</code>) and open your browser to <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>.</p>
+
+<div class="warning">
+<p><strong>Warning:</strong> Don't click any author or author detail links yet — you'll create those in the challenge!</p>
+</div>
+
+<p>Click the <strong>All books</strong> link to display the list of books. </p>
+
+<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p>
+
+<p>Then click a link to one of your books. If everything is set up correctly, you should see something like the following screenshot.</p>
+
+<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p>
+
+<h2 id="Pagination">Pagination</h2>
+
+<p>If you've just got a few records, our book list page will look fine. However, as you get into the tens or hundreds of records the page will take progressively longer to load (and have far too much content to browse sensibly). The solution to this problem is to add pagination to your list views, reducing the number of items displayed on each page. </p>
+
+<p>Django has excellent in-built support for pagination. Even better, this is built into the generic class-based list views so you don't have to do very much to enable it!</p>
+
+<h3 id="Views">Views</h3>
+
+<p>Open <strong>catalog/views.py</strong>, and add the <code>paginate_by</code> line shown in bold below.</p>
+
+<pre class="brush: python notranslate">class BookListView(generic.ListView):
+ model = Book
+ <strong>paginate_by = 10</strong></pre>
+
+<p>With this addition, as soon as you have more than 10 records the view will start paginating the data it sends to the template. The different pages are accessed using GET parameters — to access page 2 you would use the URL: <code>/catalog/books/<strong>?page=2</strong></code>.</p>
+
+<h3 id="Templates">Templates</h3>
+
+<p>Now that the data is paginated, we need to add support to the template to scroll through the results set. Because we might want to do this in all list views, we'll do this in a way that can be added to the base template. </p>
+
+<p>Open <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> and copy in the following pagination block below our content block (highlighted below in bold). The code first checks if pagination is enabled on the current page. If so then it adds next and previous links as appropriate (and the current page number). </p>
+
+<pre class="brush: python notranslate">{% block content %}{% endblock %}
+
+<strong>{% block pagination %}
+ {% if is_paginated %}
+ &lt;div class="pagination"&gt;
+ &lt;span class="page-links"&gt;
+ {% if page_obj.has_previous %}
+ &lt;a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}"&gt;previous&lt;/a&gt;
+ {% endif %}
+ &lt;span class="page-current"&gt;
+ &lt;p&gt;Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}.&lt;/p&gt;
+ &lt;/span&gt;
+ {% if page_obj.has_next %}
+ &lt;a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}"&gt;next&lt;/a&gt;
+ {% endif %}
+ &lt;/span&gt;
+ &lt;/div&gt;
+ {% endif %}
+{% endblock %} </strong></pre>
+
+<p>The <code>page_obj</code> is a <a href="https://docs.djangoproject.com/en/2.0/topics/pagination/#paginator-objects">Paginator</a> object that will exist if pagination is being used on the current page. It allows you to get all the information about the current page, previous pages, how many pages there are, etc. </p>
+
+<p>We use <code>\{{ request.path }}</code> to get the current page URL for creating the pagination links. This is useful, because it is independent of the object that we're paginating.</p>
+
+<p>Thats it!</p>
+
+<h3 id="What_does_it_look_like_3">What does it look like?</h3>
+
+<p>The screenshot below shows what the pagination looks like — if you haven't entered more than 10 titles into your database, then you can test it more easily by lowering the number specified in the <code>paginate_by</code> line in your <strong>catalog/views.py</strong> file. To get the below result we changed it to <code>paginate_by = 2</code>.</p>
+
+<p>The pagination links are displayed on the bottom, with next/previous links being displayed depending on which page you're on.</p>
+
+<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p>
+
+<h2 id="Challenge_yourself">Challenge yourself</h2>
+
+<p>The challenge in this article is to create the author detail and list views required to complete the project. These should be made available at the following URLs:</p>
+
+<ul>
+ <li><code>catalog/authors/</code> — The list of all authors.</li>
+ <li><code>catalog/author/<em>&lt;id&gt;</em></code><em> </em>— The detail view for the specific author with a primary key field named <em><code>&lt;id&gt;</code></em></li>
+</ul>
+
+<p>The code required for the URL mappers and the views should be virtually identical to the <code>Book</code> list and detail views we created above. The templates will be different, but will share similar behaviour.</p>
+
+<div class="note">
+<p><strong>Note</strong>:</p>
+
+<ul>
+ <li>Once you've created the URL mapper for the author list page you will also need to update the <strong>All authors</strong> link in the base template. Follow the <a href="#Update_the_base_template">same process</a> as we did when we updated the <strong>All books</strong> link.</li>
+ <li>Once you've created the URL mapper for the author detail page, you should also update the <a href="#Creating_the_Detail_View_template">book detail view template</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>) so that the author link points to your new author detail page (rather than being an empty URL). The line will change to add the template tag shown in bold below.
+ <pre class="brush: html notranslate">&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href="<strong>{% url 'author-detail' book.author.pk %}</strong>"&gt;\{{ book.author }}&lt;/a&gt;&lt;/p&gt;
+</pre>
+ </li>
+</ul>
+</div>
+
+<p>When you are finished, your pages should look something like the screenshots below.</p>
+
+<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<ul>
+</ul>
+
+<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="Summary">Summary</h2>
+
+<p>Congratulations, our basic library functionality is now complete! </p>
+
+<p>In this article we've learned how to use the generic class-based list and detail views and used them to create pages to view our books and authors. Along the way we've learned about pattern matching with regular expressions, and how you can pass data from URLs to your views. We've also learned a few more tricks for using templates. Last of all we've shown how to paginate list views, so that our lists are managable even when we have many records.</p>
+
+<p>In our next articles we'll extend this library to support user accounts, and thereby demonstrate user authentication, permissons, sessions, and forms.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-display/">Generic display views</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/">Introduction to class-based views</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins">Built-in template tags and filters</a> (Django docs).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/pagination/">Pagination</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/home_page/index.html b/files/zh-tw/learn/server-side/django/home_page/index.html
new file mode 100644
index 0000000000..a01d71608e
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/home_page/index.html
@@ -0,0 +1,383 @@
+---
+title: 'Django Tutorial Part 5: Creating our home page'
+slug: Learn/Server-side/Django/Home_page
+translation_of: Learn/Server-side/Django/Home_page
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">我們現在可以添加代碼,來顯示我們的第一個完整頁面 - <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站的主頁,顯示每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本URL 地圖和視圖、從數據庫獲取記錄、以及使用模板的實踐經驗。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>讀 the <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction">Django Introduction</a>. 完成上章節 (including <a href="/zh-TW/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a>).</td>
+ </tr>
+ <tr>
+ <th scope="row">目的:</th>
+ <td>了解如何創建簡單的URL映射和視圖(沒有數據編碼在URL中)以及如何從模型中獲取數據並創建模版。<br>
+ 概要</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="總覽">總覽</h2>
+
+<p>在定義了模型並創建了一些可以使用的初始庫記錄之後,是時候編寫將這些信息呈現給用戶的代碼了。 我們要做的第一件事是確定我們要在頁面中顯示的信息,並定義用於返回這些資源的URL。 然後,我們將創建一個URL映射器,視圖和模板來顯示頁面。</p>
+
+<p>下圖描述了主要數據流,以及處理HTTP請求和響應時所需的組件。 當我們已經實現了模型時,我們將創建的主要組件是:</p>
+
+<ul>
+ <li>URL映射器將支持的URL(以及URL中編碼的任何信息)轉發到適當的視圖功能。</li>
+ <li>查看函數可從模型中獲取所需的數據,創建顯示數據的HTML頁面,並將頁面返回給用戶以在瀏覽器中查看。</li>
+ <li>在視圖中呈現數據時要使用的模板。</li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="display: block; margin: 0px auto;"></p>
+
+<p>正如您將在下一節中看到的那樣,我們將顯示5頁,這是太多信息,無法在一篇文章中進行記錄。 因此,本文將重點介紹如何實現主頁,我們將在後續文章中介紹其他頁面。 這應該使您對URL映射器,視圖和模型在實踐中如何工作有很好的端到端理解。</p>
+
+<h2 id="定義資源URL">定義資源URL</h2>
+
+<p>由於此版本的LocalLibrary對於最終用戶基本上是只讀的,因此我們只需要提供該網站的登錄頁面(主頁),以及顯示書籍和作者的列表和詳細視圖的頁面。</p>
+
+<p>我們頁面所需的URL是:</p>
+
+<ul>
+ <li><code>catalog/</code> — 主頁/索引頁面。</li>
+ <li><code>catalog/books/</code> — 所有書籍的清單。</li>
+ <li><code>catalog/authors/</code> — 所有作者列表。</li>
+ <li><code>catalog/book/<em>&lt;id&gt;</em></code> — 特定書的詳細信息視圖,其主鍵為 <code><em>&lt;id&gt;</em></code> (the default)。 因此,例如<code>/catalog/book/3</code>,作為添加的第三本書。</li>
+ <li><code>catalog/author/<em>&lt;id&gt;</em></code><em> </em>— 特定作者的詳細信息視圖,其主鍵字段名為<em><code>&lt;id&gt;</code></em>。 例如,為第11位作者添加了<code>/catalog/author/11</code>。</li>
+</ul>
+
+<p>前三個URL用於列出索引,書籍和作者。 它們不對任何其他信息進行編碼,並且雖然返回的結果將取決於數據庫中的內容,但為獲取信息而運行的查詢將始終相同。</p>
+
+<p>相比之下,最後兩個URL用於顯示有關特定書籍或作者的詳細信息-這些URL編碼要顯示在URL中的項目的標識(如上顯示為&lt;id&gt;)。 URL映射器可以提取編碼信息並將其傳遞給視圖,然後將動態確定從數據庫中獲取哪些信息。 通過在我們的URL中編碼信息,我們只需要一個URL映射,視圖和模板即可處理每本書(或作者)。</p>
+
+<div class="note">
+<p>注意: Django允許您以自己喜歡的任何方式來構造URL-您可以如上所示在URL主體中編碼信息或使用URL <code>GET</code> 參數(例如<code>/book/?id=6</code>)。 無論使用哪種方法,都應保持URL的整潔,邏輯和可讀性(<a href="https://www.w3.org/Provider/Style/URI">在此處查看W3C建議</a>).</p>
+
+<p>Django文檔傾向於建議在URL正文中編碼信息,他們認為這種做法鼓勵更好的URL設計。</p>
+</div>
+
+<p>如概述中所述,本文的其餘部分描述瞭如何構造索引頁。</p>
+
+<h2 id="創建索引頁面">創建索引頁面</h2>
+
+<p>我們將創建的第一頁是索引頁 (<code>catalog/</code>)。 這將顯示一些靜態HTML,以及數據庫中不同記錄的一些計算出的“計數”。 為了完成這項工作,我們必須創建一個URL映射,視圖和模板。</p>
+
+<div class="note">
+<p><strong>注意:值得在本節中多加註意。 大多數材料是所有頁面共有的。</strong></p>
+</div>
+
+<h3 id="URL_mapping">URL mapping</h3>
+
+<p>創建<a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">skeleton website</a> 時,我們更新了<strong>locallibrary/urls.py</strong>文件,以確保每當收到以 <code>catalog/</code>  開頭的URL時, <em>URLConf </em>模組 <code>catalog.urls</code> 都將處理其餘的子字符串。</p>
+
+<p>來自 <strong>locallibrary/urls.py</strong>的以下代碼片段包括<code>catalog.urls</code> 模塊:</p>
+
+<pre>urlpatterns += [
+    path('catalog/', include('catalog.urls')),
+]
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 每當Django遇到導入函數 <code><a href="https://docs.djangoproject.com/en/2.1/ref/urls/#django.urls.include" title="django.conf.urls.include">django.urls.include()</a></code>時,它都會在指定的結束字符處分割URL字符串,並將剩餘的子字符串發送到所包含的<em>URLconf</em> 模塊以進行進一步處理。</p>
+</div>
+
+<p>我們還為<em>URLConf </em>模塊創建了一個佔位符文件,名為 <strong>/catalog/urls.py</strong>。 將以下行添加到該文件:</p>
+
+<pre class="brush: python">urlpatterns = [
+<strong> path('', views.index, name='index'),</strong>
+]</pre>
+
+<p><code>path()</code>函數定義以下內容:</p>
+
+<ul>
+ <li>URL模式,它是一個空字符串:<code>''</code>。 處理其他視圖時,我們將詳細討論URL模式。</li>
+ <li>如果檢測到URL模式,將調用一個視圖函數:<code>views.index</code>,  它是<strong>views.py</strong>文件中名為<code>index()</code> 的函數。 </li>
+</ul>
+
+<p><code>path()</code>  函數還指定一個<code>name</code>參數,它是此特定URL映射的唯一標識符。 您可以使用該名稱來“反向”映射器,即,動態創建指向映射器旨在處理的資源的URL。 例如,通過在模板中添加以下鏈接,我們可以使用name參數從任何其他頁面鏈接到我們的主頁:</p>
+
+<pre class="brush: html">&lt;a href="<strong>{% url 'index' %}</strong>"&gt;Home&lt;/a&gt;.</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 我們可以對上面的鏈接進行硬編碼 (例如<code>&lt;a href="<strong>/catalog/</strong>"&gt;Home&lt;/a&gt;</code>), 但是如果我們更改主頁的模式 (例如更改為 <code>/catalog/index</code>) 則模板將不再 正確鏈接。 使用反向URL映射更加靈活和健壯!</p>
+</div>
+
+<h3 id="View_function-based">View (function-based)</h3>
+
+<p>View是一個用來處理 HTTP 請求的函式,根據需求從資料庫取得資料,通過使用 HTML 模板呈現此數據來生成 HTML , 並且在一個 HTTP 回應中返回 HTML 來呈現給用戶。Index view 遵循這個模型 — 獲取有關數據庫中有多少 <code>Book</code>, <code>BookInstance</code>, 可用的 <code>BookInstance</code> 還有 <code>Author</code> 的訊息, 然後把他們傳遞給模板進行顯示。</p>
+
+<p>打開<strong>catalog/views.py</strong>, 並且注意該文件已經導入 <a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#django.shortcuts.render">render()</a> 快捷功能已使用模板和數據生成HTML文件。 </p>
+
+<pre class="brush: python">from django.shortcuts import render
+
+# Create your views here.
+</pre>
+
+<p>將以下代碼複製到文件底部。 第一行導入將用於訪問所有視圖中的數據的模型類。</p>
+
+<pre class="brush: python">from .models import Book, Author, BookInstance, Genre
+
+def index(request):
+ """View function for home page of site."""
+
+ # Generate counts of some of the main objects
+ num_books = Book.objects.all().count()
+ num_instances = BookInstance.objects.all().count()
+
+ # Available books (status = 'a')
+ num_instances_available = BookInstance.objects.filter(status__exact='a').count()
+
+ # The 'all()' is implied by default.
+ num_authors = Author.objects.count()
+
+ context = {
+ 'num_books': num_books,
+ 'num_instances': num_instances,
+ 'num_instances_available': num_instances_available,
+ 'num_authors': num_authors,
+ }
+
+ # Render the HTML template index.html with the data in the context variable
+ return render(request, 'index.html', context=context)</pre>
+
+<p>視圖函數的第一部分使用模型類上的 <code>objects.all()</code> 屬性獲取記錄數。 它還獲取具有狀態字段值為“ a”(可用)的<code>BookInstance</code> 物件列表。 在上一教程(<a href="/en-US/docs/Learn/Server-side/Django/Models#Searching_for_records">Django Tutorial Part 3: Using models &gt; Searching for records</a>)中,您可以找到更多有關如何從模型進行訪問的信息。.</p>
+
+<p>在函數的最後,我們調用 <code>render()</code> 函數來創建並返回HTML頁面作為響應(此快捷功能包裝了許多其他函數,從而簡化了這種非常常見的用例)。它以原始 <code>request</code> 物件 (一個 <code>HttpRequest</code>), 帶有數據佔位符的HTML模板以及上下文 <code>context</code> 變量包含將插入到這些佔位符中的數據的Python字典)為參數。</p>
+
+<p>在下一節中,我們將詳細討論模板和上下文變量。 讓我們開始創建模板,以便實際上可以向用戶顯示內容!</p>
+
+<h3 id="Template">Template</h3>
+
+<p>模板是一個文本文件,用於定義文件(例如HTML頁面)的結構或佈局,並使用佔位符表示實際內容。 Django會在您的應用程序名為'<strong>templates</strong>'的目錄中自動查找模板。 因此,例如,在我們剛剛添加的索引視圖中, <code>render()</code> 函數將有望能夠找到文件 <strong>/locallibrary/catalog/templates/<em>index.html</em></strong>,如果找不到該文件,則會引發錯誤。 如果您保存以前的更改並返回瀏覽器,則可以看到此信息-訪問<code>127.0.0.1:8000</code>現在將為您提供一個相當直觀的錯誤消息"<code>TemplateDoesNotExist at /catalog/</code>"以及其他詳細信息。</p>
+
+<div class="note">
+<p><strong>注意</strong>: Django將根據項目的設置文件在許多位置查找模板(搜索已安裝的應用程序是默認設置!)。 您可以在 <a href="https://docs.djangoproject.com/en/2.0/topics/templates/">Templates</a> (Django docs)中找到有關Django如何查找模板及其支持的模板格式的更多信息。</p>
+</div>
+
+<h4 id="Extending_templates">Extending templates</h4>
+
+<p>索引模板的頭部和身體將需要標準的HTML標記,以及用於導航的部分(到我們尚未創建的站點中的其他頁面)以及用於顯示一些介紹性文本和我們的書籍數據的部分。 對於我們網站上的每個頁面,大部分文本(HTML和導航結構)都是相同的。 Django模板語言允許您聲明一個基本模板,然後擴展它,而不是強迫開發人員在每個頁面中都複製此"樣板" ,只需替換每個特定頁面上不同的部分即可。</p>
+
+<p>例如,基本模板 <strong>base_generic.html</strong> 可能類似於以下文本。 如您所見,其中包含一些"通用" HTML以及標題,側邊欄和內容的部分,這些部分使用命名的<code>block</code> 和<code>endblock</code> 模板標記進行了標記(以粗體顯示)。 區塊可以為空,或包含將在默認情況下用於派生頁面的內容。</p>
+
+<div class="note">
+<p><strong>注意</strong>:模板<em>tags</em> 類似於可以在模板中使用的功能,可以在模板中循環使用列表,基於變量的值執行條件操作等。除了模板標記之外,模板語法還允許您引用模板變量(傳遞給 模板),並使用<em>template filters</em>,該過濾器可重新格式化變量(例如,將字符串設置為小寫)。</p>
+</div>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+ <strong>{% block title %}</strong>&lt;title&gt;Local Library&lt;/title&gt;<strong>{% endblock %}</strong>
+&lt;/head&gt;
+
+&lt;body&gt;
+ <strong>{% block sidebar %}</strong>&lt;!-- insert default navigation text for every page --&gt;<strong>{% endblock %}</strong>
+ <strong>{% block content %}</strong>&lt;!-- default content text (typically empty) --&gt;<strong>{% endblock %}</strong>
+&lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<p>當我們想為特定視圖定義模板時,我們首先指定基本模板(帶有<code>extends</code> 模板標籤-請參見下一個代碼清單)。 如果我們要在模板中替換任何節,則使用與基本模板中相同的<code>block</code>/<code>endblock</code>節來聲明這些節。</p>
+
+<p>例如,下面的代碼片段顯示了我們如何使用<code>extends</code> 模板標籤並覆蓋<code>content</code> 區塊。 生成的最終HTML將具有基本模板中定義的所有HTML和結構(包括您在<code>title</code> 區塊中定義的默認內容),但是將新的<code>content</code> 區塊插入到默認模板中。</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Local Library Home&lt;/h1&gt;
+ &lt;p&gt;Welcome to LocalLibrary, a website developed by &lt;em&gt;Mozilla Developer Network&lt;/em&gt;!&lt;/p&gt;
+{% endblock %}</pre>
+
+<h4 id="The_LocalLibrary_base_template">The LocalLibrary base template</h4>
+
+<p>下面列出了我們計劃用於<em>LocalLibrary</em> 網站的基本模板。 如您所見,其中包含一些HTML以及 <code>title</code>, <code>sidebar</code>, 和 <code>content</code>。 我們有一個默認標題(我們可能想要更改)和一個默認側邊欄,其中帶有指向所有書籍和作者列表的鏈接(我們可能不想更改,但是如果需要的話,我們允許範圍通過將其放在 在一個區塊中)。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 我們還引入了兩個附加的模板標籤:<code>url</code> 和<code>load static</code>。 這些將在以下各節中討論。</p>
+</div>
+
+<p>創建一個新文件<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> ,並為其提供以下內容:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+ {% block title %}&lt;title&gt;Local Library&lt;/title&gt;{% endblock %}
+ &lt;meta charset="utf-8"&gt;
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
+ &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"&gt;
+
+ &lt;!-- Add additional CSS in static file --&gt;
+ {% load static %}
+ &lt;link rel="stylesheet" href="{% static 'css/styles.css' %}"&gt;
+&lt;/head&gt;
+&lt;body&gt;
+ &lt;div class="container-fluid"&gt;
+ &lt;div class="row"&gt;
+ &lt;div class="col-sm-2"&gt;
+ {% block sidebar %}
+ &lt;ul class="sidebar-nav"&gt;
+ &lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href=""&gt;All books&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href=""&gt;All authors&lt;/a&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+ {% endblock %}
+ &lt;/div&gt;
+ &lt;div class="col-sm-10 "&gt;
+ {% block content %}{% endblock %}
+ &lt;/div&gt;
+ &lt;/div&gt;
+ &lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>該模板包括來自<a href="http://getbootstrap.com/">Bootstrap</a>的CSS,以改進HTML頁面的佈局和表示方式。 使用Bootstrap或其他客戶端Web框架是創建吸引人的頁面的快速方法,該頁面可以在不同的瀏覽器大小上很好地擴展。</p>
+
+<p>基本模板還引用了本地CSS文件 (<strong>styles.css</strong>) ,該文件提供了一些其他樣式。 創建 <strong>/locallibrary/catalog/static/css/styles.css</strong>並為其提供以下內容:</p>
+
+<pre class="brush: css">.sidebar-nav {
+ margin-top: 20px;
+ padding: 0;
+ list-style: none;
+}</pre>
+
+<h4 id="The_index_template">The index template</h4>
+
+<p>創建HTML文件 <strong>/locallibrary/catalog/templates/<em>index.html</em></strong> 並為其提供以下內容。 如您所見,我們在第一行中擴展了基本模板,然後使用該模板的新內容塊替換默認<code>content</code> 區塊。</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Local Library Home&lt;/h1&gt;
+ &lt;p&gt;Welcome to LocalLibrary, a website developed by &lt;em&gt;Mozilla Developer Network&lt;/em&gt;!&lt;/p&gt;
+
+ &lt;h2&gt;Dynamic content&lt;/h2&gt;
+ &lt;p&gt;The library has the following record counts:&lt;/p&gt;
+ &lt;ul&gt;
+ &lt;li&gt;&lt;strong&gt;Books:&lt;/strong&gt; <strong>\{{ num_books }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies:&lt;/strong&gt; <strong>\{{ num_instances }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies available:&lt;/strong&gt; <strong>\{{ num_instances_available }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Authors:&lt;/strong&gt; <strong>\{{ num_authors }}</strong>&lt;/li&gt;
+ &lt;/ul&gt;
+{% endblock %}</pre>
+
+<p>在 <em>Dynamic content </em>部分中,我們聲明了要從視圖中包含的信息的佔位符(<em>template variables</em>)。 變量使用“雙括號”或“把手”語法標記(請參見上面的粗體)。</p>
+
+<div class="note">
+<p><strong>注意</strong>:因為變量具有雙括號 (<code>\{{ num_books }}</code>),而標籤則用百分號括在單括號中擴展為 (<code>{% extends "base_generic.html" %}</code>),所以您可以輕鬆識別是要處理模板變量還是模板標籤(函數)。</p>
+</div>
+
+<p>這裡要注意的重要一點是,這些變量是使用我們在視圖的<code>render()</code> 函數中傳遞給<code>context</code> 字典的鍵命名的(請參見下文); 呈現模板時,這些將被其<em>values</em> 替換。</p>
+
+<pre class="brush: python">context = {
+ '<strong>num_books</strong>': num_books,
+ '<strong>num_instances</strong>': num_instances,
+ '<strong>num_instances_available</strong>': num_instances_available,
+ '<strong>num_authors</strong>': num_authors,
+}
+
+return render(request, 'index.html', context=context)</pre>
+
+<h4 id="Referencing_static_files_in_templates">Referencing static files in templates</h4>
+
+<p>您的項目可能會使用靜態資源,包括JavaScript,CSS和圖像。 由於這些文件的位置可能未知(或可能會更改),因此Django允許您相對於<code>STATIC_URL</code> 全局設置在模板中指定這些文件的位置(默認框架網站將<code>STATIC_URL</code> 的值設置為'<code>/static/</code>',但您可以選擇將其託管在內容分發網絡或其他地方)。</p>
+
+<p>在模板中,您首先調用指定為“ static”的<code>load</code> 模板標籤以添加此模板庫(如下所示)。 加載靜態文件後,您可以使用<code>static</code> 模板標籤,指定感興趣文件的相對URL。</p>
+
+<pre class="brush: html">&lt;!-- Add additional CSS in static file --&gt;
+{% load static %}
+&lt;link rel="stylesheet" href="{% static 'css/styles.css' %}"&gt;</pre>
+
+<p>如果需要,您可以以相同的方式將圖像添加到頁面中。 例如:</p>
+
+<pre class="brush: html">{% load static %}
+&lt;img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;"&gt;
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>:上面的更改指定了文件的位置,但是Django默認不提供文件。創建網站框架時 (<a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">created the website skeleton</a>),雖然我們在全局URL映射器(<strong>/locallibrary/locallibrary/urls.py</strong>)中啟用了由開發Web服務器提供的服務,但您仍需要安排它們在生產中提供。 我們待會再看。</p>
+</div>
+
+<p>有關使用靜態文件的更多信息,請參閱管理靜態文件 <a href="https://docs.djangoproject.com/en/2.0/howto/static-files/">Managing static files</a> (Django docs)。</p>
+
+<h4 id="Linking_to_URLs">Linking to URLs</h4>
+
+<p>上面的基本模板引入了<code>url</code> 模板標籤。</p>
+
+<pre class="brush: python">&lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+</pre>
+
+<p>此標記採用在 <strong>urls.py</strong>中調用的 <code>path()</code>函數的名稱以及關聯視圖將從該函數接收的任何參數的值,並返回可用於鏈接到資源的URL。</p>
+
+<h2 id="What_does_it_look_like">What does it look like?</h2>
+
+<p>此時,我們應該已經創建了顯示索引頁面所需的所有內容。 運行服務器(<code>python3 manage.py runserver</code>),然後打開瀏覽器到<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>。 如果一切設置正確,則您的站點應類似於以下螢幕截圖。</p>
+
+<p><img alt="Index page for LocalLibrary website" src="https://mdn.mozillademos.org/files/14045/index_page_ok.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 874px;"></p>
+
+<div class="note">
+<p><strong>注意</strong>:您將無法使用<strong>All books</strong>和<strong>All authors</strong>鏈接,因為尚未定義這些頁面的路徑,視圖和模板(當前我們僅在<code>base_generic.html</code> html模板中插入了這些鏈接的佔位符)。</p>
+</div>
+
+<h2 id="Challenge_yourself">Challenge yourself</h2>
+
+<p>這裡有兩個任務可以測試您對模型查詢,視圖和模板的熟悉程度。</p>
+
+<ol>
+ <li>LocalLibrary <a href="#The_LocalLibrary_base_template">base template</a> 已定義<code>title</code> 欄。 在 <a href="#The_index_template">index template</a>中覆蓋此塊並為頁面創建一些新標題。
+
+ <div class="note">
+ <p><strong>提示</strong> :<a href="#Extending_templates">Extending templates</a> 部分介紹瞭如何創建塊並將其擴展到另一個模板中。<br>
+  </p>
+ </div>
+ </li>
+ <li>修改 <a href="#View_(function-based)">view</a>以生成包含特定單詞(不區分大小寫)的流派計數和書籍計數,並將其傳遞給<code>context</code> (這與我們創建並使用<code>num_books</code> 和<code>num_instances_available</code>的方式大致相同)。 然後更新 <a href="#The_index_template">index template</a> 以使用這些變量。</li>
+</ol>
+
+<ul>
+</ul>
+
+<h2 id="Summary">Summary</h2>
+
+<p>現在,我們已經為網站創建了主頁-一個HTML頁面,該頁面顯示了數據庫中的一些記錄計數,並具有指向其他尚待創建頁面的鏈接。 在此過程中,我們學習了很多有關url映射器,視圖,使用我們的模型查詢數據庫,如何從視圖中將信息傳遞到模板以及如何創建和擴展模板的基本信息。</p>
+
+<p>在下一篇文章中,我們將基於我們的知識來創建其他四個頁面。</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial03/">Writing your first Django app, part 3: Views and Templates</a>  (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/">URL dispatcher</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/views/">View functions</a> (DJango docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/templates/">Templates</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/howto/static-files/">Managing static files</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#django.shortcuts.render">Django shortcut functions</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/index.html b/files/zh-tw/learn/server-side/django/index.html
new file mode 100644
index 0000000000..7bb4840e06
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/index.html
@@ -0,0 +1,115 @@
+---
+title: Django 網站框架 (Python)
+slug: Learn/Server-side/Django
+translation_of: Learn/Server-side/Django
+---
+<div>{{LearnSidebar}}</div>
+
+<p>Django 使用 Python 語言編寫,是一個廣受歡迎、且功能完整的服務器端網站框架。本模塊將為您展示,為什麼 Django 能夠成為一個廣受歡迎的服務器端框架,如何設置開發環境,以及如何開始創建你自己的網絡應用。</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>開始學習本模塊,並不需要任何 Django 知識. 但您要理解什麼是服務器端網絡編程、什麼是網絡框架,最好能夠閱讀我們的<a href="/zh-TW/docs/Learn/Server-side/First_steps">服務端網站編程的第一步模塊</a>。</p>
+
+<p>最好能有基本的編程概念、並了解 <a href="/zh-TW/docs/Glossary/Python">Python</a> 語言,但並不是理解本教程的核心概念的必然條件。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 對於初學者來說,Python 是最容易閱讀和理解的編程語言之一。也就是說,如果您想更好的理解本教程,網上有很多免費書籍及免費教程可供參考學習(建議初學者查看 Python 官網的 <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for Non Programmers</a> )。</p>
+</div>
+
+<h2 id="指引">指引</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Introduction">Django 簡介</a></dt>
+ <dd>在第一篇關於 Django 的文章裡,我們會回答"什麼是Django?",並概述這個網絡框架的特殊之處。我們會列出主要的功能,包括一些高級的功能特性,這些高級特性我們在這部分教程裡沒有時間詳細說明。在你設置好 Django 應用、並開始把玩它之前,我們會展示 Django 應用的一些主要模塊,讓你明白 Django 應用能做什麼。  </dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/development_environment">架設 Django 開發環境</a></dt>
+ <dd>現在你知道 Django 是做什麼的,我們會展示怎樣在 Windows、Linux(Ubuntu)、和 Mac OS X上,創建和測試 Django 的開發環境—不管你是用什麼操作系統,這篇文章會教給你能夠開發 Django 應用所需要的開發環境。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django 教學 1: 本地圖書館網站</a></dt>
+ <dd>我們實用教程系列的第一篇文章,會解釋你將學習到什麼,並提供 "本地圖書館" 網站這個例子的概述。我們會在接下來的文章裡,完成並不斷的改進這個網站。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/skeleton_website">Django 教學 2: 創建骨架網站</a></dt>
+ <dd>這篇文章會教你,怎樣創建一個網站的 "框架" 。以這個網站為基礎,你可以填充網站特定的 settings、urls、models、views 和 templates。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Models">Django 教學 3: 使用模型</a></dt>
+ <dd>這篇文章會為 “本地圖書館網站” 定義數據模板—數據模板是我們為應用存儲的數據結構。並且允許 Django 在資料庫中存儲數據(以後可以修改)。此文章解釋了什麼是數據模板、怎樣聲明它、和一些主要的數據種類。文章還簡要的介紹了一些,你可以獲得數據模板的方法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Admin_site">Django 教學 4: Django 管理員頁面</a></dt>
+ <dd>現在我們已經為本地圖書館網站,創建了模型,我們將使用 Django 管理員頁面添加一些 ‘真實的’ 的圖書數據。首先,我們將向你介紹,如何使用管理員頁面註冊模型,然後我們介紹如何登錄和創建一些數據。最後我們展示一些,進一步改進管理員頁面呈現的方法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Home_page">Django 教學 5: 創建我們的首頁</a></dt>
+ <dd>我們現在可以添加代碼,來展示我們的第一個完整頁面—本地圖書館主頁,來顯示我們對每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本 URL 地圖和視圖、從數據庫獲取記錄、以及使用模版的實踐經驗。.</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Generic_views">Django 教學 6: 通用列表與詳細視圖</a></dt>
+ <dd>本教學課程擴展了我們的本地圖書館網站,添加書籍和作者和詳細頁面。在這裡,我們將了解基於類別的通用視圖,並展示如何減少常用代碼用例的代碼量。我們還將更詳細地深入理解 URL 處理,展示如何執行基本模式匹配。   </dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Sessions">Django 教學 7: 會話框架</a></dt>
+ <dd>本教學擴展本地圖書館網站,向首頁添加了一個基於會話的訪問計數器。這是個比較簡單的例子,但它顯示如何使用會話框架,為你自己的網站中的匿名用戶,提供一致的行為。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Authentication">Django 教學 8: 使用者身份驗証和權限</a></dt>
+ <dd>本教程,我們將向你展示,如何允許使用者用自己的賬戶,登錄到你的網站,以及如何根據他們是否登錄、及其權限,來控制他們可以做什麼、和看到什麼。作為此次演示的一部分,我們將擴展本地圖書館網站,添加登錄和登出頁面,以及使用者和工作人員特定頁面,以查看已借用的書籍。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Forms">Django 教學 9: 使用表單</a></dt>
+ <dd>本教程,我們將向你展示如何使用 Django 中的 <a href="https://developer.mozilla.org/zh-TW/docs/Web/Guide/HTML/Forms">HTML Forms</a> 表單,特別是編寫表單以創建、更新、和刪除模型實例的最簡單方法。作為此次演示的一部分,我們將擴展本地圖書館網站,以便圖書館員,可以使用我們自己的表單 (而不是使用管理應用程序) 來更新書籍,創建、更新、刪除作者。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Testing">Django 教學 10: 測試 Django 網頁應用</a></dt>
+ <dd>隨著網站的的發展,手工測試越來越難測試—不僅要測試更多,而且隨著組件之間的相互作用變得越來越複雜,一個領域的一個小的變化,可能需要許多額外的測試,來驗證其對其他領域的影響。減輕這些問題的一種方法,是編寫自動化測試,每次更改時,都可以輕鬆可靠地運行。本教程將介紹如何使用 Django 的測試框架,對你的網站進行單元測試自動化。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Deployment">Django 教學 11: 部署 Django 到生產環境</a></dt>
+ <dd>現在,你已創建(並測試)一個很酷的 “本地圖書館網站”,你將要把它安裝在公共 Web 服務器上,以便圖書館員工和成員,可以通過 Internet 訪問。本文概述如何找到主機,來部署你的網站,以及你需要做什麼,才能使你的網站準備好投入生產環境。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/web_application_security">Django 網頁應用安全</a></dt>
+ <dd>保護用戶數據,是任何網站設計的重要組成部分,我們以前解釋了Web 安全文章中,一些更常見的安全威脅—本文提供了 Django 內置、如何保護處理這種危險的實際演示。</dd>
+</dl>
+
+<h2 id="評估">評估</h2>
+
+<p>以下評估,將測試你對如何使用 Django 創建網站的理解,如上述指南中所列出的項目。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django 微博客</a></dt>
+ <dd>在這個評估中,你將使用你從本單元中學到的一些知識,來創建自己的博客。</dd>
+</dl>
+<div>{{LearnSidebar}}</div>
+
+<p>Django 使用 Python 語言編寫,是一個廣受歡迎、且功能完整的服務器端網站框架。本模塊將為您展示,為什麼 Django 能夠成為一個廣受歡迎的服務器端框架,如何設置開發環境,以及如何開始創建你自己的網絡應用。</p>
+
+<h2 id="先決條件_2">先決條件</h2>
+
+<p>開始學習本模塊,並不需要任何 Django 知識. 但您要理解什麼是服務器端網絡編程、什麼是網絡框架,最好能夠閱讀我們的<a href="/zh-TW/docs/Learn/Server-side/First_steps">服務端網站編程的第一步模塊</a>。</p>
+
+<p>最好能有基本的編程概念、並了解 <a href="/zh-TW/docs/Glossary/Python">Python</a> 語言,但並不是理解本教程的核心概念的必然條件。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 對於初學者來說,Python 是最容易閱讀和理解的編程語言之一。也就是說,如果您想更好的理解本教程,網上有很多免費書籍及免費教程可供參考學習(建議初學者查看 Python 官網的 <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for Non Programmers</a> )。</p>
+</div>
+
+<h2 id="指引_2">指引</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Introduction">Django 簡介</a></dt>
+ <dd>在第一篇關於 Django 的文章裡,我們會回答"什麼是Django?",並概述這個網絡框架的特殊之處。我們會列出主要的功能,包括一些高級的功能特性,這些高級特性我們在這部分教程裡沒有時間詳細說明。在你設置好 Django 應用、並開始把玩它之前,我們會展示 Django 應用的一些主要模塊,讓你明白 Django 應用能做什麼。  </dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/development_environment">架設 Django 開發環境</a></dt>
+ <dd>現在你知道 Django 是做什麼的,我們會展示怎樣在 Windows、Linux(Ubuntu)、和 Mac OS X上,創建和測試 Django 的開發環境—不管你是用什麼操作系統,這篇文章會教給你能夠開發 Django 應用所需要的開發環境。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django 教學 1: 本地圖書館網站</a></dt>
+ <dd>我們實用教程系列的第一篇文章,會解釋你將學習到什麼,並提供 "本地圖書館" 網站這個例子的概述。我們會在接下來的文章裡,完成並不斷的改進這個網站。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/skeleton_website">Django 教學 2: 創建骨架網站</a></dt>
+ <dd>這篇文章會教你,怎樣創建一個網站的 "框架" 。以這個網站為基礎,你可以填充網站特定的 settings、urls、models、views 和 templates。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Models">Django 教學 3: 使用模型</a></dt>
+ <dd>這篇文章會為 “本地圖書館網站” 定義數據模板—數據模板是我們為應用存儲的數據結構。並且允許 Django 在資料庫中存儲數據(以後可以修改)。此文章解釋了什麼是數據模板、怎樣聲明它、和一些主要的數據種類。文章還簡要的介紹了一些,你可以獲得數據模板的方法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Admin_site">Django 教學 4: Django 管理員頁面</a></dt>
+ <dd>現在我們已經為本地圖書館網站,創建了模型,我們將使用 Django 管理員頁面添加一些 ‘真實的’ 的圖書數據。首先,我們將向你介紹,如何使用管理員頁面註冊模型,然後我們介紹如何登錄和創建一些數據。最後我們展示一些,進一步改進管理員頁面呈現的方法。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Home_page">Django 教學 5: 創建我們的首頁</a></dt>
+ <dd>我們現在可以添加代碼,來展示我們的第一個完整頁面—本地圖書館主頁,來顯示我們對每個模型類型有多少條記錄,並提供我們其他頁面的側邊欄導航鏈接。一路上,我們將獲得編寫基本 URL 地圖和視圖、從數據庫獲取記錄、以及使用模版的實踐經驗。.</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Generic_views">Django 教學 6: 通用列表與詳細視圖</a></dt>
+ <dd>本教學課程擴展了我們的本地圖書館網站,添加書籍和作者和詳細頁面。在這裡,我們將了解基於類別的通用視圖,並展示如何減少常用代碼用例的代碼量。我們還將更詳細地深入理解 URL 處理,展示如何執行基本模式匹配。   </dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Sessions">Django 教學 7: 會話框架</a></dt>
+ <dd>本教學擴展本地圖書館網站,向首頁添加了一個基於會話的訪問計數器。這是個比較簡單的例子,但它顯示如何使用會話框架,為你自己的網站中的匿名用戶,提供一致的行為。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Authentication">Django 教學 8: 使用者身份驗証和權限</a></dt>
+ <dd>本教程,我們將向你展示,如何允許使用者用自己的賬戶,登錄到你的網站,以及如何根據他們是否登錄、及其權限,來控制他們可以做什麼、和看到什麼。作為此次演示的一部分,我們將擴展本地圖書館網站,添加登錄和登出頁面,以及使用者和工作人員特定頁面,以查看已借用的書籍。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Forms">Django 教學 9: 使用表單</a></dt>
+ <dd>本教程,我們將向你展示如何使用 Django 中的 <a href="https://developer.mozilla.org/zh-TW/docs/Web/Guide/HTML/Forms">HTML Forms</a> 表單,特別是編寫表單以創建、更新、和刪除模型實例的最簡單方法。作為此次演示的一部分,我們將擴展本地圖書館網站,以便圖書館員,可以使用我們自己的表單 (而不是使用管理應用程序) 來更新書籍,創建、更新、刪除作者。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Testing">Django 教學 10: 測試 Django 網頁應用</a></dt>
+ <dd>隨著網站的的發展,手工測試越來越難測試—不僅要測試更多,而且隨著組件之間的相互作用變得越來越複雜,一個領域的一個小的變化,可能需要許多額外的測試,來驗證其對其他領域的影響。減輕這些問題的一種方法,是編寫自動化測試,每次更改時,都可以輕鬆可靠地運行。本教程將介紹如何使用 Django 的測試框架,對你的網站進行單元測試自動化。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/Deployment">Django 教學 11: 部署 Django 到生產環境</a></dt>
+ <dd>現在,你已創建(並測試)一個很酷的 “本地圖書館網站”,你將要把它安裝在公共 Web 服務器上,以便圖書館員工和成員,可以通過 Internet 訪問。本文概述如何找到主機,來部署你的網站,以及你需要做什麼,才能使你的網站準備好投入生產環境。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/web_application_security">Django 網頁應用安全</a></dt>
+ <dd>保護用戶數據,是任何網站設計的重要組成部分,我們以前解釋了 Web 安全文章中,一些更常見的安全威脅—本文提供了 Django 內置、如何保護處理這種危險的實際演示。</dd>
+</dl>
+
+<h2 id="評估_2">評估</h2>
+
+<p>以下評估,將測試你對如何使用 Django 創建網站的理解,如上述指南中所列出的項目。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django/django_assessment_blog">Django 小部落格 DIY</a></dt>
+ <dd>在這個評估中,你將使用你從本單元中學到的一些知識,來創建自己的部落格。</dd>
+</dl>
diff --git a/files/zh-tw/learn/server-side/django/introduction/index.html b/files/zh-tw/learn/server-side/django/introduction/index.html
new file mode 100644
index 0000000000..f0a9e2caa5
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/introduction/index.html
@@ -0,0 +1,306 @@
+---
+title: Django 介紹
+slug: Learn/Server-side/Django/Introduction
+translation_of: Learn/Server-side/Django/Introduction
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div>
+
+<p class="summary"> 在這第一篇Django文章中,我們將回答“什麼是Django”這個問題,並概述這個網絡框架有什麼特性。我們將描述主要功能,包括一些高級功能,但我們並不會在本單元中詳細介紹。我們還會展示一些Django應用程序的主要構建模塊(儘管此時你還沒有要測試的開發環境)。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>基本的電腦知識.對<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">服務器端網站編程的一般了解</a> ,特別是<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">網站中客戶端-服務器交互的機制</a> .</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解Django是什麼,它提供了哪些功能,以及Django應用程序的主要構建塊。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是_Django">什麼是 Django?</h2>
+
+<p>Django 是一個高級的 Python 網路框架,可以快速開發安全和可維護的網站。由經驗豐富的開發者構建,Django 負責處理網站開發中麻煩的部分,因此你可以專注於編寫應用程序,而無需重新開發。</p>
+
+<p>它是免費和開源的,有活躍繁榮的社區、豐富的文檔、以及很多免費和付費的解決方案。</p>
+
+<p>Django 可以使你的應用具有以下優點:</p>
+
+<dl>
+ <dt>完備</dt>
+ <dd>Django 遵循 “功能完備” 的理念,提供開發人員可能想要 “開箱即用” 的幾乎所有功能。因為你需要的一切,都是一個 ”產品“ 的一部分,它們都可以無縫結合在一起,遵循一致性設計原則,並且具有廣泛、和<a href="https://docs.djangoproject.com/en/2.0/">最新的文檔</a>。</dd>
+ <dt>通用</dt>
+ <dd>
+ <p>Django 可以(並已經)用於構建幾乎任何類型的網站—從內容管理系統和維基,到社交網絡和新聞網站。它可以與任何客戶端框架一起工作,並且可以提供幾乎任何格式(包括 HTML、RSS、JSON、XML等)的內容。你正在閱讀的網站就是基於 Django。</p>
+
+ <p>在內部,儘管它為幾乎所有可能需要的功能(例如幾個流行的資料庫,模版引擎等)提供了選擇,但是如果需要,它也可以擴展到使用其他組件。</p>
+ </dd>
+ <dt>安全</dt>
+ <dd>
+ <p>Django 幫助開發人員,通過提供一個被設計為 “做正確的事情” 來自動保護網站的框架,來避免許多常見的安全錯誤。例如,Django 提供了一種安全的方式,來管理用戶帳號和密碼,避免了常見的錯誤,比如將 session 放在 cookie 中這種易受攻擊的做法(取而代之的是,cookies 只包含一個密鑰,實際數據存儲在數據庫中),或直接存儲密碼,而不是密碼的 hash 值。</p>
+
+ <p>密碼 hash ,是讓密碼通過加密 hash 函數,而創建的固定長度值。 Django 能通過運行 hash 函數,來檢查輸入的密碼 - 就是將輸出的 hash 值,與存儲的 hash 值進行比較是否正確。然而由於功能的 “單向” 性質,假使存儲的 hash 值受到威脅,攻擊者也難以解出原始密碼。 (但其實有彩虹表-譯者觀點)</p>
+
+ <p>默認情況下,Django 可以防範許多漏洞,包括 SQL 注入,跨站點腳本,跨站點請求偽造,和點擊劫持 (請參閱 網站安全 相關信息,如有興趣)。</p>
+ </dd>
+ <dt>可擴展</dt>
+ <dd>Django 使用基於組件的 “無共享” 架構 (架構的每一部分獨立於其他架構,因此可以根據需要進行替換或更改)。在不同部分之間,有明確的分隔,意味著它可以通過在任何級別添加硬件,來擴展服務:緩存服務器,數據庫服務器,或應用程序服務器。一些最繁忙的網站,已經在 Django 架構下成功地縮放了網站的規模大小,以滿足他們的需求(例如 Instagram 和 Disqus,僅舉兩個例子,可自行添加)。 </dd>
+ <dt>可維護</dt>
+ <dd>Django 代碼編寫,是遵照設計原則和模式,鼓勵創建可維護和可重複使用的代碼。特別是,它使用了不要重複自己(DRY)原則,所以沒有不必要的重複,減少了代碼的數量。 Django 還將相關功能,分組到可重用的 “應用程序” 中,並且在較低級別,將相關代碼分組或模塊( 模型視圖控制器 <a href="/en-US/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model View Controller (MVC)</a> 模式)。</dd>
+ <dt>可移植</dt>
+ <dd>Django 是用 Python 編寫的,它在許多平台上運行。這意味著,你不受任務特定的服務器平台的限制,並且可以在許多種類的 Linux,Windows 和 Mac OS X 上運行應用程序。此外,Django 得到許多網路託管提供商的好評,他們經常提供特定的基礎設施,和託管 Django 網站的文檔。</dd>
+</dl>
+
+<h2 id="Django的起源">Django的起源?</h2>
+
+<p>Django 最初在 2003 年到 2005 年間,由負責創建和維護報紙網站的網絡團隊開發。在創建了許多網站後,團隊開始考慮、並重用許多常見的代碼和設計模式。這個共同的代碼,演變一個通用的網絡開發框架,2005 年 7 月,被開源為 “Django” 項目。</p>
+
+<p>Django 不斷發展壯大 — 從 2008 年 9 月的第一個里程碑版本(1.0),到最近發布的(2.0)-(2018)版本。每個版本都添加了新功能,和錯誤修復,從支持新類型的數據庫,模版引擎和緩存,到添加 “通用” 視圖函數和類別(這減少了開發人員在一些編程任務必須編寫的代碼量)。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 查看 Django 網站上的發行說明 <a href="https://docs.djangoproject.com/en/2.0/releases/">release notes</a>,看看最近版本發生了什麼變化,以及 Django 能做多少工作</p>
+</div>
+
+<p>Django 現在是一個蓬勃發展的合作開源項目,擁有數千個用戶和貢獻者。雖然它仍然具有反映其起源的一些功能,但 Django 已經發展成為,能夠開發任何類型的網站的多功能框架。</p>
+
+<h2 id="Django有多受歡迎">Django有多受歡迎?</h2>
+
+<p>服務器端框架的受歡迎程度沒有任何可靠和明確的測量(儘管<a class="external external-icon" href="http://hotframeworks.com/" rel="noopener">Hot Frameworks</a>網站嘗試使用諸如計算每個平台的GitHub項目數量和StackOverflow問題的機制來評估流行度)。一個更好的問題是Django是否“足夠流行”,以避免不受歡迎的平台的問題。它是否繼續發展?如果您需要幫助,可以幫您嗎?如果您學習Django,有機會獲得付費工作嗎?</p>
+
+<p>基於使用Django的流行網站數量,為代碼庫貢獻的人數以及提供免費和付費支持的人數,那麼是的,Django是一個流行的框架!</p>
+
+<p>使用Django的流行網站包括:Disqus,Instagram,騎士基金會,麥克阿瑟基金會,Mozilla,國家地理,開放知識基金會,Pinterest和開放棧(來源:<a class="external external-icon" href="https://www.djangoproject.com/" rel="noopener">Django home page</a> ).</p>
+
+<h2 id="Django_是特定用途的">Django 是特定用途的?</h2>
+
+<p>Web框架通常將自己稱為“特定”或“無限制”。</p>
+
+<p>特定框架是對處理任何特定任務的“正確方法”有意見的框架。他們經常支持特定領域的快速發展(解決特定類型的問題),因為正確的做法是通常被很好地理解和記錄在案。然而,他們在解決其主要領域之外的問題時可能不那麼靈活,並且傾向於為可以使用哪些組件和方法提供較少的選擇。</p>
+
+<p>相比之下,无限制的框架对于将组件粘合在一起以实现目标或甚至应使用哪些组件的最佳方式的限制较少。它们使开发人员更容易使用最合适的工具来完成特定任务,尽管您需要自己查找这些组件。</p>
+
+<p>Django“有點有意義”,因此提供了“兩個世界的最佳”。它提供了一組組件來處理大多數Web開發任務和一個(或兩個)首選的使用方法。然而,Django的解耦架構意味著您通常可以從多個不同的選項中進行選擇,也可以根據需要添加對全新的支持。</p>
+
+<h2 id="Django_代碼是什麼樣子">Django 代碼是什麼樣子?</h2>
+
+<p>在傳統的數據驅動網站中,Web應用程序會等待來自Web瀏覽器(或其他客戶端)的HTTP 請求。當接收到請求時,應用程序根據URL 和可能的<code>POST</code> 數據或<code>GET</code> 數據中的信息確定需要的內容。根據需要,可以從數據庫讀取或寫入信息,或執行滿足請求所需的其他任務。然後,該應用程序將返回對Web瀏覽器的響應,通常通過將檢索到的數據插入HTML模板中的佔位符來動態創建用於瀏覽器顯示的HTML 頁面。</p>
+
+<p>Django 網絡應用程序通常將處理每個步驟的代碼分組到單獨的文件中:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png"></p>
+
+<ul>
+ <li><strong>URLs: </strong>雖然可以通過單個功能來處理來自每個URL的請求,但是編寫單獨的視圖函數來處理每個資源是更加可維護的。URL映射器用於根據請求URL將HTTP請求重定向到相應的視圖。URL映射器還可以匹配出現在URL中的字符串或數字的特定模式,並將其作為數據傳遞給視圖功能。<br>
+ </li>
+ <li><strong>View:</strong> 視圖是一個請求處理函數,它接收HTTP請求並返回HTTP響應。視圖通過模型訪問滿足請求所需的數據,並將響應的格式委託給模板。<br>
+ </li>
+ <li><strong>Models:</strong> 模型是定義應用程序數據結構的Python對象,並提供在數據庫中管理(添加,修改,刪除)和查詢記錄的機制。<br>
+ </li>
+ <li><strong>Templates:</strong> 模板是定義文件(例如HTML頁面)的結構或佈局的文本文件,用於表示實際內容的佔位符。一個視圖可以使用HTML模板,從數據填充它動態地創建一個HTML頁面模型。可以使用模板來定義任何類型的文件的結構;它不一定是HTML!</li>
+</ul>
+
+<div class="note">
+<p><strong>注意</strong> : Django將此組織稱為“模型視圖模板(MVT)”架構。它與更加熟悉的<a href="https://developer.mozilla.org/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model View Controller</a>架構有許多相似之處. </p>
+</div>
+
+<ul>
+</ul>
+
+<p>以下部分將為您提供Django應用程序的這些主要部分的想法(稍後我們將在進一步詳細介紹後,我們將在開發環境中進行更詳細的介紹)。</p>
+
+<h3 id="將請求發送到正確的視圖(urls.py)">將請求發送到正確的視圖(urls.py)</h3>
+
+<p>URL映射器通常存儲在名為urls.py的文件中。在下面的示例中,mapper(<code>urlpatterns</code>)定義了特定URL 模式和相應視圖函數之間的映射列表。如果接收到具有與指定模式匹配的URL(例如r'^$',下面)的HTTP請求,則將調用相關聯的視圖功能(例如 views.index)並傳遞請求。</p>
+
+<pre>urlpatterns = [
+ <strong>path('admin/', admin.site.urls),
+ </strong>path('book/&lt;int:id&gt;/', views.book_detail, name='book_detail'),
+ path('catalog/', include('catalog.urls')),
+ re_path(r'^([0-9]+)/$', views.best),
+]
+</pre>
+
+<p><code>urlpatterns</code>對像是<code>path()</code>和/或<code>re_path()</code>函數的列表(Python列表使用方括號定義,其中項目用逗號分隔,可以有一個<a href="https://docs.python.org/2/faq/design.html#why-does-python-allow-commas-at-the-end-of-lists-and-tuples">可選的尾隨逗號</a>。例如:[<code>item1, item2, item3,</code> ])。</p>
+
+<p>兩種方法的第一個參數,是將要匹配的路由(模式)。<code> path()</code>方法使用尖括號,來定義將被捕獲、並作為命名參數傳遞給視圖函數的 URL 的部分。<code> re_path()</code>函數使用靈活的模式匹配方法,稱為正則表達式。我們將在後面的文章中討論這些內容!</p>
+
+<p>第二個參數,是在匹配模式時將調用的另一個函數。註釋 <code>views.book_detail</code>表示該函數名為<code>book_detail()</code>,可以在名為<code>views</code>的模塊中找到(即在名為<code>views.py</code>的文件中)</p>
+
+<h3 id="處理請求(views.py)">處理請求(views.py)</h3>
+
+
+
+<p>視圖是Web應用程序的核心,從Web客戶端接收HTTP請求並返回HTTP響應。在兩者之間,他們編制框架的其他資源來訪問數據庫,渲染模板等。</p>
+
+<p>下面的例子顯示了一個最小的視圖功能index(),這可以通過我們的URL映射器在上一節中調用。像所有視圖函數一樣,它接收一個HttpRequest對像作為參數(request)並返回一個HttpResponse對象。在這種情況下,我們對請求不做任何事情,我們的響應只是返回一個硬編碼的字符串。我們會向您顯示一個請求,在稍後的部分中會提供更有趣的內容。</p>
+
+
+
+<pre class="brush: python">## filename: views.py (Django view functions)
+
+from django.http import HttpResponse
+
+def index(request):
+ # Get an HttpRequest - the request parameter
+ # perform operations using information from the request.
+ # Return HttpResponse
+ return HttpResponse('Hello from Django!')
+</pre>
+
+<div class="note">
+<p><strong>注意</strong> :一點點Python:</p>
+
+<ul>
+ <li><a class="external external-icon" href="https://docs.python.org/3/tutorial/modules.html" rel="noopener">Python模塊</a>是函數的“庫”,存放在單獨的文件中,我們可能希望在代碼中使用。在這裡,我們只導入了<code>HttpResponse</code>從對象<code>django.http</code>模塊,使我們可以在視圖中使用<br>
+ <code>from django.http import HttpResponse</code>。<br>
+ 還有其他方法可以從模塊導入一些或所有對象</li>
+ <li>使用<code>def</code>,如上所示的關鍵字聲明函數,命參數在函數名稱後面的括號中列出:整行以冒號結尾。注意下一行是否都<strong>縮進</strong>。縮進很重要,因為它指定代碼行在該特定塊內(強制縮進是Python的一個關鍵特徵,而且是Python代碼很容易閱讀的一個原因)。</li>
+</ul>
+
+
+</div>
+
+<ul>
+</ul>
+
+<p>視圖通常存放在一個名為<strong>views.py</strong>的文件中。</p>
+
+<h3 id="定義數據模型(models.py)">定義數據模型(models.py)</h3>
+
+
+
+<p>Django Web應用程序,通過被稱為模型的Python對象,來管理和查詢數據。模型定義存儲數據的結構,包括字段類型 以及字段可能的最大值,默認值,選擇列表選項,文檔幫助文本,表單的標籤文本等。模型的定義與底層數據庫無關-您可以選擇其中一個,作為項目設置的一部分。一旦您選擇了要使用的數據庫,您就不需要直接與之交談- 只需編寫模型結構和其他代碼,Django可以處理與數據庫通信的所有辛苦的工作。</p>
+
+<p>下面的代碼片段為<code>Team</code>對象,展示了一個非常簡單的Django模型。本<code>Team</code>類別是從Django的類別派生<code>models.Model</code>。它將團隊名稱和團隊級別,定義為字符字段,並為每個記錄指定了要存放的最大字符數。<code>team_level</code>可以是幾個值中的一個,因此,我們將其定義為一個選擇字段,並在被展示的數據、和被儲存的數據之間,建立映射,並設置一個默認值。</p>
+
+
+
+<pre class="brush: python"># filename: models.py
+
+from django.db import models
+
+class Team(models.Model):
+ team_name = models.CharField(max_length=40)
+
+ TEAM_LEVELS = (
+ ('U09', 'Under 09s'),
+ ('U10', 'Under 10s'),
+ ('U11', 'Under 11s'),
+ ... #list other team levels
+ )
+ team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11')
+</pre>
+
+<div class="note">
+<p><strong>注意</strong> : Python小知識:</p>
+
+<ul>
+ <li>Python支持“面向對象編程”,這是一種編程風格,我們將代碼組織到對像中,其中包括用於對該對象進行操作的相關數據和功能。對像也可以從其他對象繼承/擴展/派生,允許相關對象之間的共同行為被共享。在Python中,我們使用關鍵字<strong>Class</strong>定義對象的“藍圖”。我們可以根據類中的模型創建類型的多個特定實例。</li>
+ <li>例如,我們有個<strong>Team</strong>類,它來自於<strong>Model</strong>類。這意味著它是一個模型,並且將包含模型的所有方法,但是我們也可以給它自己的專門功能。在我們的模型中,我們定義了我們的數據庫需要存儲我們的數據字段,給出它們的具體名稱。Django使用這些定義(包括字段名稱)來創建底層數據庫。</li>
+</ul>
+
+
+</div>
+
+<h3 id="查詢數據(views.py)">查詢數據(views.py)</h3>
+
+
+
+<p>Django模型提供了一個,用於搜索數據庫的簡單查詢API。這可以使用不同的標準(例如,精確,不區分大小寫,大於等等)來匹配多個字段,並且可以支持複雜語句(例如,您可以在擁有一個團隊的<strong>U11</strong>團隊上指定搜索名稱以“Fr ”開頭或以“al”結尾)。</p>
+
+<p>代碼片段顯示了一個視圖函數(資源處理程序),用於顯示我們所有的<strong>U09</strong>團隊。<strong>粗體</strong>顯示如何使用模型查詢API,過濾所有記錄,其中該 <strong>team_level</strong>字段,具有正確的文本“ <strong>U09</strong> ”(請注意,該條件如何filter()作為參數傳遞給該函數,該字段名稱和匹配類型由雙下劃線: <strong>team_level__exact</strong>)</p>
+
+
+
+<pre class="brush: python">## filename: views.py
+
+from django.shortcuts import render
+from .models import Team
+
+def index(request):
+ <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong>
+ context = {'youngest_teams': list_teams}
+ return render(request, '/best/index.html', context)
+</pre>
+
+<dl>
+</dl>
+
+<p>此功能使用<strong>render</strong> ()功能創建<strong>HttpResponse</strong>發送回瀏覽器的功能。這個函數是一個快捷方式;它通過組合指定的HTML模版和一些數據來插入模版(在名為“ <strong>content</strong> ”的變量中提供)來創建一個<strong>HTML</strong>文件。在下一節中,我們將介紹如何在其中插入數據以創建<strong>HTML</strong>。</p>
+
+<h3 id="呈現數據(HTML模版)">呈現數據(HTML模版)</h3>
+
+<p>模板系統允許您使用佔位符指定輸出文檔的結構,以便在生成頁面時填充數據。模板通常用於創建HTML,但也可以創建其他類型的文檔。 Django支持其本機模板系統,和另一個流行的Python庫,名為 Jinja2(如果需要,它也可以支持其他系統)。</p>
+
+<p>代碼片段,顯示了上一節中<code>render()</code>函數調用的HTML模板的外觀。這個模板的編寫假設它在渲染時可以訪問名為<code>youngest_teams</code>的列表變量(包含在上面<code>render()</code>函數中的上下文變量<code>context</code>中)。在HTML框架內部,我們有一個表達式,首先檢查<code>youngest_teams</code>變量是否存在,然後在<code>for</code>循環中迭代它。在每次迭代中,模板在{{htmlelement(“li”)}}元素中顯示每個團隊的<code>team_name</code>值。</p>
+
+<pre class="brush: python">## filename: best/templates/best/index.html
+
+&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;body&gt;
+
+ {% if youngest_teams %}
+ &lt;ul&gt;
+ {% for team in youngest_teams %}
+ &lt;li&gt;\{\{ team.team_name \}\}&lt;/li&gt;
+ {% endfor %}
+ &lt;/ul&gt;
+{% else %}
+ &lt;p&gt;No teams are available.&lt;/p&gt;
+{% endif %}
+
+&lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<h2 id="你還能做什麼?">你還能做什麼?</h2>
+
+
+
+<p>前面的部分,展示了幾乎每個Web應用程序將使用的主要功能:URL映射,視圖,模型和模版。Django提供的其他內容包括:</p>
+
+<ul>
+ <li><strong>表單</strong> : HTML表單用於收集用戶數據,以便在服務器上進行處理。Django簡化了表單創建,驗證和處理。</li>
+ <li><strong>用戶身份驗證和權限</strong> : Django包含了一個強大的用戶身份驗證和權限系統,該系統已經構建了安全性。</li>
+ <li><strong>緩存</strong> :與提供靜態內容相比,動態創建內容需要更大的計算強度(也更緩慢)。Django提供靈活的緩存,以便你可以存儲所有或部分的頁面。如無必要,不會重新呈現網頁。</li>
+ <li><strong>管理網站</strong> :當你使用基本骨架創建應用時,就已經默認包含了一個Django管理站點。它十分輕鬆地創建了一個管理頁面,使網站管理員能夠創建、編輯和查看站點中的任何數據模型。</li>
+ <li><strong>序列化數據</strong> : Django可以輕鬆地將數據序列化,並支持XML或JSON格式。這會有助於創建一個Web服務(Web服務指數據純粹為其他應用程序或站點所用,並不會在自己的站點中顯示),或是有助於創建一個由客戶端代碼處理、和呈現所有數據的網站。</li>
+</ul>
+
+
+
+<h2 id="總結">總結</h2>
+
+
+
+<p>恭喜,您已經完成了Django之旅的第一步!您現在應該了解Django的主要優點,一些關於它的歷史,以及Django應用程序的每個主要部分可能是什麼樣子。您還應該了解Python編程語言的一些內容,包括列表,函數和類別的語法。</p>
+
+<p>您已經看到上面的一些真正的Django代碼,但與客戶端代碼不同,您需要設置一個開發環境來運行它。這是我們的下一步。</p>
+
+
+
+<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div>
+
+<h2 id="本教學連結">本教學連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/models/index.html b/files/zh-tw/learn/server-side/django/models/index.html
new file mode 100644
index 0000000000..c075d8d35a
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/models/index.html
@@ -0,0 +1,475 @@
+---
+title: 'Django Tutorial Part 3: Using models'
+slug: Learn/Server-side/Django/Models
+translation_of: Learn/Server-side/Django/Models
+---
+<div>,{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</div>
+
+<p class="summary"></p>
+
+<p class="summary">本文介紹如何為 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站定義模型。它解釋了模型是什麼、聲明的方式以及一些主要字段類型。它還簡要展示了您可以訪問模型數據的幾個主要方法。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django 教學 2: 創建骨架網站。</a></td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>
+ <p>能夠設計和創建自己的模型,選擇適當的欄位。</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>Django Web 應用程序通過被稱為模型的 Python 對象,訪問和管理數據。模型定義儲存數據的結構,包括欄位類型、以及可能還有最大大小,默認值,選擇列表選項,幫助文檔,表單的標籤文本等。模型的定義與底層數據庫無關 — 你可以選擇其中一個,作為項目設置的一部分。一旦你選擇了要使用的數據庫,你就不需要直接與之交談 — 只需編寫模型結構和其他代碼,Django 可以處理與數據庫通信的所有繁瑣工作。</p>
+
+<p>本教程將介紹如何定義和訪問 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 範例網站的模型。</p>
+
+<h2 id="設計LocalLibrary模型"><font><font>設計LocalLibrary模型</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在你投入開始編寫模型之前,花幾分鐘時間考慮我們需要存放的數據、以及不同物件之間的關係。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們知道,我們需要存放書籍的信息(標題,摘要,作者,語言,類別,ISBN),並且我們可能有多個副本(具有全域唯一的ID,可用狀態等)。</font><font>我們可以存放更多關於作者的信息,而不僅僅是他的名字,或多個作者的相同或相似的名稱。</font><font>我們希望能根據書名,作者名,語言和類別對信息進行排序。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在設計模型時,為每個“物件”分別設置模型(相關信息分組)是有意義的。在這種情況下,明顯的物件是書籍,書本實例和作者。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你可能想要使用模型,來表示選擇列表選項(例如:選擇下拉列表),而不是硬編碼,將選項編寫進網站—這是當所有選項面臨未知、或改變時候的建議。在本網站,模型的明顯候選,包括書籍類型(例如:科幻小說,法國詩歌等)和語言(英語,法語,日語)。</font></font></p>
+
+<p><font><font>一旦我們已經決定了我們的模型和字段,我們需要考慮它們的關聯性。</font><font>Django允許你來定義一對一的關聯(</font></font><code>OneToOneField</code><font><font>),一對多(</font></font><code>ForeignKey</code><font><font>)和多對多(</font></font><code>ManyToManyField</code><font><font>)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>思考一下,在網站中,我們將定義模型展示在下面UML關聯圖中(下圖)。</font><font>如以上,我們創建了書的模型(書的通用細節),書本實例(系統中特定物理副本的書籍狀態),和作者。</font><font>我們也決定了各類型模型,以便通過管理界面創建/選擇值。</font><font>我們決定不給</font></font><code>BookInstance:status</code>一個模型 <font><font>—我們硬編碼了(</font></font><code>LOAN_STATUS</code><font><font>)的值,因為我們不希望其改變。</font><font>在每個框中,你可以看到模型名稱,字段名稱和類型,以及方法和返回類型。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該圖顯示模型之間的關係,包括它們的多重性。</font><font>多重性是圖中的數字,顯示可能存在於關係中的每個模型的數量(最大值和最小值)。</font><font>例如,盒子之間的連接線,顯示書和類型相關。</font><font>書模型中數字表明,一本書必須有一個或多個類型(想要多少就多少),而類型(</font></font>Genres<font><font>)模型線的另一端的數字(0..*),表明它可以有零個或多個關聯書本(可以有這個書籍類別,也有對應的書;也可以是有這個書籍類別,但沒有對應的書)。</font></font></p>
+
+<p><img alt="LocalLibrary Model UML" src="https://mdn.mozillademos.org/files/15646/local_library_model_uml.png" style="height: 660px; width: 977px;"></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>:下一節提供一個基本解釋模型的定義與使用,當你在讀的時候,也需要一邊考慮如何構建上圖中的每個模型。</font></font><br>
+  </p>
+</div>
+
+<h2 id="模型入門"><font><font>模型入門</font></font></h2>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>本節簡要概述了模型定義,和一些重要的字段、和字段參數。</span></p>
+
+<h3 id="模型定義">模型定義</h3>
+
+<p><font><font>模型通常在 app 中的 </font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>models.py</font></font></strong><font><font><span> 檔案</span>中定義。</font><font>它們是繼承自 </font></font> <code>django.db.models.Model</code>的子類, 可以包括屬性,方法和描述性資料(metadata)。下面區段為一個名為<code>MyModelName</code>的「典型」模型範例碼:</p>
+
+<pre class="notranslate">from django.db import models
+
+class MyModelName(models.Model):
+    """A typical class defining a model, derived from the Model class."""
+
+  # Fields
+    my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
+  ...
+
+  # Metadata
+ class Meta:
+  ordering = ['-my_field_name']
+
+  # Methods
+    def get_absolute_url(self):
+         """Returns the url to access a particular instance of MyModelName."""
+         return reverse('model-detail-view', args=[str(self.id)])
+
+    def __str__(self):
+        """String for representing the MyModelName object (in Admin site etc.)."""
+        return self.field_name</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在下面章節中,我們將更詳細解釋模型的每個功能。</font></font></p>
+
+<h4 id="字段" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>字段</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>模型可以有任意數量的字段、任何類型的字段 — 每個字段都表示我們要存放在我們的一個資料庫中的一欄數據(a column of data)。</font><font>每筆資料庫記錄(列 row)將由每個字段值之一組成。</font><font>我們來看看上面看到的例子。</font></font></p>
+
+<pre class="syntaxbox notranslate">my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')</pre>
+
+<div class="hidden">
+<p>Our above example has a single field called <code>my_field_name</code>, of type <code>models.CharField</code> — which means that this field will contain strings of alphanumeric characters. The field types are assigned using specific classes, which determine the type of record that is used to store the data in the database, along with validation criteria to be used when values are received from an HTML form (i.e. what constitutes a valid value). The field types can also take arguments that further specify how the field is stored or can be used. In this case we are giving our field two arguments:</p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在上面例子中,有個叫 </font></font><code>my_field_name</code> 的單一字段<font><font>,其類型為 </font></font><code>models.CharField</code> <font><font><span> </span>— 這意味著這個字段將會包含字母、數字字符串。</font><font>使用特定的類別分配字段類型,這些類別,決定了用於將數據存放在資料庫中的記錄的類型,以及從HTML表單接收到值(即構成有效值)時使用的驗證標準。</font><font>字段類型還可以獲取參數,進一步指定字段如何存放或如何被使用。</font><font>在這裡的情況下,我們給了字段兩個參數:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>max_length=20</code><font><font><span> </span>— 表示此字段中值的最大長度為20個字符的狀態。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>help_text="Enter field documentation"</code><font><font><span> </span>— 提供一個幫助用戶的文本標籤,讓用戶知道當前透過HTML表單輸入時要提供什麼值。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>字段名稱用於在視圖和模版中引用它。</font><font>字段還有一個標籤,它被指定一個參數(</font></font><code>verbose_name</code><font><font>),或者通過大寫字段的變量名的第一個字母,並用空格替換下劃線(例如</font></font><code>my_field_name</code><font><font> 的默認標籤為 My field name )。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>如果模型在表單中呈現(例如:在管理站點中),則聲明該字段的順序,將影響其默認順序,但可能會被覆蓋。</font></font></p>
+
+<h5 id="常用字段參數">常用字段參數</h5>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>當聲明很多/大多數不同的字段類型時,可以使用以下常用參數:</span></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#help-text" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>help_text</font></font></a><font><font><span> </span>:提供HTML表單文本標籤(eg i在管理站點中),如上所述。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#verbose-name" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>verbose_name</font></font></a><font><font><span> </span>:字段標籤中的可讀性名稱,如果沒有被指定,Django將從字段名稱推斷默認的詳細名稱。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#default" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>default</font></font></a><font><font><span> </span>:該字段的默認值。</font><font>這可以是值或可呼叫物件(callable object),在這種情況下,每次創建新紀錄時都將呼叫該物件。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#null" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>null</font></font></a><font><font>:如為 <code>True</code>,即允許 Django 於資料庫該欄位寫入 <code>NULL</code>(但欄位型態如為 <code>CharField</code> 則會寫入空字串)。預設值是 <code>False</code>。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#blank" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>blank</font></font></a><font><font><span> </span>:如果</font></font><code><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>True</font></font></strong></code><font><font>,表單中的字段被允許為空白。</font><font>默認是<code>False</code>,這意味著Django的表單驗證將強制你輸入一個值。</font><font>這通常搭配 <code>NULL=True</code> 使用,因為如果要允許空值,你還希望數據庫能夠適當地表示它們。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#choices" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>choices</font></font></a><font><font><span> </span>:這是給此字段的一組選項。</font><font>如果提供這一項,預設對應的表單部件是「該組選項的列表」,而不是原先的標准文本字段。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#primary-key" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>primary_key</font></font></a><font><font><span> </span>:如果是True,將當前字段設置為模型的主鍵(主鍵是被指定用來唯一辨識所有不同表記錄的特殊數據庫欄位(column))。</font><font>如果沒有指定字段作為主鍵,則Django將自動為此添加一個字段。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>還有許多其他選項 — 你可以在</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-options" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>這裡看到完整的字段選項</font></font></a><font><font>。</font></font></p>
+
+<h5 id="常用字段類型">常用字段類型</h5>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>以下列表描述了一些更常用的字段類型。</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.CharField" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">CharField</a> </font></font><font><font>是用來定義短到中等長度的字段字符串。</font><font>你必須指定<code>max_length</code>要存儲的數據。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.TextField" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>TextField </font></font></a><font><font>用於大型任意長度的字符串。</font><font>你可以<code>max_length</code>為該字段指定一個字段,但僅當該字段以表單顯示時才會使用(不會在數據庫級別強制執行)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.IntegerField" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;" title="django.db.models.IntegerField">IntegerField</a> </font></font><font><font>是一個用於存儲整數(整數)值的字段,用於在表單中驗證輸入的值為整數。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#datefield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">DateField</a> </font></font><font><font>和</font></font><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#datetimefield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">DateTimeField</a> </font></font><font><font>用於存儲/表示日期和日期/時間信息(分別是<code>Python.datetime.date</code> 和 <code>datetime.datetime</code> 對象)。這些字段可以另外表明(互斥)參數 <code>auto_now=Ture</code> (在每次保存模型時將該字段設置為當前日期),<code>auto_now_add</code>(僅設置模型首次創建時的日期)和 <code>default</code>(設置默認日期,可以被用戶覆蓋)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#emailfield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">EmailField</a> </font></font><font><font>用於存儲和驗證電子郵件地址。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#filefield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">FileField</a> </font></font><font><font>和</font></font><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#imagefield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">ImageField</a> </font></font><font><font>分別用於上傳文件和圖像(<code>ImageField</code> 只需添加上傳的文件是圖像的附加驗證)。</font><font>這些參數用於定義上傳文件的存儲方式和位置。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#autofield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">AutoField</a> </font></font><font><font>是一種 </font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>IntegerField </font></font></strong><font><font>自動遞增的特殊類型。</font><font>如果你沒有明確指定一個主鍵,則此類型的主鍵將自動添加到模型中。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#foreignkey" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">ForeignKey</a> </font></font><font><font>用於指定與另一個數據庫模型的一對多關係(例如,汽車有一個製造商,但製造商可以製作許多汽車)。</font><font>關係的“一”側是包含密鑰的模型。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#manytomanyfield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">ManyToManyField</a> </font></font><font><font>用於指定</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#manytomanyfield" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>多對多</font></font></a><font><font>關係(例如,一本書可以有幾種類型,每種類型可以包含幾本書)。</font><font>在我們的圖書館應用程序中,我們將非常類似地使用它們 ForeignKeys,但是可以用更複雜的方式來描述組之間的關係。</font><font>這些具有參數 <code>on_delete</code> 來定義關聯記錄被刪除時會發生什麼(例如,值 <code>models.SET_NULL</code> 將簡單地設置為值 NULL )。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>還有許多其他類型的字段,包括不同類型數字的字段(大整數,小整數,浮點數),布林值,URLs,唯一 ids 和其他 “時間相關” 的信息(持續時間,時間等)。</font><font>你可以查閱</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>完整列表</font></font></a><font><font><span> </span>.</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'></p>
+
+<h4 id="元數據Metadata"><font><font>元數據(Metadata)</font></font></h4>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>你可以通過宣告 class Meta 來宣告模型級別的元數據,如圖所示:</span></p>
+
+<pre class="brush: python notranslate">class Meta:
+ ordering = ['-my_field_name']
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>此元數據最有用的功能之一是控制在查詢模型類型時返回之記錄的默認排序。</font><font>你可以透過在</font></font><code>ordering</code><font><font> 屬性的字段名稱列表中指定匹配順序來執行此操作,如上所示。排序將依賴字段的類型(字符串字段按字母順序排序,而日期字段按時間順序排序)。如上所示,你可以使用減號(-)前綴字段名稱以反轉排序順序。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>例如,如果我們選擇依照此預設來排列書單:</font></font></p>
+
+<pre class="brush: python notranslate">ordering = ['title', '-pubdate']</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>書單通過標題依據--字母排序--排列,從A到Z,然後再依每個標題的出版日期,從最新到最舊排列。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>另一個常見的屬性是 </font></font><code>verbose_name</code><font><font> ,一個 </font></font><code>verbose_name</code><font><font> 說明單數和複數形式的類別。</font></font></p>
+
+<pre class="brush: python notranslate">verbose_name = 'BetterName'</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>其他有用的屬性允許你為模型創建和應用新的“訪問權限”(預設權限會被自動套用),允許基於其他的字段排序,或聲明該類是”抽象的“(你無法創建的記錄基類,並將由其他型號派生)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>許多其他元數據選項控制模型中必須使用哪些數據庫以及數據的存儲方式。</font><font>(如果你需要模型映射一個現有數據庫,這會有用)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>完整有用的元數據選項在這裡</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/models/options/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Model metadata options</font></font></a><font><font><span> </span>(Django docs).</font></font></p>
+
+<h4 id="方法Methods" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>方法(Methods)</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>一個模型也可以有方法。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><strong><font><font>最起碼,在每個模型中,你應該定義標準的Python 類方法</font></font><code>__str__()</code> </strong><font><font> ,<strong>來為每個物件返回一個人類可讀的字符串</strong>。</font><font>此字符用於表示管理站點的各個記錄(以及你需要引用模型實例的任何其他位置)。</font><font>通常這將返回模型中的標題或名稱字段。</font></font></p>
+
+<pre class="brush: python notranslate">def __str__(self):
+  return self.field_name</pre>
+
+<p><font>Django 方法中另一個常用方法是</font> <code>get_absolute_url()</code> <font>,這函數返回一個在網站上顯示個人模型記錄的 URL(如果你定義了該方法,那麼 Django 將自動在“管理站點”中添加“在站點中查看“按鈕在模型的記錄編輯欄)。</font><code>get_absolute_url()</code><font>的典型示例如下:</font></p>
+
+<pre class="brush: python notranslate">def get_absolute_url(self):
+ """Returns the url to access a particular instance of the model."""
+ return reverse('model-detail-view', args=[str(self.id)])
+</pre>
+
+<div class="note">
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><strong style="border: 0px; font-style: normal; font-weight: 700; margin: 0px; padding: 0px;"><font><font>注意</font></font></strong><font><font><span> </span>:假設你將使用URL</font></font><code>/myapplication/mymodelname/2</code> <font><font>來顯示模型的單個記錄(其中“2”是id特定記錄),則需要創建一個URL映射器來將響應和id傳遞給“模型詳細視圖” (這將做出顯示記錄所需的工作)。</font><font>以上示例中,</font></font><code>reverse()</code><font><font>函數可以“反轉”你的url映射器(在上訴命名為“model-detail-view”的案例中,以創建正確格式的URL。</font></font></p>
+
+<p style='font-style: normal; margin: 0px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><font><font>當然要做這個工作,你還是要寫URL映射,視圖和模版!</font></font></p>
+</div>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>你可以定義一些你喜歡的其他方法,並從你的代碼或模版調用它們(只要它們不帶任何參數)。</span></p>
+
+<h3 id="模型管理">模型管理</h3>
+
+<p><font>一旦你定義了模型類,你可以使用它們來創建,更新或刪除記錄,並運行查詢獲取所有記錄或特定的記錄子集。</font><font>當我們定義我們的視圖,我們將展示給你在這個教程如何去做。</font></p>
+
+<h4 id="創建和修改記錄"><font><font>創建和修改記錄</font></font></h4>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>要創建一個記錄,你可以定義一個模型實例,然後呼叫 </span><code>save()</code><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>。</span></p>
+
+<pre class="brush: python notranslate"># Create a new record using the model's constructor.
+record = MyModelName(my_field_name="Instance #1")
+
+# Save the object into the database.
+record.save()</pre>
+
+<div class="note">
+<p><strong>註:</strong>如果沒有任何的欄位被宣告為<code>主鍵</code>,這筆新的紀錄會被自動的賦予一個主鍵並將主鍵欄命名為 <code>id</code>。上例的那筆資料被儲存後,試著查詢這筆紀錄會看到它被自動賦予 1 的編號。</p>
+</div>
+
+<p>你可以透過「點(dot)的語法」取得或變更這筆新資料的欄位(字段)。你需要呼叫 <code>save()</code> 將變更過的資料存進資料庫。</p>
+
+<pre class="brush: python notranslate"># Access model field values using Python attributes.
+print(record.id) #should return 1 for the first record.
+print(record.my_field_name) # should print 'Instance #1'
+
+# Change record by modifying the fields, then calling save().
+record.my_field_name = "New Instance Name"
+record.save()
+</pre>
+
+<h4 id="搜尋紀錄">搜尋紀錄</h4>
+
+<p>你可以使用模型的 <code>objects</code> 屬性(由 base class 提供)搜尋符合某個條件的紀錄。You can search for records that match a certain criteria using the model's attribute (provided by the base class).</p>
+
+<div class="note">
+<p><strong>Note</strong>: 要用"抽象的"模型還有欄位說明怎麼搜尋紀錄可能會有點令人困惑。我們會以一個Book模型,其包含<code>title</code>與<code>genre</code>字段,而genre 也是一個僅有<code>name</code>一個字段的模型。</p>
+</div>
+
+<p>我們可以取得一個模型的所有紀錄,為一個 <code>QuerySet</code> 使用<code>objects.all()。</code> <code>QuerySet</code> 是一個可迭代的物件,表示他含有多個物件,而我們可以藉由迭代/迴圈取得每個物件。</p>
+
+<pre class="brush: python notranslate">all_books = Book.objects.all()
+</pre>
+
+<p>Django的 <code>filter()</code> 方法讓我們可以透過符合特定文字或數值的字段篩選回傳的<code>QuerySet</code>。例如篩選書名裡有 "wild" 的書並且計算總數,如下面所示。</p>
+
+<pre class="brush: python notranslate">wild_books = Book.objects.filter(title__contains='wild')
+number_wild_books = Book.objects.filter(title__contains='wild').count()
+</pre>
+
+<p>要比對的字段與比對方法都要被定義在篩選的參數名稱裡,並且使用這個格式:<code>比對字段__比對方法</code> (請注意上方範例中的 <code>title</code> 與 <code>contains</code> 中間隔了兩個底線唷)。在上面我們使用大小寫區分的方式比對<code>title</code> 。還有很多比對方式可以使用: <code>icontains</code> (不區分大小寫), <code>iexact</code> (大小寫區分且完全符合), <code>exact</code> (不區分大小寫但完全符合) 還有 <code>in</code>, <code>gt</code> (大於), <code>startswith</code>, 之類的。<a href="https://docs.djangoproject.com/en/2.0/ref/models/querysets/#field-lookups">全部的用法在這裡。</a></p>
+
+<p>有時候你會須要透過某個一對多的字段來篩選(例如一個 <code>外鍵</code>)。 這樣的狀況下,你可以使用兩個底線來指定相關模型的字段。例如透過某個特定的genre名稱篩選書籍,如下所示:</p>
+
+<pre class="brush: python notranslate"># 會比對到: Fiction, Science fiction, non-fiction etc.
+books_containing_genre = Book.objects.filter(genre<strong>__</strong>name<strong>__</strong>icontains='fiction')
+</pre>
+
+<div class="note">
+<p><strong>Note</strong>: 你可隨心地使用雙底線 (__) 來探索更多層的關係 (<code>ForeignKey</code>/<code>ManyToManyField</code>). 例如, 一本 <code>Book</code> 有許多不同的 types, 其進一步定義有參數 name 關聯的"cover":<code>type__cover__name__exact='hard'.</code></p>
+</div>
+
+<p>還有很多是你可以用索引(queries)來做的,包含從相關的模型做向後查詢(backwards searches)、連鎖過濾器(chaining filters)、回傳「值的小集合」等。更多資訊可以到 <a href="https://docs.djangoproject.com/en/2.0/topics/db/queries/">Making queries</a> (Django Docs) 查詢。</p>
+
+<h2 id="定義_LocalLibrary_模型">定義 LocalLibrary 模型</h2>
+
+<p>這部份我們會開始定義圖書館的模型。</p>
+
+<p>先打開 models.py (在 <em>/locallibrary/catalog/</em>),頁面的最上方可以看到樣板導入了 models 模組,其包含了模型的基本類別 <code>models.Model</code> ,能使我們的模型能夠繼承。</p>
+
+<pre class="brush: python notranslate">from django.db import models
+
+# Create your models here.</pre>
+
+<h3 id="書籍類型模型_Genre_model">書籍類型模型 (Genre model)</h3>
+
+<p>複製下方 <code>Genre</code> 模型的程式碼,並貼在你的 <code>models.py</code> 檔案底部,這個模型是用來儲存書籍類型的資訊 — 例如:該本書是否為科幻小說、羅曼史、軍事歷史等。</p>
+
+<p>就像先前提到的,我們以「模型」的方式建立一個書籍類型模型,而非以自由文本(free text)或者選擇列表(selection list)的方式,這樣做讓我們可以透過資料庫的形式而非硬編碼(hard coded)的方式來管理所有可能的值。</p>
+
+<pre class="brush: python notranslate">class Genre(models.Model):
+    """Model representing a book genre."""
+    name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return self.name</pre>
+
+<p>此模型有一個單一的 <code>CharField</code> 字段(<code>name</code>) 被用來描述書籍類別(限制輸入字元長度最多200個,同時也有提示文本(help_text) )。</p>
+
+<p>在模型最下方我們宣告一個 <code>__str__()</code> 方法來簡單回傳被特定一筆紀錄定義的書籍類別名稱。</p>
+
+<p>因為詳細名稱(verbose name)沒有被定義,所以字段在形式上會被稱為 <code>Name</code> 。</p>
+
+<h3 id="書本模型_Book_model">書本模型 (Book model)</h3>
+
+<p>複製下方 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">Book</span></font> 模型的程式碼,並貼在你的 <code>models.py</code> 檔案底部,這個 <code>Book</code> 模型一般來說代表一個可用書本的所有資訊,但並非包含特定的物理實例(physical instance)或者副本資訊(copy),此模型使用 <code>CharField</code> 來表示書的 <code>title</code> 和 <code>isbn</code> (國際標準書號)(note how the <code>isbn</code> specifies its label as "ISBN" using the first unnamed parameter because the default label would otherwise be "Isbn").,另外此模型使用 <code>TextField</code> 來存 <code>summary</code> ,因為此文本可能會很長。</p>
+
+<pre class="brush: python notranslate">from django.urls import reverse #Used to generate URLs by reversing the URL patterns
+
+class Book(models.Model):
+    """Model representing a book (but not a specific copy of a book)."""
+    title = models.CharField(max_length=200)
+    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
+
+ # Foreign Key used because book can only have one author, but authors can have multiple books
+    # Author as a string rather than object because it hasn't been declared yet in the file.
+    summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
+    isbn = models.CharField('ISBN', max_length=13, help_text='13 Character &lt;a href="https://www.isbn-international.org/content/what-isbn"&gt;ISBN number&lt;/a&gt;')
+
+    # ManyToManyField used because genre can contain many books. Books can cover many genres.
+    # Genre class has already been defined so we can specify the object above.
+ genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return self.title
+
+    def get_absolute_url(self):
+        """Returns the url to access a detail record for this book."""
+        return reverse('book-detail', args=[str(self.id)])
+
+</pre>
+
+<p>「書籍類別」(<code>genre</code>)是一個 <code>ManyToManyField</code> ,因此一本書可以有很多書籍類別,而一個書結類別也能夠對應到很多本書。作者(<code>author</code>)被宣告為外鍵(<code>ForeignKey</code>),因此每本書只會有一名作者,但一名作者可能會有多本書(實際上,一本書可能會有多名作者,不過這個案例不會有,所以在別的例子這種作法可能會有問題)</p>
+
+<p>在上面兩個宣告關聯性模型的敘述句內,關聯的對象都是用對象的模型類或字串的方式作為首個未具名參數的方式傳入句內做宣告。在關聯對象尚未被定義前,若要參照到該對象,必須使用該對象名稱字串的方式來宣告關聯性!還有一些 <code>author</code> 欄位的其它值得一提的參數:<code>null=True</code> 表示如果沒有作者的話,允許在資料庫中存入 <code>Null</code> 值;<code>on_delete=models.SET_NULL</code> 表示如果某筆作者紀錄被刪除的話,與該作者相關連的欄位都會被設成 <code>Null</code>。</p>
+
+<p>這個模型也定義了 <code>__str__()</code> ,使用書本的 <code>title</code> 字段來表示一筆 <code>Book</code> 的紀錄。而最後一個方法,<code>get_absolute_url()</code> ,則會回傳一個可以被用來存取該模型細節紀錄的 URL (要讓其有效運作,我們必須定義一個 URL 的映射,我們將其命名為 <code>book-detail</code> ,另外還得定義一個關聯示圖(view)與模板(template) )。</p>
+
+<h3 id="書本詳情模型_BookInstance_model">書本詳情模型 (BookInstance model)</h3>
+
+<p>接下來,複製下方 <code>BookInstance</code> 的模型,貼在其他模型下面,這個 <code>BookInstance</code> 模型表示一個特定的書籍副本(可會被某人借走),並且包含如「副本是否可用」、「預計歸還日期」、「版本說明」或「版本細節」等資訊,還有一個在圖書館中唯一的 id 。</p>
+
+<p>有些字段(fields)和方法(methods)現在你也熟悉了。此模型使用了:</p>
+
+<ul>
+ <li><code>ForeignKey</code> 用來辨識相關的 <code>Book</code> (每本書可以有很多副本,但每個副本只能有一個<code>Book</code>)</li>
+ <li><code>CharField</code> 用來表示該本書的版本說明(特定版本)</li>
+</ul>
+
+<pre class="brush: python notranslate">import uuid # Required for unique book instances
+
+class BookInstance(models.Model):
+ """Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library')
+ book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True)
+ imprint = models.CharField(max_length=200)
+ due_back = models.DateField(null=True, blank=True)
+
+ LOAN_STATUS = (
+ ('m', 'Maintenance'),
+ ('o', 'On loan'),
+ ('a', 'Available'),
+ ('r', 'Reserved'),
+ )
+
+ status = models.CharField(
+ max_length=1,
+ choices=LOAN_STATUS,
+ blank=True,
+ default='m',
+ help_text='Book availability',
+ )
+
+ class Meta:
+ ordering = ['due_back']
+
+ def __str__(self):
+ """String for representing the Model object."""
+ return f'{self.id} ({self.book.title})'</pre>
+
+<p>我們額外宣告了一些新的字段(field)類別(types):</p>
+
+<ul>
+ <li><code>UUIDField</code> 被用來將 <code>id</code> 字段再這個模型中設定為 <code>primary_key</code> ,這類別的字段會分配一個全域唯一的值給每一個實例(instance),也就是任何一本你能在圖書館找到的書。</li>
+ <li><code>DateField</code> 會被用來設定 <code>due_back</code> 的日期(紀錄書本何時會被歸還,可再被使用,或者是否正在保養期),這個字段允許 <code>blank</code> 或 <code>null</code> 值,而當元數據模型 (<code>Class Meta</code>)收到請求(query)時也會使用此字段來做資料排序。</li>
+ <li> <code>status</code> 是一個 <code>CharField</code> 字段,用來定義一個選項列表。你可以看到,我們定義了一個包含「鍵-值對元組」的元組(tuple) 並使其成為選項的參數,鍵-值對中的值會陳列出來並可以被使用者選擇,當選項被選定後,鍵(key)也會被儲存下來。我們也設定了預設的鍵值為 "m" (maintenance) 用來表示當每本書在初始創造還未放上書架時是不可被使用的。</li>
+</ul>
+
+<p>而 <code>__str__()</code> 模型用來表示 <code>BookInstance</code> 這個物件的「唯一 ID」和「相關之 <code>Book</code> 書本名稱(title)」的組合。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 關於 Python 的小提醒:</p>
+
+<ul>
+ <li>從 Python3.6 開始,你可以使用「字串插值語法」(又稱做 f-string):<br>
+ <code>f'{self.id} ({self.book.title})'</code></li>
+ <li>在舊版 Python 這部分的教學中,我們則使用了另一種有效的 <a href="https://www.python.org/dev/peps/pep-3101/">formatted string</a> 語法<br>
+ (e.g. <code>'{0} ({1})'.format(self.id,self.book.title)</code>)</li>
+</ul>
+</div>
+
+<h3 id="作者模型Author_model">作者模型(Author model)</h3>
+
+<p>複製下方 <code>Author</code> 的模型程式碼並貼在 <strong>models.py</strong> 文件的最下方。</p>
+
+<p>現在所有的字段(fields)與方法(methods)你應該都熟悉了,此模型定義了作者的「名」、「姓」、「出生年月日」、「死亡日期(非必填)」。該模型也指定,預設情況下,<code>__str__()</code> 方法會回傳作者姓名(按照姓、名排序)。而 <code>get_absolute_url()</code> 方法會反轉 author-detail 的URL映射,來獲得顯示單個作者的URL。</p>
+
+<pre class="brush: python notranslate">class Author(models.Model):
+    """Model representing an author."""
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    class Meta:
+        ordering = ['last_name', 'first_name']
+
+    def get_absolute_url(self):
+        """Returns the url to access a particular author instance."""
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        """String for representing the Model object."""
+        return f'{self.last_name}, {self.first_name}'
+
+</pre>
+
+<h2 id="再次執行資料庫遷移database_migrations">再次執行資料庫遷移(database migrations)</h2>
+
+<p>你的所有模型都建立好了,現在必須再次執行你的資料庫 migrations 指令來將這些修改內容更信到資料庫中。</p>
+
+<pre class="notranslate"><code>python3 manage.py makemigrations
+python3 manage.py migrate</code></pre>
+
+<h2 id="語言模型Language_model_—_挑戰">語言模型(Language model) — 挑戰</h2>
+
+<p>請想像一下,現在來了一位善心人士捐了一堆用不同語言寫的書(例如:波斯語),而你的挑戰是必須制定一個最好在我們的圖說館網站呈現的方式,並把它做成模組。</p>
+
+<p>幾件事情需要思考:</p>
+
+<ul>
+ <li>「語言」需要與 <code>Book</code> 、<code>BookInstance</code> 或其他物件(Object)相關聯嗎?</li>
+ <li>「不同語言」能以什麼形式來表示?<br>
+ 模型?自由文本字段(free text field)?硬編碼選擇列表(hard-coded selection list)?</li>
+</ul>
+
+<p>當你決定好了,就開始動手吧!你可以在<a href="https://github.com/mdn/django-locallibrary-tutorial/blob/master/catalog/models.py">Github的這裡</a>看到我們是怎麼思考的。</p>
+
+<ul>
+</ul>
+
+<ul>
+</ul>
+
+<h2 id="小結">小結</h2>
+
+<p>在這篇文章我們學到如何定義模型,並且利用這些資訊來設計與實作適合的模型給 <em>LocalLibrary 網站。</em></p>
+
+<p><em>再來我們要稍微撇開建立網站,先來看看 Django 的管理站(Django Administration site),這個管理站能讓我們加入一些資料到圖書館中,讓我們再來能夠透過「示圖(views)與模板(templates)」(當然我們現在都還沒建立)來展示。</em></p>
+
+<h2 id="延伸閱讀">延伸閱讀</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial02/">Writing your first Django app, part 2</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/db/queries/">Making queries</a> (Django Docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/querysets/">QuerySet API Reference</a> (Django Docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/sessions/index.html b/files/zh-tw/learn/server-side/django/sessions/index.html
new file mode 100644
index 0000000000..86b534adaf
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/sessions/index.html
@@ -0,0 +1,185 @@
+---
+title: 'Django Tutorial Part 7: Sessions framework'
+slug: Learn/Server-side/Django/Sessions
+translation_of: Learn/Server-side/Django/Sessions
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">本教程擴展了我們的<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站,為主頁添加了一個基於會話的訪問計數器。這是一個相對簡單的例子,但它確實顯示了,如何使用會話框架,為匿名用戶提供持久的行為。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand how sessions are used.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>我們在之前的教程中創建的<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 網站允許用戶瀏覽目錄中的書籍和作者。 雖然內容是從數據庫動態生成的,但每個用戶在使用該網站時基本上都可以訪問相同的頁面和信息類型。</p>
+
+<p>在一個"真實"的庫中,您可能希望根據用戶以前對網站的使用,首選項等為單個用戶提供定制的體驗。例如,您可以隱藏或存儲用戶下次訪問網站時之前已確認的警告消息,或尊重他們的偏好(例如,他們希望在每個頁面上顯示的搜索結果的數量)。</p>
+
+<p>會話框架允許您實現這種行為,從而允許您基於每個站點訪問者存儲和檢索任意數據。</p>
+
+<h2 id="What_are_sessions">What are sessions?</h2>
+
+<p>Web瀏覽器和服務器之間的所有通信都是通過HTTP協議進行的,該協議是無狀態的。該協議是無狀態的事實意味著客戶端和服務器之間的消息是完全相互獨立的-沒有基於先前消息的“序列”或行為的概念。因此,如果您想擁有一個跟踪與客戶之間正在進行的關係的站點,則需要自己實施。</p>
+
+<p>會話是Django(以及大多數Internet)使用的機制,用於跟踪站點與特定瀏覽器之間的“狀態”。會話允許您在每個瀏覽器中存儲任意數據,並且只要瀏覽器連接,該數據就可用於站點。然後,與會話相關聯的單個數據項被一個``鍵''引用,該鍵既用於存儲又用於檢索數據。</p>
+
+<p>Django使用包含特殊會話ID的cookie來標識每個瀏覽器及其與站點的關聯會話。默認情況下,實際會話數據默認存儲在站點數據庫中(這比將數據存儲在cookie中更安全,因為cookie在cookie中更容易受到惡意用戶的攻擊)。您可以將Django配置為將會話數據存儲在其他位置(緩存,文件或是“安全” Cookie),但是默認位置是一個很好且相對安全的選擇。</p>
+
+<h2 id="Enabling_sessions">Enabling sessions</h2>
+
+<p>當我們<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Django/skeleton_website">創建框架網站</a>時(在教程2中),將自動啟用會話。</p>
+
+<p>在項目文件的<code>INSTALLED_APPS</code> 和<code>MIDDLEWARE</code> 部分中進行配置(<strong>locallibrary/locallibrary/settings.py</strong>),如下所示:</p>
+
+<pre class="brush: python notranslate">INSTALLED_APPS = [
+ ...
+<strong> 'django.contrib.sessions',</strong>
+ ....
+
+MIDDLEWARE = [
+ ...
+<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong>
+ ....</pre>
+
+<h2 id="Using_sessions">Using sessions</h2>
+
+<p>您可以從<code>request</code> 參數(作為視圖的第一個參數傳入的<code>HttpRequest</code> )中訪問視圖中的<code>session</code> 屬性。 此會話屬性表示與當前用戶的特定連接(或更確切地說,與當前瀏覽器的連接,由該站點的瀏覽器cookie中的會話ID標識)。</p>
+
+<p><code>session</code> 屬性是一個類似於字典的對象,您可以在視圖中隨意讀取和寫入多次,並根據需要對其進行修改。 您可以執行所有正常的字典操作,包括清除所有數據,測試是否存在鍵,循環訪問數據等。儘管如此,在大多數情況下,您只會使用標準的``字典''API來獲取和設置值。</p>
+
+<p>下面的代碼片段顯示瞭如何獲取,設置和刪除與當前會話(瀏覽器)相關的鍵“ <code>my_car</code>”的某些數據。</p>
+
+<div class="note">
+<p><strong>注意</strong>: Django的一大優點是,您無需考慮將會話綁定到視圖中當前請求的機制。 如果我們在視圖中使用以下片段,我們將知道有關<code>my_car</code> 的信息僅與發送當前請求的瀏覽器相關聯。</p>
+</div>
+
+<pre class="brush: python notranslate"># Get a session value by its key (e.g. 'my_car'), raising a KeyError if the key is not present
+my_car = request.session['my_car']
+
+# Get a session value, setting a default if it is not present ('mini')
+my_car = request.session.get('my_car', 'mini')
+
+# Set a session value
+request.session['my_car'] = 'mini'
+
+# Delete a session value
+del request.session['my_car']
+</pre>
+
+<p>該API還提供了許多其他方法,這些方法主要用於管理關聯的會話cookie。 例如,有一些方法可以測試客戶端瀏覽器是否支持cookie,設置和檢查cookie到期日期以及從數據存儲中清除過期的會話。 您可以在如 <a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> 找到完整的API(Django文檔)。</p>
+
+<h2 id="Saving_session_data">Saving session data</h2>
+
+<p>默認情況下,當會話已被修改(分配)或刪除時,Django僅保存到會話數據庫並將會話cookie發送給客戶端。 如果您要使用上一節中所示的會話密鑰更新某些數據,則無需擔心! 例如:</p>
+
+<pre class="brush: python notranslate"># This is detected as an update to the session, so session data is saved.
+request.session['my_car'] = 'mini'</pre>
+
+<p>如果您要更新會話數據中的某些信息,則Django將不會識別您已對會話進行了更改並保存了數據(例如,如果要在“ <code>my_car</code>”數據中更改“ <code>wheels</code>”數據, 如下所示)。 在這種情況下,您需要將會話明確標記為已修改。</p>
+
+<pre class="brush: python notranslate"># Session object not directly modified, only data within the session. Session changes not saved!
+request.session['my_car']['wheels'] = 'alloy'
+
+# Set session as modified to force data updates/cookie to be saved.
+<code>request.session.modified = True</code>
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>:您可以更改行為,以便站點可以通過在您的項目設置(<strong>locallibrary/locallibrary/settings.py</strong>)中添加<code>SESSION_SAVE_EVERY_REQUEST = True</code> 來更新每個請求的數據庫/發送cookie。</p>
+</div>
+
+<h2 id="Simple_example_—_getting_visit_counts">Simple example — getting visit counts</h2>
+
+<p>作為一個簡單的真實示例,我們將更新我們的庫以告知當前用戶他們訪問LocalLibrary主頁的次數。</p>
+
+<p>打開/ <strong>/locallibrary/catalog/views.py</strong>,然後進行以下粗體顯示的更改。</p>
+
+<pre class="brush: python notranslate">def index(request):
+ ...
+
+ num_authors = Author.objects.count() # The 'all()' is implied by default.
+
+<strong> # Number of visits to this view, as counted in the session variable.
+ num_visits = request.session.get('num_visits', 0)
+ request.session['num_visits'] = num_visits + 1</strong>
+
+<strong> context = {
+ 'num_books': num_books,
+ 'num_instances': num_instances,
+ 'num_instances_available': num_instances_available,
+ 'num_authors': num_authors,
+ 'num_visits': num_visits,
+ }</strong>
+
+ # Render the HTML template index.html with the data in the context variable.
+ return render(request, 'index.html', context=context)</pre>
+
+<p>在這裡,我們首先獲取<code>'num_visits'</code>會話密鑰的值,如果之前未設置,則將其設置為0。 每次接收到請求時,我們都將增加該值並將其存儲回會話中(對於下一次用戶訪問該頁面)。 然後將<code>num_visits</code> 變量傳遞到我們的上下文變量中的模板。</p>
+
+<div class="note">
+<p><strong>注意:</strong>我們也可能會在此處測試瀏覽器是否甚至支持cookie(例如,請參閱<a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a>)或設計我們的UI,以便無論是否支持cookie都無關緊要。</p>
+</div>
+
+<p>將以下區塊底部看到的行添加到``動態內容''部分底部的主HTML模板(<strong>/locallibrary/catalog/templates/index.html</strong>)中以顯示上下文變量:</p>
+
+<pre class="brush: html notranslate">&lt;h2&gt;Dynamic content&lt;/h2&gt;
+
+&lt;p&gt;The library has the following record counts:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;&lt;strong&gt;Books:&lt;/strong&gt; \{{ num_books }}&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies:&lt;/strong&gt; \{{ num_instances }}&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies available:&lt;/strong&gt; \{{ num_instances_available }}&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Authors:&lt;/strong&gt; \{{ num_authors }}&lt;/li&gt;
+&lt;/ul&gt;
+
+<strong>&lt;p&gt;You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.&lt;/p&gt;</strong>
+</pre>
+
+<p>保存更改,然後重新啟動測試服務器。 每次刷新頁面時,數字都會更新。</p>
+
+<h2 id="總結">總結</h2>
+
+<p>現在,您知道使用會話來改善與匿名用戶的交互是多麼容易。</p>
+
+<p>在接下來的文章中,我們將說明身份驗證和授權(權限)框架,並向您展示如何支持用戶帳戶。</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/skeleton_website/index.html b/files/zh-tw/learn/server-side/django/skeleton_website/index.html
new file mode 100644
index 0000000000..b57b351eae
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/skeleton_website/index.html
@@ -0,0 +1,388 @@
+---
+title: 'Django 教學 2: 創建一個骨架網站'
+slug: Learn/Server-side/Django/skeleton_website
+translation_of: Learn/Server-side/Django/skeleton_website
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">Django 教學的第二篇文章,會展示怎樣創建一個網站的"框架",在這個框架的基礎上,你可以繼續填充整站使用的 settings, urls,模型(models),視圖(views)和模板(templates )。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>創建 Django 的開發環境。複習 Django 教學。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>能夠使用 Django 提供的工具,搭建你自己的網站。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>這篇文章會展示怎樣創建一個網站的"框架",在這個框架的基礎上,你可以繼續填充整站使用的settings, urls,模型(models),視圖(views)和模板(templates)(我們會在接下來的文章裡討論)。</p>
+
+<p>搭建 “框架” 的過程很直接:</p>
+
+<ol>
+ <li>使用 <code style="font-style: normal; font-weight: normal; line-height: 1.5;">django-admin</code>工具創建工程的文件夾,基本的文件模板和工程管理腳本(<strong style="line-height: 1.5;">manage.py</strong>)。</li>
+ <li>用 <strong>manage.py</strong> 創建一個或多個<em>應用</em>。
+ <div class="note">
+ <p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 14px; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>一個網站可能由多個部分組成,比如,主要頁面,博客,wiki,下載區域等。</font><font>Django鼓勵將這些部分作為分開的應用開發。</font><font>如果這樣的話,在需要可以在不同的工程中復用這些應用。</font></font></p>
+ </div>
+ </li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>工程裡註冊新的應用。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>為每個應用分配url。</font></font></li>
+</ol>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>為 <span> </span></font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>locallibrary</font></font></a><font><font><span> </span> 這個項目創建的網站文件夾和它的工程文件夾都命名為</font></font><em><font><font>locallibrary</font></font></em><font><font>。</font><font>我們只創建一個名為</font></font><em><font><font>catalog</font></font></em><font><font>的應用。</font><font>最高層的項目文件結構如下所示:</font></font></p>
+
+<pre class="brush: bash"><em>locallibrary/ # Website folder</em>
+  <strong>manage.py </strong># Script to run Django tools for this project (created using django-admin)
+  <em>locallibrary/ # Website/project folder </em>(created using django-admin)
+ <em>catalog/ # Application folder </em>(created using manage.py)
+</pre>
+
+<p><font>接下來的部分,會詳細討論創建網站框架的過程,並會展示怎麼測試這些變化。</font><font>最後,我們會討論在這個階段裡,你可以設置的全站配置。</font></p>
+
+<h2 id="創建專案項目">創建專案項目</h2>
+
+<p>首先打開命令提示符/終端,確保您在<a href="/zh-TW/docs/Learn/Server-side/Django/development_environment#Using_a_virtual_environment">虛擬環境</a>中,導航到您要存放Django應用程序的位置(在文檔文件夾中,輕鬆找到它的位置),並為您的新網站,創建一個文件夾(在這種情況下:locallibrary)。然後使用cd命令進入該文件夾:</p>
+
+<pre class="brush: bash">mkdir locallibrary
+cd locallibrary</pre>
+
+<p><font><font>用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>django-admin startproject</code><font><font>命令創建新項目,並進入該文件夾。</font></font></p>
+
+<pre class="brush: bash">django-admin startproject locallibrary
+cd locallibrary</pre>
+
+<p><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>django-admin</code><font><font>工具會創建如下所示的文件夾結構</font></font></p>
+
+<pre class="brush: bash line-numbers language-bash"><code class="language-bash"><em>locallibrary/</em>
+  manage.py
+  <em>locallibrary/</em>
+ __init__.py
+    settings.py
+    urls.py
+    wsgi.py</code></pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>locallibrary項目的子文件夾是整個網站的進入點:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><strong>__init__.py</strong> 是一個空文件,指示 Python 將此目錄視為 Python 套件。</li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>settings.py</font></font></strong><font><font><span> </span> 包含所有的網站設置。</font><font>這是可以註冊所有創建的應用的地方,也是靜態文件,數據庫配置的地方,等等。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>urls.py</font></font></strong><font><font>定義了網站url到view的映射</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>。</font></font></strong><font><font>雖然這裡可以包含所有的url,但是更常見的做法是把應用相關的url包含在相關應用中,你可以在接下來的教程裡看到。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><strong style="border: 0px; font-style: normal !important; line-height: 1.5; margin: 0px; padding: 0px;"><font><font>wsgi.py<span> </span></font></font></strong><span style="border: 0px; font-style: normal !important; line-height: 1.5; margin: 0px; padding: 0px;"><font><font> 幫助Django應用和網絡服務器間的通訊。</font><font>你可以把這個當作模板。</font></font></span></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>manage.py</font></font></strong><font><font>腳本可以創建應用,和資料庫通訊,啟動開發用網絡服務器。</font></font></p>
+
+<h2 id="創建_catalog_應用">創建 catalog 應用</h2>
+
+<p><font><font>接下來,在locallibrary項目裡,使用下面的命令創建catalog應用(和您項目的</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>manage.py</font></font></strong><font><font>在同一個文件夾下)</font></font></p>
+
+<pre class="brush: bash">python3 manage.py startapp catalog</pre>
+
+<div class="note">
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><span style="border: 0px; font-size: 14px; font-style: normal !important; margin: 0px; padding: 0px;"><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>注意:</font></font></strong><font><font><span> </span>Linux/Mac OS X應用可以使用上面的命令。</font><font>在windows平台下應該改為:</font></font></span> <code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>py -3 manage.py startapp catalog</code></p>
+
+<p style='font-style: normal; margin: 0px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><font><font>如果你是windows系統,在這個部分用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>py -3</code><font><font>替代</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>python3</code><font><font>。</font></font></p>
+
+<p>如果您使用的是Python 3.7.0,則應使用<code>py manage.py startapp catalog</code></p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>這個工具創建了一個新的文件夾,並為該應用創建了不同的文件(下面黑體所示)。</font><font>絕大多數文件的命名和它們的目的有關(比如視圖函數就是</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>views.py,</font></font></strong><font><font>模型就是</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>models.py,</font></font></strong><font><font>測試是</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>tests.py,</font></font></strong><font><font>網站管理設置是</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>admin.py,</font></font></strong><font><font>註冊應用是</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>apps.py)</font></font></strong><font><font>,並且還包含了為項目所用的最小模板。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>執行命令後的文件夾結構如下所示:</font></font></p>
+
+<pre class="brush: bash"><em>locallibrary/</em>
+  manage.py
+  <em>locallibrary/
+</em><strong>  <em>catalog/</em>
+      admin.py
+      apps.py
+      models.py
+      tests.py
+      views.py
+      __init__.py
+  <em>migrations/</em></strong>
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>除上面所說的文件外,我們還有:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>一個</font></font><em><font><font>migration</font></font></em><font><font>文件夾,用來存放 “migrations” ——當你修改你的數據模型時,這個文件會自動升級你的資料庫。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>__init__.py</font></font></strong><font><font><span> </span>—一個空文件,Django/Python會將這個文件作為</font></font><a class="external external-icon" href="https://docs.python.org/3/tutorial/modules.html#packages" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Python套件包</font></font></a><font><font>並允許你在項目的其他部分使用它。</font></font></li>
+</ul>
+
+<div class="note">
+<p><span style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 14px; font-style: normal; font-weight: 400; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>注意</font></font></strong></span><font><font><span> </span>:你注意到上面的文件裡有些缺失嘛?</font><font>儘管有了 views 和 models 的文件,可是 url 映射,網站模板,靜態文件在哪裡呢?</font><font>我們會在接下來的部分展示如何創建它們(並不是每個網站都需要,不過這個例子需要)。</font></font></p>
+</div>
+
+<h2 id="註冊catalog應用"><font><font>註冊catalog應用</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>既然應用已經創建好了,我們還必須在項目裡註冊它,以便工具在運行時它會包括在裡面(比如在數據庫裡添加模型時)。</font><font>在項目的settings裡,把應用添加進</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>INSTALLED_APPS</code><font><font> ,就完成了註冊。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開項目設置文件 <span> </span></font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>locallibrary/locallibrary/settings.py</font></font></strong><font><font>找到  <span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>INSTALLED_APPS</code><font><font> 列表裡的定義。</font><font>如下所示,在列表的最後添加新的一行。</font></font></p>
+
+<pre class="brush: bash">INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+<strong> 'catalog.apps.CatalogConfig', </strong>
+]</pre>
+
+<p><font><font>新的這行,詳細說明了應用配置文件在(<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>CatalogConfig</code><font><font>) </font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>/locallibrary/catalog/apps.py</font></font></strong><font><font><span> </span> 裡,當你創建應用時就完成了這個過程。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>:注意到</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>INSTALLED_APPS已经有许多其他的应用了</code><font><font> (還有 </font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>MIDDLEWARE</code><font><font>,在settings的下面)。</font><font>這些應用為  <span> </span></font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Admin_site" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 243, 212);'><font><font>Django administration site</font></font></a><font><font><span> </span> 提供了支持和許多功能(包括會話,認證系統等)。</font></font></p>
+</div>
+
+<h2 id="配置資料庫"><font><font>配置資料庫</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>現在可以為項目配置資料庫了——為了避免性能上的差異,最好在生產和開發中使用同一種資料庫。你可以在</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/settings/#databases" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>資料庫</font></font></a><font><font><span> </span> 裡找到不同的設置方法(Django文檔)。 </font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在這個項目裡,我們使用SQLite。</font><font>因為在展示用的數據庫中,我們不會有很多並發存取的行為。</font><font>同時,也因為SQLite不需要額外的配置工作。</font><font>你可以在</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>settings.py</font></font></strong><font><font>裡看到這個數據庫怎樣配置的。</font><font>(更多信息如下所示)</font></font></p>
+
+<pre class="brush: python">DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+</pre>
+
+<p><font>因為我們使用SQLite,不需要其他的設置了。</font><font>我們繼續吧!</font></p>
+
+<h2 id="其他項目設置"><font><font>其他項目設置</font></font></h2>
+
+<p><font><font>settings.py裡還包括其他的一些設置,現在只需要改變</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-TIME_ZONE" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>時區</font></font></a><font><font><span> </span>—改為和標準</font></font><a class="external external-icon" href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>tz時區數據表</font></font></a><font><font><span> </span> 裡的字符串相同就可以了(數據表裡的TZ列有你想要的時區)。</font><font>把</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>TIME_ZONE</code><font><font>的值改為你的時區,比如</font></font></p>
+
+<pre class="brush: python">TIME_ZONE = 'Europe/London'</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>有兩個設置你現在不會用到,不過你應該留意:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>SECRET_KEY</code><font><font>. 這個密匙值,是Django網站安全策略的一部分。</font><font>如果在開發環境中,沒有保護好這個密匙,把代碼投入生產環境時,最好用不同的密匙代替。</font><font>(可能從環境變量或文件中讀取)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>DEBUG</code><font><font>. 這個會在debug日誌裡輸出錯誤信息,而不是輸入H​​TTP的返回碼。</font><font>在生產環境中,它應設置為false,因為輸出的錯誤信息,會幫助想要攻擊網站的人。</font></font></li>
+</ul>
+
+<h2 id="鏈接URL映射器"><font><font>鏈接URL映射器</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在項目文件夾裡,創建網站時同時生成了URL映射器(</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>urls.py</font></font></strong><font><font>)。</font><font>儘管你可以用它來管理所有的URL映射,但是更常用的做法是把URL映射留到它們相關的應用中。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>locallibrary/locallibrary/urls.py</font></font></strong><font><font><span> </span> 注意指導文字解釋了一些使用URL映射器的方法。</font></font></p>
+
+<pre class="brush: python">"""locallibrary URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/2.0/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+]
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>URL映射通過</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>urlpatterns</code><font><font> 變量管理,它是一個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>path()</code><font><font>函數的Python列表。</font><font>每個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>path()</code><font><font>函數,要么將URL式樣(URL pattern)關聯到特定視圖(<span> </span></font></font><em><font><font>specific view)</font></font></em><font><font>,當模式匹配時將會顯示,要么關聯到某個URL式樣列表的測試代碼。</font><font>(第二種情況下,URL式樣是目標模型裡的“基本URL”).<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>urlpatterns</code><font><font> 列表初始化定義了單一函數,把所有帶有 </font></font>'admin/' 模式的 <font><font>URL,映射到<code>admin.site.urls</code>。這個函數,包含了Administration應用自己的URL映射定義。</font></font></p>
+
+<div class="note">
+<p><strong>注意</strong>: <code>path()</code>中的路由是一個字符串,用於定義要匹配的URL模式。該字符串可能包括一個命名變量(在尖括號中),例如<code>'catalog/&lt;id&gt;/'</code>。此模式將匹配<strong> /catalog/</strong><em>any_chars</em><strong>/</strong> 等URL,並將any_chars 作為參數名稱為<code>id</code> 的字符串,傳遞給視圖。我們將在後面的主題中,進一步討論路徑方法和路由模式</p>
+</div>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>在</span><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>urlpatterns</code><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'> 列表的下面一行,插入下面的代码。</span>這個新項目包括一個 <code>path()</code> ,它使用模式 <code>catalog/</code> 轉發請求到模塊 <code>catalog.urls</code>(具有相對 URL <strong>/catalog/urls.py </strong>的文件)。</p>
+
+<pre class="brush: python"># Use include() to add paths from the catalog application
+from django.conf.urls import include
+from django.urls import path
+
+urlpatterns += [
+    path('catalog/', include('catalog.urls')),
+]
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>現在我們把我們網站的根URL(例如</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>127.0.0.1:8000</code><font><font>),重新導向URL<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>127.0.0.1:8000/catalog/</code><font><font>;這是項目中唯一的應用,所以我們最好這樣做。</font><font>為了完成這個目標,我們使用一個特別的視圖函數(<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>RedirectView</code><font><font>),當</font></font><code>path()</code><font><font>函數中的 url 式樣被識別以後(在這個例子中是根 url),就會把第一個參數,也就是新的相對 URL ,重定向到(</font></font><code>/catalog/</code><font><font>)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>把下面的代碼加到文件最後:</font></font></p>
+
+<pre class="brush: python">#Add URL maps to redirect the base URL to our application
+from django.views.generic import RedirectView
+urlpatterns += [
+ path('', RedirectView.as_view(url='/catalog/')),
+]</pre>
+
+<p>將路徑函數的第一個參數留空,用以表示'/'。如果您將第一個參數寫為'/',Django會在您啟動開發服務器時給出以下警告:</p>
+
+<pre class="brush: python">System check identified some issues:
+
+WARNINGS:
+?: (urls.W002) Your URL pattern '/' has a route beginning with a '/'.
+Remove this slash as it is unnecessary.
+If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'.
+</pre>
+
+<p>Django默認不提供CSS,JavaScript和圖像等靜態文件,但在創建站點時,開發Web服務器這樣做是有用的。作為此URL映射器的最終添加,您可以通過附加以下幾行,在開發期間啟用靜態文件的提供。</p>
+
+<p>現在將以下最終區塊,添加到文件的底部:</p>
+
+<pre><code># Use static() to add url mapping to serve static files during development (only)
+from django.conf import settings
+from django.conf.urls.static import static
+
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code>
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 有許多方法可以擴充<code>urlpatterns</code>列表(上面我們只是使用<code>+= </code>運算符,附加一個新的列表項,來清楚地分隔舊代碼和新代碼)。我們可以改為在原始列表定義中,包含這個新的模式映射:</p>
+
+<pre class="brush: python">urlpatterns = [
+  path('admin/', admin.site.urls),
+  path('catalog/', include('catalog.urls')),
+ path('', RedirectView.as_view(url='/catalog/', permanent=True)),
+] + <code>static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code>
+</pre>
+
+<p>此外,我們將導入行(<code>from django.urls import include</code>)包含在使用它的代碼中(因此很容易看到我們添加的內容),但通常將所有導入行包含在一個Python文件的頂部。</p>
+</div>
+
+<p>最後一步,在<strong>catalog</strong>文件夾中,創建一個名為<strong>urls.py</strong>的文件,並添加以下文本,以定義(空)導入的<code>urlpatterns</code>。這是我們在構建應用程序時,添加模式的地方。</p>
+
+<pre class="brush: python">from django.urls import path
+from . import views
+
+
+urlpatterns = [
+
+]
+</pre>
+
+<h2 id="測試網站框架"><font><font>測試網站框架</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>現在我們有了一個完整的框架項目。</font><font>這個網站現在還什麼都不能做,但是我們仍然要運行,以確保我們的更改是有效的。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在運行前,我們應該先運行</font></font><em><font><font>數據庫遷移</font></font></em><font><font>。</font><font>這會更新我們的數據庫並且包含所有安裝的應用(同時去除一些警告)。</font></font></p>
+
+<h3 id="運行資料庫遷移">運行資料庫遷移</h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>Django使用對象關係映射器(ORM),將Django代碼中的模型定義,映射到底層資料庫使用的數據結構。</font><font>當我們更改模型定義時,Django會跟踪更改,並創建資料庫遷移腳本(位於<span> </span></font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/locallibrary/catalog/migrations/</font></font></strong><font><font><span> </span>),來自動遷移資料庫中的底層數據結構。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>當我們創建網站時,Django會自動添加一些模型,供網站的管理部分使用(稍後我們會解釋)。</font><font>運行以下命令,來定義資料庫中這些模型的表(確認你位於包含 </font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>manage.py </font></font></strong><font><font>的目錄中):</font></font></p>
+
+<pre class="brush: bash">python3 manage.py makemigrations
+python3 manage.py migrate
+</pre>
+
+<div class="warning">
+<p><strong>重要</strong>: <span style='background-color: #ffe7e8; color: #333333; display: inline !important; float: none; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>每次模型改變,都需要運行以上命令,來影響需要存放的數據結構(包括添加和刪除整個模型和單個字段)。</span></p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>makemigrations</code></strong><font><font>命令,創建(但不實施)項目中安裝的所有應用程序的遷移(你可以指定應用程序名稱,也可以為單個項目運行遷移)。</font><font>這讓你有機會在應用這些遷移之前,檢查這些遷移代碼—當你是Django專家時,你可以選擇稍微調整它們。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>這個 </font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>migrate</code></strong><font><font>命令,真正對你的資料庫實施遷移(Django跟踪哪些已添加到當前資料庫)。</font></font></p>
+
+<div class="note">
+<p><strong>注意</strong>: 參見 <a href="https://docs.djangoproject.com/en/2.0/topics/migrations/">Migrations</a> (Django 文件) <span style='background-color: #fff3d4; color: #333333; display: inline !important; float: none; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>,了解較少使用的遷移命令的其他信息。</span></p>
+</div>
+
+<h3 id="運行網站">運行網站</h3>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>在開發期間,你首先要使用開發網頁服務器,然後用你本機的瀏覽器觀看,來測試你的網站。</span></p>
+
+<div class="note">
+<p><strong>注意</strong>: <font><font>這個開發網頁服務器並不夠強大,不足以用於生產使用,但是它使你在開發期間,能非常容易獲得你的 Django 網站和運行它,以此來進行快速測試。默認情況下,服務器會開通(http://127.0.0.1:8000/),但你也可以選擇其他端口。有關更多信息,查閱(</font></font><a class="external external-icon" href="https://docs.djangoproject.com/en/1.10/ref/django-admin/#runserver" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>django-admin and manage.py: runserver</font></font></a><font><font>)(Django docs).</font></font></p>
+</div>
+
+<p><font><font>通過如下</font></font><code>runserver</code><font><font>命令,運行開發網頁服務器。(同樣的要在</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>manage.py</font></font></strong><font><font>的目錄)</font></font></p>
+
+<pre class="brush: bash">python3 manage.py runserver
+
+ Performing system checks...
+
+ System check identified no issues (0 silenced).
+ September 22, 2016 - 16:11:26
+ Django version 1.10, using settings 'locallibrary.settings'
+ Starting development server at http://127.0.0.1:8000/
+ Quit the server with CTRL-BREAK.
+</pre>
+
+<p><font><font>一旦服務器運行,你可以用你的瀏覽器導航到</font></font><a class="external external-icon" href="http://127.0.0.1:8000/" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>http://127.0.0.1:8000/</font></font></a><font><font> 查看。你應該會看到一個錯誤頁面,如下。</font></font></p>
+
+<p><img alt="Django Debug page for Django 2.0" src="https://mdn.mozillademos.org/files/15729/django_404_debug_page.png"></p>
+
+<p><font><font>別擔心,這個錯誤頁面是預期的結果。</font><font>因為我們沒有在</font></font> <code>catalogs.urls</code><font><font>模塊中,定義任何頁面或網址(即是當我們使用一個指向根目錄的URL時,會被重新定向的地方)。</font></font></p>
+
+<div class="note">
+<p><strong>注意</strong>: 上面的頁面,演示了一個很棒的Django功能 - 自動除錯日誌記錄。只要找不到頁面,或者代碼引發任何錯誤,就會顯示錯誤畫面,其中包含有用的信息。在這種情況下,我們可以看到我們提供的URL,與我們的任何URL模式都不匹配(如列出的那樣)。在生產期間(當我們將網站放在網上時),日誌記錄將被關閉,在這種情況下,將提供信息量較少、但用戶友好的頁面。</p>
+</div>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>這個時候,我們知道Django正在工作!</span></p>
+
+<div class="note">
+<p><strong>注意</strong>: <font>在進行重大更改時,你應該重新運行遷移,並重新測試站點。這不需要很長時間!</font></p>
+</div>
+
+<h2 id="挑戰自我"><font><font>挑戰自我</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該 </font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>catalog/ <span> </span></font></font></strong><font><font>目錄包含應用程序的視圖、模型、和應用的其他部分,你可以打開這些文件並查看樣板。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>如上所述,管理站點的URL映射,已經添加到項目的</font></font> <strong>urls.py</strong><font><font>。</font><font>在瀏覽器中查看管理區域,看看會發生什麼(你可以從上面映射,推斷正確的URL)。</font></font></p>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>你現在已經創建了一個完整的骨架網站項目,你可以繼續加入網址、模型、視圖、和模版。</font></font></p>
+
+<p><font><font>現在,</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>Local Library website</font></font></a><font><font>的骨架已經完成並運行了,是時候開始</font></font>寫些代碼,讓網站做些它應該做的事了。</p>
+
+<h2 id="參見">參見</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial01/">Writing your first Django app - part 1</a>  (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/applications/#configuring-applications">Applications</a> (Django Docs). Contains information on configuring applications.</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</p>
+
+
+
+<h2 id="本教程連結">本教程連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/testing/index.html b/files/zh-tw/learn/server-side/django/testing/index.html
new file mode 100644
index 0000000000..d559585a50
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/testing/index.html
@@ -0,0 +1,907 @@
+---
+title: 'Django Tutorial Part 10: Testing a Django web application'
+slug: Learn/Server-side/Django/Testing
+translation_of: Learn/Server-side/Django/Testing
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">隨著網站的增長,他們越來越難以手動測試。不僅要進行更多的測試,而且隨著組件之間的互動,變得越來越複雜,一個區域的小改變,可能會影響到其他區域,所以需要做更多的改變,來確保一切正常運行,並且在進行更多更改時,不會引入錯誤。減輕這些問題的一種方法,是編寫自動化測試,每當您進行更改時,都可以輕鬆可靠地運行測試。本教程演示如何使用 Django 的測試框架,自動化您的網站的單元測試。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand how to write unit tests for Django-based websites.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Overview">Overview</h2>
+
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> currently has pages to display lists of all books and authors, detail views for <code>Book</code> and <code>Author</code> items, a page to renew <code>BookInstance</code>s, and pages to create, update, and delete <code>Author</code> items (and <code>Book</code> records too, if you completed the <em>challenge</em> in the <a href="/en-US/docs/Learn/Server-side/Django/Forms">forms tutorial</a>). Even with this relatively small site, manually navigating to each page and <em>superficially</em> checking that everything works as expected can take several minutes. As we make changes and grow the site, the time required to manually check that everything works "properly" will only grow. If we were to continue as we are, eventually we'd be spending most of our time testing, and very little time improving our code.</p>
+
+<p>Automated tests can really help with this problem! The obvious benefits are that they can be run much faster than manual tests, can test to a much lower level of detail, and test exactly the same functionality every time (human testers are nowhere near as reliable!) Because they are fast, automated tests can be executed more regularly, and if a test fails, they point to exactly where code is not performing as expected.</p>
+
+<p>In addition, automated tests can act as the first real-world "user" of your code, forcing you to be rigorous about defining and documenting how your website should behave. Often they are basis for your code examples and documentation. For these reasons, some software development processes start with test definition and implementation, after which the code is written to match the required behavior (e.g. <a href="https://en.wikipedia.org/wiki/Test-driven_development">test-driven</a> and <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">behaviour-driven</a> development).</p>
+
+<p>This tutorial shows how to write automated tests for Django, by adding a number of tests to the <em>LocalLibrary</em> website.</p>
+
+<h3 id="Types_of_testing">Types of testing</h3>
+
+<p>There are numerous types, levels, and classifications of tests and testing approaches. The most important automated tests are:</p>
+
+<dl>
+ <dt>Unit tests</dt>
+ <dd>Verify functional behavior of individual components, often to class and function level.</dd>
+ <dt>Regression tests</dt>
+ <dd>Tests that reproduce historic bugs. Each test is initially run to verify that the bug has been fixed, and then re-run to ensure that it has not been reintroduced following later changes to the code.</dd>
+ <dt>Integration tests</dt>
+ <dd>Verify how groupings of components work when used together. Integration tests are aware of the required interactions between components, but not necessarily of the internal operations of each component. They may cover simple groupings of components through to the whole website.</dd>
+</dl>
+
+<div class="note">
+<p><strong>Note: </strong>Other common types of tests include black box, white box, manual, automated, canary, smoke, conformance, acceptance, functional, system, performance, load, and stress tests. Look them up for more information.</p>
+</div>
+
+<h3 id="What_does_Django_provide_for_testing">What does Django provide for testing?</h3>
+
+<p>Testing a website is a complex task, because it is made of several layers of logic – from HTTP-level request handling, queries models, to form validation and processing, and template rendering.</p>
+
+<p>Django provides a test framework with a small hierarchy of classes that build on the Python standard <code><a href="https://docs.python.org/3/library/unittest.html#module-unittest" title="(in Python v3.5)">unittest</a></code> library. Despite the name, this test framework is suitable for both unit and integration tests. The Django framework adds API methods and tools to help test web and Django-specific behaviour. These allow you to simulate requests, insert test data, and inspect your application's output. Django also provides an API (<a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>) and tools for <a href="https://docs.djangoproject.com/en/2.0/topics/testing/advanced/#other-testing-frameworks">using different testing frameworks</a>, for example you can integrate with the popular <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> framework to simulate a user interacting with a live browser.</p>
+
+<p>To write a test you derive from any of the Django (or <em>unittest</em>) test base classes (<a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#simpletestcase">SimpleTestCase</a>, <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#transactiontestcase">TransactionTestCase</a>, <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">TestCase</a>, <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>) and then write separate methods to check that specific functionality works as expected (tests use "assert" methods to test that expressions result in <code>True</code> or <code>False</code> values, or that two values are equal, etc.) When you start a test run, the framework executes the chosen test methods in your derived classes. The test methods are run independently, with common setup and/or tear-down behaviour defined in the class, as shown below.</p>
+
+<pre class="brush: python">class YourTestClass(TestCase):
+
+    def setUp(self):
+  #Setup run before every test method.
+        pass
+
+    def tearDown(self):
+  #Clean up run after every test method.
+        pass
+
+    def test_something_that_will_pass(self):
+        self.assertFalse(False)
+
+    def test_something_that_will_fail(self):
+        self.assertTrue(False)
+</pre>
+
+<p>The best base class for most tests is <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">django.test.TestCase</a>.  This test class creates a clean database before its tests are run, and runs every test function in its own transaction. The class also owns a test <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.Client" title="django.test.Client">Client</a> that you can use to simulate a user interacting with the code at the view level. In the following sections we're going to concentrate on unit tests, created using this <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">TestCase</a> base class.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">django.test.TestCase</a> class is very convenient, but may result in some tests being slower than they need to be (not every test will need to set up its own database or simulate the view interaction). Once you're familiar with what you can do with this class, you may want to replace some of your tests with the available simpler test classes.</p>
+</div>
+
+<h3 id="What_should_you_test">What should you test?</h3>
+
+<p>You should test all aspects of your own code, but not any libraries or functionality provided as part of Python or Django.</p>
+
+<p>So for example, consider the <code>Author</code> model defined below. You don't need to explicitly test that <code>first_name</code> and <code>last_name</code> have been stored properly as <code>CharField</code> in the database because that is something defined by Django (though of course in practice you will inevitably test this functionality during development). Nor do you need to test that the <code>date_of_birth</code> has been validated to be a date field, because that is again something implemented in Django.</p>
+
+<p>However you should check the text used for the labels (<em>First name, Last_name, Date of birth, Died</em>), and the size of the field allocated for the text (<em>100 chars</em>), because these are part of your design and something that could be broken/changed in future.</p>
+
+<pre class="brush: python">class Author(models.Model):
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        return '%s, %s' % (self.last_name, self.first_name)</pre>
+
+<p>Similarly, you should check that the custom methods <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> and <code style="font-style: normal; font-weight: normal;">__str__()</code> behave as required because they are your code/business logic. In the case of <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> you can trust that the Django <code>reverse()</code> method has been implemented properly, so what you're testing is that the associated view has actually been defined.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Astute readers may note that we would also want to constrain the date of birth and death to sensible values, and check that death comes after birth. In Django this constraint would be added to your form classes (although you can define validators for the fields these appear to only be used at the form level, not the model level).</p>
+</div>
+
+<p>With that in mind lets start looking at how to define and run tests.</p>
+
+<h2 id="Test_structure_overview">Test structure overview</h2>
+
+<p>Before we go into the detail of "what to test", let's first briefly look at <em>where</em> and <em>how</em> tests are defined.</p>
+
+<p>Django uses the unittest module’s <a href="https://docs.python.org/3/library/unittest.html#unittest-test-discovery" title="(in Python v3.5)">built-in test discovery</a>, which will discover tests under the current working directory in any file named with the pattern <strong>test*.py</strong>. Provided you name the files appropriately, you can use any structure you like. We recommend that you create a module for your test code, and have separate files for models, views, forms, and any other types of code you need to test. For example:</p>
+
+<pre>catalog/
+  /tests/
+  __init__.py
+  test_models.py
+  test_forms.py
+  test_views.py
+</pre>
+
+<p>Create a file structure as shown above in your <em>LocalLibrary</em> project. The <strong>__init__.py</strong> should be an empty file (this tells Python that the directory is a package). You can create the three test files by copying and renaming the skeleton test file <strong>/catalog/tests.py</strong>.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The skeleton test file <strong>/catalog/tests.py</strong> was created automatically when we <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">built the Django skeleton website</a>. It is perfectly "legal" to put all your tests inside it, but if you test properly, you'll quickly end up with a very large and unmanageable test file.</p>
+
+<p>Delete the skeleton file as we won't need it.</p>
+</div>
+
+<p>Open <strong>/catalog/tests/test_models.py</strong>. The file should import <code>django.test.TestCase</code>, as shown:</p>
+
+<pre class="brush: python">from django.test import TestCase
+
+# Create your tests here.
+</pre>
+
+<p>Often you will add a test class for each model/view/form you want to test, with individual methods for testing specific functionality. In other cases you may wish to have a separate class for testing a specific use case, with individual test functions that test aspects of that use-case (for example, a class to test that a model field is properly validated, with functions to test each of the possible failure cases). Again, the structure is very much up to you, but it is best if you are consistent.</p>
+
+<p>Add the test class below to the bottom of the file. The class demonstrates how to construct a test case class by deriving from <code>TestCase</code>.</p>
+
+<pre class="brush: python">class YourTestClass(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        print("setUpTestData: Run once to set up non-modified data for all class methods.")
+        pass
+
+    def setUp(self):
+        print("setUp: Run once for every test method to setup clean data.")
+        pass
+
+    def test_false_is_false(self):
+        print("Method: test_false_is_false.")
+        self.assertFalse(False)
+
+    def test_false_is_true(self):
+        print("Method: test_false_is_true.")
+        self.assertTrue(False)
+
+    def test_one_plus_one_equals_two(self):
+        print("Method: test_one_plus_one_equals_two.")
+        self.assertEqual(1 + 1, 2)</pre>
+
+<p>The new class defines two methods that you can use for pre-test configuration (for example, to create any models or other objects you will need for the test):</p>
+
+<ul>
+ <li><code>setUpTestData()</code> is called once at the beginning of the test run for class-level setup. You'd use this to create objects that aren't going to be modified or changed in any of the test methods.</li>
+ <li><code>setUp()</code> is called before every test function to set up any objects that may be modified by the test (every test function will get a "fresh" version of these objects).</li>
+</ul>
+
+<div class="note">
+<p>The test classes also have a <code>tearDown()</code> method which we haven't used. This method isn't particularly useful for database tests, since the <code>TestCase</code> base class takes care of database teardown for you.</p>
+</div>
+
+<p>Below those we have a number of test methods, which use <code>Assert</code> functions to test whether conditions are true, false or equal (<code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code>). If the condition does not evaluate as expected then the test will fail and report the error to your console.</p>
+
+<p>The <code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code> are standard assertions provided by <strong>unittest</strong>.  There are other standard assertions in the framework, and also <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#assertions">Django-specific assertions</a> to test if a view redirects (<code>assertRedirects</code>), to test if a particular template has been used (<code>assertTemplateUsed</code>), etc.</p>
+
+<div class="note">
+<p>You should <strong>not </strong>normally include <strong>print()</strong> functions in your tests as shown above. We do that here only so that you can see the order that the setup functions are called in the console (in the following section).</p>
+</div>
+
+<h2 id="How_to_run_the_tests">How to run the tests</h2>
+
+<p>The easiest way to run all the tests is to use the command:</p>
+
+<pre class="brush: bash">python3 manage.py test</pre>
+
+<p>This will discover all files named with the pattern <strong>test*.py</strong> under the current directory and run all tests defined using appropriate base classes (here we have a number of test files, but only <strong>/catalog/tests/test_models.py</strong> currently contains any tests.) By default the tests will individually report only on test failures, followed by a test summary.</p>
+
+<div class="note">
+<p>If you get errors similar to: <code>ValueError: Missing staticfiles manifest entry ...</code> this may be because testing does not run <em>collectstatic</em> by default and your app is using a storage class that requires it (see <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage.manifest_strict">manifest_strict</a> for more information). There are a number of ways you can overcome this problem - the easiest is to simply run <em>collectstatic</em> before running the tests:</p>
+
+<pre class="brush: bash">python3 manage.py collectstatic
+</pre>
+</div>
+
+<p>Run the tests in the root directory of <em>LocalLibrary</em>. You should see an output like the one below.</p>
+
+<pre class="brush: bash">&gt;python3 manage.py test
+
+Creating test database for alias 'default'...
+<strong>setUpTestData: Run once to set up non-modified data for all class methods.
+setUp: Run once for every test method to setup clean data.
+Method: test_false_is_false.
+.setUp: Run once for every test method to setup clean data.
+Method: test_false_is_true.
+FsetUp: Run once for every test method to setup clean data.
+Method: test_one_plus_one_equals_two.</strong>
+.
+======================================================================
+FAIL: test_false_is_true (catalog.tests.tests_models.YourTestClass)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "D:\Github\django_tmp\library_w_t_2\locallibrary\catalog\tests\tests_models.py", line 22, in test_false_is_true
+    self.assertTrue(False)
+AssertionError: False is not true
+
+----------------------------------------------------------------------
+Ran 3 tests in 0.075s
+
+FAILED (failures=1)
+Destroying test database for alias 'default'...</pre>
+
+<p>Here we see that we had one test failure, and we can see exactly what function failed and why (this failure is expected, because <code>False</code> is not <code>True</code>!).</p>
+
+<div class="note">
+<p><strong>Tip: </strong>The most important thing to learn from the test output above is that it is much more valuable if you use descriptive/informative names for your objects and methods.</p>
+</div>
+
+<p>The text shown in <strong>bold</strong> above would not normally appear in the test output (this is generated by the <code>print()</code> functions in our tests). This shows how the <code>setUpTestData()</code> method is called once for the class and <code>setUp()</code> is called before each method.</p>
+
+<p>The next sections show how you can run specific tests, and how to control how much information the tests display.</p>
+
+<h3 id="Showing_more_test_information">Showing more test information</h3>
+
+<p>If you want to get more information about the test run you can change the <em>verbosity</em>. For example, to list the test successes as well as failures (and a whole bunch of information about how the testing database is set up) you can set the verbosity to "2" as shown:</p>
+
+<pre class="brush: bash">python3 manage.py test --verbosity 2</pre>
+
+<p>The allowed verbosity levels are 0, 1, 2, and 3, with the default being "1".</p>
+
+<h3 id="Running_specific_tests">Running specific tests</h3>
+
+<p>If you want to run a subset of your tests you can do so by specifying the full dot path to the package(s), module, <code>TestCase</code> subclass or method:</p>
+
+<pre class="brush: bash">python3 manage.py test catalog.tests # Run the specified module
+python3 manage.py test catalog.tests.test_models # Run the specified module
+python3 manage.py test catalog.tests.test_models.YourTestClass # Run the specified class
+python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one_equals_two # Run the specified method
+</pre>
+
+<h2 id="LocalLibrary_tests">LocalLibrary tests</h2>
+
+<p>Now we know how to run our tests and what sort of things we need to test, let's look at some practical examples.</p>
+
+<div class="note">
+<p><strong>Note: </strong>We won't write every possible test, but this should give you and idea of how tests work, and what more you can do.</p>
+</div>
+
+<h3 id="Models">Models</h3>
+
+<p>As discussed above, we should test anything that is part of our design or that is defined by code that we have written, but not libraries/code that is already tested by Django or the Python development team.</p>
+
+<p>For example, consider the <code>Author</code> model below. Here we should test the labels for all the fields, because even though we haven't explicitly specified most of them, we have a design that says what these values should be. If we don't test the values, then we don't know that the field labels have their intended values. Similarly while we trust that Django will create a field of the specified length, it is worthwhile to specify a test for this length to ensure that it was implemented as planned.</p>
+
+<pre class="brush: python">class Author(models.Model):
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        return reverse('author-detail', args=[str(self.id)])
+
+    def __str__(self):
+        return '%s, %s' % (self.last_name, self.first_name)</pre>
+
+<p>Open our <strong>/catalog/tests/test_models.py</strong>, and replace any existing code with the following test code for the <code>Author</code> model.</p>
+
+<p>Here you'll see that we first import <code>TestCase</code> and derive our test class (<code>AuthorModelTest</code>) from it, using a descriptive name so we can easily identify any failing tests in the test output. We then call <code>setUpTestData()</code> to create an author object that we will use but not modify in any of the tests.</p>
+
+<pre class="brush: python">from django.test import TestCase
+
+# Create your tests here.
+
+from catalog.models import Author
+
+class AuthorModelTest(TestCase):
+
+ @classmethod
+ def setUpTestData(cls):
+ #Set up non-modified objects used by all test methods
+ Author.objects.create(first_name='Big', last_name='Bob')
+
+ def test_first_name_label(self):
+ author=Author.objects.get(id=1)
+ field_label = author._meta.get_field('first_name').verbose_name
+ self.assertEquals(field_label,'first name')
+
+ def test_date_of_death_label(self):
+ author=Author.objects.get(id=1)
+ field_label = author._meta.get_field('date_of_death').verbose_name
+ self.assertEquals(field_label,'died')
+
+ def test_first_name_max_length(self):
+ author=Author.objects.get(id=1)
+ max_length = author._meta.get_field('first_name').max_length
+ self.assertEquals(max_length,100)
+
+ def test_object_name_is_last_name_comma_first_name(self):
+ author=Author.objects.get(id=1)
+ expected_object_name = '%s, %s' % (author.last_name, author.first_name)
+ self.assertEquals(expected_object_name,str(author))
+
+ def test_get_absolute_url(self):
+ author=Author.objects.get(id=1)
+ #This will also fail if the urlconf is not defined.
+ self.assertEquals(author.get_absolute_url(),'/catalog/author/1')</pre>
+
+<p>The field tests check that the values of the field labels (<code>verbose_name</code>) and that the size of the character fields are as expected. These methods all have descriptive names, and follow the same pattern:</p>
+
+<pre class="brush: python">author=Author.objects.get(id=1) # Get an author object to test
+field_label = author._meta.get_field('first_name').verbose_name # Get the metadata for the required field and use it to query the required field data
+self.assertEquals(field_label,'first name') # Compare the value to the expected result</pre>
+
+<p>The interesting things to note are:</p>
+
+<ul>
+ <li>We can't get the <code>verbose_name</code> directly using <code>author.first_name.verbose_name</code>, because <code>author.first_name</code> is a <em>string</em> (not a handle to the <code>first_name</code> object that we can use to access its properties). Instead we need to use the author's <code>_meta</code> attribute to get an instance of the field and use that to query for the additional information.</li>
+ <li>We chose to use <code>assertEquals(field_label,'first name')</code> rather than <code>assertTrue(field_label == 'first name')</code>. The reason for this is that if the test fails the output for the former tells you what the label actually was, which makes debugging the problem just a little easier.</li>
+</ul>
+
+<div class="note">
+<p><strong>Note:</strong> Tests for the <code>last_name</code> and <code>date_of_birth</code> labels, and also the test for the length of the <code>last_name</code> field have been omitted. Add your own versions now, following the naming conventions and approaches shown above.</p>
+</div>
+
+<p>We also need to test our custom methods. These essentially just check that the object name was constructed as we expected using "Last Name", "First Name" format, and that the URL we get for an <code>Author</code> item is as we would expect.</p>
+
+<pre class="brush: python">def test_object_name_is_last_name_comma_first_name(self):
+    author=Author.objects.get(id=1)
+    expected_object_name = '%s, %s' % (author.last_name, author.first_name)
+    self.assertEquals(expected_object_name,str(author))
+
+def test_get_absolute_url(self):
+    author=Author.objects.get(id=1)
+    #This will also fail if the urlconf is not defined.
+    self.assertEquals(author.get_absolute_url(),'/catalog/author/1')</pre>
+
+<p>Run the tests now. If you created the Author model as we described in the models tutorial it is quite likely that you will get an error for the <code>date_of_death</code> label as shown below. The test is failing because it was written expecting the label definition to follow Django's convention of not capitalising the first letter of the label (Django does this for you).</p>
+
+<pre class="brush: bash">======================================================================
+FAIL: test_date_of_death_label (catalog.tests.test_models.AuthorModelTest)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+ File "D:\...\locallibrary\catalog\tests\test_models.py", line 32, in test_date_of_death_label
+ self.assertEquals(field_label,'died')
+AssertionError: 'Died' != 'died'
+- Died
+? ^
++ died
+? ^</pre>
+
+<p>This is a very minor bug, but it does highlight how writing tests can more thoroughly check any assumptions you may have made.</p>
+
+<div class="note">
+<p><strong>Note: </strong>Change the label for the date_of_death field (/catalog/models.py) to "died" and re-run the tests.</p>
+</div>
+
+<p>The patterns for testing the other models are similar so we won't continue to discuss these further. Feel free to create your own tests for the our other models.</p>
+
+<h3 id="Forms">Forms</h3>
+
+<p>The philosophy for testing your forms is the same as for testing your models; you need to test anything that you've coded or your design specifies, but not the behaviour of the underlying framework and other third party libraries.</p>
+
+<p>Generally this means that you should test that the forms have the fields that you want, and that these are displayed with appropriate labels and help text. You don't need to verify that Django validates the field type correctly (unless you created your own custom field and validation) — i.e. you don't need to test that an email field only accepts emails. However you would need to test any additional validation that you expect to be performed on the fields and any messages that your code will generate for errors.</p>
+
+<p>Consider our form for renewing books. This has just one field for the renewal date, which will have a label and help text that we will need to verify.</p>
+
+<pre class="brush: python">class RenewBookForm(forms.Form):
+ """
+ Form for a librarian to renew books.
+ """
+ renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+ def clean_renewal_date(self):
+ data = self.cleaned_data['renewal_date']
+
+ #Check date is not in past.
+ if data &lt; datetime.date.today():
+ raise ValidationError(_('Invalid date - renewal in past'))
+ #Check date is in range librarian allowed to change (+4 weeks)
+ if data &gt; datetime.date.today() + datetime.timedelta(weeks=4):
+ raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+ # Remember to always return the cleaned data.
+ return data</pre>
+
+<p>Open our <strong>/catalog/tests/test_forms.py</strong> file and replace any existing code with the following test code for the <code>RenewBookForm</code> form. We start by importing our form and some Python and Django libraries to help test time-related functionality. We then declare our form test class in the same way as we did for models, using a descriptive name for our <code>TestCase</code>-derived test class.</p>
+
+<pre class="brush: python">from django.test import TestCase
+
+# Create your tests here.
+
+import datetime
+from django.utils import timezone
+from catalog.forms import RenewBookForm
+
+class RenewBookFormTest(TestCase):
+
+    def test_renew_form_date_field_label(self):
+        form = RenewBookForm()
+        self.assertTrue(form.fields['renewal_date'].label == None or form.fields['renewal_date'].label == 'renewal date')
+
+    def test_renew_form_date_field_help_text(self):
+        form = RenewBookForm()
+        self.assertEqual(form.fields['renewal_date'].help_text,'Enter a date between now and 4 weeks (default 3).')
+
+    def test_renew_form_date_in_past(self):
+        date = datetime.date.today() - datetime.timedelta(days=1)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertFalse(form.is_valid())
+
+    def test_renew_form_date_too_far_in_future(self):
+        date = datetime.date.today() + datetime.timedelta(weeks=4) + datetime.timedelta(days=1)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertFalse(form.is_valid())
+
+    def test_renew_form_date_today(self):
+        date = datetime.date.today()
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertTrue(form.is_valid())
+
+    def test_renew_form_date_max(self):
+        date = timezone.now() + datetime.timedelta(weeks=4)
+        form_data = {'renewal_date': date}
+        form = RenewBookForm(data=form_data)
+        self.assertTrue(form.is_valid())
+</pre>
+
+<p>The first two functions test that the field's <code>label</code> and <code>help_text</code> are as expected. We have to access the field using the fields dictionary (e.g. <code>form.fields['renewal_date']</code>). Note here that we also have to test whether the label value is <code>None</code>, because even though Django will render the correct label it returns <code>None</code> if the value is not <em>explicitly</em> set.</p>
+
+<p>The rest of the functions test that the form is valid for renewal dates just inside the acceptable range and invalid for values outside the range. Note how we construct test date values around our current date (<code>datetime.date.today()</code>) using <code>datetime.timedelta()</code> (in this case specifying a number of days or weeks). We then just create the form, passing in our data, and test if it is valid.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Here we don't actually use the database or test client. Consider modifying these tests to use <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase">SimpleTestCase</a>.</p>
+
+<p>We also need to validate that the correct errors are raised if the form is invalid, however this is usually done as part of view processing, so we'll take care of that in the next section.</p>
+</div>
+
+<p>That's all for forms; we do have some others, but they are automatically created by our generic class-based editing views, and should be tested there! Run the tests and confirm that our code still passes!</p>
+
+<h3 id="Views">Views</h3>
+
+<p>To validate our view behaviour we use the Django test <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.Client">Client</a>. This class acts like a dummy web browser that we can use to simulate <code>GET</code> and <code>POST</code> requests on a URL and observe the response. We can see almost everything about the response, from low-level HTTP (result headers and status codes) through to the template we're using to render the HTML and the context data we're passing to it. We can also see the chain of redirects (if any) and check the URL and status code at each step. This allows us to verify that each view is doing what is expected.</p>
+
+<p>Let's start with one of our simplest views, which provides a list of all Authors. This is displayed at URL <strong>/catalog/authors/</strong> (an URL named 'authors' in the URL configuration).</p>
+
+<pre class="brush: python">class AuthorListView(generic.ListView):
+ model = Author
+ paginate_by = 10
+</pre>
+
+<p>As this is a generic list view almost everything is done for us by Django. Arguably if you trust Django then the only thing you need to test is that the view is accessible at the correct URL and can be accessed using its name. However if you're using a test-driven development process you'll start by writing tests that confirm that the view displays all Authors, paginating them in lots of 10.</p>
+
+<p>Open the <strong>/catalog/tests/test_views.py</strong> file and replace any existing text with the following test code for <code>AuthorListView</code>. As before we import our model and some useful classes. In the <code>setUpTestData()</code> method we set up a number of <code>Author</code> objects so that we can test our pagination.</p>
+
+<pre class="brush: python">from django.test import TestCase
+
+# Create your tests here.
+
+from catalog.models import Author
+from django.urls import reverse
+
+class AuthorListViewTest(TestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        #Create 13 authors for pagination tests
+        number_of_authors = 13
+        for author_num in range(number_of_authors):
+            Author.objects.create(first_name='Christian %s' % author_num, last_name = 'Surname %s' % author_num,)
+
+    def test_view_url_exists_at_desired_location(self):
+        resp = self.client.get('/catalog/authors/')
+        self.assertEqual(resp.status_code, 200)
+
+    def test_view_url_accessible_by_name(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+
+    def test_view_uses_correct_template(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+
+        self.assertTemplateUsed(resp, 'catalog/author_list.html')
+
+    def test_pagination_is_ten(self):
+        resp = self.client.get(reverse('authors'))
+        self.assertEqual(resp.status_code, 200)
+        self.assertTrue('is_paginated' in resp.context)
+        self.assertTrue(resp.context['is_paginated'] == True)
+        self.assertTrue( len(resp.context['author_list']) == 10)
+
+    def test_lists_all_authors(self):
+        #Get second page and confirm it has (exactly) remaining 3 items
+        resp = self.client.get(reverse('authors')+'?page=2')
+        self.assertEqual(resp.status_code, 200)
+        self.assertTrue('is_paginated' in resp.context)
+        self.assertTrue(resp.context['is_paginated'] == True)
+        self.assertTrue( len(resp.context['author_list']) == 3)</pre>
+
+<p>All the tests use the client (belonging to our <code>TestCase</code>'s derived class) to simulate a <code>GET</code> request and get a response (<code>resp</code>). The first version checks a specific URL (note, just the specific path without the domain) while the second generates the URL from its name in the URL configuration.</p>
+
+<pre class="brush: python">resp = self.client.get('/catalog/authors/')
+resp = self.client.get(reverse('authors'))
+</pre>
+
+<p>Once we have the response we query it for its status code, the template used, whether or not the response is paginated, the number of items returned, and the total number of items.</p>
+
+<p>The most interesting variable we demonstrate above is <code>resp.context</code>, which is the context variable passed to the template by the view. This is incredibly useful for testing, because it allows us to confirm that our template is getting all the data it needs. In other words we can check that we're using the intended template and what data the template is getting, which goes a long way to verifying that any rendering issues are solely due to template.</p>
+
+<h4 id="Views_that_are_restricted_to_logged_in_users">Views that are restricted to logged in users</h4>
+
+<p>In some cases you'll want to test a view that is restricted to just logged in users. For example our <code>LoanedBooksByUserListView</code> is very similar to our previous view but is only available to logged in users, and only displays <code>BookInstance</code> records that are borrowed by the current user, have the 'on loan' status, and are ordered "oldest first".</p>
+
+<pre class="brush: python">from django.contrib.auth.mixins import LoginRequiredMixin
+
+class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
+ """
+ Generic class-based view listing books on loan to current user.
+ """
+ model = BookInstance
+ template_name ='catalog/bookinstance_list_borrowed_user.html'
+ paginate_by = 10
+
+ def get_queryset(self):
+ return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre>
+
+<p>Add the following test code to <strong>/catalog/tests/test_views.py</strong>. Here we first use <code>SetUp()</code> to create some user login accounts and <code>BookInstance</code> objects (along with their associated books and other records) that we'll use later in the tests. Half of the books are borrowed by each test user, but we've initially set the status of all books to "maintenance". We've used <code>SetUp()</code> rather than <code>setUpTestData()</code> because we'll be modifying some of these objects later.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The <code>setUp()</code> code below creates a book with a specified <code>Language</code>, but <em>your</em> code may not include the <code>Language</code> model as this was created as a <em>challenge</em>. If this is the case, simply  comment out the parts of the code that create or import Language objects. You should also do this in the <code>RenewBookInstancesViewTest</code> section that follows.</p>
+</div>
+
+<pre class="brush: python">import datetime
+from django.utils import timezone
+
+from catalog.models import BookInstance, Book, Genre, Language
+from django.contrib.auth.models import User #Required to assign User as a borrower
+
+class LoanedBookInstancesByUserListViewTest(TestCase):
+
+    def setUp(self):
+        #Create two users
+        test_user1 = User.objects.create_user(username='testuser1', password='12345')
+        test_user1.save()
+        test_user2 = User.objects.create_user(username='testuser2', password='12345')
+        test_user2.save()
+
+        #Create a book
+        test_author = Author.objects.create(first_name='John', last_name='Smith')
+        test_genre = Genre.objects.create(name='Fantasy')
+        test_language = Language.objects.create(name='English')
+        test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language)
+        # Create genre as a post-step
+        genre_objects_for_book = Genre.objects.all()
+  test_book.genre.set(genre_objects_for_book) #Direct assignment of many-to-many types not allowed.
+        test_book.save()
+
+        #Create 30 BookInstance objects
+        number_of_book_copies = 30
+        for book_copy in range(number_of_book_copies):
+            return_date= timezone.now() + datetime.timedelta(days=book_copy%5)
+            if book_copy % 2:
+                the_borrower=test_user1
+            else:
+                the_borrower=test_user2
+            status='m'
+            BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=the_borrower, status=status)
+
+    def test_redirect_if_not_logged_in(self):
+        resp = self.client.get(reverse('my-borrowed'))
+        self.assertRedirects(resp, '/accounts/login/?next=/catalog/mybooks/')
+
+    def test_logged_in_uses_correct_template(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Check we used correct template
+        self.assertTemplateUsed(resp, 'catalog/bookinstance_list_borrowed_user.html')
+</pre>
+
+<p>To verify that the view will redirect to a login page if the user is not logged in we use <code>assertRedirects</code>, as demonstrated in <code>test_redirect_if_not_logged_in()</code>. To verify that the page is displayed for a logged in user we first log in our test user, and then access the page again and check that we get a <code>status_code</code> of 200 (success). </p>
+
+<p>The rest of the tests verify that our view only returns books that are on loan to our current borrower. Copy the (self-explanatory) code at the end of the test class above.</p>
+
+<pre class="brush: python">    def test_only_borrowed_books_in_list(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Check that initially we don't have any books in list (none on loan)
+        self.assertTrue('bookinstance_list' in resp.context)
+        self.assertEqual( len(resp.context['bookinstance_list']),0)
+
+        #Now change all books to be on loan
+        get_ten_books = BookInstance.objects.all()[:10]
+
+        for copy in get_ten_books:
+            copy.status='o'
+            copy.save()
+
+        #Check that now we have borrowed books in the list
+        resp = self.client.get(reverse('my-borrowed'))
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        self.assertTrue('bookinstance_list' in resp.context)
+
+        #Confirm all books belong to testuser1 and are on loan
+        for bookitem in resp.context['bookinstance_list']:
+            self.assertEqual(resp.context['user'], bookitem.borrower)
+            self.assertEqual('o', bookitem.status)
+
+    def test_pages_ordered_by_due_date(self):
+
+        #Change all books to be on loan
+        for copy in BookInstance.objects.all():
+            copy.status='o'
+            copy.save()
+
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('my-borrowed'))
+
+        #Check our user is logged in
+        self.assertEqual(str(resp.context['user']), 'testuser1')
+        #Check that we got a response "success"
+        self.assertEqual(resp.status_code, 200)
+
+        #Confirm that of the items, only 10 are displayed due to pagination.
+        self.assertEqual( len(resp.context['bookinstance_list']),10)
+
+        last_date=0
+        for copy in resp.context['bookinstance_list']:
+            if last_date==0:
+                last_date=copy.due_back
+            else:
+                self.assertTrue(last_date &lt;= copy.due_back)</pre>
+
+<p>You could also add pagination tests, should you so wish!</p>
+
+<h4 id="Testing_views_with_forms">Testing views with forms</h4>
+
+<p>Testing views with forms is a little more complicated than in the cases above, because you need to test more code paths: initial display, display after data validation has failed, and display after validation has succeeded. The good news is that we use the client for testing in almost exactly the same way as we did for display-only views.</p>
+
+<p>To demonstrate, let's write some tests for the view used to renew books (<code>renew_book_librarian()</code>):</p>
+
+<pre class="brush: python">from .forms import RenewBookForm
+
+@permission_required('catalog.can_mark_returned')
+def renew_book_librarian(request, pk):
+    """
+    View function for renewing a specific BookInstance by librarian
+    """
+    book_inst=get_object_or_404(BookInstance, pk = pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>We'll need to test that the view is only available to users who have the <code>can_mark_returned </code>permission, and that users are redirected to an HTTP 404 error page if they attempt to renew a <code>BookInstance</code> that does not exist. We should check that the initial value of the form is seeded with a date three weeks in the future, and that if validation succeeds we're redirected to the "all-borrowed books" view. As part of checking the validation-fail tests we'll also check that our form is sending the appropriate error messages.</p>
+
+<p>Add the first part of the test class (shown below) to the bottom of <strong>/catalog/tests/test_views.py</strong>. This creates two users and two book instances, but only gives one user the permission required to access the view. The code to grant permissions during tests is shown in bold:</p>
+
+<pre class="brush: python">from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned.
+
+class RenewBookInstancesViewTest(TestCase):
+
+ def setUp(self):
+ #Create a user
+ test_user1 = User.objects.create_user(username='testuser1', password='12345')
+ test_user1.save()
+
+ test_user2 = User.objects.create_user(username='testuser2', password='12345')
+ test_user2.save()
+<strong> permission = Permission.objects.get(name='Set book as returned')
+ test_user2.user_permissions.add(permission)
+ test_user2.save()</strong>
+
+ #Create a book
+ test_author = Author.objects.create(first_name='John', last_name='Smith')
+ test_genre = Genre.objects.create(name='Fantasy')
+ test_language = Language.objects.create(name='English')
+ test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language,)
+ # Create genre as a post-step
+ genre_objects_for_book = Genre.objects.all()
+ test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed.
+ test_book.save()
+
+ #Create a BookInstance object for test_user1
+ return_date= datetime.date.today() + datetime.timedelta(days=5)
+ self.test_bookinstance1=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user1, status='o')
+
+ #Create a BookInstance object for test_user2
+ return_date= datetime.date.today() + datetime.timedelta(days=5)
+ self.test_bookinstance2=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user2, status='o')</pre>
+
+<p>Add the following tests to the bottom of the test class. These check that only users with the correct permissions (<em>testuser2</em>) can access the view. We check all the cases: when the user is not logged in, when a user is logged in but does not have the correct permissions, when the user has permissions but is not the borrower (should succeed), and what happens when they try to access a <code>BookInstance</code> that doesn't exist. We also check that the correct template is used.</p>
+
+<pre class="brush: python">   def test_redirect_if_not_logged_in(self):
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable)
+        self.assertEqual( resp.status_code,302)
+        self.assertTrue( resp.url.startswith('/accounts/login/') )
+
+    def test_redirect_if_logged_in_but_not_correct_permission(self):
+        login = self.client.login(username='testuser1', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+
+        #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable)
+        self.assertEqual( resp.status_code,302)
+        self.assertTrue( resp.url.startswith('/accounts/login/') )
+
+    def test_logged_in_with_permission_borrowed_book(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance2.pk,}) )
+
+        #Check that it lets us login - this is our book and we have the right permissions.
+        self.assertEqual( resp.status_code,200)
+
+    def test_logged_in_with_permission_another_users_borrowed_book(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+
+        #Check that it lets us login. We're a librarian, so we can view any users book
+        self.assertEqual( resp.status_code,200)
+
+    def test_HTTP404_for_invalid_book_if_logged_in(self):
+        import uuid
+        test_uid = uuid.uuid4() #unlikely UID to match our bookinstance!
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':test_uid,}) )
+        self.assertEqual( resp.status_code,404)
+
+    def test_uses_correct_template(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        self.assertEqual( resp.status_code,200)
+
+        #Check we used correct template
+        self.assertTemplateUsed(resp, 'catalog/book_renew_librarian.html')
+</pre>
+
+<p>Add the next test method, as shown below. This checks that the initial date for the form is three weeks in the future. Note how we are able to access the value of the initial value of the form field (shown in bold).</p>
+
+<pre class="brush: python">    def test_form_renewal_date_initially_has_date_three_weeks_in_future(self):
+        login = self.client.login(username='testuser2', password='12345')
+        resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
+        self.assertEqual( resp.status_code,200)
+
+        date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3)
+        self.assertEqual(<strong>resp.context['form'].initial['renewal_date']</strong>, date_3_weeks_in_future )
+</pre>
+
+<p>The next test (add this to the class too) checks that the view redirects to a list of all borrowed books if renewal succeeds. What differs here is that for the first time we show how you can <code>POST</code> data using the client. The post <em>data</em> is the second argument to the post function, and is specified as a dictionary of key/values.</p>
+
+<pre class="brush: python">    def test_redirects_to_all_borrowed_book_list_on_success(self):
+        login = self.client.login(username='testuser2', password='12345')
+        valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2)
+        resp = <strong>self.client.<em>post</em>(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future} )</strong>
+        self.assertRedirects(resp, reverse('all-borrowed') )
+</pre>
+
+<div class="warning">
+<p>The <em>all-borrowed</em> view was added as a <em>challenge</em>, and your code may instead redirect to the home page '/'. If so, modify the last two lines of the test code to be like the code below. The <code>follow=True</code> in the request ensures that the request returns the final destination URL (hence checking <code>/catalog/</code> rather than <code>/</code>).</p>
+
+<pre class="brush: python"> resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future},<strong>follow=True</strong> )
+ <strong>self.assertRedirects(resp, '/catalog/')</strong></pre>
+</div>
+
+<p>Copy the last two functions into the class, as seen below. These again test <code>POST</code> requests, but in this case with invalid renewal dates. We use <code>assertFormError() </code>to verify that the error messages are as expected.</p>
+
+<pre class="brush: python">    def test_form_invalid_renewal_date_past(self):
+        login = self.client.login(username='testuser2', password='12345')
+        date_in_past = datetime.date.today() - datetime.timedelta(weeks=1)
+        resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':date_in_past} )
+        self.assertEqual( resp.status_code,200)
+        <strong>self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal in past')</strong>
+
+    def test_form_invalid_renewal_date_future(self):
+        login = self.client.login(username='testuser2', password='12345')
+        invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5)
+        resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':invalid_date_in_future} )
+        self.assertEqual( resp.status_code,200)
+        <strong>self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')</strong>
+</pre>
+
+<p>The same sorts of techniques can be used to test the other view.</p>
+
+<h3 id="Templates">Templates</h3>
+
+<p>Django provides test APIs to check that the correct template is being called by your views, and to allow you to verify that the correct information is being sent. There is however no specific API support for testing in Django that your HTML output is rendered as expected.</p>
+
+<h2 id="Other_recommended_test_tools">Other recommended test tools</h2>
+
+<p>Django's test framework can help you write effective unit and integration tests — we've only scratched the surface of what the underlying <strong>unittest</strong> framework can do, let alone Django's additions (for example, check out how you can use <a href="https://docs.python.org/3.5/library/unittest.mock-examples.html">unittest.mock</a> to patch third party libraries so you can more thoroughly test your own code).</p>
+
+<p>While there are numerous other test tools that you can use, we'll just highlight two:</p>
+
+<ul>
+ <li><a href="http://coverage.readthedocs.io/en/latest/">Coverage</a>: This Python tool reports on how much of your code is actually executed by your tests. It is particularly useful when you're getting started, and you are trying to work out exactly what you should test.</li>
+ <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> is a framework to automate testing in a real browser. It allows you to simulate a real user interacting with the site, and provides a great framework for system testing your site (the next step up from integration testing).</li>
+</ul>
+
+<h2 id="Challenge_yourself">Challenge yourself</h2>
+
+<p>There are a lot more models and views we can test. As a simple task, try to create a test case for the <code>AuthorCreate</code> view.</p>
+
+<pre class="brush: python">class AuthorCreate(PermissionRequiredMixin, CreateView):
+ model = Author
+ fields = '__all__'
+ initial={'date_of_death':'12/10/2016',}
+ permission_required = 'catalog.can_mark_returned'</pre>
+
+<p>Remember that you need to check anything that you specify or that is part of the design. This will include who has access, the initial date, the template used, and where the view redirects on success.</p>
+
+<h2 id="Summary">Summary</h2>
+
+<p>Writing test code is neither fun nor glamorous, and is consequently often left to last (or not at all) when creating a website. It is however an essential part of making sure that your code is safe to release after making changes, and cost-effective to maintain.</p>
+
+<p>In this tutorial we've shown you how to write and run tests for your models, forms, and views. Most importantly we've provided a brief summary of what you should test, which is often the hardest thing to work out when you're getting started. There is a lot more to know, but even with what you've learned already you should be able to create effective unit tests for your websites.</p>
+
+<p>The next and final tutorial shows how you can deploy your wonderful (and fully tested!) Django website.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/overview/">Writing and running tests</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial05/">Writing your first Django app, part 5 &gt; Introducing automated testing</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/">Testing tools reference</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/advanced/">Advanced testing topics</a> (Django docs)</li>
+ <li><a href="http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/">A Guide to Testing in Django</a> (Toast Driven Blog, 2011)</li>
+ <li><a href="http://test-driven-django-development.readthedocs.io/en/latest/index.html">Workshop: Test-Driven Web Development with Django</a> (San Diego Python, 2014)</li>
+ <li><a href="https://realpython.com/blog/python/testing-in-django-part-1-best-practices-and-examples/">Testing in Django (Part 1) - Best Practices and Examples</a> (RealPython, 2013)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html b/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html
new file mode 100644
index 0000000000..3e2cae3be5
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/tutorial_local_library_website/index.html
@@ -0,0 +1,92 @@
+---
+title: 'Django 教學 1: 本地圖書館網站'
+slug: Learn/Server-side/Django/Tutorial_local_library_website
+tags:
+ - django
+ - 初學者
+translation_of: Learn/Server-side/Django/Tutorial_local_library_website
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">我們實戰教學系列的第一篇,會解釋你將學到什麼。並提供一個“本地圖書館” 的例子,作為概述。在接下來的教學裡,我們會不斷完善和改進這個網站。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提:</th>
+ <td>閱讀 Django 介紹。在接下來的文章裡,你需要創建 Django 開發環境.</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>介紹教學裡使用的網站應用,讓讀者明白要討論的主題。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>歡迎來到 MDN 的 ”本地圖書館“ Django 教學。在教學裡,我們會開發一個網站,用來管理本地圖書館的目錄。</p>
+
+<p>在這一系列的教學裡,你將:</p>
+
+<ul>
+ <li>運用 Django 的工具,創建網站和應用的框架。</li>
+ <li>啟動和停止開發用的服務器。</li>
+ <li>創建模型(models)用來表示應用裡的數據。</li>
+ <li>運用 Django 的 admin 網站,以填充網站數據。</li>
+ <li>面對不同的網路請求,創建視圖函數(views)取回相應的數據。並把數據用模板(templates ),渲染成 HTML ,展示在瀏覽器裡。</li>
+ <li>創建網路映射,將不同的 URL 模式,分發給特定的視圖函數(views)。</li>
+ <li>添加用戶認證和會話(sessions),管理網站行為和進入權限。</li>
+ <li>使用表單。</li>
+ <li>為應用編寫測試。</li>
+ <li>有效運用 Django 的安全系統。</li>
+ <li>把應用佈置到生產環境中。</li>
+</ul>
+
+<p>關於這些主題,你已經學會了一些,並對其他的也有了簡單的了解。在這系列教學的最後,你會學到足夠多,而可以自己開發簡單的Django 應用了。</p>
+
+<h2 id="本地圖書館網站">本地圖書館網站</h2>
+
+<p>本地圖書館,是我們在本系列教學裡,創建和不斷改善的網站。跟你期望的一樣,這個網站的目標,是為一個小型的圖書館,提供一個線上目錄。在這個小型圖書館裡,用戶能瀏覽書籍,和管理他們的帳號。</p>
+
+<p>這個例子是精心挑選出來的,因為它可以根據我們的需要,增加或多或少的細節。也能用來展示,幾乎所有的 Django 特性。更重要的是,它提供了一條指南式的路線,在這條路線中,我們會用到 Django 網路框架最重要的功能:</p>
+
+<ul>
+ <li>在第一篇教學裡,我們會定義一個,簡單到只能瀏覽的圖書館。圖書館的會員,可以查找哪些書可以借閱。我們得以探索那些,幾乎所有網站都會運用的操作:閱讀和展示數據庫裡的內容。</li>
+ <li>接下來,圖書館會慢慢擴展,以展示更高級的 Django 特性。例如,我們會擴展功能,讓會員能夠保留圖書。這個特性會展示如何使用表單,並支持用戶認證。</li>
+</ul>
+
+<p>儘管這是一個非常容易擴展的例子,它被稱為本地圖書館是有原因的——我們希望用最少的訊息,幫助你快速創建、和運用 Django。最後,我們會存儲圖書訊息,圖書數量,作者和其他重要訊息。我們不會儲存圖書館可能會儲存的其他訊息,或是提供一個支持多個圖書館、或是 ”大型圖書館“ 功能的建構。</p>
+
+<h2 id="我卡住了,從哪裡獲得源程式碼呢?">我卡住了,從哪裡獲得源程式碼呢?</h2>
+
+<p>在學習本系列教程時,我們會提供合適的代碼片段,你可以粘貼複製,但是有些代碼我們希望你能自己擴展(在提示下)。</p>
+
+<p>如果你卡在某個地方,你可以在 <a href="https://github.com/mdn/django-locallibrary-tutorial">Github </a>裡找到網站的完整代碼。</p>
+
+<h2 id="總結">總結</h2>
+
+<p>現在你對本地圖書館網站有了一些了解並知道你會學到什麼。是時候創建我們例子會用到的<a href="/zh-TW/docs/Learn/Server-side/Django/skeleton_website">網站框架</a>了。</p>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</p>
+
+<h2 id="本系列教學">本系列教學</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django 介紹</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">設定Django開發環境</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django 教學: 本地圖書館網站</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django 教學 第2部分: 建立網站骨架</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django 教學 第3部分: 使用模型</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django 教學 第4部分: Django的管理員頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django 教學 第5部分: 創建我們的首頁</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django 教學 第6部分: 通用列表與詳細視圖</a><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django 教學 第7部分: 會話 (Sessions) 框架 </a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django 教學 第8部分: 使用者的身分驗證與權限</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django 教學 第9部分: 使用表單</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django 教學 第10部分: 測試Django 網頁應用</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django 教學 第11部分: 部署 Django 到生產環境(production)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django 網頁應用安全</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django 迷你部落格</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/django/web_application_security/index.html b/files/zh-tw/learn/server-side/django/web_application_security/index.html
new file mode 100644
index 0000000000..f644f400b9
--- /dev/null
+++ b/files/zh-tw/learn/server-side/django/web_application_security/index.html
@@ -0,0 +1,180 @@
+---
+title: Django web application security
+slug: Learn/Server-side/Django/web_application_security
+translation_of: Learn/Server-side/Django/web_application_security
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">保護用戶數據是任何網站設計的重要部分。我們之前在文章 web 安全中,解釋了一些更常見的安全威脅 -- 本文提供了 Django 的內置保護如何處理這些威脅的實際演示。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Read the Server-side progamming "<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>" topic. Complete the Django tutorial topics up to (and including) at least <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand the main things you need to do (or not do) to secure your Django web application.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Overview">Overview</h2>
+
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Website security</a> topic provides an overview of what website security means for server-side design, and some of the more common threats that you may need to protect against. One of the key messages in that article is that almost all attacks are successful when the web application trusts data from the browser.</p>
+
+<div class="warning">
+<p><strong>Important:</strong> The single most important lesson you can learn about website security is to <strong>never trust data from the browser</strong>. This includes <code>GET</code> request data in URL parameters, <code>POST</code> data, HTTP headers and cookies, user-uploaded files, etc. Always check and sanitize all incoming data. Always assume the worst.</p>
+</div>
+
+<p>The good news for Django users is that many of the more common threats are handled by the framework! The <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> (Django docs) article explains Django's security features and how to secure a Django-powered website.</p>
+
+<h2 id="Common_threatsprotections">Common threats/protections</h2>
+
+<p>Rather than duplicate the Django documentation here, in this article we'll demonstrate just a few of the security features in the context of our Django <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> tutorial.</p>
+
+<h3 id="Cross_site_scripting_(XSS)">Cross site scripting (XSS)</h3>
+
+<p>XSS is a term used to describe a class of attacks that allow an attacker to inject client-side scripts <em>through</em> the website into the browsers of other users. This is usually achieved by storing malicious scripts in the database where they can be retrieved and displayed to other users, or by getting users to click a link that will cause the attacker’s JavaScript to be executed by the user’s browser.</p>
+
+<p>Django's template system protects you against the majority of XSS attacks by <a href="https://docs.djangoproject.com/en/2.0/ref/templates/language/#automatic-html-escaping">escaping specific characters</a> that are "dangerous" in HTML. We can demonstrate this by attempting to inject some JavaScript into our LocalLibrary website using the Create-author form we set up in <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a>.</p>
+
+<ol>
+ <li>Start the website using the development server (<code>python3 manage.py runserver</code>).</li>
+ <li>Open the site in your local browser and login to your superuser account.</li>
+ <li>Navigate to the author-creation page (which should be at URL: <code><a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a></code>).</li>
+ <li>Enter names and date details for a new user, and then append the following text to the Last Name field:<br>
+ <code>&lt;script&gt;alert('Test alert');&lt;/script&gt;</code>.<br>
+ <img alt="Author Form XSS test" src="https://mdn.mozillademos.org/files/14305/author_create_form_alert_xss.png" style="border-style: solid; border-width: 1px; height: 245px; width: 594px;">
+ <div class="note">
+ <p><strong>Note:</strong> This is a harmless script that, if executed, will display an alert box in your browser. If the alert is displayed when you submit the record then the site is vulnerable to XSS threats.</p>
+ </div>
+ </li>
+ <li>Press <strong>Submit</strong> to save the record.</li>
+ <li>When you save the author it will be displayed as shown below. Because of the XSS protections the <code>alert()</code> should not be run. Instead the script is displayed as plain text.<img alt="Author detail view XSS test" src="https://mdn.mozillademos.org/files/14307/author_detail_alert_xss.png" style="border-style: solid; border-width: 1px; height: 248px; width: 986px;"></li>
+</ol>
+
+<p>If you view the page HTML source code, you can see that the dangerous characters for the script tags have been turned into their harmless escape code equivalents (e.g. <code>&gt;</code> is now <code>&amp;gt;</code>)</p>
+
+<pre class="brush: html">&lt;h1&gt;Author: Boon&amp;lt;script&amp;gt;alert(&amp;#39;Test alert&amp;#39;);&amp;lt;/script&amp;gt;, David (Boonie) &lt;/h1&gt;
+</pre>
+
+<p>Using Django templates protects you against the majority of XSS attacks. However it is possible to turn off this protection, and the protection isn't automatically applied to all tags that wouldn't normally be populated by user input (for example, the <code>help_text</code> in a form field is usually not user-supplied, so Django doesn't escape those values).</p>
+
+<p>It is also possible for XSS attacks to originate from other untrusted source of data, such as cookies, Web services or uploaded files (whenever the data is not sufficiently sanitized before including in a page). If you're displaying data from these sources, then you may need to add your own sanitisation code.</p>
+
+<h3 id="Cross_site_request_forgery_(CSRF)_protection">Cross site request forgery (CSRF) protection</h3>
+
+<p>CSRF attacks allow a malicious user to execute actions using the credentials of another user without that user’s knowledge or consent. For example consider the case where we have a hacker who wants to create additional authors for our LocalLibrary.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Obviously our hacker isn't in this for the money! A more ambitious hacker could use the same approach on other sites to perform much more harmful tasks (e.g. transfer money to their own accounts, etc.)</p>
+</div>
+
+<p>In order to do this, they might create an HTML file like the one below, which contains an author-creation form (like the one we used in the previous section) that is submitted as soon as the file is loaded. They would then send the file to all the Librarians and suggest that they open the file (it contains some harmless information, honest!). If the file is opened by any logged in librarian, then the form would be submitted with their credentials and a new author would be created.</p>
+
+<pre class="brush: html">&lt;html&gt;
+&lt;body onload='document.EvilForm.submit()'&gt;
+
+&lt;form action="http://127.0.0.1:8000/catalog/author/create/" method="post" name='EvilForm'&gt;
+ &lt;table&gt;
+ &lt;tr&gt;&lt;th&gt;&lt;label for="id_first_name"&gt;First name:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;&lt;input id="id_first_name" maxlength="100" name="first_name" type="text" value="Mad" required /&gt;&lt;/td&gt;&lt;/tr&gt;
+ &lt;tr&gt;&lt;th&gt;&lt;label for="id_last_name"&gt;Last name:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;&lt;input id="id_last_name" maxlength="100" name="last_name" type="text" value="Man" required /&gt;&lt;/td&gt;&lt;/tr&gt;
+ &lt;tr&gt;&lt;th&gt;&lt;label for="id_date_of_birth"&gt;Date of birth:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;&lt;input id="id_date_of_birth" name="date_of_birth" type="text" /&gt;&lt;/td&gt;&lt;/tr&gt;
+ &lt;tr&gt;&lt;th&gt;&lt;label for="id_date_of_death"&gt;Died:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;&lt;input id="id_date_of_death" name="date_of_death" type="text" value="12/10/2016" /&gt;&lt;/td&gt;&lt;/tr&gt;
+ &lt;/table&gt;
+ &lt;input type="submit" value="Submit" /&gt;
+&lt;/form&gt;
+
+&lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<p>Run the development web server, and log in with your superuser account. Copy the text above into a file and then open it in the browser. You should get a CSRF error, because Django has protection against this kind of thing!</p>
+
+<p>The way the protection is enabled is that you include the <code>{% csrf_token %}</code> template tag in your form definition. This token is then rendered in your HTML as shown below, with a value that is specific to the user on the current browser.</p>
+
+<pre class="brush: html">&lt;input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' /&gt;
+</pre>
+
+<p>Django generates a user/browser specific key and will reject forms that do not contain the field, or that contain an incorrect field value for the user/browser.</p>
+
+<p>To use this type of attack the hacker now has to discover and include the CSRF key for the specific target user. They also can't use the "scattergun" approach of sending a malicious file to all librarians and hoping that one of them will open it, since the CSRF key is browser specific.</p>
+
+<p>Django's CSRF protection is turned on by default. You should always use the <code>{% csrf_token %}</code> template tag in your forms and use <code>POST</code> for requests that might change or add data to the database.</p>
+
+<h3 id="Other_protections">Other protections</h3>
+
+<p>Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):</p>
+
+<dl>
+ <dt>SQL injection protection</dt>
+ <dd>SQL injection vulnerabilities enable malicious users to execute arbitrary SQL code on a database, allowing data to be accessed, modified, or deleted irrespective of the user's permissions. In almost every case you'll be accessing the database using Django’s querysets/models, so the resulting SQL will be properly escaped by the underlying database driver. If you do need to write raw queries or custom SQL then you'll need to explicitly think about preventing SQL injection.</dd>
+ <dt>Clickjacking protection</dt>
+ <dd>In this attack a malicious user hijacks clicks meant for a visible top level site and routes them to a hidden page beneath. This technique might be used, for example, to display a legitimate bank site but capture the login credentials in an invisible <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe" title="The HTML Inline Frame Element (&lt;iframe>) represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an &lt;iframe> can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window."><code>&lt;iframe&gt;</code></a> controlled by the attacker. Django contains <a href="https://docs.djangoproject.com/en/2.0/ref/clickjacking/#clickjacking-prevention">clickjacking protection</a> in the form of the <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#django.middleware.clickjacking.XFrameOptionsMiddleware" title="django.middleware.clickjacking.XFrameOptionsMiddleware"><code>X-Frame-Options middleware</code></a> which, in a supporting browser, can prevent a site from being rendered inside a frame.</dd>
+ <dt>Enforcing SSL/HTTPS</dt>
+ <dd>SSL/HTTPS can be enabled on the web server in order to encrypt all traffic between the site and browser, including authentication credentials that would otherwise be sent in plain text (enabling HTTPS is highly recommended). If HTTPS is enabled then Django provides a number of other protections you can use:</dd>
+</dl>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER"><code>SECURE_PROXY_SSL_HEADER</code></a> can be used to check whether content is secure, even if it is incoming from a non-HTTP proxy.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_SSL_REDIRECT"><code>SECURE_SSL_REDIRECT</code></a> is used to redirect all HTTP requests to HTTPS.</li>
+ <li>Use <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#http-strict-transport-security">HTTP Strict Transport Security</a> (HSTS). This is an HTTP header that informs a browser that all future connections to a particular site should always use HTTPS. Combined with redirecting HTTP requests to HTTPS, this setting ensures that HTTPS is always used after a successful connection has occurred. HSTS may either be configured with <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_SECONDS"><code>SECURE_HSTS_SECONDS</code></a> and <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_INCLUDE_SUBDOMAINS"><code>SECURE_HSTS_INCLUDE_SUBDOMAINS</code></a> or on the Web server.</li>
+ <li>Use ‘secure’ cookies by setting <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SESSION_COOKIE_SECURE"><code>SESSION_COOKIE_SECURE</code></a> and <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-CSRF_COOKIE_SECURE"><code>CSRF_COOKIE_SECURE</code></a> to <code>True</code>. This will ensure that cookies are only ever sent over HTTPS.</li>
+</ul>
+
+<dl>
+ <dt>Host header validation</dt>
+ <dd>Use <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-ALLOWED_HOSTS"><code>ALLOWED_HOSTS</code></a> to only accept requests from trusted hosts.</dd>
+</dl>
+
+<p>There are many other protections, and caveats to the usage of the above mechanisms. While we hope that this has given you an overview of what Django offers, you should still read the Django security documentation.</p>
+
+<ul>
+</ul>
+
+<h2 id="Summary">Summary</h2>
+
+<p>Django has effective protections against a number of common threats, including XSS and CSRF attacks. In this article we've demonstrated how those particular threats are handled by Django in our <em>LocalLibrary</em> website. We've also provided a brief overview of some of the other protections.</p>
+
+<p>This has been a very brief foray into web security. We strongly recommend that you read <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> to gain a deeper understanding.</p>
+
+<p>The next and final step in this module about Django is to complete the <a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">assessment task</a>.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> (Django docs)</li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Server side website security</a> (MDN)</li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> (MDN)</li>
+ <li><a href="/en-US/docs/Web/Security/Securing_your_site">Securing your site</a> (MDN)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</p>
+
+<p> </p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html b/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html
new file mode 100644
index 0000000000..d7c2089cd1
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/deployment/index.html
@@ -0,0 +1,521 @@
+---
+title: 'Express 教學 7: 佈署到生產環境'
+slug: Learn/Server-side/Express_Nodejs/deployment
+translation_of: Learn/Server-side/Express_Nodejs/deployment
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">現在你已經創建(並測試)了一個不錯的 本地圖書館 網站了,你打算把它發佈到一個公共網絡服務器,這樣圖書館管理員和網路上的其他成員就可以訪問它了。這篇文章總結了你可以怎樣找到一台主機部署你的網站,以及你需要為網站準備好佈署到生產環境該做什麼。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">預備知識:</th>
+ <td>完成前面所有的指南主題,包括 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>學習你可以怎樣以及在哪裡部署一個 Express 應用到生產環境。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>一旦您的站點完成(或完成 “足夠” 以開始公共測試),您將需要將其託管在比您的個人開發計算機,更公開和可訪問的地方。</p>
+
+<p>到目前為止,您一直在開發環境中工作,使用Express / Node 作為 Web 服務器,將您的站點共享到本地瀏覽器/網路,並使用(不安全的)開發設置運行您的網站,以顯示調試和其他私人信息。在您可以在外部託管網站之前,您首先必須:</p>
+
+<ul>
+ <li>選擇託管 Express 應用程序的環境。</li>
+ <li>對項目設置進行一些更改。</li>
+ <li>設置生產級別的基礎架構,以服務您的網站。</li>
+</ul>
+
+<p>本教程提供了,有關選擇託管站點的選項的一些指導,簡要概述了為使您的Express 應用程序準備好生產,所需執行的操作,以及一個工作示例,演示如何將 LocalLibrary 網站安裝到 <a href="https://www.heroku.com/">Heroku</a> 雲託管上的服務。</p>
+
+<p>請記住,您不必使用 Heroku - 還有其他託管服務可用。我們還提供了一個單獨的教程,以展示如何在 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">PWS/Cloud Foundry </a>上安裝 LocalLibrary。</p>
+
+<h2 id="什麼是生產環境?">什麼是生產環境?</h2>
+
+<p>生產環境是服務器計算機提供的環境,您可以在其中運行網站,以供外部使用。環境包括:</p>
+
+<ul>
+ <li>網站運行的計算機硬件。</li>
+ <li>操作系統(例如 Linux 或 Windows)。</li>
+ <li>編程語言運行庫和框架庫,在其上編寫您的網站。</li>
+ <li>Web 服務器基礎結構,可能包含 Web 服務器,反向代理,負載平衡器等。</li>
+ <li>您的網站所依賴的數據庫。</li>
+</ul>
+
+<p>服務器計算機,可以位於您的場所,並通過快速鏈接,連接到 Internet,但使用 “託管在雲上” 的計算機更為常見。這實際上意味著,您的代碼運行在託管公司的數據中心的某台遠程計算機(或可能是“虛擬”計算機)。遠程服務器,通常會以特定價格提供互聯網連接,和一些保證級別的計算資源(例如CPU,RAM,存儲器等)。</p>
+
+<p>這種可遠程訪問的計算/網絡硬件,稱為基礎架構即服務(IaaS)。許多 IaaS 供應商,提供預安裝特定操作系統的選項,您必須在其上,安裝生產環境的其他組件。其他供應商,允許您選擇功能更全面的環境,可能包括完整的 node 設置。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 預構建環境,可以使您的網站設置變得非常簡單,因為它們會減少配置,但可用選項可能會限制您使用不熟悉的服務器(或其他組件),並且可能基於較舊版本的操作系統。通常最好自己安裝組件,以便獲得所需的組件,並且當您需要升級系統的某些部分時,您可以知道從哪裡開始!</p>
+</div>
+
+<p>其他託管服務提供商,支持 Express 作為平台即服務(PaaS)產品的一部分。使用此類託管時,您無需擔心大多數生產環境(服務器,負載平衡器等),因為主機平台會為您處理這些問題。這使得部署非常簡單,因為您只需要專注於 Web 應用程序,而不是任何其他服務器基礎結構。</p>
+
+<p>一些開發人員選擇 IaaS ,相對於 PaaS ,IaaS 提供更高靈活性,而其他開發人員偏好 PaaS 的降低維護開銷,和更輕鬆的擴展性。當您在一開始使用時,在 PaaS 系統上設置您的網站,要容易得多,因此我們將在本教程中使用 PaaS。</p>
+
+<div class="note">
+<p><strong>提示:</strong> 如果您選擇 Node/Express 友好的託管服務提供商,他們應該提供,有關如何使用 Web 服務器,應用程序服務器,反向代理等不同配置,來設置 Express 網站的說明。例如,在<a href="https://www.digitalocean.com/community/tutorials?q=node"> Digital Ocean</a> 的node 社區文檔中,有許多各種配置的手把手指南。</p>
+</div>
+
+<h2 id="選擇一個主機供應商">選擇一個主機供應商</h2>
+
+<p>眾所周知,眾多託管服務提供商,都積極支持或與 Node(和Express)合作。這些供應商提供不同類型的環境(IaaS,PaaS),以及不同價格的不同級別的計算和網絡資源。</p>
+
+<div class="note">
+<p><strong>提示:</strong> 有很多託管解決方案,他們的服務和定價,可能會隨著時間而改變。雖然我們在下面介紹幾個選項,但在選擇託管服務提供商之前,有必要自己進行互聯網搜索。</p>
+</div>
+
+<p>選擇主機時需要考慮的一些事項:</p>
+
+<ul>
+ <li>您的網站可能有多忙,以及滿足該需求所需的數據,和計算資源的成本。</li>
+ <li>水平擴展(添加更多機器)和垂直擴展(升級到更強大的機器)的支持級別,以及這樣做的成本。</li>
+ <li>供應商有數據中心的地方,因此訪問可能是最快的。</li>
+ <li>主機正常運行時間和停機時間的歷史表現。</li>
+ <li>用於管理站點的工具 - 易於使用且安全(例如 SFTP 與 FTP)。</li>
+ <li>用於監控服務器的內置框架。</li>
+ <li>已知限制。有些主機會故意阻止某些服務(例如電子郵件)。其他在某些價格層中,僅提供一定數小時的 “實時時間”,或者僅提供少量存儲空間。</li>
+ <li>額外的好處。一些提供商將提供免費域名和 SSL 證書支持,否則您將不得不為此另外支付費用。</li>
+ <li>您所依賴的“免費”等級,是否會隨著時間的推移而過期,以及遷移到更昂貴等級的成本,是否意味著您最好在一開始就使用其他服務!</li>
+</ul>
+
+<p>當你剛開始時,好消息是有很多網站提供“免費”的計算環境,儘管有一些條件。例如, <a href="https://www.heroku.com/">Heroku</a>  “永遠” 提供免費但資源有限的 PaaS 環境,而 <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/">Microsoft Azure</a> 和開源選項 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">PWS/Cloud Foundry</a> 在您第一次加入時,提供免費信用額度。</p>
+
+<p>許多提供商還擁有“基本”層,可提供更多有用的計算能力,和更少的限制。舉例來說, <a href="https://www.digitalocean.com/">Digital Ocean</a> 是一個流行的託管服務提供商,它提供了一個相對便宜的基本計算層(在本教程寫作時,是每月5美元的較低範圍)。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 請記住,價格不是唯一的選擇標準。如果您的網站成功,可能會發現可擴展性是最重要的考慮因素。</p>
+</div>
+
+<h2 id="準備好發布你的網站">準備好發布你的網站</h2>
+
+<p>發佈網站時,要考慮的主要問題是網絡安全性和性能。至少,您需要刪除開發期間,錯誤頁面上包含的堆棧跟踪,整理日誌記錄,並設置適當的標頭,以避免許多常見的安全威脅。</p>
+
+<p>在以下小節中,我們概述了您應該對應用進行的、最重要的更改。</p>
+
+<div class="note">
+<p><strong>提示:</strong> Express文檔中還有其他有用的提示 - 請參閱“<a href="https://expressjs.com/en/advanced/best-practice-performance.html">生產最佳實踐:性能和可靠性</a>”,以及“<a href="https://expressjs.com/en/advanced/best-practice-security.html">生產最佳實踐:安全性</a>”。</p>
+</div>
+
+<h3 id="設置_NODE_ENV_為_'production'">設置 NODE_ENV 為 'production'</h3>
+
+<p>我們可以通過將 <code>NODE_ENV</code> 環境變量,設置為 production ,來刪除錯誤頁面中的堆棧跟踪(默認設置為 “development” )。除了生成較為不詳細的錯誤消息之外,還要將變量設置為生產緩存視圖模板,和從 CSS 擴展生成的 CSS 文件。測試表明,將<code>NODE_ENV</code>設置為生產,可以將應用程序性能提高三倍!</p>
+
+<p>可以使用導出或環境文件,或使用 OS 初始化系統,以進行此更改。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 這實際上是在環境設置,而不是應用中所做的更改,但重要的是,要注意這裡!我們將在下面,展示我們的託管示例要如何設置。</p>
+</div>
+
+<h3 id="Log_appropriately">Log appropriately</h3>
+
+<p>記錄呼叫會對高流量網站產生影響。在生產環境中,您可能需要記錄網站活動(例如,跟踪流量,或記錄API調用),但您應嘗試最小化為調試目的而添加的日誌記錄量。</p>
+
+<p>在生產環境中,最小化“調試”日誌記錄的一種方法,是使用類似調試 <a href="https://www.npmjs.com/package/debug">debug </a> 的模塊,允許您通過設置環境變量,來控制執行的日誌記錄。例如,下面的代碼片段,顯示如何設置 “author” 日誌記錄。調試變量使用名稱 “author” 聲明,並且將自動顯示,來自此對象的所有日誌的前綴 “author”。</p>
+
+<pre class="brush: js"><strong>var debug = require('debug')('author');</strong>
+
+// Display Author update form on GET
+exports.author_update_get = function(req, res, next) {
+
+ req.sanitize('id').escape().trim();
+ Author.findById(req.params.id, function(err, author) {
+ if (err) {
+<strong> debug('update error:' + err);</strong>
+ return next(err);
+  }
+ //On success
+ res.render('author_form', { title: 'Update Author', author: author });
+ });
+
+};</pre>
+
+<p>然後,您可以通過在 <code>DEBUG </code>環境變量中,將它們指定為逗號分隔列表,來啟用特定日誌集。您可以設置顯示作者和書籍日誌的變量,如圖所示(也支持通配符)。</p>
+
+<pre class="brush: bash">#Windows
+set DEBUG=author,book
+
+#Linux
+export DEBUG="author,book"
+</pre>
+
+<div class="note">
+<p><strong>挑戰:</strong> 調用<code>debug</code>可以替換您以前使用 <code>console.log()</code>或<code>console.error()</code>執行的日誌記錄。通過調試模塊 <a href="https://www.npmjs.com/package/debug">debug </a>進行日誌記錄,替換代碼中的所有<code>console.log()</code>調用。通過設置 DEBUG 變量,並在其中記錄對日誌記錄的影響,在開發環境中,打開和關閉日誌記錄。</p>
+</div>
+
+<p>如果您需要記錄網站活動,可以使用 Winston 或 Bunyan 等日誌庫。有關此主題的更多信息,請參閱:<a href="https://expressjs.com/en/advanced/best-practice-performance.html">生產最佳實踐:性能和可靠性</a>。</p>
+
+<h3 id="使用_gzipdeflate_壓縮響應">使用 gzip/deflate 壓縮響應</h3>
+
+<p>Web 服務器,通常可以壓縮發送回客戶端的 HTTP 響應,從而顯著減少客戶端獲取和加載頁面所需的時間。使用的壓縮方法,取決於客戶端在請求中支持的解壓縮方法(如果不支持壓縮方法,則響應將以未壓縮的方式發送)。</p>
+
+<p>您可以使用壓縮中間件 <a href="https://www.npmjs.com/package/compression">compression</a>,將其添加到您的站點。通過在項目的根目錄下,運行以下命令,將其安裝到項目中。</p>
+
+<pre class="brush: bash">npm install compression</pre>
+
+<p>打開<strong>./app.js</strong>,並導入壓縮庫,如圖所示。使用<code> use()</code>方法,將壓縮庫添加到中間件鏈(這應該出現在您想要壓縮的任何路由之前 - 在本教程這種情況下,全部都是!)</p>
+
+<pre class="brush: js">var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site
+<strong>var compression = require('compression');</strong>
+
+// Create the Express application object
+var app = express();
+
+...
+
+<strong>app.use(compression()); //Compress all routes</strong>
+
+app.use(express.static(path.join(__dirname, 'public')));
+
+app.use('/', indexRouter);
+app.use('/users', usersRouter);
+app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.
+
+...
+</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 對於生產中流量較大的網站,您不會使用此中間件。相反,你會使用像 Nginx 這樣的反向代理。</p>
+</div>
+
+<h3 id="使用_Helmet_避免被常見漏洞侵襲">使用 Helmet 避免被常見漏洞侵襲</h3>
+
+<p><a href="https://www.npmjs.com/package/helmet">Helmet</a> 是一個中間件包,可以通過設置適當的 HTTP 標頭,來幫助保護您的應用,免受一些眾所周知的 Web 漏洞的影響(有關它設置的標頭/防護漏洞的詳細信息,請參閱文檔 <a href="https://helmetjs.github.io/docs/">docs</a>) 。</p>
+
+<p>通過在項目的根目錄下,運行以下命令,將其安裝到項目中。</p>
+
+<pre class="brush: bash">npm install helmet
+</pre>
+
+<p>打開<strong>./app.js</strong>,並導入如圖所示的 helmet 庫。然後使用<code>use()</code>方法,將模塊添加到中間件鏈。</p>
+
+<pre class="brush: js">var compression = require('compression');
+<strong>var helmet = require('helmet');
+</strong>
+// Create the Express application object
+var app = express();
+
+<strong>app.use(helmet())</strong>;
+...</pre>
+
+<div class="note">
+<p id="production-best-practices-performance-and-reliability"><strong>注意:</strong> 上面的命令,添加了對大多數站點有意義的可用標頭子集。您可以按照 <a href="https://www.npmjs.com/package/helmet">npm </a>上的說明,根據需要添加/禁用特定標頭。</p>
+</div>
+
+<h2 id="例子:在_Heroku_上安裝本地圖書館">例子:在 Heroku 上安裝本地圖書館</h2>
+
+<p>本節提供如何在 <a href="http://heroku.com">Heroku PaaS cloud</a> 雲上安裝 LocalLibrary 的實際演示。</p>
+
+<h3 id="為什麼選擇_Heroku">為什麼選擇 Heroku?</h3>
+
+<p>Heroku 是運行時間最長,且最受歡迎的基於雲的 PaaS 服務之一。它最初只支持 Ruby 應用程序,但現在可用於託管來自許多編程環境的應用程序,包括 Node(以及Express)!</p>
+
+<p>我們選擇使用 Heroku 有以下幾個原因:</p>
+
+<ul>
+ <li>Heroku 有一個免費套餐 <a href="https://www.heroku.com/pricing">free tier</a>(儘管有一些限制)。</li>
+ <li>作為 PaaS,Heroku 為我們提供了大量的 Web 基礎架構。這使得入門更加容易,因為您不必擔心服務器,負載平衡器,反向代理,崩潰時重新啟動網站,或者 Heroku 為我們提供的任何其他 Web 基礎結構。</li>
+ <li>雖然它確實有一些限制,但這些不會影響這個特定的應用程序。例如:
+ <ul>
+ <li>Heroku 只提供短期存儲,因此用戶上傳的文件無法安全地存儲在 Heroku本身。</li>
+ <li>如果半小時內沒有請求,免費套餐將使不活動的網絡應用程序進入睡眠。然後,該網站可能需要幾秒鐘才能被喚醒。</li>
+ <li>免費套餐將您網站運行的時間,限制為每月一定的小時數(不包括網站“睡著”的時間)。這對於低使用/演示站點來說很好,但如果需要100%的正常運行時間,則不適用。</li>
+ <li>Heroku 官方文檔 <a href="https://devcenter.heroku.com/articles/limits">Limits </a>中列出的其他限制。</li>
+ </ul>
+ </li>
+ <li>大多數情況下,它只是可以工作,如果你最終喜歡它,並希望升級,那麼擴展你的應用程序非常容易。</li>
+</ul>
+
+<p>雖然 Heroku 非常適合舉辦此演示,但它可能並不適合您的真實網站。 Heroku 可以輕鬆設置和擴展,但代價是靈活性較低,而且一旦退​​​​出免費套餐,可能會花費更多。</p>
+
+<h3 id="Heroku_如何工作">Heroku 如何工作?</h3>
+
+<p>Heroku在一個或多個 "<a href="https://devcenter.heroku.com/articles/dynos">Dynos</a>" 中運行網站,這些 “Dynos” 是獨立的虛擬化Unix容器,提供運行應用程序所需的環境。 Dynos 是完全隔離的,並且有一個短暫的文件系統(一個短暫的文件系統,每次dyno重新啟動時都會清理/清空)。 dynos 默認共享的唯一內容,是應用程序配置變量 <a href="https://devcenter.heroku.com/articles/config-vars">configuration variables</a>。 Heroku 內部使用負載均衡器,將Web流量分配給所有 “web” dynos。由於它們之間沒有任何共享,Heroku 可以通過添加更多 dynos,來水平擴展應用程序(當然,您可能還需要擴展數據庫,以接受其他連接)。</p>
+
+<p>由於文件系統是短暫的,因此無法直接安裝應用程序所需的服務(例如數據庫,隊列,緩存系統,存儲,電子郵件服務等)。相反,Heroku Web應用程序使用 Heroku 或第三方作為獨立“附加組件”提供的支持服務。連接到Web應用程序後,可以通過環境變量,在Web應用程序中訪問附加服務。</p>
+
+<p>為了執行您的應用程序,Heroku 需要能夠設置適當的環境和依賴關係,並了解它是如何啟動的。對於 Node 應用程序,它所需的所有信息都是從 <strong>package.json</strong>文件中獲取的。</p>
+
+<p>開發人員使用特殊的客戶端應用程序/終端,與 Heroku 交互,這很像 Unix bash 腳本。這允許您上傳存儲在 git 儲存庫中的代碼,檢查正在運行的進程,查看日誌,設置配置變量等等!</p>
+
+<p>為了讓我們的應用程序在 Heroku 上工作,我們需要將我們的 Express Web 應用程序放入 git 儲存庫,並對 package.json 進行一些小的更改。完成後,我們可以設置Heroku 帳戶,獲取 Heroku 客戶端,並使用它來安裝我們的網站。</p>
+
+<p>這是您開始教程所需的全部概述(有關更全面的指南,請參閱帶有 Node.js 的<a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Heroku</a> 入門)。</p>
+
+<h3 id="在_Github_上創建一個應用倉庫">在 Github 上創建一個應用倉庫</h3>
+
+<p>Heroku 與 <strong>git</strong> 源代碼版本控制系統緊密集成,使用它來上傳/同步您對實時運行系統所做的任何更改。它通過添加一個名為 heroku 的新 Heroku“遠程”儲存庫,來指向您在Heroku雲上的源儲存庫。在開發期間,您使用 git 在“主”儲存庫 master 中儲存更改。如果要部署站點,請將更改同步到 Heroku 存儲庫。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 如果您習慣於遵循良好的軟件開發實踐,那麼您可能已經在使用 git 或其他一些 SCM 系統。如果您已有 git 儲存庫,則可以跳過此步驟。</p>
+</div>
+
+<p>有很多方法可以使用git,但最簡單的方法之一,是首先在 <a href="https://github.com/">GitHub </a>上建立一個帳戶,在那裡創建儲存庫,然後在本地同步它:</p>
+
+<ol>
+ <li>訪問 <a href="https://github.com/">https://github.com/</a> 並創建一個帳戶。</li>
+ <li>登錄後,單擊頂部工具欄中的 + 號鏈接,然後選擇新建儲存庫  <strong>New repository</strong>。</li>
+ <li>填寫此表單上的所有字段。雖然這些不是強制性的,但強烈建議使用它們。
+ <ul>
+ <li>輸入新的存儲庫名稱(例如,express-locallibrary-tutorial)和描述(例如 “以Express(node)編寫的本地圖書館網站”)。</li>
+ <li>在 Add .gitignore 選擇列表中選擇 <strong>Node</strong>。</li>
+ <li>在添加許可證 Add license 選擇列表中,選擇您偏好的許可證。</li>
+ <li>點選 使用自述文件初始化此儲存庫 <strong>Initialize this repository with a README</strong>.</li>
+ </ul>
+ </li>
+ <li>按 <strong>Create repository</strong>.</li>
+ <li>單擊新倉庫頁面上的綠色“克隆或下載”按鈕 "<strong>Clone or download</strong>" 。</li>
+ <li>從顯示的對話框的文本字段,複製 URL值(它應該類似於:<strong>https://github.com/<em>&lt;your_git_user_id&gt;</em>/express-locallibrary-tutorial.git</strong>)。</li>
+</ol>
+
+<p>現在創建了儲存庫(“repo”),我們將要在本地計算機上克隆它:</p>
+
+<ol>
+ <li>為您的本地計算機安裝 git(您可以在<a href="https://git-scm.com/downloads">此處找到不同平台的版本</a>)。<br>
+  </li>
+ <li>打開命令提示符/終端,並使用您在上面複製的 URL ,克隆儲存庫:
+ <pre class="brush: bash">git clone https://github.com/<strong><em>&lt;your_git_user_id&gt;</em></strong>/express-locallibrary-tutorial.git
+</pre>
+ 這將在當前時間點之後,創建儲存庫。</li>
+ <li>到新的儲存庫。
+ <pre class="brush: bash">cd express-locallibrary-tutorial</pre>
+ </li>
+</ol>
+
+<p>最後一步,是複制你的應用程序,然後使用 git ,將文件添加到你的倉庫:</p>
+
+<ol>
+ <li>將Express應用程序,複製到此文件夾中(不包括 <strong>/node_modules</strong>,其中包含您應根據需要,從 NPM 獲取的依賴項文件)。</li>
+ <li>打開命令提示符/終端,並使用 <code>add </code>命令,將所有文件添加到 git。</li>
+ <li>
+ <pre class="brush: bash">git add -A
+</pre>
+ </li>
+ <li>使用 status 命令,檢查要添加的所有文件是否正確(您希望包含源文件,而不是二進製文件,臨時文件等)。它應該看起來有點像下面的列表。
+ <pre>&gt; git status
+On branch master
+Your branch is up-to-date with 'origin/master'.
+Changes to be committed:
+  (use "git reset HEAD &lt;file&gt;..." to unstage)
+
+        new file:   ...</pre>
+ </li>
+ <li>如果您滿意,請將文件提交到本地儲存庫:
+ <pre class="brush: bash">git commit -m "First version of application moved into github"</pre>
+ </li>
+ <li>然後使用以下內容,將本地儲存庫同步到 Github 網站:
+ <pre>git push origin master</pre>
+ </li>
+</ol>
+
+<p>完成此操作後,您應該可以返回創建儲存庫的 Github 上的頁面,刷新頁面,並查看您的整個應用程序現已上傳。使用此添加/提交/推送循環,您可以在文件更改時,繼續更新儲存庫。</p>
+
+<div class="note">
+<p><strong>提示:</strong> 這是備份你的“vanilla”項目的好時機 - 雖然我們將在以下部分中進行的一些更改,可能對任何平台(或開發)上的部署有用,而一些其他的更改可能沒有用。</p>
+
+<p>執行此操作的最佳方法,是使用 git 來管理您的修訂。使用 git,您不僅可以回到特定的舊版本,而且可以在生產變更的單獨“分支”中進行維護,並選擇在生產和開發分支之間移動的任何更改。<a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">學習Git</a>非常值得,但超出了本主題的範圍。</p>
+
+<p>最簡單的方法,是將文件複製到另一個位置。以您對 git 了解,使用最符合的方法!</p>
+</div>
+
+<h3 id="更新_Heroku_的應用程序">更新 Heroku 的應用程序</h3>
+
+<p>本節介紹了您需要對 LocalLibrary 應用程序進行的更改,以使其在 Heroku 上運行。</p>
+
+<h4 id="設置_node_版本">設置 node 版本</h4>
+
+<p><strong>package.json</strong> 包含解決應用程序依賴項所需的所有內容,以及啟動站點時,應啟動的文件。 Heroku 檢測到此文件的存在,並將使用它來配置您的應用程序環境。</p>
+
+<p>我們當前的 <strong>package.json</strong> 中,缺少的唯一有用信息,是 node 的版本。我們可以通過輸入命令,找到我們用於開發的 node 版本:</p>
+
+<pre class="brush: bash">&gt;node --version
+v8.9.1</pre>
+
+<p>打開 <strong>package.json</strong>,並將此信息添加為 <strong>engines &gt; node</strong> 部分,如圖所示(使用系統的版本號)。</p>
+
+<pre class="brush: json">{
+ "name": "express-locallibrary-tutorial",
+ "version": "0.0.0",
+<strong> "engines": {
+ "node": "8.9.1"
+ },</strong>
+ "private": true,
+  ...
+</pre>
+
+<h4 id="數據庫配置">數據庫配置</h4>
+
+<p>到目前為止,在本教程中,我們使用了一個硬編碼到 <strong>app.js</strong> 的單個數據庫。通常我們希望,能夠為生產和開發創建不同的數據庫,接下來我們將修改 LocalLibrary 網站,以從 OS 環境獲取數據庫 URI(如果已定義),否則使用我們的開發數據庫。</p>
+
+<p>打開 <strong>app.js</strong>,並找到設置 mongoDB 連接變量的行。它看起來像這樣:</p>
+
+<pre class="brush: js">var mongoDB = 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';</pre>
+
+<p>使用以下代碼替換該行,該代碼使用 <code>process.env.MONGODB_URI </code>從名為 <code>MONGODB_URI </code>的環境變量中,獲取連接字符串(如果已設置)(使用您自己的數據庫URL,而不是下面的佔位符。)</p>
+
+<pre class="brush: js">var mongoDB = <strong>process.env.MONGODB_URI</strong> || 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';
+</pre>
+
+<h4 id="安裝依賴並重新測試">安裝依賴並重新測試</h4>
+
+<p>在我們繼續之前,讓我們再次測試該網站,並確保它不受我們的任何更改的影響。</p>
+
+<p>首先,我們需要獲取我們的依賴項(你會記得,我們​​沒有將 <strong>node_modules</strong>文件夾,複製到我們的 git 樹中)。您可以通過在項目根目錄的終端中,運行以下命令來執行此操作:</p>
+
+<pre class="brush: bash">npm install
+</pre>
+
+<p>現在運行該站點(請參閱<a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/routes#Testing_the_routes">測試路由</a>的相關命令),並檢查該站點,是否仍按預期運行。</p>
+
+<h4 id="將更改保存到_Github">將更改保存到 Github</h4>
+
+<p>接下來,讓我們將所有更改保存到 Github。在終端中(在我們的儲存庫中),輸入以下命令:</p>
+
+<pre class="brush: bash">git add -A
+git commit -m "Added files and changes required for deployment to heroku"
+git push origin master</pre>
+
+<p>我們現在應該準備開始在 Heroku 上,部署 LocalLibrary。</p>
+
+<h3 id="獲取一個_Heroku_帳戶">獲取一個 Heroku 帳戶</h3>
+
+<p>要開始使用 Heroku,您首先需要創建一個帳戶(如果您已經擁有一個帳戶,並安裝了 Heroku 客戶端,請跳過創建並上傳網站):</p>
+
+<ul>
+ <li>訪問 <a href="https://www.heroku.com/">www.heroku.com</a> 並單擊免費註冊按鈕 <strong>SIGN UP FOR FREE</strong></li>
+ <li>輸入您的詳細信息,然後按 <strong>CREATE FREE ACCOUNT</strong>。系統會要求您,檢查帳戶中是否有註冊電子郵件。</li>
+ <li>單擊註冊電子郵件中的帳戶激活鏈接。您將在網絡瀏覽器上收回您的帳戶。</li>
+ <li>輸入您的密碼,然後單擊 <strong>SET PASSWORD AND LOGIN</strong>.</li>
+ <li>然後,您將登錄並進入Heroku儀表板: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li>
+</ul>
+
+<h3 id="安裝客戶端">安裝客戶端</h3>
+
+<p>按照 <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">Heroku 上的說明</a>,下載並安裝 Heroku 客戶端。</p>
+
+<p>安裝客戶端后,您將能夠運行命令。例如,要獲得客戶端的幫助說明:</p>
+
+<pre class="brush: bash">heroku help
+</pre>
+
+<h3 id="創建並上傳網站">創建並上傳網站</h3>
+
+<p>要創建應用程序,我們在儲存庫的根目錄中,運行 “create” 命令。這將在我們的本地git 環境中,創建一個名為 heroku 的 git remote(“指向遠程儲存庫的指針”)。</p>
+
+<pre class="brush: bash">heroku create</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 如果您願意,可以在“創建”create 之後指定遠程儲存庫的命名。如果你不這樣做,你會得到一個隨機的名字。該名稱用於默認 URL。</p>
+</div>
+
+<p>然後,我們可以將我們的應用程序,推送到 Heroku 儲存庫,如下所示。這將上傳應用程序,獲取所有依賴項,將其打包到 dyno 中,然後啟動該站點。</p>
+
+<pre class="brush: bash">git push heroku master</pre>
+
+<p>如果我們很幸運,該應用程序現在正在網站上“運行”。要打開瀏覽器並運行新網站,請使用以下命令:</p>
+
+<pre class="brush: bash">heroku open</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 該站點將使用我們的開發數據庫運行。創建一些書本和其他對象,並檢查該網站是否按預期運行。在下一節中,我們將其設置為使用我們的新數據庫。</p>
+</div>
+
+<h3 id="設定配置變量">設定配置變量</h3>
+
+<p>您將從前一節回憶起,我們需要將 NODE_ENV 設置為 'production',以便提高性能,並生成更簡潔的錯誤消息。我們通過輸入以下命令,來完成此操作:</p>
+
+<pre class="brush: bash">&gt;heroku config:set NODE_ENV='production'
+Setting NODE_ENV and restarting limitless-tor-18923... done, v13
+NODE_ENV: production
+</pre>
+
+<p>我們還應該使用單獨的數據庫進行生產,在<strong>MONGODB_URI</strong>環境變量中,設置其URI。您可以完全按照<a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/mongoose#Setting_up_the_MongoDB_database">我們原來的方式</a>,設置新數據庫和數據庫用戶,並獲取其URI。您可以如下圖所示設置URI(顯然,要使用您自己的URI!)</p>
+
+<pre class="brush: bash">&gt;heroku config:set <strong>MONGODB_URI</strong>='mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production'
+Setting MONGODB_URI and restarting limitless-tor-18923... done, v13
+MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
+</pre>
+
+<p>您可以使用 <code>heroku config </code>命令,隨時檢查配置變量 - 立即嘗試:</p>
+
+<pre class="brush: bash">&gt;heroku config
+=== limitless-tor-18923 Config Vars
+MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
+NODE_ENV:    production
+</pre>
+
+<p>Heroku 會在更新變量時,重新啟動應用程序。如果您現在檢查主頁,它應該顯示對象計數的零值,因為上面的更改,意味著我們現在正在使用新的(空)數據庫。</p>
+
+<h3 id="管理附加組件">管理附加組件</h3>
+
+<p>Heroku 使用獨立的附加組件,為應用程序提供支持服務 - 例如電子郵件或數據庫服務。我們不在本網站中使用任何插件,但它們是使用 Heroku 的重要部分,因此您可能需要查看主題 - <a href="https://devcenter.heroku.com/articles/managing-add-ons">管理插件(Heroku 官方文件)</a>。</p>
+
+<h3 id="除錯">除錯</h3>
+
+<p>Heroku 客戶端提供了一些除錯工具:</p>
+
+<pre class="brush: bash">heroku logs # Show current logs
+heroku logs --tail # Show current logs and keep updating with any new results
+heroku ps #Display dyno status
+</pre>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>本教程介紹在生產環境中,如何配置 Express 應用。是Express系列教程的最後一個。我們希望你覺得這些教程有用。你可以在 <a href="https://github.com/mdn/express-locallibrary-tutorial">Github </a>上取得完整的源碼。</p>
+
+<h2 id="相關鏈接">相關鏈接</h2>
+
+<ul>
+ <li id="production-best-practices-performance-and-reliability"><a href="https://expressjs.com/en/advanced/best-practice-performance.html">Production best practices: performance and reliability</a> (Express docs)</li>
+ <li><a href="https://expressjs.com/en/advanced/best-practice-security.html">Production Best Practices: Security</a> (Express docs)</li>
+ <li>Heroku
+ <ul>
+ <li><a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Getting Started on Heroku with Node.js</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/deploying-nodejs">Deploying Node.js Applications on Heroku</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/nodejs-support">Heroku Node.js Support</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/node-concurrency">Optimizing Node.js Application Concurrency</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/config-vars">Configuration and Config Vars</a> (Heroku docs)</li>
+ <li><a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs)</li>
+ </ul>
+ </li>
+ <li>Digital Ocean
+ <ul>
+ <li><a href="https://www.digitalocean.com/community/tutorials?q=express">Express</a> tutorials</li>
+ <li><a href="https://www.digitalocean.com/community/tutorials?q=node.js">Node.js</a> tutorials </li>
+ </ul>
+ </li>
+</ul>
+
+<p>{{PreviousMenu("Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<p> </p>
+
+<h2 id="本教學鏈接">本教學鏈接</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html b/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html
new file mode 100644
index 0000000000..3e556ada3a
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/development_environment/index.html
@@ -0,0 +1,385 @@
+---
+title: Setting up a Node development environment
+slug: Learn/Server-side/Express_Nodejs/development_environment
+translation_of: Learn/Server-side/Express_Nodejs/development_environment
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">現在你已經了解Express的目的了,接下來繼續說明如何設定和測試 Windows、Linux (Ubuntu)和Mac OS X上的Node/Express開發環境。不管你用的是什麼作業系統,你都能在本文中找到開發Express應用的入門需知。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置需求:</th>
+ <td>了解如何開啟terminal / command line. 了解如何在開發系統上安裝套件。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>在你的電腦上設定Express(X.XX)開發環境。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Express_開發環境概覽">Express 開發環境概覽</h2>
+
+<p>為了使你能快速的開發web應用,<em>Node</em> 和 <em>Express</em> 非常容易安裝,這個部分說明哪些工具是需要的、在Ubuntu、macOS和Windows中安裝Node和Express的最簡單方法、展示如何測試安裝成功與否。</p>
+
+<h3 id="什麼是Express開發環境">什麼是Express開發環境?</h3>
+
+<p><em>Express</em> 開發環境包含 <em>Nodejs、</em><em>NPM </em>套件管理器的安裝, 還有 <em>Express Application </em>產生器(可選)<em>。</em></p>
+
+<p><em>Node </em>和 <em>NPM</em> 套件管理器會從準備好的 binary package、安裝檔、 作業系統的套件管理器或是從源檔一起安裝。接著 <em>Express </em>會透過 NPM 進行安裝,成為你所有個別 Express web 應用的依賴項(以及其他函式庫,如模板引擎,資料庫驅動程式,身份驗證中間層,用於提供靜態文件的中間件等)</p>
+
+<p>NPM 也可用來安裝 Express 應用程式產生器(全域用),一個方便的工具幫助你創造符合 <a href="https://developer.mozilla.org/en-US/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">MVC模式</a>的 Express web app 骨架。你不一定要使用應用程式產生器,因為每個Express應用程式不需要擁有同樣的檔案結構或依賴項。但為了專注於學習本身以及習慣模組化架構,我們會在接下來的教學中使用它。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 與其他不包含單獨的web開發伺服器的Web框架不同。 在Node / Express中,Web應用程式創建並運行自己的Web伺服器!</p>
+</div>
+
+<p>典型的開發環境還包含其他工具,例如:編輯程式碼使用的<a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Available_text_editors">文字編輯器</a>、IDE,進行版本控置管理不同版本程式碼的<a href="/zh-TW/docs/Glossary/Git">Git</a>。這邊假設你已經有這種工具了(尤其是文字編輯器)</p>
+
+<h3 id="哪些作業系統有支援">哪些作業系統有支援?</h3>
+
+<p>Node 可以執行在 Windows、macOS、各種 Linux、Docker 等等(nodejs 的<a href="https://nodejs.org/en/download/">下載</a>頁面有完整的列表),在開發階段中個人電腦應該都有足夠的效能來執行 Node 。Express 執行在 Node 環境中,所以也能所有有安裝Node的平台上執行。</p>
+
+<p>在這份教學中我們提供 Windows、macOS 和 Ubuntu Linux 的 Node 安裝教學。</p>
+
+<h3 id="該用什麼版本的_NodeExpress">該用什麼版本的 Node/Express?</h3>
+
+<p>Node 有許多<a href="https://nodejs.org/en/blog/release/">版本</a>,更新的版本代表著 bug 的修復、支援更新版本的 ECMAScript(JavaScript)標準和更好的 Node APIs 。</p>
+
+<p>基本上你應該使用最新的 LTS 版本(<em>long-term supported,</em>長期維護版)。這種版本比『Current』版本更穩定而且還擁有最新的功能及持續性的更新維護。除非LTS不支援你需要的功能才使用『Current』版本。</p>
+
+<p>而 Express ?永遠使用最新版!</p>
+
+<h3 id="關於資料庫和其他依賴項呢">關於資料庫和其他依賴項呢?</h3>
+
+<p>諸如資料庫、模版引擎、驗證引擎等等都屬於應用程式的一部分,這些依賴項會透過NPM導入應用程式環境中,在後續的章節將會進一步探討。</p>
+
+<h2 id="安裝Node">安裝Node</h2>
+
+<p>為了使用Express,首先要在你的電腦上安裝Node和<a href="https://docs.npmjs.com/">Node Package Manager (NPM)</a>。接下來用最簡單的方法在 Ubuntu Linux 16.04、 macOS和 Windows 10上安裝Nodejs的 Long Term Supported (LTS)版本吧</p>
+
+<div class="note">
+<p>以下的部分用最簡單的方法在上述的作業系統中安裝Node和NPM。如果你使用其他作業系統或想看看其他平台的安裝方式,請查閱<a href="https://nodejs.org/en/download/package-manager/">透過套件管理器安裝Node.js</a> (nodejs.org)。</p>
+</div>
+
+<h3 id="Windows_和macOS">Windows 和macOS</h3>
+
+<p>直接使用安裝檔吧!</p>
+
+<ol>
+ <li>下載需要的安裝檔:
+ <ol>
+ <li>開啟 <a href="https://nodejs.org/en/">https://nodejs.org/en/</a></li>
+ <li>對於大部分的使用者來說,直接下載LTS版本</li>
+ </ol>
+ </li>
+ <li>下載完成後雙擊安裝檔,並照著安裝流程繼續。</li>
+</ol>
+
+<h3 id="Ubuntu_16.04">Ubuntu 16.04</h3>
+
+<p>安裝Node 8.x LTS版本最簡單的方法是使用<a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">套件管理器</a>,只要在terminal上執行兩行指令</p>
+
+<pre class="brush: bash notranslate"><code>curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
+sudo apt-get install -y nodejs</code>
+
+</pre>
+
+<div class="warning">
+<p><strong>警告:</strong> 不要直接從普通的Ubuntu repositories 安裝,那邊只有很舊的版本。</p>
+</div>
+
+<ol>
+</ol>
+
+<h3 id="測試_Nodejs_和NPM_的安裝">測試 Nodejs 和NPM 的安裝</h3>
+
+<p>測試Node安裝最簡單的方法是在terminal/command上執行"version"這個指令,它會顯示當前的Node版本:</p>
+
+<pre class="brush: bash notranslate">&gt;node -v
+v8.9.4</pre>
+
+<p>NPM應該會隨著Node一起安裝,可以用相同的方法進行測試:</p>
+
+<pre class="brush: bash notranslate">&gt;npm -v
+5.6.0</pre>
+
+<p>接著用稍為令人興奮的方法來測試吧!讓我們創件一個非常基本的『純Node』伺服器,當你開啟正確的網頁時它會在瀏覽器上顯示"Hello World"</p>
+
+<ol>
+ <li>複製以下的文字到名為<strong>hellonode.js</strong>的檔案中,目前我們只用到Node而已。
+
+ <pre class="brush: js notranslate">//載入HTTP模組
+var http = require("http");
+
+//創建HTTP 伺服器並監聽8000埠
+http.createServer(function (request, response) {
+
+ // Set the response HTTP header with HTTP status and Content type
+ response.writeHead(200, {'Content-Type': 'text/plain'});
+
+ // Send the response body "Hello World"
+ response.end('Hello World\n');
+}).listen(8000);
+
+// Print URL for accessing server
+console.log('Server running at http://127.0.0.1:8000/')
+</pre>
+
+ <p>這段程式載入『http』模組,並創建一個伺服器 (<code>createServer()</code>,並在8000埠上監聽HTTP requests。 The script then prints a message to the console about what browser URL you can use to test the server. The <code>createServer()</code> function takes as an argument a callback function that will be invoked when an HTTP request is received — this simply returns a response with an HTTP status code of 200 ("OK") and the plain text "Hello World".</p>
+ </li>
+ <li>
+ <div class="note">
+ <p><strong>Note:</strong>  Don't worry if you don't understand exactly what this code is doing yet! We'll explain our code in greater detail once we start using Express!</p>
+ </div>
+ </li>
+ <li>Start the server by navigating into the same directory as your <code>hellonode.js</code> file in your command prompt, and calling <code>node</code> along with the script name, like so:
+ <pre class="brush: bash notranslate">&gt;node hellonode.js
+Server running at http://127.0.0.1:8000/
+</pre>
+ </li>
+ <li>Navigate to the URL (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>). If everything is working, the browser should simply display the string "Hello World".</li>
+</ol>
+
+<h2 id="Using_NPM">Using NPM</h2>
+
+<p>Next to <em>Node</em> itself, <a href="https://docs.npmjs.com/">NPM</a> is the most important tool for working with<em> Node </em>applications. NPM is used to fetch any packages (JavaScript libraries) that an application needs for development, testing, and/or production, and may also be used to run tests and tools used in the development process. </p>
+
+<div class="note">
+<p><strong>Note:</strong> From Node's perspective, <em>Express</em> is just another package that you need to install using NPM and then require in your own code.</p>
+</div>
+
+<p>You can manually use NPM to separately fetch each needed package. Typically we instead manage dependencies using a plain-text definition file named <a href="https://docs.npmjs.com/files/package.json">package.json</a>. This file lists all the dependencies for a specific JavaScript "package", including the package's name, version, description, initial file to execute, production dependencies, development dependencies, versions of <em>Node</em> it can work with, etc. The <strong>package.json</strong> file should contain everything NPM needs to fetch and run your application (if you were writing a reusable library you could use this definition to upload your package to the npm respository and make it available for other users).</p>
+
+<h3 id="Adding_dependencies">Adding dependencies</h3>
+
+<p>The following steps show how you can use NPM to download a package, save it into the project dependencies, and then require it in a Node application.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Here we show the instructions to fetch and install the <em>Express</em> package. Later on we'll show how this package, and others, are already specified for us using the <em>Express Application Generator</em>. This section is provided because it is useful to understand how NPM works and what is being created by the application generator.</p>
+</div>
+
+<ol>
+ <li>First create a directory for your new application and navigate into it:
+ <pre class="brush: bash notranslate">mkdir myapp
+cd myapp</pre>
+ </li>
+ <li>Use the npm <code>init</code> command to create a <strong>package.json</strong> file for your application. This command prompts you for a number of things, including the name and version of your application and the name of the initial entry point file (by default this is <strong>index.js</strong>). For now, just accept the defaults:
+ <pre class="brush: bash notranslate">npm init</pre>
+
+ <p>If you display the <strong>package.json</strong> file (<code>cat package.json</code>), you will see the defaults that you accepted, ending with the license.</p>
+
+ <pre class="brush: json notranslate">{
+ "name": "myapp",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
+</pre>
+ </li>
+ <li>Now install the <em>Express</em> library in the <strong>myapp</strong> directory. The package will automatically be saved to the dependencies list in your <strong>package.json</strong> file.
+ <pre class="brush: bash notranslate">npm install express</pre>
+
+ <p>The dependencies section of your <strong>package.json</strong> will now appear at the end of the <strong>package.json</strong> file and will include <em>Express</em>.</p>
+
+ <pre class="brush: json notranslate">{
+ "name": "myapp",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+<strong> "dependencies": {
+ "express": "^4.16.2"
+ }</strong>
+}
+</pre>
+ </li>
+ <li>To use the library you call the <code>require()</code> function as shown below.
+ <pre class="notranslate"><code><strong>var express = require('express')</strong>
+var app = express()
+
+app.get('/', function (req, res) {
+ res.send('Hello World!')
+})
+
+app.listen(</code>8000<code>, function () {
+ console.log('Example app listening on port </code>8000<code>!')
+})</code>
+</pre>
+
+ <p>This code shows a minimal "HelloWorld" Express web application. This imports the "express" module and uses it to create a server (<code>app</code>) that listens for HTTP requests on port 8000 and prints a message to the console explaining what browser URL you can use to test the server. The <code>app.get()</code> function only responds to HTTP <code>GET</code> requests with the specified URL path ('/'), in this case by calling a function to send our <em>Hello World!</em> message. <br>
+ <br>
+ Create a file named <strong>index.js</strong> in the root of the "myapp" application directory and give it the contents shown above.</p>
+ </li>
+ <li>You can start the server by calling node with the script in your command prompt:
+ <pre class="brush: bash notranslate">&gt;node index.js
+Example app listening on port 8000
+</pre>
+ </li>
+ <li>Navigate to the URL (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>). If everything is working, the browser should simply display the string "Hello World!".</li>
+</ol>
+
+<h3 id="Development_dependencies">Development dependencies</h3>
+
+<p>If a dependency is only used during development, you should instead save it as a "development dependency" (so that your package users don't have to install it in production). For example, to use the popular JavaScript Linting tool <a href="http://eslint.org/">eslint</a> you would call NPM as shown:</p>
+
+<pre class="brush: bash notranslate"><code>npm install eslint --save-dev</code></pre>
+
+<p>The following entry would then be added to your application's <strong>package.json</strong>:</p>
+
+<pre class="brush: js notranslate"> "devDependencies": {
+ "eslint": "^4.12.1"
+ }
+</pre>
+
+<div class="note">
+<p><strong>Note:</strong> "<a href="https://en.wikipedia.org/wiki/Lint_(software)">Linters</a>" are tools that perform static analysis on software in order to recognise and report adherence/non-adherance to some set of coding best practice.</p>
+</div>
+
+<h3 id="Running_tasks">Running tasks</h3>
+
+<p>In addition to defining and fetching dependencies you can also define <em>named</em> scripts in your <strong>package.json</strong> files and call NPM to execute them with the <a href="https://docs.npmjs.com/cli/run-script">run-script</a> command. This approach is commonly used to automate running tests and parts of the development or build toolchain (e.g., running tools to minify JavaScript, shrink images, LINT/analyse your code, etc).</p>
+
+<div class="note">
+<p><strong>Note:</strong> Task runners like <a href="http://gulpjs.com/">Gulp</a> and <a href="http://gruntjs.com/">Grunt</a> can also be used to run tests and other external tools.</p>
+</div>
+
+<p>For example, to define a script to run the <em>eslint</em> development dependency that we specified in the previous section we might add the following script block to our <strong>package.json</strong> file (assuming that our application source is in a folder /src/js):</p>
+
+<pre class="brush: js notranslate">"scripts": {
+ ...
+ "lint": "eslint src/js"
+  ...
+}
+</pre>
+
+<p>To explain a little further, <code>eslint src/js</code> is a command that we could enter in our terminal/command line to run <code>eslint</code> on JavaScript files contained in the <code>src/js</code> directory inside our app directory. Including the above inside our app's package.json file provides a shortcut for this command — <code>lint</code>.</p>
+
+<p>We would then be able to run <em>eslint</em> using NPM by calling:</p>
+
+<pre class="brush: bash notranslate"><code>npm run-script lint
+# OR (using the alias)
+npm run lint</code>
+</pre>
+
+<p>This example may not look any shorter than the original command, but you can include much bigger commands inside your npm scripts, including chains of multiple commands. You could identify a single npm script that runs all your tests at once.</p>
+
+<h2 id="Installing_the_Express_Application_Generator">Installing the Express Application Generator</h2>
+
+<p>The <a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> tool generates an Express application "skeleton". Install the generator using NPM as shown (the <code>-g</code> flag installs the tool globally so that you can call it from anywhere):</p>
+
+<pre class="notranslate"><code>npm install express-generator -g</code></pre>
+
+<p>To create an <em>Express</em> app named "helloworld" with the default settings, navigate to where you want to create it and run the app as shown:</p>
+
+<pre class="brush: bash notranslate">express helloworld</pre>
+
+<div class="note">
+<p><strong>Note: </strong>You can also specify the template library to use and a number of other settings. Use the <code>help</code> command to see all the options:</p>
+
+<pre class="brush: bash notranslate">express --help
+</pre>
+</div>
+
+<p>NPM will create the new Express app in a sub folder of your current location, displaying build progress on the console. On completion, the tool will display the commands you need to enter to install the Node dependencies and start the app.</p>
+
+<div class="note">
+<p>The new app will have a <strong>package.json</strong> file in its root directory. You can open this to see what dependencies are installed, including Express and the template library Jade:</p>
+
+<pre class="brush: js notranslate">{
+  "name": "helloworld",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www"
+  },
+  "dependencies": {
+    "body-parser": "~1.18.2",
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.15.5",
+    "jade": "~1.11.0",
+    "morgan": "~1.9.0",
+    "serve-favicon": "~2.4.5"
+  }
+}</pre>
+</div>
+
+<p>Install all the dependencies for the helloworld app using NPM as shown:</p>
+
+<pre class="brush: bash notranslate">cd helloworld
+npm install
+</pre>
+
+<p>Then run the app (the commands are slightly different for Windows and Linux/macOS), as shown below:</p>
+
+<pre class="brush: bash notranslate"># Run the helloworld on Windows
+SET DEBUG=helloworld:* &amp; npm start
+
+# Run helloworld on Linux/macOS
+DEBUG=helloworld:* npm start
+</pre>
+
+<p>The DEBUG command creates useful logging, resulting in an output like that shown below.</p>
+
+<pre class="brush: bash notranslate">&gt;SET DEBUG=helloworld:* &amp; npm start
+
+&gt; helloworld@0.0.0 start D:\Github\expresstests\helloworld
+&gt; node ./bin/www
+
+  helloworld:server Listening on port 3000 +0ms</pre>
+
+<p>Open a browser and navigate to <a href="http://127.0.0.1:3000/">http://127.0.0.1:3000/</a> to see the default Express welcome page.</p>
+
+<p><img alt="Express - Generated App Default Screen" src="https://mdn.mozillademos.org/files/14331/express_default_screen.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 675px;"></p>
+
+<p>We'll talk more about the generated app when we get to the article on generating a skeleton application.</p>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>你現在有一個 Node 開發環境在你的電腦上運行,可以用來創造 Express 網頁應用。你也看到如何用 NPM 來加載 Express到一個應用中,以及看到如何使用 Express 應用產生器,創建應用,然後執行它們。</p>
+
+<p>下一篇文章,我們開始跟著教程一步一步實作,使用這個開發環境與搭配工具,建立一個完整的網頁應用。</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://nodejs.org/en/download/">Downloads</a> page (nodejs.org)</li>
+ <li><a href="https://nodejs.org/en/download/package-manager/">Installing Node.js via package manager</a> (nodejs.org)</li>
+ <li><a href="http://expressjs.com/en/starter/installing.html">Installing Express</a> (expressjs.com)</li>
+ <li><a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> (expressjs.com)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</p>
+
+
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html
new file mode 100644
index 0000000000..df7a5180e5
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_detail_page/index.html
@@ -0,0 +1,89 @@
+---
+title: 作者詳情頁面
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page
+---
+<p>作者細節頁面,需要呈現指定作者 <code>Author </code>的信息,使用 <code>_id</code> 欄位的值(自動產生)識別,接著是這個作者 <code>Author </code>的所有書本物件 <code>Book </code>的列表。</p>
+
+<h2 id="Controller_控制器">Controller 控制器</h2>
+
+<p>打開 <strong>/controllers/authorController.js</strong>.</p>
+
+<p>在檔案最上方,加入底下幾行,引入 <em>async</em> 和 <em>Book</em> 模組(作者細節頁面需要它們)。</p>
+
+<pre class="brush: js">var async = require('async');
+var Book = require('../models/book');</pre>
+
+<p>找到 exported <code>author_detail()</code> 控制器方法,並用底下代碼置換。</p>
+
+<pre class="brush: js">// Display detail page for a specific Author.
+exports.author_detail = function(req, res, next) {
+
+<strong>    async.parallel({
+        author: function(callback) {
+            Author.findById(req.params.id)
+              .exec(callback)
+        },
+        authors_books: function(callback) {
+          Book.find({ 'author': req.params.id },'title summary')
+          .exec(callback)
+        },
+    }, function(err, results) {
+        if (err) { return next(err); } // Error in API usage.
+        if (results.author==null) { // No results.
+            var err = new Error('Author not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render.
+        res.render('author_detail', { title: 'Author Detail', author: results.author, author_books: results.authors_books } );
+    });</strong>
+
+};
+</pre>
+
+<p>此處的控制器方法使用<code> async.parallel()</code>,用平行的方式,查詢作者 <code>Author</code>和相應的書本實例,並附加上繪製本頁面的回調,如果 2 個要求都成功完成,就運行回調。這個方式,就跟前面的<em>種類細節頁面</em>所說明的完全相同。</p>
+
+<h2 id="View_視圖">View 視圖</h2>
+
+<p>創建 <strong>/views/author_detail.pug</strong> ,並複制貼上底下的文字。</p>
+
+<pre class="brush: js">extends layout
+
+block content
+
+<strong>  h1 Author: #{author.name}</strong>
+  p #{author.date_of_birth} - #{author.date_of_death}
+
+  div(style='margin-left:20px;margin-top:20px')
+
+    h4 Books
+
+    dl
+     each book in author_books
+      dt
+        a(href=book.url) #{book.title}
+      dd #{book.summary}
+
+     else
+      p This author has no books.
+</pre>
+
+<p>本模板裡的所有事物,都在先前的章節演示過了。</p>
+
+<h2 id="它看起來像是">它看起來像是?</h2>
+
+<p>運行本應用,並打開瀏覽器訪問 <a href="http://localhost:3000/">http://localhost:3000/</a>。選擇 <em>All Authors</em> 連結,然後選擇一個作者。如果每個東西都設定正確了,你的網站看起來應該會像底下的截圖。</p>
+
+<p><img alt="Author Detail Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14466/LocalLibary_Express_Author_Detail.png" style="border-style: solid; border-width: 1px; display: block; height: 422px; margin: 0px auto; width: 1000px;"></p>
+
+<div class="note">
+<p><strong>注意:</strong>  作者的出生與死亡日期的外觀很醜!我們將在本文最後的自我挑戰處理它。</p>
+</div>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+ <li>繼續教學 5 的最後一個部分: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge">書本實例詳情頁面與自我挑戰</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html
new file mode 100644
index 0000000000..f207126ed1
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html
@@ -0,0 +1,85 @@
+---
+title: Author list page and Genre list page challenge
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page
+---
+<p>作者列表頁面,需要呈現數據庫中所有作者的列表,有每位作者的名字,並連結到作者詳細內容頁面。出生與死亡日期應該在名字後面,並且在同一列。</p>
+
+<h2 class="highlight-spanned" id="Controller_控制器"><span class="highlight-span">Controller </span>控制器</h2>
+
+<p>作者列表控制器函數,需要獲取所有作者實例的列表,然後將這些實例傳遞給模板進行渲染。</p>
+
+<p>打開 <strong>/controllers/authorController.js</strong>。在文件頂部附近,找到導出的 <code>author_list() </code>控制器方法,並將其替換為以下代碼(更改後的代碼以<strong>粗體</strong>顯示)。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all Authors.</span>
+exports<span class="punctuation token">.</span>author_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+
+ Author<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">sort</span><span class="punctuation token">(</span><span class="punctuation token">[</span><span class="punctuation token">[</span><span class="string token">'family_name'</span><span class="punctuation token">,</span> <span class="string token">'ascending'</span><span class="punctuation token">]</span><span class="punctuation token">]</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_authors<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">//Successful, so render</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'author_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Author List'</span><span class="punctuation token">,</span> author_list<span class="punctuation token">:</span> list_authors <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<p>The method uses the model's <code>find()</code>, <code>sort()</code> and <code>exec()</code> functions to return all <code>Author</code> objects sorted by <code>family_name</code> in alphabetic order. The callback passed to the <code>exec()</code> method is called with any errors (or <code>null</code>) as the first parameter, or a list of all authors on success. If there is an error it calls the next middleware function with the error value, and if not it renders the <strong>author_list</strong>(.pug) template, passing the page <code>title</code> and the list of authors (<code>author_list</code>).</p>
+
+<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2>
+
+<p>Create <strong>/views/author_list.pug</strong> and replace its content with the text below.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span>
+
+block content
+ h1<span class="operator token">=</span> title
+
+ ul
+ each author <span class="keyword token">in</span> author_list
+ li
+ <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>author<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>author<span class="punctuation token">.</span>name<span class="punctuation token">}</span>
+ <span class="operator token">|</span> <span class="punctuation token">(</span>#<span class="punctuation token">{</span>author<span class="punctuation token">.</span>date_of_birth<span class="punctuation token">}</span> <span class="operator token">-</span> #<span class="punctuation token">{</span>author<span class="punctuation token">.</span>date_of_death<span class="punctuation token">}</span><span class="punctuation token">)</span>
+
+ <span class="keyword token">else</span>
+ li There are no authors<span class="punctuation token">.</span></code></pre>
+
+<p>The view follows exactly the same pattern as our other templates.</p>
+
+<h2 class="highlight-spanned" id="What_does_it_look_like"><span class="highlight-span">What does it look like?</span></h2>
+
+<p>Run the application and open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Then select the <em>All authors </em>link. If everything is set up correctly, the page should look something like the following screenshot.</p>
+
+<p><img alt="Author List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14468/LocalLibary_Express_Author_List.png" style="display: block; height: 453px; margin: 0px auto; width: 1200px;"></p>
+
+<div class="note">
+<p><strong>Note:</strong> The appearance of the author <em>lifespan </em>dates is ugly! You can improve this using the <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data#date_formatting">same approach</a> as we used for the <code>BookInstance</code> list (adding the virtual property for the lifespan to the <code>Author</code> model). This time, however, there are missing dates, and references to nonexistent properties are ignored unless strict mode is in effect. <code>moment()</code> returns the current time, and you don't want missing dates to be formatted as if they were today. One way to deal with this is to define the body of the function that returns a formatted date so it returns a blank string unless the date actually exists. For example:</p>
+
+<p><code>return this.date_of_birth ? moment(this.date_of_birth).format('YYYY-MM-DD') : '';</code></p>
+</div>
+
+<h2 id="Genre_list_page—challenge!Edit">Genre list page—challenge!<a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data$edit#Genre_list_page—challenge!" rel="nofollow, noindex"><span>Edit</span></a></h2>
+
+<p>In this section you should implement your own genre list page. The page should display a list of all genres in the database, with each genre linked to its associated detail page. A screenshot of the expected result is shown below.</p>
+
+<p><img alt="Genre List - Express Local Library site" src="https://mdn.mozillademos.org/files/14460/LocalLibary_Express_Genre_List.png" style="border-style: solid; border-width: 1px; display: block; height: 346px; margin: 0px auto; width: 600px;"></p>
+
+<p>The genre list controller function needs to get a list of all <code>Genre</code> instances, and then pass these to the template for rendering.</p>
+
+<ol>
+ <li>You will need to edit <code>genre_list()</code> in <strong>/controllers/genreController.js</strong>. </li>
+ <li>The implementation is almost exactly the same as the <code>author_list()</code> controller.
+ <ul>
+ <li>Sort the results by name, in ascending order.</li>
+ </ul>
+ </li>
+ <li>The template to be rendered should be named <strong>genre_list.pug</strong>.</li>
+ <li>The template to be rendered should be passed the variables <code>title</code> ('Genre List') and <code>genre_list</code> (the list of genres returned from your <code>Genre.find()</code> callback.</li>
+ <li>The view should match the screenshot/requirements above (this should have a very similar structure/format to the Author list view, except for the fact that genres do not have dates).</li>
+</ol>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<p>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</p>
+
+<p>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page">Genre detail page</a>.</p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html
new file mode 100644
index 0000000000..31f3d65284
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_detail_page/index.html
@@ -0,0 +1,112 @@
+---
+title: 書本詳情頁面
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page
+---
+<p><em>書本細節頁面</em>需要呈現一本指定書本(<code>Book</code>)的信息, 使用它的 <code>_id</code> 字段值(自動產生)做為識別,接著是圖書館中書本實例(<code>BookInstance</code>)的信息。無論我們在哪裡呈現一個作者、種類、或書本實例,都應該連結到它的細節頁面。</p>
+
+<h2 id="Controller_控制器">Controller 控制器</h2>
+
+<p>打開 <strong>/controllers/bookController.js.</strong> ,找到 exported <code>book_detail()</code> 控制器方法,用底下的代碼置換。</p>
+
+<pre class="brush: js">// Display detail page for a specific book.
+exports.book_detail = function(req, res, next) {
+
+<strong>    async.parallel({
+        book: function(callback) {
+
+            Book.findById(req.params.id)
+              .populate('author')
+              .populate('genre')
+              .exec(callback);
+        },
+        book_instance: function(callback) {
+
+          BookInstance.find({ 'book': req.params.id })
+          .exec(callback);
+        },
+    }, function(err, results) {
+        if (err) { return next(err); }
+        if (results.book==null) { // No results.
+            var err = new Error('Book not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render.
+        res.render('book_detail', { title: 'Title', book:  results.book, book_instances: results.book_instance } );
+    });</strong>
+
+};
+
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong>  我們不需要用 require 導入 <em>async</em> 和 <em>BookInstance</em>,當我們實作主頁面控制器的時候,我們就已經引入這些模組。</p>
+</div>
+
+<p>此處的控制器方法使用 <code>async.parallel()</code>,用平行的方式找到 <code>Book</code> 以及它的相應複本 (<code>BookInstances</code>) 。這樣的處理方式,就跟上面的 <em>種類細節頁面</em> 所說明的完全相同。</p>
+
+<h2 id="View_視圖">View 視圖</h2>
+
+<p>創建 <strong>/views/book_detail.pug </strong>並加入底下文字。</p>
+
+<pre class="brush: js">extends layout
+
+block content
+  h1 #{title}: #{book.title}
+
+  p #[strong Author:]
+    a(href=book.author.url) #{book.author.name}
+  p #[strong Summary:] #{book.summary}
+  p #[strong ISBN:] #{book.isbn}
+  p #[strong Genre:]&amp;nbsp;
+    each val, index in book.genre
+      a(href=val.url) #{val.name}
+  if index &lt; book.genre.length - 1
+      |,
+
+  div(style='margin-left:20px;margin-top:20px')
+    h4 Copies
+
+    each val in book_instances
+      hr
+      if val.status=='Available'
+        <strong>p.text-success</strong> #{val.status}
+      else if val.status=='Maintenance'
+        p.text-danger #{val.status}
+      else
+        p.text-warning #{val.status}
+      p #[strong Imprint:] #{val.imprint}
+      if val.status!='Available'
+        p #[strong Due back:] #{val.due_back}
+      p #[strong Id:]&amp;nbsp;
+        a(href=val.url) #{val._id}
+
+    else
+      p There are no copies of this book in the library.
+</pre>
+
+<p>在這個模板裡,幾乎每個東西都在先前的章節演示過了。</p>
+
+<div class="note">
+<p><strong>注意:</strong>  與該書相關的種類列表,在模板中的實作,如以下代碼。除了最後一本書之外,在與本書相關的每個種類之後,都會添加一個逗號。</p>
+
+<pre> p #[strong Genre:]
+  each val, index in book.genre
+  a(href=val.url) #{val.name}
+  if index &lt; book.genre.length - 1
+  |, </pre>
+</div>
+
+<h2 id="它看起來像是">它看起來像是?</h2>
+
+<p>運行本應用,並打開瀏覽器訪問 <a href="http://localhost:3000/">http://localhost:3000/</a>。選擇 <em>All books</em> 連結,然後選擇其中一本書。如果每個東西都設定正確了,你的頁面看起來應該像是底下的截圖。</p>
+
+<p><img alt="Book Detail Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14470/LocalLibary_Express_Book_Detail.png" style="border-style: solid; border-width: 1px; display: block; height: 616px; margin: 0px auto; width: 1200px;"></p>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到  <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+ <li>繼續教學 5 下一個部分: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page">作者詳情頁面</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html
new file mode 100644
index 0000000000..a35b31767d
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html
@@ -0,0 +1,72 @@
+---
+title: 書本清單頁面
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page
+---
+<p>接下做我們將實作書本列表頁面。這個頁面需要呈現數據庫中所有書本的列表,包含每本書的作者、標題,標題將成為一個超連結,連到書本詳細內容頁面。</p>
+
+<h2 class="highlight-spanned" id="控制器">控制器</h2>
+
+<p>書本列表控制器函數,需要獲取數據庫中所有 <code>Book</code>對象的列表,然後將這些對像傳給模板進行呈現。</p>
+
+<p>打開 <strong>/controllers/bookController.js</strong>. 找到導出的 <code>book_list()</code>控制器方法,並替換為下面的代碼。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all Books.</span>
+exports<span class="punctuation token">.</span>book_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+
+ Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span> <span class="string token">'title author'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'author'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_books<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">//Successful, so render</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'book_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Book List'</span><span class="punctuation token">,</span> book_list<span class="punctuation token">:</span> list_books <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<p>該方法使用模型的<code>find()</code>函數,返回所有 <code>Book </code>對象,選擇僅返回標題 <code>title </code>和作者 <code>author</code>,因為我們不需要其他字段(它也會返回 <code>_id </code>和虛擬欄位字段)。這裡我們還調用 <code>Book </code>上的 <code>populate()</code>,指定作者 <code>author</code>欄位字段 — 這將用完整的作者信息,替換儲存的書本作者 id。</p>
+
+<p>成功時,傳遞給查詢的回調,將呈現 <strong>book_list</strong>(.pug) 模板,將標題 <code>title </code>和<code>book_list</code>(包含作者的書本列表)作為變量傳遞。</p>
+
+<h2 class="highlight-spanned" id="View視圖"><span class="highlight-span">View</span>視圖</h2>
+
+<p>創建<strong> /views/book_list.pug</strong> 並複制底下的文字。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span>
+
+block content
+ h1<span class="operator token">=</span> title
+
+ ul
+ each book <span class="keyword token">in</span> book_list
+ li
+ <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>book<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>book<span class="punctuation token">.</span>title<span class="punctuation token">}</span>
+ <span class="operator token">|</span> <span class="punctuation token">(</span>#<span class="punctuation token">{</span>book<span class="punctuation token">.</span>author<span class="punctuation token">.</span>name<span class="punctuation token">}</span><span class="punctuation token">)</span>
+
+ <span class="keyword token">else</span>
+ li There are no books<span class="punctuation token">.</span></code></pre>
+
+<p>這個視圖擴展了<strong> layout.pug</strong> 基本模板,並覆蓋了名為 '<strong>content</strong>' 的 <code>block </code>區塊 。它顯示我們從控制器傳入的標題 <code>title</code>(通過 <code>render()</code>方法),然後使用 <code>each</code>-<code>in</code>-<code>else </code>語法,遍歷 <code>book_list</code>變量。為每本圖書創建一個列表項,以顯示書名,並作為書的詳細信息頁面的鏈接,後面跟著作者姓名。如果 <code>book_list</code>中沒有書,則執行 <code>else</code> 子句,並顯示文字 “沒有書本” 'There are no books'。</p>
+
+<p> </p>
+
+<div class="note">
+<p><strong>注意:</strong>   我們使用 <code>book.url</code>,為每本書提供詳細記錄鏈接(我們已經實現了此路由,但尚未實現此頁面)。這是 <code>Book</code> 模型的一個虛擬屬性,它使用模型實例的 <code>_id</code> 字段,生成唯一的 URL 路徑。</p>
+</div>
+
+<p>在這裡,我們感興趣的是,每本書被定義為兩行,第二行使用管道(上面高亮顯示)。這種方法是必要的,因為如果作者姓名位於上一行,那麼它將成為超鏈接的一部分。</p>
+
+<h2 class="highlight-spanned" id="它看起來像是">它看起來像是?</h2>
+
+<p>運行本應用 (參見 <a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/routes#Testing_the_routes">測試路由</a> 有相關的命令) ,並打開你的瀏覽器,訪問 <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>。然後選擇所有書本連結 <em>All books</em>。如果每樣東西都設定正確了,你的網站看起來應該像底下的截圖。</p>
+
+<p> </p>
+
+<p><img alt="Book List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14464/LocalLibary_Express_Book_List.png" style="border-style: solid; border-width: 1px; display: block; height: 387px; margin: 0px auto; width: 918px;"></p>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+ <li>繼續教學 5 下個部分: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page">書本實例清單頁面</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html
new file mode 100644
index 0000000000..e04981411c
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_detail_page_and_challenge/index.html
@@ -0,0 +1,91 @@
+---
+title: 書本實例詳情頁面與自我挑戰
+slug: >-
+ Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge
+translation_of: >-
+ Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge
+---
+<h2 id="書本實例詳情頁面">書本實例詳情頁面</h2>
+
+<p><code>BookInstance</code> 詳情頁面,需要呈現每一個 <code>BookInstance </code>的信息,用 <code>_id</code> 欄位字段值(自動產生)做識別。它包含了 <code>Book</code> 名稱 (也是一個連結,連到 <em>書本細節</em>頁面),接著是紀錄中的其它的信息。</p>
+
+<h3 id="Controller_控制器">Controller 控制器</h3>
+
+<p>打開 <strong>/controllers/bookinstanceController.js</strong>. 找到 exported <code>bookinstance_detail()</code> 控制器方法,並用底下代碼置換。</p>
+
+<pre class="brush: js">// Display detail page for a specific BookInstance.
+exports.bookinstance_detail = function(req, res, next) {
+
+<strong>    BookInstance.findById(req.params.id)
+    .populate('book')
+    .exec(function (err, bookinstance) {
+      if (err) { return next(err); }
+      if (bookinstance==null) { // No results.
+          var err = new Error('Book copy not found');
+          err.status = 404;
+          return next(err);
+        }
+      // Successful, so render.
+      res.render('bookinstance_detail', { title: 'Book:', bookinstance:  bookinstance});
+    })</strong>
+
+};
+</pre>
+
+<p>該方法使用從 URL(使用路由)中提取的特定書本實例的ID,調用<code>BookInstance.findById()</code>,並通過請求參數(<code style="font-style: normal; font-weight: normal;">req.params.id</code>),在控制器中訪問。然後調用<code>populate()</code>來獲取相關 <code>Book </code>的詳細信息。</p>
+
+<h3 id="View_視圖">View 視圖</h3>
+
+<p>創建 <strong>/views/bookinstance_detail.pug</strong> ,並複製下面的內容。</p>
+
+<pre class="brush: js">extends layout
+
+block content
+
+<strong>  h1 ID: #{bookinstance._id}</strong>
+
+  p #[strong Title:]
+    a(href=bookinstance.book.url) #{bookinstance.book.title}
+  p #[strong Imprint:] #{bookinstance.imprint}
+
+  p #[strong Status:]
+    if bookinstance.status=='Available'
+      span.text-success #{bookinstance.status}
+    else if bookinstance.status=='Maintenance'
+      span.text-danger #{bookinstance.status}
+    else
+      span.text-warning #{bookinstance.status}
+
+  if bookinstance.status!='Available'
+    p #[strong Due back:] #{bookinstance.due_back}
+</pre>
+
+<p>本模組中的所有東西,都在先前的章節演示過了。</p>
+
+<h3 id="它看起來像是">它看起來像是?</h3>
+
+<p>運行本應用,並打開瀏覽器訪問 <a href="http://localhost:3000/">http://localhost:3000/</a>/。選擇 <em>All book-instances</em> 連結,然後選擇其中一本。如果每個東西都設定正確了,你的網站看起來應該像是底下的截圖。</p>
+
+<p><img alt="BookInstance Detail Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14472/LocalLibary_Express_BookInstance_Detail.png" style="border-style: solid; border-width: 1px; display: block; height: 362px; margin: 0px auto; width: 1000px;"></p>
+
+<h2 id="自我挑戰">自我挑戰</h2>
+
+<p>目前,我們網站上顯示的大多數日期,都使用默認的 JavaScript 格式(例如 <em>Tue Dec 06 2016 15:49:58 GMT+1100 </em>(AUS東部夏令時間))。本文的挑戰,是改善作者<code>Author</code>生命週期日期顯示的外觀信息(死亡/誔生日期)和<em>BookInstance詳細信息</em>頁面,使用格式:December 6th, 2016。</p>
+
+<div class="note">
+<p><strong>注意:</strong>  您可以使用與我們用於 <em>Book Instance List</em> 的相同方法(將生命週期的虛擬屬性,添加到<code>Author</code>模型,並使用 <a href="https://www.npmjs.com/package/moment">moment </a>來設置日期字符串的格式)。</p>
+</div>
+
+<p>這個挑戰的要求:  </p>
+
+<ol>
+ <li>用 BookInstance 詳細信息頁面中的 <code>due_back_formatted</code> 替換 <code>due_back</code>。</li>
+ <li>更新作者模塊以添加壽命虛擬屬性。壽命應該有兩個值: <em>date_of_birth - date_of_death</em>,這兩個值的格式與 <code>BookInstance.due_back_formatted</code>的日期格式相同。</li>
+ <li>在當前使用 <code>date_of_birth</code> 和 <code>date_of_death</code>的所有視圖中,使用 <code>Author.lifespan</code> 。</li>
+</ol>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html
new file mode 100644
index 0000000000..1b1656258e
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html
@@ -0,0 +1,71 @@
+---
+title: 書本實例清單頁面
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page
+---
+<p>接下來,我們將實作圖書館中所有書本實例 (<code>BookInstance</code>) 的列表頁面。這個頁面需要包含與每個 <code>BookInstance</code> (鏈接到其詳細信息頁面) 關聯的書本 <code>Book</code> 標題,以及 <code>BookInstance</code>模型中的其他信息,包含每個副本的狀態,印記和唯一ID。唯一ID的文字,應該鏈接到 <code>BookInstance</code> 詳細信息頁面。</p>
+
+<h2 class="highlight-spanned" id="Controller_控制器"><span class="highlight-span">Controller</span> 控制器</h2>
+
+<p><code>BookInstance</code>列表控制器函數,需要獲取所有書本實例的列表,填充關聯的書本信息,然後將列表傳遞給模板以進行呈現。</p>
+
+<p>打開 <strong>/controllers/bookinstanceController.js</strong>。找到導出的 <code>bookinstance_list()</code>控制器方法,並用以下代碼替換它(更改後的代碼以<strong>粗體</strong>顯示)。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all BookInstances.</span>
+exports<span class="punctuation token">.</span>bookinstance_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+
+ BookInstance<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_bookinstances<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Successful, so render</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Book Instance List'</span><span class="punctuation token">,</span> bookinstance_list<span class="punctuation token">:</span> list_bookinstances <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<p>此方法使用模型的<code>find()</code>函數,返回所有 <code>BookInstance</code>對象。然後它將一個調用,以菊花鏈方式連接到 <code>populate()</code>,附加書本 <code>book</code>欄位字段,這將使用完整的 <code>Book</code>文檔,替換每個 <code>BookInstance</code>儲存的書本 ID。</p>
+
+<p>成功時,傳遞給查詢的回調,會呈現 <strong>bookinstance_list</strong> (.pug)模板,並將標題<code>title</code>和書籍實例列表 <code>bookinstance_list</code>作為變量傳遞。</p>
+
+<h2 class="highlight-spanned" id="View_視圖"><span class="highlight-span">View</span> 視圖</h2>
+
+<p>創建 <strong>/views/bookinstance_list.pug </strong>,並複制貼上底下的文字。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span>
+
+block content
+ h1<span class="operator token">=</span> title
+
+ ul
+ each val <span class="keyword token">in</span> bookinstance_list
+ li
+ <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>val<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>book<span class="punctuation token">.</span>title<span class="punctuation token">}</span> <span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>imprint<span class="punctuation token">}</span> <span class="operator token">-</span>
+ <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">==</span><span class="string token">'Available'</span>
+ span<span class="punctuation token">.</span>text<span class="operator token">-</span>success #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">==</span><span class="string token">'Maintenance'</span>
+ span<span class="punctuation token">.</span>text<span class="operator token">-</span>danger #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span>
+ <span class="keyword token">else</span>
+ span<span class="punctuation token">.</span>text<span class="operator token">-</span>warning #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span>
+ <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">!=</span><span class="string token">'Available'</span>
+ span <span class="function token"> </span><span class="punctuation token">(</span>Due<span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>due_back<span class="punctuation token">}</span> <span class="punctuation token">)</span>
+
+ <span class="keyword token">else</span>
+ li There are no book copies <span class="keyword token">in</span> <span class="keyword token">this</span> library<span class="punctuation token">.</span></code></pre>
+
+<p>這個視圖與其他視圖非常相似。它擴展了佈局,替換內容區塊,顯示從控制器傳入的標題 <code>title</code>,並遍歷 <code>bookinstance_list</code> 中的所有書籍副本。對於每個副本,我們都會顯示它的狀態(用顏色編碼),如果書本不可用,則顯示其預期返回日期。這裡引入了一個新功能 — 我們可以在標籤之後使用點符號表示法,來指定一個類別。因此,<code>span.text-success </code>將被編譯為 &lt;<code>span class="text-success"</code>&gt; (也可以用 Pug 編寫為 <code>span(class="text-success"</code>)。</p>
+
+<p> </p>
+
+<h2 class="highlight-spanned" id="它看起來像是">它看起來像是?</h2>
+
+<p>運行本應用,打開瀏覽器訪問 <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>,然後選擇 All book-instances 連結。假如每個東西都設定正確了,你的網站看起來應該像是底下的截圖。</p>
+
+<p><img alt="BookInstance List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14474/LocalLibary_Express_BookInstance_List.png" style="border-style: solid; border-width: 1px; display: block; height: 322px; margin: 0px auto; width: 1200px;"></p>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+ <li>繼續教學 5下一個部分: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment">格式化日期 - 使用 moment</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html
new file mode 100644
index 0000000000..ecd3ee7f0d
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html
@@ -0,0 +1,60 @@
+---
+title: 使用 moment 做日期格式化
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment
+---
+<p>我們模型的日期預設呈現很難看: <em>Tue Dec 06 2016 15:49:58 GMT+1100 (AUS Eastern Daylight Time)</em>。在本節中,我們將展示如何更新上一節中的 <em>書本實例 BookInstance 列表頁面</em>,以更友好的格式顯示<code>due_date</code>欄位字段:December 6th, 2016。</p>
+
+<p>我們將使用的方法,是在我們的<code>BookInstance</code>模型中,創建一個返回格式化日期的虛擬屬性。我們將使用 <a class="external external-icon" href="https://www.npmjs.com/package/moment" rel="noopener">moment</a> 來做實際的格式化,這是一個輕量級 JavaScript日期庫,用於解析,驗證,操作和格式化日期。</p>
+
+<div class="note">
+<p><strong>注意:</strong>  我們可以直接在 Pug 模板中,使用 moment 格式化字符串,或者可以在許多其它地方格式化字符串。使用虛擬屬性,可以使我們獲得格式化的日期,這與我們當前獲取 <code>due_date</code> 的方式完全相同。</p>
+</div>
+
+<h2 class="highlight-spanned" id="安裝_moment"><span class="highlight-span">安裝 moment</span></h2>
+
+<p>在項目的根目錄,輸入下列命令</p>
+
+<p> </p>
+
+<pre class="brush: bash line-numbers language-bash"><code class="language-bash">npm install moment</code></pre>
+
+<h2 class="highlight-spanned" id="創建虛擬屬性">創建虛擬屬性</h2>
+
+<ol>
+ <li>打開 <strong>./models/bookinstance.js</strong>.</li>
+ <li>在此頁面最上方,引入 <em>moment</em>.
+ <pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">var</span> moment <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'moment'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+ </li>
+</ol>
+
+<p>在 url 屬性後面,加入虛擬屬性 <code>due_back_formatted</code> 。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">BookInstanceSchema
+<span class="punctuation token">.</span><span class="function token">virtual</span><span class="punctuation token">(</span><span class="string token">'due_back_formatted'</span><span class="punctuation token">)</span>
+<span class="punctuation token">.</span><span class="keyword token">get</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">return</span> <span class="function token">moment</span><span class="punctuation token">(</span><span class="keyword token">this</span><span class="punctuation token">.</span>due_back<span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">format</span><span class="punctuation token">(</span><span class="string token">'MMMM Do, YYYY'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<div class="note">
+<p><strong>注意:</strong>  格式化方法可以使用幾乎任何模式顯示日期。 <a class="external external-icon" href="http://momentjs.com/docs/#/displaying/" rel="noopener">moment</a>文檔中,可以找到表示不同日期組件的語法。</p>
+</div>
+
+<h2 class="highlight-spanned" id="更新視圖">更新視圖</h2>
+
+<p>打開 <strong>/views/bookinstance_list.pug</strong> ,然後用 <code>due_back_formatted</code> 取代 <code>due_back</code> 。</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"> <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">!=</span><span class="string token">'Available'</span>
+ <span class="comment token">//span (Due: #{val.due_back} )</span>
+ span <span class="function token"> </span><span class="punctuation token">(</span>Due<span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>due_back_formatted<span class="punctuation token">}</span> <span class="punctuation token">)</span> </code></pre>
+
+<p>這就是本章節的全部了。如果你訪問側邊欄的 <em>All book-instances</em> ,你應該會看到所有的歸還日期都更吸引人了!</p>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學 5: 呈現圖書館資料</a></li>
+ <li>繼續教學 5 的下一個部分: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page">Author list page and Genre list page challenge</a>.</li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html
new file mode 100644
index 0000000000..5271bd6722
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html
@@ -0,0 +1,137 @@
+---
+title: 使用 async 進行非同步流控制
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async
+---
+<p>有些<em>本地圖書館</em>網頁的控制器代碼,會依賴多重非同步要求的結果,可能會需要以某種特定次序運行,或者以平行方式運行。為了管理流控制,並在我們所有需要用到的信息,都已經可以取用的時候,再繪製網頁,我們將使用許多人採用的 node <a class="external external-icon" href="https://www.npmjs.com/package/async" rel="noopener">async</a> 模組。</p>
+
+<div class="note">
+<p><strong>注意:</strong>  在 JavaScript 中有許多其他方法,可以管理異步行為和流控制,包括相對較新的 JavaScript 語言功能,如 <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Techniques/Promises">Promises</a>。</p>
+</div>
+
+<p>Async 有很多有用的方法(請查看<a href="http://caolan.github.io/async/docs.html">文檔</a>)。一些最重要的功能是:</p>
+
+<p> </p>
+
+<ul>
+ <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> 執行必須並行執行的任何操作。</li>
+ <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> 用於當需要確保異步操作是序列執行的。</li>
+ <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code> 用於必須序列運行的操作,每個操作取決於前面操作的結果。</li>
+</ul>
+
+<h2 class="highlight-spanned" id="為什麼需要這麼做">為什麼需要這麼做?</h2>
+
+<p>我們在 <em>Express</em> 中使用的大多數方法,都是異步的 - 您指定要執行的操作,傳遞回調。該方法立即返回,並在請求的操作完成時,調用回調。按照 <em>Express</em> 中的慣例,回調函數將<em>錯誤值</em>作為第一個參數傳遞(或成功時為 <code>null</code>),並將函數的結果(如果有的話)作為第二個參數傳遞。</p>
+
+<p>如果控制器只需要<em>執行<strong>一個</strong>異步操作</em>,來獲取呈現頁面所需的信息,那麼實現很簡單 - 我們只需在回調中呈現模板。下面的代碼片段,顯示了一個函數,該函數呈現模型 <code>SomeModel</code> 的計數(使用Mongoose <code><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.count" rel="noopener">count()</a></code>方法):</p>
+
+<pre class="brush: js"><code>exports.some_model_count = function(req, res, next) {
+
+</code> SomeModel.count({ a_model_field: 'match_value' }, function (err, count) {
+ // ... do something if there is an err
+
+  // On success, render the result by passing count into the render function (here, as the variable 'data').
+  res.render('the_template', { data: count } );
+  });
+<code>}</code>
+</pre>
+
+<p>但是,如果您需要進行<strong>多個</strong>異步查詢,並且在完成所有操作之前,無法呈現頁面,該怎麼辦?一個單純的實現可以用 “菊花鏈” 連接請求,在先前請求的回調中,啟動後續請求,並在最終回調中呈現響應。這種方法的問題,是我們的請求必須串行運行,即使並行運行它們可能更有效。這也可能導致複雜的嵌套代碼,通常稱為<a href="http://callbackhell.com/">回調地獄</a>。</p>
+
+<p>一個更好的解決方案,是並行執行所有請求,然後在所有查詢完成後執行單個回調。這是 <em>Async</em> 模塊簡化的流操作!</p>
+
+<h2 class="highlight-spanned" id="Asynchronous_operations_in_parallel"><span class="highlight-span">Asynchronous operations in parallel</span></h2>
+
+<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> is used to run multiple asynchronous operations in parallel.</p>
+
+<p>The first argument to <code>async.parallel()</code> is a collection of the asynchronous functions to run (an array, object or other iterable). Each function is passed a <code>callback(err, result)</code> which it must call on completion with an error <code>err</code> (which can be <code>null</code>) and an optional <code>results</code> value.</p>
+
+<p>The optional second argument to  <code>async.parallel()</code> is a callback that will be run when all the functions in the first argument have completed. The callback is invoked with an error argument and a result collection that contains the results of the individual asynchronous operations. The result collection is of the same type as the first argument (i.e. if you pass an array of asynchronous functions, the final callback will be invoked with an array of results). If any of the parallel functions reports an error the callback is invoked early (with the error value).</p>
+
+<p>The example below shows how this works when we pass an object as the first argument. As you can see, the results are <em>returned</em> in an object with the same property names as the original functions that were passed in.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">parallel</span><span class="punctuation token">(</span><span class="punctuation token">{</span>
+ one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span>
+ something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="comment token">// optional callback</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// 'results' is now equal to: {one: 1, two: 2, ..., something_else: some_value}</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>If you instead pass an array of functions as the first argument, the results will be an array (the array order results will match the original order that the functions were declared—not the order in which they completed).</p>
+
+<h2 class="highlight-spanned" id="Asynchronous_operations_in_series"><span class="highlight-span">Asynchronous operations in series</span></h2>
+
+<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> is used to run multiple asynchronous operations in sequence, when subsequent functions do not depend on the output of earlier functions. It is essentially declared and behaves in the same way as <code>async.parallel()</code>.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">{</span>
+ one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span>
+ something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="comment token">// optional callback after the last asynchronous function completes.</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// 'results' is now equals to: {one: 1, two: 2, ..., something_else: some_value} </span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<div class="note">
+<p><strong>Note:</strong> The ECMAScript (JavaScript) language specification states that the order of enumeration of an object is undefined, so it is possible that the functions will not be called in the same order as you specify them on all platforms. If the order really is important, then you should pass an array instead of an object, as shown below.</p>
+</div>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">[</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// do some stuff ...</span>
+ <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// do some more stuff ... </span>
+ <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="punctuation token">]</span><span class="punctuation token">,</span>
+ <span class="comment token">// optional callback</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// results is now equal to ['one', 'two'] </span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Dependent_asynchronous_operations_in_series"><span class="highlight-span">Dependent asynchronous operations in series</span></h2>
+
+<p>The method <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code> is used to run multiple asynchronous operations in sequence when each operation is dependent on the result of the previous operation.</p>
+
+<p>The callback invoked by each asynchronous function contains <code>null</code> for the first argument and results in subsequent arguments. Each function in the series takes the results arguments of the previous callback as the first parameters, and then a callback function. When all operations are complete, a final callback is invoked with the result of the last operation. The way this works is more clear when you consider the code fragment below (this example is from the <em>async</em> documentation):</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">waterfall</span><span class="punctuation token">(</span><span class="punctuation token">[</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> arg2<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// arg1 now equals 'one' and arg2 now equals 'two' </span>
+ <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'three'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">,</span>
+ <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// arg1 now equals 'three'</span>
+ <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'done'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">]</span><span class="punctuation token">,</span> <span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> result<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// result now equals 'done'</span>
+<span class="punctuation token">}</span>
+<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Installing_async"><span class="highlight-span">Installing async</span></h2>
+
+<p>Install the async module using the NPM package manager so that we can use it in our code. You do this in the usual way, by opening a prompt in the root of the <em>LocalLibrary</em> project and enter the following command:</p>
+
+<pre class="brush: bash line-numbers language-bash"><code class="language-bash">npm install async</code></pre>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li>
+ <li>Proceed to the next subarticle of Part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">Template primer</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html
new file mode 100644
index 0000000000..2c7f1e938b
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html
@@ -0,0 +1,123 @@
+---
+title: Genre detail page
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page
+---
+<p>種類<em>細節</em>頁面,需要利用<code>_id</code> 字段值 (自動生成) ,以呈現特定種類實例的信息。此頁面應該呈現種類名稱,各個種類的所有書本列表(每本書都連結到書本的細節頁面)。</p>
+
+<p> </p>
+
+<h2 id="Controller_控制器">Controller 控制器</h2>
+
+<p>打開 <strong>/controllers/genreController.js</strong> ,並在檔案最上方引用 <em>async</em> 和 <em>Book</em> 模組。</p>
+
+<pre class="brush: js">var Book = require('../models/book');
+var async = require('async');
+</pre>
+
+<p>Find the exported <code>genre_detail</code><code>()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js">// Display detail page for a specific Genre.
+exports.genre_detail = function(req, res, next) {
+
+<strong>    async.parallel({
+        genre: function(callback) {
+            Genre.findById(req.params.id)
+              .exec(callback);
+        },
+
+        genre_books: function(callback) {
+          Book.find({ 'genre': req.params.id })
+          .exec(callback);
+        },
+
+    }, function(err, results) {
+        if (err) { return next(err); }
+        if (results.genre==null) { // No results.
+            var err = new Error('Genre not found');
+            err.status = 404;
+            return next(err);
+        }
+        // Successful, so render
+        res.render('genre_detail', { title: 'Genre Detail', genre: results.genre, genre_books: results.genre_books } );
+    });</strong>
+
+};
+</pre>
+
+<p>The method uses <code>async.parallel()</code> to query the genre name and its associated books in parallel, with the callback rendering the page when (if) both requests complete successfully.</p>
+
+<p>The ID of the required genre record is encoded at the end of the URL and extracted automatically based on the route definition (<strong>/genre/:id</strong>). The ID is accessed within the controller via the request parameters: <code style="font-style: normal; font-weight: normal;">req.params.id</code>. It is used in <code style="font-style: normal; font-weight: normal;">Genre.findById()</code> to get the current genre. It is also used to get all <code>Book</code> objects that have the genre ID in their <code>genre</code> field: <code>Book.find({ 'genre': req.params.id })</code>.</p>
+
+<div class="note">
+<p><strong>Note:</strong> If the genre does not exist in the database (i.e. it may have been deleted) then <code>findById()</code>  will return successfully with no results. In this case we want to display a "not found" page, so we create an <code>Error</code> object and pass it to the <code>next</code> middleware function in the chain. </p>
+
+<pre class="brush: js"><strong>if (results.genre==null) { // No results.
+ var err = new Error('Genre not found');
+ err.status = 404;
+ return next(err);
+}</strong>
+</pre>
+
+<p>The message will then propagate through to our error handling code (this was set up when we <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website#error_handling">generated the app skeleton</a> - for more information see <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Handling_errors">Handling Errors</a>).</p>
+</div>
+
+<p>The rendered view is <strong>genre_detail</strong> and it is passed variables for the <code>title</code>, <code>genre</code> and the list of books in this genre (<code>genre_books</code>).</p>
+
+<h2 id="View">View</h2>
+
+<p>Create <strong>/views/genre_detail.pug</strong> and fill it with the text below:</p>
+
+<pre class="brush: js">extends layout
+
+block content
+
+  <strong>h1 Genre: #{genre.name}</strong>
+
+  div(style='margin-left:20px;margin-top:20px')
+
+    h4 Books
+
+    dl
+    each book in genre_books
+      dt
+        a(href=book.url) #{book.title}
+      dd #{book.summary}
+
+    else
+      p This genre has no books
+</pre>
+
+<p>The view is very similar to all our other templates. The main difference is that we don't use the <code>title</code> passed in for the first heading (though it is used in the underlying <strong>layout.pug</strong> template to set the page title).</p>
+
+<h2 id="What_does_it_look_like">What does it look like?</h2>
+
+<p>Run the application and open your browser to <a href="http://localhost:3000/">http://localhost:3000/</a>. Select the <em>All genres</em> link, then select one of the genres (e.g. "Fantasy"). If everything is set up correctly, your page should look something like the following screenshot.</p>
+
+<p><img alt="Genre Detail Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14462/LocalLibary_Express_Genre_Detail.png" style="border-style: solid; border-width: 1px; display: block; height: 523px; margin: 0px auto; width: 1000px;"></p>
+
+<div class="note">
+<p>You might get an error similar to this:</p>
+
+<pre class="brush: bash">Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "_id" for model "Genre"
+</pre>
+
+<p>This is a mongoose error coming from the <strong>req.params.id</strong>. To solve this problem, first you need to require mongoose on the <strong>genreController.js</strong> page like this:</p>
+
+<pre class="brush: js"> var mongoose = require('mongoose');
+</pre>
+
+<p>Then use <strong>mongoose.Types.ObjectId() </strong>to convert the id to a that can be used. For example:</p>
+
+<pre class="brush: js">exports.genre_detail = function(req, res, next) {
+ var id = mongoose.Types.ObjectId(req.params.id);
+ ...
+</pre>
+</div>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li>
+ <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page">Book detail page</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html
new file mode 100644
index 0000000000..8adc4b11f9
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/home_page/index.html
@@ -0,0 +1,133 @@
+---
+title: 主頁
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page
+---
+<p>我們創建的第一個頁面,是網站的主頁面,可以從網站的根目錄 (<code>'/'</code>) ,或者 catalog 的根目錄 (<code>catalog/</code>) 訪問。這將呈現一些網站的靜態文字描述,以及動態計算數據庫中不同記錄類型的“計數”。</p>
+
+<p>我們已經為主頁創建了一個路由。為了完成頁面,我們需要更新控制器函數,以從數據庫中提取記錄的“計數”,並創建一個可用於呈現頁面的視圖(模板)。</p>
+
+<h2 id="路由">路由</h2>
+
+<p>在<a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/routes">前面的教程</a>,我們創建 index 頁面路由。此處要提醒的是,所有的路由函式,都定義在<strong> /routes/catalog.js</strong>:</p>
+
+<pre class="brush: js ">// GET catalog home page.
+router.get('/', book_controller.index); //This actually maps to /catalog/ because we import the route with a /catalog prefix</pre>
+
+<p>Where the callback function parameter (<code>book_controller.index</code>) is defined in <strong>/controllers/bookController.js</strong>:</p>
+
+<pre class="brush: js">exports.index = function(req, res, next) {
+ res.send('NOT IMPLEMENTED: Site Home Page');
+}</pre>
+
+<p>It is this controller function that we extend to get information from our models and then render it using a template (view).</p>
+
+<h2 id="Controller">Controller</h2>
+
+<p>The index controller function needs to fetch information about how many <code>Book</code>, <code>BookInstance</code>, available <code>BookInstance</code>, <code>Author</code>, and <code>Genre</code> records we have in the database, render this data in a template to create an HTML page, and then return it in an HTTP response.</p>
+
+<div class="note">
+<p><strong>Note:</strong> We use the <code><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.countDocuments" rel="noopener">countDocuments()</a></code> method to get the number of instances of each model. This is called on a model with an optional set of conditions to match against in the first argument and a callback in the second argument (as discussed in <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Using a Database (with Mongoose)</a>, and you can also return a <code>Query</code> and then execute it with a callback later. The callback will be returned when the database returns the count, with an error value (or <code>null</code>) as the first parameter and the count of records (or null if there was an error) as the second parameter.</p>
+
+<pre class="brush: js ">SomeModel.countDocuments({ a_model_field: 'match_value' }, function (err, count) {
+ // ... do something if there is an err
+ // ... do something with the count if there was no error
+ });</pre>
+</div>
+
+<p>Open <strong>/controllers/bookController.js</strong>. Near the top of the file you should see the exported <code>index()</code> function.</p>
+
+<pre class="brush: python ">var Book = require('../models/book')
+
+exports.index = function(req, res, next) {
+ res.send('NOT IMPLEMENTED: Site Home Page');
+}</pre>
+
+<p>Replace all the code above with the following code fragment. The first thing this does is import (<code>require()</code>) all the models (highlighted in bold). We need to do this because we'll be using them to get our counts of records. It then imports the <em>async</em> module.</p>
+
+<pre class="brush: js ">var Book = require('../models/book');
+var Author = require('../models/author');
+var Genre = require('../models/genre');
+var BookInstance = require('../models/bookinstance');
+
+var async = require('async');
+
+exports.index = function(req, res) {
+
+ async.parallel({
+ book_count: function(callback) {
+ Book.countDocuments({}, callback); // Pass an empty object as match condition to find all documents of this collection
+ },
+ book_instance_count: function(callback) {
+ BookInstance.countDocuments({}, callback);
+ },
+ book_instance_available_count: function(callback) {
+ BookInstance.countDocuments({status:'Available'}, callback);
+ },
+ author_count: function(callback) {
+ Author.countDocuments({}, callback);
+ },
+ genre_count: function(callback) {
+ Genre.countDocuments({}, callback);
+ },
+ }, function(err, results) {
+ res.render('index', { title: 'Local Library Home', error: err, data: results });
+ });
+};</pre>
+
+<p>The <code>async.parallel()</code> method is passed an object with functions for getting the counts for each of our models. These functions are all started at the same time. When all of them have completed the final callback is invoked with the counts in the results parameter (or an error).</p>
+
+<p>On success the callback function calls <code><a class="external external-icon" href="http://expressjs.com/en/4x/api.html#res.render" rel="noopener">res.render()</a></code>, specifying a view (template) named '<strong>index</strong>' and an object containing the data that is to be inserted into it (this includes the results object that contains our model counts). The data is supplied as key-value pairs, and can be accessed in the template using the key.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The callback function from <code>async.parallel()</code> above is a little unusual in that we render the page whether or not there was an error (normally you might use a separate execution path for handling the display of errors).</p>
+</div>
+
+<h2 id="View">View</h2>
+
+<p>Open <strong>/views/index.pug</strong> and replace its content with the text below.</p>
+
+<pre class="brush: js ">extends layout
+
+block content
+ h1= title
+ p Welcome to #[em LocalLibrary], a very basic Express website developed as a tutorial example on the Mozilla Developer Network.
+
+ h1 Dynamic content
+
+ if error
+ p Error getting dynamic content.
+ else
+ p The library has the following record counts:
+
+ ul
+ li #[strong Books:] !{data.book_count}
+ li #[strong Copies:] !{data.book_instance_count}
+ li #[strong Copies available:] !{data.book_instance_available_count}
+ li #[strong Authors:] !{data.author_count}
+ li #[strong Genres:] !{data.genre_count}</pre>
+
+<p>The view is straightforward. We extend the <strong>layout.pug</strong> base template, overriding the <code>block</code> named '<strong>content</strong>'. The first <code>h1</code> heading will be the escaped text for the <code>title</code> variable that was passed into the <code>render()</code> function—note the use of the '<code>h1=</code>' so that the following text is treated as a JavaScript expression. We then include a paragraph introducing the LocalLibrary.</p>
+
+<p>Under the <em>Dynamic content</em> heading we check whether the error variable passed in from the <code>render()</code> function has been defined. If so, we note the error. If not, we get and list the number of copies of each model from the <code>data</code> variable.</p>
+
+<div class="note">
+<p><strong>Note:</strong> We didn't escape the count values (i.e. we used the <code>!{}</code> syntax) because the count values are calculated. If the information was supplied by end-users then we'd escape the variable for display.</p>
+</div>
+
+<h2 id="What_does_it_look_like">What does it look like?</h2>
+
+<p>At this point we should have created everything needed to display the index page. Run the application and open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. If everything is set up correctly, your site should look something like the following screenshot.</p>
+
+<p><img alt="Home page - Express Local Library site" src="https://mdn.mozillademos.org/files/14458/LocalLibary_Express_Home.png" style="display: block; height: 440px; margin: 0px auto; width: 1000px;"></p>
+
+<div class="note">
+<p><strong>Note:</strong> You won't be able to use the sidebar links yet because the urls, views, and templates for those pages haven't been defined. If you try you'll get errors like "NOT IMPLEMENTED: Book list" for example, depending on the link you click on.  These string literals (which will be replaced with proper data) were specified in the different controllers that live inside your "controllers" file.</p>
+</div>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li>
+ <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page">Book list page</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html
new file mode 100644
index 0000000000..2073a02bc8
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/index.html
@@ -0,0 +1,87 @@
+---
+title: 'Express 教程 5: 呈現圖書館數據'
+slug: Learn/Server-side/Express_Nodejs/Displaying_data
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">我們現在準備好要新增網頁,以顯示本地圖書館網站的書本與其它資料。這些網頁將包括一個主頁 ,顯示我們每個模型的型態有多少筆紀錄,以及我們所有模型的清單與細節頁面。藉此,我們將得到從數據庫取得紀錄、以及使用樣版的實務經驗。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置條件:</th>
+ <td>完成先前教程主題 (包含 Express 教程 4: 路由與控制器)。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解如何使用非同步模組與 Pug 樣版語言,以及如何從我們的控制器函式中的 URL 得取資料。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>在我們先前的教程中,定義了可以用來跟資料庫互動的 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Mongoose models</a> ,並創建了一些初始的圖書館紀錄。我們接著<a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/routes">創建本地圖書館網站需要的所有路由</a>,但僅使用"空殼控制器" 函式(這些是骨架控制器函式,當一個網頁被存取時,只回傳一個"未實作" 信息)。</p>
+
+<p>下一步,是為這些顯示圖書館信息的網頁,提供充分的實作(我們將在後面的文章,檢視網頁表單的實作,像是創建、更新、刪除信息)。這包含了更新控制器函式,以利用我們的模型取得紀錄,並定義模板,為使用者顯示這些信息。</p>
+
+<p>我們在一開始,提供概略的總覽/重點主題,解釋在控制器函式中,如何管理非同步操作,以及如何使用 Pug 撰寫模板。然後我們將為每一個主要的 "唯讀" 網頁提供實作步驟,並且在使用到任何特別的、或新的特性時,會附上簡短的解釋說明。</p>
+
+<p>本教程的最後,你對路由、非同步函式、視圖、模型如何實際運作,應該有了更好的理解。</p>
+
+<h2 id="本教程的章節">本教程的章節</h2>
+
+<p>本教程分為下列章節,說明為了顯示圖書館網站頁面,如何新增各種特性 。在進入下一個教程之前,你需要閱讀並逐一實作下列章節。</p>
+
+<ol>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async">使用 async 控制非同步流</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">模板入門</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template">本地圖書館基礎模板</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page">主頁</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page">書本清單頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page">書本實例清單頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment">日期格式化 - 使用 moment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page">作者清單頁面、分類清單頁面、與自我挑戰</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page">分類詳情頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page">書本詳情頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page">作者詳情頁面</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge">書本實例詳情頁面與自我挑戰</a></li>
+</ol>
+
+<h2 id="總結">總結</h2>
+
+<p>我們現在已經為我們的網站,創建了所有 "唯讀" 的頁面: 一個主頁,可以顯示每一個模組的實例數量,書本的列表與詳細信息頁面,書本的實例、作者、分類。沿著目前的學習路徑,我們學到了許多基本知識,有控制器、在非同步作業時管理流控制、使用 Pug 創建視圖、使用模型查詢數據庫、如何從視圖傳送信息到模板、如何創建並擴展模板。而完成挑戰的人,還會學到如何用 moment 處理日期。</p>
+
+<p>在下一篇文章,我們將依據目前為止學到的知識,創建HTML 表單以及表單管理代碼,開始修改儲存在網站中的資料。</p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="http://caolan.github.io/async/docs.html">Async module</a> (Async docs)</li>
+ <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using Template engines with Express</a> (Express docs)</li>
+ <li><a href="https://pugjs.org/api/getting-started.html">Pug</a> (Pug docs)</li>
+ <li><a href="http://momentjs.com/docs/">Moment</a> (Moment docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<p> </p>
+
+<h2 id="本教學連結">本教學連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html
new file mode 100644
index 0000000000..c67e82f07e
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html
@@ -0,0 +1,71 @@
+---
+title: 本地圖書館基礎模板
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template
+---
+<p> </p>
+
+<p>現在我們了解如何使用 Pug 拓展模板,讓我們開始項目,創建一個基礎模板。這個模板會有一個側邊欄,連結到本教程中將要創建的各個頁面(例如,呈現並創建書本、種類、作者等等),以及一個主要內容區域,我們將在每個頁面中進行覆寫。</p>
+
+<p>開啟 <strong>/views/layout.pug </strong>,並以下列代碼,置換其內容。</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html
+html(lang='en')
+ head
+ title= title
+ meta(charset='utf-8')
+ meta(name='viewport', content='width=device-width, initial-scale=1')
+ link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css')
+ script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js')
+ script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js')
+ link(rel='stylesheet', href='/stylesheets/style.css')
+ body
+ div(class='container-fluid')
+ div(class='row')
+ div(class='col-sm-2')
+ block sidebar
+ ul(class='sidebar-nav')
+ li
+ a(href='/catalog') Home
+ li
+ a(href='/catalog/books') All books
+ li
+ a(href='/catalog/authors') All authors
+ li
+ a(href='/catalog/genres') All genres
+ li
+ a(href='/catalog/bookinstances') All book-instances
+ li
+ hr
+ li
+ a(href='/catalog/author/create') Create new author
+ li
+ a(href='/catalog/genre/create') Create new genre
+ li
+ a(href='/catalog/book/create') Create new book
+ li
+ a(href='/catalog/bookinstance/create') Create new book instance (copy)
+
+ div(class='col-sm-10')
+ block content</code></pre>
+
+<p>此模板使用(並包含)來自 <a class="external external-icon" href="http://getbootstrap.com/" rel="noopener">Bootstrap</a> 的 JavaScript 和 CSS ,以改進 HTML 頁面的佈局和呈現方式。使用 Bootstrap 或其它客戶端網頁框架,是一種快速的方式,可以創建吸引人的網頁,能夠良好地適應不同的瀏覽器尺寸,並且允許我們處理頁面的呈現,而不需要糾纒於任何不同尺寸的細節—此處我們只想專注於伺服端代碼!</p>
+
+<p>佈局的安排應該相當明白,假如你已經閱讀了之前的 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data#Template_primer">模板入門</a>。注意,使用 <code>block content</code> 當做定位符號,放到頁面內容將要放置的地方。</p>
+
+<p>基礎模板也參考了一個本地 css 檔 (<strong>style.css</strong>) ,此檔提供了一些額外的樣式。打開 <strong>/public/stylesheets/style.css</strong> ,並用底下的 CSS 代碼,取代它的內容:</p>
+
+<pre class="brush: css line-numbers language-css"><code class="language-css"><span class="selector token"><span class="class token">.sidebar-nav</span> </span><span class="punctuation token">{</span>
+ <span class="property token">margin-top</span><span class="punctuation token">:</span> <span class="number token">20</span>px<span class="punctuation token">;</span>
+ <span class="property token">padding</span><span class="punctuation token">:</span> <span class="number token">0</span><span class="punctuation token">;</span>
+ <span class="property token">list-style</span><span class="punctuation token">:</span> none<span class="punctuation token">;</span>
+<span class="punctuation token">}</span></code></pre>
+
+<p>當我們開始運行網站時,我們應該看到側邊欄出現!在本教程的下個部分,我們將使用以上的佈局,來定義各個頁面。</p>
+
+<h2 id="下一步">下一步</h2>
+
+<ul>
+ <li>回到 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li>
+ <li>繼續教學 5 下個章節: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page">Home page</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html
new file mode 100644
index 0000000000..af976b7155
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/displaying_data/template_primer/index.html
@@ -0,0 +1,149 @@
+---
+title: 模板入門
+slug: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer
+translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer
+---
+<p>模板是一個文字檔,定義了一個輸出檔的<em>結構</em>或者排版,使用定位符號表示,當模板被繪製時,資料將插入到何處(在<em>Express</em>,模板被稱為<em>視圖</em>)。</p>
+
+<h2 id="Express_模板選擇">Express 模板選擇</h2>
+
+<p>Express 可以與許多不同的<a href="https://expressjs.com/zh-tw/guide/using-template-engines.html">模板渲染引擎</a>一起使用。在本教程中,我們使用 <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">Pug</a>(以前稱為 <em>Jade</em>)作為模板。這是最流行的 Node 模板語言,並且官方將自身描述為 “用於編寫 HTML,語法乾淨且空格敏感,受 <a class="external external-icon" href="http://haml.info/" rel="noopener">Haml </a>影響很大”。</p>
+
+<p>不同的模板語言使用不同的方法,來定義佈局和標記數據的佔位符 — 一些使用 HTML 來定義佈局,而另一些則使用可以編譯為 HTML 的不同標記格式。 Pug 是第二種類型;它使用 HTML 的<em>表示形式</em>,其中任何行中的第一個單詞,通常表示HTML元素,後續行中的縮進,用於表示嵌套在這些元素中的任何內容。結果是一個頁面定義直接轉換為 HTML,但可以說更簡潔,更容易閱讀。</p>
+
+<div class="note">
+<p><strong>Note:</strong> The downside of using <em>Pug</em> is that it is sensitive to indentation and whitespace (if you add an extra space in the wrong place you may get an unhelpful error code). However once you have your templates in place, they are very easy to read and maintain.</p>
+</div>
+
+<h2 class="highlight-spanned" id="Template_configuration"><span class="highlight-span">Template configuration</span></h2>
+
+<p>The <em>LocalLibrary</em> was configured to use <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">Pug</a> when we <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">created the skeleton website</a>. You should see the pug module included as a dependency in the website's <strong>package.json</strong> file, and the following configuration settings in the <strong>app.js</strong> file. The settings tell us that we're using pug as the view engine, and that <em>Express</em> should search for templates in the <strong>/views</strong> subdirectory.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// View engine setup.</span>
+app<span class="punctuation token">.</span><span class="keyword token">set</span><span class="punctuation token">(</span><span class="string token">'views'</span><span class="punctuation token">,</span> path<span class="punctuation token">.</span><span class="function token">join</span><span class="punctuation token">(</span>__dirname<span class="punctuation token">,</span> <span class="string token">'views'</span><span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+app<span class="punctuation token">.</span><span class="keyword token">set</span><span class="punctuation token">(</span><span class="string token">'view engine'</span><span class="punctuation token">,</span> <span class="string token">'pug'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>If you look in the views directory you will see the .pug files for the project's default views. These include the view for the home page (<strong>index.pug</strong>) and base template (<strong>layout.pug</strong>) that we will need to replace with our own content.</p>
+
+<pre><code>/express-locallibrary-tutorial //the project root
+ /views
+ error.pug
+ <strong>index.pug</strong>
+ layout.pug</code>
+</pre>
+
+<h2 class="highlight-spanned" id="Template_syntax"><span class="highlight-span">Template syntax</span></h2>
+
+<p>The example template file below shows off many of Pug's most useful features.</p>
+
+<p>The first thing to notice is that the file maps the structure of a typical HTML file, with the first word in (almost) every line being an HTML element, and indentation being used to indicate nested elements. So for example, the <code>body</code> element is inside an <code>html</code> element, and paragraph elements (<code>p</code>) are within the <code>body</code> element, etc. Non-nested elements (e.g. individual paragraphs) are on separate lines.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html
+html(lang="en")
+ head
+ title= title
+ script(type='text/javascript').
+ body
+ h1= title
+
+ p This is a line with #[em some emphasis] and #[strong strong text] markup.
+ p This line has un-escaped data: !{'<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span> is emphasised<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>'} and escaped data: #{'<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span> is not emphasised<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>'}.
+ | This line follows on.
+ p= 'Evaluated and <span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span>escaped expression<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>:' + title
+
+ <span class="comment token">&lt;!-- You can add HTML comments directly --&gt;</span>
+ // You can add single line JavaScript comments and they are generated to HTML comments
+ //- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML
+
+ p A line with a link
+ a(href='/catalog/authors') Some link text
+ | and some extra text.
+
+ #container.col
+ if title
+ p A variable named "title" exists.
+ else
+ p A variable named "title" does not exist.
+ p.
+ Pug is a terse and simple template language with a
+ strong focus on performance and powerful features.
+
+ h2 Generate a list
+
+ ul
+ each val in [1, 2, 3, 4, 5]
+ li= val</code></pre>
+
+<p>Element attributes are defined in parentheses after their associated element. Inside the parentheses, the attributes are defined in comma- or whitespace- separated lists of the pairs of attribute names and attribute values, for example:</p>
+
+<ul>
+ <li><code>script(type='text/javascript')</code>, <code>link(rel='stylesheet', href='/stylesheets/style.css')</code></li>
+ <li><code>meta(name='viewport' content='width=device-width initial-scale=1')</code></li>
+</ul>
+
+<p>The values of all attributes are <em>escaped</em> (e.g. characters like "<code>&gt;</code>" are converted to their HTML code equivalents like "<code>&amp;gt;"</code>) to prevent injection of JavaScript/cross-site scripting attacks.</p>
+
+<p>If a tag is followed by the equals sign, the following text is treated as a JavaScript <em>expression</em>. So for example, in the first line below, the content of the <code>h1</code> tag will be <em>variable</em> <code>title</code> (either defined in the file or passed into the template from Express). In the second line the paragraph content is a text string concatented with the <code>title</code> variable. In both cases the default behaviour is to <em>escape</em> the line.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">h1= title
+p= 'Evaluated and <span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span>escaped expression<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>:' + title</code></pre>
+
+<p>If there is no equals symbol after the tag then the content is treated as plain text. Within the plain text you can insert escaped and unescaped data using the <code>#{}</code> and<code> !{}</code> syntax, as shown below. You can also add raw HTML within the plain text.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">p This is a line with #[em some emphasis] and #[strong strong text] markup.
+p This line has an un-escaped string: !{'<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span> is emphasised<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>'}, an escaped string: #{'<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;</span>em</span><span class="punctuation token">&gt;</span></span> is not emphasised<span class="tag token"><span class="tag token"><span class="punctuation token">&lt;/</span>em</span><span class="punctuation token">&gt;</span></span>'}, and escaped variables: #{title}.</code></pre>
+
+<div class="note">
+<p><strong>Tip:</strong> You will almost always want to escape data from users (via the <strong><code>#{}</code></strong> syntax). Data that can be trusted (e.g. generated counts of records, etc.) may be displayed without escaping the values.</p>
+</div>
+
+<p>You can use the pipe ('<strong>|</strong>') character at the beginning of a line to indicate "<a class="external external-icon" href="https://pugjs.org/language/plain-text.html" rel="noopener">plain text</a>". For example, the additional text shown below will be displayed on the same line as the preceding anchor, but will not be linked.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">a(href='http://someurl/') Link text
+| Plain text</code></pre>
+
+<p>Pug allows you to perform conditional operations using <code>if</code>, <code>else</code> , <code>else if</code> and <code>unless</code>—for example:</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">if title
+ p A variable named "title" exists
+else
+ p A variable named "title" does not exist</code></pre>
+
+<p>You can also perform loop/iteration operations using <code>each-in</code> or <code>while</code> syntax. In the code fragment below we've looped through an array to display a list of variables (note the use of the 'li=' to evaluate the "val" as a variable below. The value you iterate across can also be passed into the template as a variable!</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">ul
+ each val in [1, 2, 3, 4, 5]
+ li= val</code></pre>
+
+<p>The syntax also supports comments (that can be rendered in the output—or not—as you choose), mixins to create reusable blocks of code, case statements, and many other features. For more detailed information see <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">The Pug docs</a>.</p>
+
+<h2 class="highlight-spanned" id="Extending_templates"><span class="highlight-span">Extending templates</span></h2>
+
+<p>Across a site, it is usual for all pages to have a common structure, including standard HTML markup for the head, footer, navigation, etc. Rather than forcing developers to duplicate this "boilerplate" in every page, <em>Pug</em> allows you to declare a base template and then extend it, replacing just the bits that are different for each specific page.</p>
+
+<p>For example, the base template <strong>layout.pug</strong> created in our <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">skeleton project</a> looks like this:</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html
+html
+ head
+ title= title
+ link(rel='stylesheet', href='/stylesheets/style.css')
+ body
+ block content</code></pre>
+
+<p>The <code>block</code> tag is used to mark up sections of content that may be replaced in a derived template (if the block is not redefined then its implementation in the base class is used).</p>
+
+<p>The default <strong>index.pug</strong> (created for our skeleton project) shows how we override the base template. The <code>extends</code> tag identifies the base template to use, and then we use <code>block <em>section_name</em></code> to indicate the new content of the section that we will override.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1= title
+ p Welcome to #{title}</code></pre>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li>
+ <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template">The LocalLibrary base template</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html
new file mode 100644
index 0000000000..9d4563376e
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_author_form/index.html
@@ -0,0 +1,155 @@
+---
+title: Create Author form
+slug: Learn/Server-side/Express_Nodejs/forms/Create_author_form
+translation_of: Learn/Server-side/Express_Nodejs/forms/Create_author_form
+---
+<p><a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms$edit#Create_author_form" rel="nofollow, noindex"><span>Edi</span></a>本章節演示,如何為創建作者對象 <code>Author</code>定義一個頁面。</p>
+
+<h2 class="highlight-spanned" id="導入驗證和清理方法">導入驗證和清理方法</h2>
+
+<p>為了在種類表單使用 <em>express</em> 驗證器,我們必須用 <em>require</em> 導入我們想用的函式。</p>
+
+<p>打開 <strong>/controllers/authorController.js</strong>,並在檔案最上方,加入底下幾行:</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">const</span> <span class="punctuation token">{</span> body<span class="punctuation token">,</span>validationResult <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/check'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="keyword token">const</span> <span class="punctuation token">{</span> sanitizeBody <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/filter'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Controller—get_route"><span class="highlight-span">Controller—get route</span></h2>
+
+<p>Find the exported <code>author_create_get()</code> controller method and replace it with the following code. This simply renders the <strong>author_form.pug</strong> view, passing a <code>title</code> variable.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display Author create form on GET.</span>
+exports<span class="punctuation token">.</span>author_create_get <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'author_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Author'</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Controller—post_route"><span class="highlight-span">Controller—post route</span></h2>
+
+<p>Find the exported <code>author_create_post()</code> controller method, and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Handle Author create on POST.</span>
+exports<span class="punctuation token">.</span>author_create_post <span class="operator token">=</span> <span class="punctuation token">[</span>
+
+ <span class="comment token">// Validate fields.</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'first_name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">withMessage</span><span class="punctuation token">(</span><span class="string token">'First name must be specified.'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">isAlphanumeric</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">withMessage</span><span class="punctuation token">(</span><span class="string token">'First name has non-alphanumeric characters.'</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'family_name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">withMessage</span><span class="punctuation token">(</span><span class="string token">'Family name must be specified.'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">isAlphanumeric</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">withMessage</span><span class="punctuation token">(</span><span class="string token">'Family name has non-alphanumeric characters.'</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'date_of_birth'</span><span class="punctuation token">,</span> <span class="string token">'Invalid date of birth'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">optional</span><span class="punctuation token">(</span><span class="punctuation token">{</span> checkFalsy<span class="punctuation token">:</span> <span class="keyword token">true</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isISO8601</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'date_of_death'</span><span class="punctuation token">,</span> <span class="string token">'Invalid date of death'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">optional</span><span class="punctuation token">(</span><span class="punctuation token">{</span> checkFalsy<span class="punctuation token">:</span> <span class="keyword token">true</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isISO8601</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Sanitize fields.</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'first_name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'family_name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'date_of_birth'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">toDate</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'date_of_death'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">toDate</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Process request after validation and sanitization.</span>
+ <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">{</span>
+
+ <span class="comment token">// Extract the validation errors from a request.</span>
+ <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// There are errors. Render form again with sanitized values/errors messages.</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'author_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Author'</span><span class="punctuation token">,</span> author<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="keyword token">return</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Data from form is valid.</span>
+
+ <span class="comment token">// Create an Author object with escaped and trimmed data.</span>
+ <span class="keyword token">var</span> author <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Author</span><span class="punctuation token">(</span>
+ <span class="punctuation token">{</span>
+ first_name<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>first_name<span class="punctuation token">,</span>
+ family_name<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>family_name<span class="punctuation token">,</span>
+ date_of_birth<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>date_of_birth<span class="punctuation token">,</span>
+ date_of_death<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>date_of_death
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ author<span class="punctuation token">.</span><span class="function token">save</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Successful - redirect to new author record.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>author<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">]</span><span class="punctuation token">;</span></code></pre>
+
+<p>The structure and behaviour of this code is almost exactly the same as for creating a <code>Genre</code> object. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid then we save the new author record and redirect the user to the author detail page.</p>
+
+<div class="note">
+<p><strong>Note:</strong>  Unlike with the <code>Genre</code> post handler, we don't check whether the <code>Author</code> object already exists before saving it. Arguably we should, though as it is now we can have multiple authors with the same name.</p>
+</div>
+
+<p>The validation code demonstrates several new features:</p>
+
+<ul>
+ <li>We can daisy chain validators, using <code>withMessage()</code> to specify the error message to display if the previous validation method fails. This makes it very easy to provide specific error messages without lots of code duplication.
+
+ <pre class="brush: js">// Validate fields.
+body('first_name').isLength({ min: 1 }).trim().withMessage('First name must be specified.')
+   .isAlphanumeric().withMessage('First name has non-alphanumeric characters.'),<code>
+</code></pre>
+ </li>
+ <li>We can use the <code>optional()</code> function to run a subsequent validation only if a field has been entered (this allows us to validate optional fields). For example, below we check that the optional date of birth is an ISO8601-compliant date (the <code>checkFalsy</code> flag means that we'll accept either an empty string or <code>null</code> as an empty value).
+ <pre class="line-numbers language-html"><code class="language-html">body('date_of_birth', 'Invalid date of birth').optional({ checkFalsy: true }).isISO8601(),</code></pre>
+ </li>
+</ul>
+
+<ul>
+ <li>Parameters are recieved from the request as strings. We can use <code>toDate()</code> (or <code>toBoolean()</code>, etc.) to cast these to the proper JavaScript types.
+
+ <pre class="brush: js line-numbers language-js"><code class="language-js"><span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'date_of_birth'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">toDate</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span></code></pre>
+ </li>
+</ul>
+
+<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2>
+
+<p>Create <strong>/views/author_form.pug</strong> and copy in the text below.</p>
+
+<pre class="line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1=title
+
+ form(method='POST' action='')
+ div.form-group
+ label(for='first_name') First Name:
+ input#first_name.form-control(type='text' placeholder='First name (Christian) last' name='first_name' required='true' value=(undefined===author ? '' : author.first_name) )
+ label(for='family_name') Family Name:
+ input#family_name.form-control(type='text' placeholder='Family name (surname)' name='family_name' required='true' value=(undefined===author ? '' : author.family_name))
+ div.form-group
+ label(for='date_of_birth') Date of birth:
+ input#date_of_birth.form-control(type='date' name='date_of_birth' value=(undefined===author ? '' : author.date_of_birth) )
+ button.btn.btn-primary(type='submit') Submit
+ if errors
+ ul
+ for error in errors
+ li!= error.msg</code></pre>
+
+<p>The structure and behaviour for this view is exactly the same as for the <strong>genre_form.pug</strong> template, so we won't describe it again.</p>
+
+<div class="note">
+<p><strong>Note:</strong> Some browsers don’t support the input <code>type=“date”</code>, so you won’t get the datepicker widget or the default <em><code>dd/mm/yyyy</code></em> placeholder, but will instead get an empty plain text field. One workaround is to explicitly add the attribute <code>placeholder='dd/mm/yyyy'</code> so that on less capable browsers you will still get information about the desired text format.</p>
+</div>
+
+<h3 id="Challenge_Adding_the_date_of_death">Challenge: Adding the date of death</h3>
+
+<p>The template above is missing a field for entering the <code>date_of_death</code>. Create the field following the same pattern as the date of birth form group!</p>
+
+<h2 class="highlight-spanned" id="What_does_it_look_like"><span class="highlight-span">What does it look like?</span></h2>
+
+<p>Run the application, open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, then select the <em>Create new author </em>link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the author detail page.</p>
+
+<p><img alt="Author Create Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14482/LocalLibary_Express_Author_Create_Empty.png" style="display: block; height: 426px; margin: 0px auto; width: 800px;"></p>
+
+<div class="note">
+<p><strong>Note:</strong> If you experiment with various input formats for the dates, you may find that the format <code>yyyy-mm-dd</code> misbehaves. This is because JavaScript treats date strings as including the time of 0 hours, but additionally treats date strings in that format (the ISO 8601 standard) as including the time 0 hours UTC, rather than the local time. If your time zone is west of UTC, the date display, being local, will be one day before the date you entered. This is one of several complexities (such as multi-word family names and multi-author books) that we are not addressing here.</p>
+</div>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li>
+ <li>Proceed to the next subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_book_form">Create Book form</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html
new file mode 100644
index 0000000000..c15b2ca385
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_book_form/index.html
@@ -0,0 +1,214 @@
+---
+title: Create Book form
+slug: Learn/Server-side/Express_Nodejs/forms/Create_book_form
+translation_of: Learn/Server-side/Express_Nodejs/forms/Create_book_form
+---
+<p><a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms$edit#Create_book_form" rel="nofollow, noindex">Edit</a>此章節展示如何定義頁面/表單以創建<code>Book</code>對象。這比相同的作者<code>Author</code>或種類<code>Genre</code>頁面稍微複雜一點,因為我們需要在我們的書本表單中,獲取並顯示可用的作者和種類記錄。</p>
+
+<p> </p>
+
+<h2 id="導入驗證和清理方法">導入驗證和清理方法</h2>
+
+<p>打開 <strong>/controllers/bookController.js</strong>,並在文件頂部添加以下幾行:</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');</code></pre>
+
+<h2 id="Controller—get_route">Controller—get route</h2>
+
+<p>Find the exported <code>book_create_get()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Display book create form on GET.
+exports.book_create_get = function(req, res, next) {
+
+ // Get all authors and genres, which we can use for adding to our book.
+ async.parallel({
+ authors: function(callback) {
+ Author.find(callback);
+ },
+ genres: function(callback) {
+ Genre.find(callback);
+ },
+ }, function(err, results) {
+ if (err) { return next(err); }
+ res.render('book_form', { title: 'Create Book', authors: results.authors, genres: results.genres });
+ });
+
+};</code></pre>
+
+<p>This uses the async module (described in <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>) to get all <code>Author</code> and <code>Genre</code> objects. These are then passed to the view <code><strong>book_form.pug</strong></code> as variables named <code>authors</code> and <code>genres</code> (along with the page <code>title</code>).</p>
+
+<h2 id="Controller—post_route">Controller—post route</h2>
+
+<p>Find the exported <code>book_create_post()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Handle book create on POST.
+exports.book_create_post = [
+ // Convert the genre to an array.
+ (req, res, next) =&gt; {
+ if(!(req.body.genre instanceof Array)){
+ if(typeof req.body.genre==='undefined')
+ req.body.genre=[];
+ else
+ req.body.genre=new Array(req.body.genre);
+ }
+ next();
+ },
+
+ // Validate fields.
+ body('title', 'Title must not be empty.').isLength({ min: 1 }).trim(),
+ body('author', 'Author must not be empty.').isLength({ min: 1 }).trim(),
+ body('summary', 'Summary must not be empty.').isLength({ min: 1 }).trim(),
+ body('isbn', 'ISBN must not be empty').isLength({ min: 1 }).trim(),
+
+ // Sanitize fields (using wildcard).
+ sanitizeBody('*').trim().escape(),
+
+ // Process request after validation and sanitization.
+ (req, res, next) =&gt; {
+
+ // Extract the validation errors from a request.
+ const errors = validationResult(req);
+
+ // Create a Book object with escaped and trimmed data.
+ var book = new Book(
+ { title: req.body.title,
+ author: req.body.author,
+ summary: req.body.summary,
+ isbn: req.body.isbn,
+ genre: req.body.genre
+ });
+
+ if (!errors.isEmpty()) {
+ // There are errors. Render form again with sanitized values/error messages.
+
+ // Get all authors and genres for form.
+ async.parallel({
+ authors: function(callback) {
+ Author.find(callback);
+ },
+ genres: function(callback) {
+ Genre.find(callback);
+ },
+ }, function(err, results) {
+ if (err) { return next(err); }
+
+ // Mark our selected genres as checked.
+ for (let i = 0; i &lt; results.genres.length; i++) {
+ if (book.genre.indexOf(results.genres[i]._id) &gt; -1) {
+ results.genres[i].checked='true';
+ }
+ }
+ res.render('book_form', { title: 'Create Book',authors:results.authors, genres:results.genres, book: book, errors: errors.array() });
+ });
+ return;
+ }
+ else {
+ // Data from form is valid. Save book.
+ book.save(function (err) {
+ if (err) { return next(err); }
+ //successful - redirect to new book record.
+ res.redirect(book.url);
+ });
+ }
+ }
+];</code></pre>
+
+<p>The structure and behaviour of this code is almost exactly the same as for creating a <code>Genre</code> or <code>Author</code> object. First we validate and sanitize the data. If the data is invalid then we re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we then save the new <code>Book</code> record and redirect the user to the book detail page.</p>
+
+<p>The first main difference with respect to the other form handling code is that we use a wildcard to trim and escape all fields in one go (rather than sanitising them individually):</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">sanitizeBody('*').trim().escape(),</code></pre>
+
+<p>The next main difference with respect to the other form handling code is how we sanitize the genre information. The form returns an array of <code>Genre</code> items (while for other fields it returns a string). In order to validate the information we first convert the request to an array (required for the next step).</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Convert the genre to an array.
+(req, res, next) =&gt; {
+ if(!(req.body.genre instanceof Array)){
+ if(typeof req.body.genre==='undefined')
+ req.body.genre=[];
+ else
+ req.body.genre=new Array(req.body.genre);
+ }
+ next();
+},</code></pre>
+
+<p>We then use a wildcard (<code>*</code>) in the sanitiser to individually validate each of the genre array entries. The code below shows how - this translates to "sanitise every item below key <code>genre</code>".</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">sanitizeBody('genre.*').trim().escape(),</code></pre>
+
+<p>The final difference with respect to the other form handling code is that we need to pass in all existing genres and authors to the form. In order to mark the genres that were checked by the user we iterate through all the genres and add the <code>checked='true'</code> parameter to those that were in our post data (as reproduced in the code fragment below).</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Mark our selected genres as checked.
+for (let i = 0; i &lt; results.genres.length; i++) {
+ if (book.genre.indexOf(results.genres[i]._id) &gt; -1) {
+ // Current genre is selected. Set "checked" flag.
+ results.genres[i].checked='true';
+ }
+}</code></pre>
+
+<h2 id="View">View</h2>
+
+<p>Create <strong>/views/book_form.pug</strong> and copy in the text below.</p>
+
+<pre class="line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1= title
+
+ form(method='POST' action='')
+ div.form-group
+ label(for='title') Title:
+ input#title.form-control(type='text', placeholder='Name of book' name='title' required='true' value=(undefined===book ? '' : book.title) )
+ div.form-group
+ label(for='author') Author:
+ select#author.form-control(type='select', placeholder='Select author' name='author' required='true' )
+ for author in authors
+ if book
+ option(value=author._id selected=(author._id.toString()==book.author ? 'selected' : false) ) #{author.name}
+ else
+ option(value=author._id) #{author.name}
+ div.form-group
+ label(for='summary') Summary:
+ input#summary.form-control(type='textarea', placeholder='Summary' name='summary' value=(undefined===book ? '' : book.summary) required='true')
+ div.form-group
+ label(for='isbn') ISBN:
+ input#isbn.form-control(type='text', placeholder='ISBN13' name='isbn' value=(undefined===book ? '' : book.isbn) required='true')
+ div.form-group
+ label Genre:
+ div
+ for genre in genres
+ div(style='display: inline; padding-right:10px;')
+ input.checkbox-input(type='checkbox', name='genre', id=genre._id, value=genre._id, checked=genre.checked )
+ label(for=genre._id) #{genre.name}
+ button.btn.btn-primary(type='submit') Submit
+
+ if errors
+ ul
+ for error in errors
+ li!= error.msg</code></pre>
+
+<p>The view structure and behaviour is almost the same as for the <strong>genre_form.pug</strong> template.</p>
+
+<p>The main differences are in how we implement the selection-type fields: <code>Author</code> and <code>Genre</code>.</p>
+
+<ul>
+ <li>The set of genres are displayed as checkboxes, using the <code>checked</code> value we set in the controller to determine whether or not the box should be selected.</li>
+ <li>The set of authors are displayed as a single-selection drop-down list. In this case we determine what author to display by comparing the id of the current author option with the value previously entered by the user (passed in as the <code>book</code> variable). This is highlighted above!
+ <div class="note">
+ <p><strong>Note:</strong> If there is an error in the submitted form, then, when the form is to be re-rendered, the new book's author is identified only with a string (the value of the selected option in the list of authors). By contrast, the existing books' authors have <code>_id</code> properties that are not strings. So to compare the new with the existing we must cast each existing book's author's <code>_id</code> to a string, as shown above.</p>
+ </div>
+ </li>
+</ul>
+
+<h2 id="What_does_it_look_like">What does it look like?</h2>
+
+<p>Run the application, open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, then select the <em>Create new book </em>link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid book, it should be saved and you'll be taken to the book detail page.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14484/LocalLibary_Express_Book_Create_Empty.png" style="display: block; height: 498px; margin: 0px auto; width: 1000px;"></p>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<p>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</p>
+
+<p>Proceed to the next subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form">Create BookInstance form</a>.</p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html
new file mode 100644
index 0000000000..14288f4678
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html
@@ -0,0 +1,150 @@
+---
+title: Create BookInstance form
+slug: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form
+translation_of: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form
+---
+<p><a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms$edit#Create_BookInstance_form" rel="nofollow, noindex"><span>Edi</span></a>本章節演示如何定義一個頁面/表單,以創建 <code>BookInstance</code> 物件。這很像我們用來創建書本 <code>Book</code> 物件的表單。</p>
+
+<h2 class="highlight-spanned" id="導入驗證和清理方法">導入驗證和清理方法</h2>
+
+<p>打開 <strong>/controllers/bookinstanceController.js</strong>,並在檔案最上方,加入以下幾行:</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">const</span> <span class="punctuation token">{</span> body<span class="punctuation token">,</span>validationResult <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/check'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="keyword token">const</span> <span class="punctuation token">{</span> sanitizeBody <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/filter'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Controller—get_route"><span class="highlight-span">Controller—get route</span></h2>
+
+<p>At the top of the file, require the <em>Book</em> module (needed because each <code>BookInstance</code> is associated with a particular <code>Book</code>).</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">var</span> Book <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'../models/book'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>Find the exported <code>bookinstance_create_get()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display BookInstance create form on GET.</span>
+exports<span class="punctuation token">.</span>bookinstance_create_get <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+
+ Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span><span class="string token">'title'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> books<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Successful, so render.</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span>title<span class="punctuation token">:</span> <span class="string token">'Create BookInstance'</span><span class="punctuation token">,</span> book_list<span class="punctuation token">:</span>books<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<p>The controller gets a list of all books (<code>book_list</code>) and passes it to the view <code><strong>bookinstance_form.pug</strong></code> (along with the <code>title</code>)</p>
+
+<h2 class="highlight-spanned" id="Controller—post_route"><span class="highlight-span">Controller—post route</span></h2>
+
+<p>Find the exported <code>bookinstance_create_post()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Handle BookInstance create on POST.</span>
+exports<span class="punctuation token">.</span>bookinstance_create_post <span class="operator token">=</span> <span class="punctuation token">[</span>
+
+ <span class="comment token">// Validate fields.</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">,</span> <span class="string token">'Book must be specified'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'imprint'</span><span class="punctuation token">,</span> <span class="string token">'Imprint must be specified'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'due_back'</span><span class="punctuation token">,</span> <span class="string token">'Invalid date'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">optional</span><span class="punctuation token">(</span><span class="punctuation token">{</span> checkFalsy<span class="punctuation token">:</span> <span class="keyword token">true</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isISO8601</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Sanitize fields.</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'imprint'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'status'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'due_back'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">toDate</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Process request after validation and sanitization.</span>
+ <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">{</span>
+
+ <span class="comment token">// Extract the validation errors from a request.</span>
+ <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="comment token">// Create a BookInstance object with escaped and trimmed data.</span>
+ <span class="keyword token">var</span> bookinstance <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">BookInstance</span><span class="punctuation token">(</span>
+ <span class="punctuation token">{</span> book<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>book<span class="punctuation token">,</span>
+ imprint<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>imprint<span class="punctuation token">,</span>
+ status<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>status<span class="punctuation token">,</span>
+ due_back<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>due_back
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// There are errors. Render form again with sanitized values and error messages.</span>
+ Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span><span class="string token">'title'</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> books<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Successful, so render.</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create BookInstance'</span><span class="punctuation token">,</span> book_list <span class="punctuation token">:</span> books<span class="punctuation token">,</span> selected_book <span class="punctuation token">:</span> bookinstance<span class="punctuation token">.</span>book<span class="punctuation token">.</span>_id <span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> bookinstance<span class="punctuation token">:</span>bookinstance <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="keyword token">return</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Data from form is valid.</span>
+ bookinstance<span class="punctuation token">.</span><span class="function token">save</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Successful - redirect to new record.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>bookinstance<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">]</span><span class="punctuation token">;</span></code></pre>
+
+<p>The structure and behaviour of this code is the same as for creating our other objects. First we validate and sanitize the data. If the data is invalid, we then re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we save the new <code>BookInstance</code> record and redirect the user to the detail page.</p>
+
+<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2>
+
+<p>Create <strong>/views/bookinstance_form.pug</strong> and copy in the text below.</p>
+
+<pre class="line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1=title
+
+ form(method='POST' action='')
+ div.form-group
+ label(for='book') Book:
+ select#book.form-control(type='select' placeholder='Select book' name='book' required='true')
+ for book in book_list
+ if bookinstance
+ option(value=book._id selected=(bookinstance.book.toString()==book._id.toString() ? 'selected' : false)) #{book.title}
+ else
+ option(value=book._id) #{book.title}
+
+ div.form-group
+ label(for='imprint') Imprint:
+ input#imprint.form-control(type='text' placeholder='Publisher and date information' name='imprint' required='true' value=(undefined===bookinstance ? '' : bookinstance.imprint))
+ div.form-group
+ label(for='due_back') Date when book available:
+ input#due_back.form-control(type='date' name='due_back' value=(undefined===bookinstance ? '' : bookinstance.due_back))
+
+ div.form-group
+ label(for='status') Status:
+ select#status.form-control(type='select' placeholder='Select status' name='status' required='true')
+ option(value='Maintenance') Maintenance
+ option(value='Available') Available
+ option(value='Loaned') Loaned
+ option(value='Reserved') Reserved
+
+ button.btn.btn-primary(type='submit') Submit
+
+ if errors
+ ul
+ for error in errors
+ li!= error.msg</code></pre>
+
+<p>The view structure and behaviour is almost the same as for the <strong>book_form.pug</strong> template, so we won't go over it again.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The above template hard-codes the <em>Status</em> values (Maintenance, Available, etc.) and does not "remember" the user's entered values. Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed.</p>
+</div>
+
+<h2 class="highlight-spanned" id="What_does_it_look_like"><span class="highlight-span">What does it look like?</span></h2>
+
+<p>Run the application and open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Then select the <em>Create new book instance (copy) </em>link. If everything is set up correctly, your site should look something like the following screenshot. After you submit a valid <code>BookInstance</code>, it should be saved and you'll be taken to the detail page.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14490/LocalLibary_Express_BookInstance_Create_Empty.png" style="display: block; height: 554px; margin: 0px auto; width: 1000px;"></p>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li>
+ <li>Proceed to the next subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form">Delete Author form</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html
new file mode 100644
index 0000000000..3e648e48ea
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/create_genre_form/index.html
@@ -0,0 +1,294 @@
+---
+title: 創建種類表單
+slug: Learn/Server-side/Express_Nodejs/forms/Create_genre_form
+translation_of: Learn/Server-side/Express_Nodejs/forms/Create_genre_form
+---
+<p>本章節演示如何定義我們的頁面,創建<code>Genre</code> 物件(這是一個很好的起點,因為類型<code>Genre</code>只有一個欄位,就是它的名稱 <code>name</code>,沒有依賴項)。像任何其他頁面一樣,我們需要設置路由,控制器和視圖。</p>
+
+<p> </p>
+
+<h2 class="highlight-spanned" id="引入驗證與無害化方法">引入驗證與無害化方法</h2>
+
+<p>在我們的控制器中使用 <em>express-validator</em> 驗證器,我們必須導入我們想要從 '<strong>express-validator/check</strong>' 和 '<strong>express-validator/filter</strong>' 模塊中使用的函數。</p>
+
+<p>打開 <strong>/controllers/genreController.js</strong>,並在文件頂部添加以下幾行:</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">const</span> <span class="punctuation token">{</span> body<span class="punctuation token">,</span>validationResult <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/check'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="keyword token">const</span> <span class="punctuation token">{</span> sanitizeBody <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/filter'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Controller—get_route"><span class="highlight-span">Controller—get route</span></h2>
+
+<p>Find the exported <code>genre_create_get()</code> controller method and replace it with the following code. This simply renders the <strong>genre_form.pug</strong> view, passing a title variable.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display Genre create form on GET.</span>
+exports<span class="punctuation token">.</span>genre_create_get <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'genre_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Genre'</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre>
+
+<h2 class="highlight-spanned" id="Controller—post_route"><span class="highlight-span">Controller—post route</span></h2>
+
+<p>Find the exported <code>genre_create_post()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Handle Genre create on POST.</span>
+exports<span class="punctuation token">.</span>genre_create_post <span class="operator token">=</span> <span class="punctuation token">[</span>
+
+ <span class="comment token">// Validate that the name field is not empty.</span>
+ <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'name'</span><span class="punctuation token">,</span> <span class="string token">'Genre name required'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Sanitize (trim and escape) the name field.</span>
+ <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+ <span class="comment token">// Process request after validation and sanitization.</span>
+ <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">{</span>
+
+ <span class="comment token">// Extract the validation errors from a request.</span>
+ <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="comment token">// Create a genre object with escaped and trimmed data.</span>
+ <span class="keyword token">var</span> genre <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Genre</span><span class="punctuation token">(</span>
+ <span class="punctuation token">{</span> name<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>name <span class="punctuation token">}</span>
+ <span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+
+ <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// There are errors. Render the form again with sanitized values/error messages.</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'genre_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Genre'</span><span class="punctuation token">,</span> genre<span class="punctuation token">:</span> genre<span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="keyword token">return</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Data from form is valid.</span>
+ <span class="comment token">// Check if Genre with same name already exists.</span>
+ Genre<span class="punctuation token">.</span><span class="function token">findOne</span><span class="punctuation token">(</span><span class="punctuation token">{</span> <span class="string token">'name'</span><span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>name <span class="punctuation token">}</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span> <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> found_genre<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>found_genre<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Genre exists, redirect to its detail page.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>found_genre<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+
+ genre<span class="punctuation token">.</span><span class="function token">save</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Genre saved. Redirect to genre detail page.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>genre<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="punctuation token">}</span>
+
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">]</span><span class="punctuation token">;</span></code></pre>
+
+<p>The first thing to note is that instead of being a single middleware function (with arguments <code>(req, res, next)</code>) the controller specifies an <em>array</em> of middleware functions. The array is passed to the router function and each method is called in order.</p>
+
+<ul>
+</ul>
+
+<div class="note">
+<p><strong>Note:</strong> This approach is needed, because the sanitisers/validators are middleware functions.</p>
+</div>
+
+<p>The first method in the array defines a validator (<code>body</code>) to check that the <em>name</em> field is not empty (calling <code>trim()</code> to remove any trailing/leading whitespace before performing the validation). The  second method in the array (<code>sanitizeBody()</code>) creates a sanitizer to <code>trim()</code> the <em>name</em> field and <code>escape()</code> any dangerous  HTML characters.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Validate that the name field is not empty.</span>
+<span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'name'</span><span class="punctuation token">,</span> <span class="string token">'Genre name required'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span>
+
+<span class="comment token">// Sanitize (trim and escape) the name field.</span>
+<span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'name'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span></code></pre>
+
+<ul>
+</ul>
+
+<div class="note">
+<p><strong>Note:</strong> Sanitizers run during validation do not modify the request. That is why we have to call <code>trim()</code> in both steps above!</p>
+</div>
+
+<p>After specifying the validators and sanitizers we create a middleware function to extract any validation errors. We use <code>isEmpty()</code> to check whether there are any errors in the validation result. If there are then we render the form again, passing in our sanitised genre object and the array of error messages (<code>errors.array()</code>).</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Process request after validation and sanitization.</span>
+<span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">&gt;</span> <span class="punctuation token">{</span>
+
+ <span class="comment token">// Extract the validation errors from a request.</span>
+ <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="comment token">// Create a genre object with escaped and trimmed data.</span>
+ <span class="keyword token">var</span> genre <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Genre</span><span class="punctuation token">(</span>
+ <span class="punctuation token">{</span> name<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>name <span class="punctuation token">}</span>
+ <span class="punctuation token">)</span><span class="punctuation token">;</span>
+
+ <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// There are errors. Render the form again with sanitized values/error messages.</span>
+ res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'genre_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Genre'</span><span class="punctuation token">,</span> genre<span class="punctuation token">:</span> genre<span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="keyword token">return</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Data from form is valid.</span>
+ <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="operator token">&lt;</span>save the result<span class="operator token">&gt;</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">}</span></code></pre>
+
+<p>If the genre name data is valid then we check if a <code>Genre</code> with the same name already exists (as we don't want to create duplicates). If it does we redirect to the existing genre's detail page. If not, we save the new <code>Genre</code> and redirect to its detail page.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Check if Genre with same name already exists.</span>
+Genre<span class="punctuation token">.</span><span class="function token">findOne</span><span class="punctuation token">(</span><span class="punctuation token">{</span> <span class="string token">'name'</span><span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>name <span class="punctuation token">}</span><span class="punctuation token">)</span>
+ <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span> <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> found_genre<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>found_genre<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="comment token">// Genre exists, redirect to its detail page.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>found_genre<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+ <span class="keyword token">else</span> <span class="punctuation token">{</span>
+ genre<span class="punctuation token">.</span><span class="function token">save</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span>
+ <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span>
+ <span class="comment token">// Genre saved. Redirect to genre detail page.</span>
+ res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>genre<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+ <span class="punctuation token">}</span>
+<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>This same pattern is used in all our post controllers: we run validators, then sanitisers,  then check for errors and either re-render the form with error information or save the data. </p>
+
+<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2>
+
+<p>The same view is rendered in both the <code>GET</code> and <code>POST</code> controllers/routes when we create a new <code>Genre</code> (and later on it is also used when we <em>update</em> a <code>Genre</code>). In the <code>GET</code> case the form is empty and we just pass a title variable. In the <code>POST</code> case the user has previously entered invalid data—in the <code>genre</code> variable we pass back a sanitized version of the entered data and in the <code>errors</code> variable we pass back an array of error messages.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'genre_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Genre'</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
+res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'genre_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create Genre'</span><span class="punctuation token">,</span> genre<span class="punctuation token">:</span> genre<span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
+
+<p>Create <strong>/views/genre_form.pug</strong> and copy in the text below.</p>
+
+<pre class="line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1 #{title}
+
+ form(method='POST' action='')
+ div.form-group
+ label(for='name') Genre:
+ input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name))
+ button.btn.btn-primary(type='submit') Submit
+
+ if errors
+ ul
+ for error in errors
+ li!= error.msg</code></pre>
+
+<p>Much of this template will be familiar from our previous tutorials. First we extend the <strong>layout.pug</strong> base template and override the <code>block</code> named '<strong>content</strong>'. We then have a heading with the <code>title</code> we passed in from the controller (via the <code>render()</code> method).</p>
+
+<p>Next we have the pug code for our HTML form that uses the <code>POST</code> <code>method</code> to send the data to the server, and because the <code>action</code> is an empty string, will send the data to the same URL as the page.</p>
+
+<p>The form defines a single required field of type "text" called "name". The default <em>value</em> of the field depends on whether the <code>genre</code> variable is defined. If called from the <code>GET</code> route it will be empty as this is a new form. If called from a <code>POST</code> route it will contain the (invalid) value originally entered by the user.</p>
+
+<p>The last part of the page is the error code. This simply prints a list of errors, if the error variable has been defined (in other words, this section will not appear when the template is rendered on the <code>GET</code> route).</p>
+
+<div class="note">
+<p><strong>Note:</strong> This is just one way to render the errors. You can also get the names of the affected fields from the error variable, and use these to control where the error messages are rendered, whether to apply custom CSS, etc.</p>
+</div>
+
+<h2 class="highlight-spanned" id="What_does_it_look_like"><span class="highlight-span">What does it look like?</span></h2>
+
+<p>Run the application, open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, then select the <em>Create new genre </em>link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the genre detail page.</p>
+
+<p><img alt="Genre Create Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14476/LocalLibary_Express_Genre_Create_Empty.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 800px;"></p>
+
+<p>The only error we validate against server-side is that the genre field must not be empty. The screenshot below shows what the error list would look like if you didn't supply a genre (highlighted in red).</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14480/LocalLibary_Express_Genre_Create_Error.png" style="border-style: solid; border-width: 1px; display: block; height: 249px; margin: 0px auto; width: 400px;"></p>
+
+<div class="note">
+<p><strong>Note:</strong> Our validation uses <code>trim()</code> to ensure that whitespace is not accepted as a genre name. We can also validate that the field is not empty on the client side by adding the value <code>required='true'</code> to the field definition in the form:</p>
+
+<pre class="brush: js"><code>input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name), <strong>required='true'</strong> )</code></pre>
+</div>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms.</a></li>
+ <li>Proceed to the next subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_author_form">Create Author form</a>.</li>
+</ul>
+
+<div id="SL_balloon_obj" style="display: block;">
+<div class="SL_ImTranslatorLogo" id="SL_button" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; display: none; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important; opacity: 1;"> </div>
+
+<div id="SL_shadow_translation_result2" style="display: none;"> </div>
+
+<div id="SL_shadow_translator" style="display: none;">
+<div id="SL_planshet">
+<div id="SL_arrow_up" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;"> </div>
+
+<div id="SL_Bproviders">
+<div class="SL_BL_LABLE_ON" id="SL_P0" title="Google">G</div>
+
+<div class="SL_BL_LABLE_ON" id="SL_P1" title="Microsoft">M</div>
+
+<div class="SL_BL_LABLE_ON" id="SL_P2" title="Translator">T</div>
+</div>
+
+<div id="SL_alert_bbl" style="display: none;">
+<div id="SLHKclose" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;"> </div>
+
+<div id="SL_alert_cont"> </div>
+</div>
+
+<div id="SL_TB">
+<table id="SL_tables">
+ <tbody>
+ <tr>
+ <td class="SL_td"><input></td>
+ <td class="SL_td"><select><option value="auto">Detect language</option><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="be">Belarusian</option><option value="bn">Bengali</option><option value="bs">Bosnian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="ceb">Cebuano</option><option value="ny">Chichewa</option><option value="zh-CN">Chinese (Simplified)</option><option value="zh-TW">Chinese (Traditional)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian Creole</option><option value="ha">Hausa</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hmn">Hmong</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="ig">Igbo</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="jw">Javanese</option><option value="kn">Kannada</option><option value="kk">Kazakh</option><option value="km">Khmer</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="mg">Malagasy</option><option value="ms">Malay</option><option value="ml">Malayalam</option><option value="mt">Maltese</option><option value="mi">Maori</option><option value="mr">Marathi</option><option value="mn">Mongolian</option><option value="my">Myanmar (Burmese)</option><option value="ne">Nepali</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="pa">Punjabi</option><option value="ro">Romanian</option><option value="ru">Russian</option><option value="sr">Serbian</option><option value="st">Sesotho</option><option value="si">Sinhala</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option value="so">Somali</option><option value="es">Spanish</option><option value="su">Sundanese</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="tg">Tajik</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="uz">Uzbek</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option><option value="yo">Yoruba</option><option value="zu">Zulu</option></select></td>
+ <td class="SL_td">
+ <div id="SL_switch_b" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Switch languages"> </div>
+ </td>
+ <td class="SL_td"><select><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="be">Belarusian</option><option value="bn">Bengali</option><option value="bs">Bosnian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="ceb">Cebuano</option><option value="ny">Chichewa</option><option value="zh-CN">Chinese (Simplified)</option><option value="zh-TW">Chinese (Traditional)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option selected value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian Creole</option><option value="ha">Hausa</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hmn">Hmong</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="ig">Igbo</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="jw">Javanese</option><option value="kn">Kannada</option><option value="kk">Kazakh</option><option value="km">Khmer</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="mg">Malagasy</option><option value="ms">Malay</option><option value="ml">Malayalam</option><option value="mt">Maltese</option><option value="mi">Maori</option><option value="mr">Marathi</option><option value="mn">Mongolian</option><option value="my">Myanmar (Burmese)</option><option value="ne">Nepali</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="pa">Punjabi</option><option value="ro">Romanian</option><option value="ru">Russian</option><option value="sr">Serbian</option><option value="st">Sesotho</option><option value="si">Sinhala</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option value="so">Somali</option><option value="es">Spanish</option><option value="su">Sundanese</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="tg">Tajik</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="uz">Uzbek</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option><option value="yo">Yoruba</option><option value="zu">Zulu</option></select></td>
+ <td class="SL_td">
+ <div id="SL_TTS_voice" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Listen to the translation"> </div>
+ </td>
+ <td class="SL_td">
+ <div class="SL_copy" id="SL_copy" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Copy translation"> </div>
+ </td>
+ <td class="SL_td">
+ <div id="SL_bbl_font_patch"> </div>
+
+ <div class="SL_bbl_font" id="SL_bbl_font" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Font size"> </div>
+ </td>
+ <td class="SL_td">
+ <div id="SL_bbl_help" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Help"> </div>
+ </td>
+ <td class="SL_td">
+ <div class="SL_pin_off" id="SL_pin" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Pin pop-up bubble"> </div>
+ </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+</div>
+
+<div id="SL_shadow_translation_result" style=""> </div>
+
+<div class="SL_loading" id="SL_loading" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;"> </div>
+
+<div id="SL_player2"> </div>
+
+<div id="SL_alert100">Text-to-speech function is limited to 200 characters</div>
+
+<div id="SL_Balloon_options" style="background: rgb(0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;">
+<div id="SL_arrow_down" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;"> </div>
+
+<table id="SL_tbl_opt" style="width: 100%;">
+ <tbody>
+ <tr>
+ <td><input></td>
+ <td>
+ <div id="SL_BBL_IMG" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%; text-shadow: rgb(0, 0, 0) 0px 0px 1px, rgb(0, 0, 0) 0px 0px 2px, rgb(0, 0, 0) 0px 0px 3px, rgb(0, 0, 0) 0px 0px 4px, rgb(0, 0, 0) 0px 0px 5px !important;" title="Show Translator's button 3 second(s)"> </div>
+ </td>
+ <td><a class="SL_options" title="Show options">Options</a> : <a class="SL_options" title="Translation History">History</a> : <a class="SL_options" title="ImTranslator Feedback">Feedback</a> : <a class="SL_options" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=GD9D8CPW8HFA2" title="Make a small contribution">Donate</a></td>
+ <td><span id="SL_Balloon_Close" title="Close">Close</span></td>
+ </tr>
+ </tbody>
+</table>
+</div>
+</div>
+</div>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html
new file mode 100644
index 0000000000..f26b87bce7
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/delete_author_form/index.html
@@ -0,0 +1,167 @@
+---
+title: Delete Author form
+slug: Learn/Server-side/Express_Nodejs/forms/Delete_author_form
+translation_of: Learn/Server-side/Express_Nodejs/forms/Delete_author_form
+---
+<p> </p>
+
+<p>此子文檔展示,如何定義頁面以刪除 <code>Author</code>對象。</p>
+
+<p>正如<a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs/forms#form_design">表單設計</a>部分所討論的那樣,我們的策略是,只允許刪除“未被其他對象引用” 的對象(在這種情況下,這意味著如果作者<code>Author</code>被一本書<code>Book</code>引用,我們將不允許刪除作者)。在實現方面,這意味著,表單需要在刪除作者之前,先確認沒有關聯的書籍。如果存在關聯的書籍,則應顯示它們,並說明在刪除<code>Author</code>對象之前,必須刪除它們。</p>
+
+<h2 class="highlight-spanned" id="Controller—get_route">Controller—get route</h2>
+
+<p>Open <strong>/controllers/authorController.js</strong>. Find the exported <code>author_delete_get()</code> controller method and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Display Author delete form on GET.
+exports.author_delete_get = function(req, res, next) {
+
+ async.parallel({
+ author: function(callback) {
+ Author.findById(req.params.id).exec(callback)
+ },
+ authors_books: function(callback) {
+ Book.find({ 'author': req.params.id }).exec(callback)
+ },
+ }, function(err, results) {
+ if (err) { return next(err); }
+ if (results.author==null) { // No results.
+ res.redirect('/catalog/authors');
+ }
+ // Successful, so render.
+ res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } );
+ });
+
+};</code></pre>
+
+<p>The controller gets the id of the <code>Author</code> instance to be deleted from the URL parameter (<code>req.params.id</code>). It uses the <code>async.parallel()</code> method to get the author record and all associated books in parallel. When both operations have completed it renders the <code><strong>author_delete</strong></code><strong>.pug</strong> view, passing variables for the <code>title</code>, <code>author</code>, and <code>author_books</code>.</p>
+
+<div class="note">
+<p><strong>Note:</strong> If  <code>findById()</code><strong> </strong>returns no results the author is not in the database. In this case there is nothing to delete, so we immediately render the list of all authors. </p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">}, function(err, results) {
+ if (err) { return next(err); }
+ if (results.author==null) { // No results.
+ res.redirect('/catalog/authors')
+ }</code></pre>
+</div>
+
+<h2 class="highlight-spanned" id="Controller—post_route">Controller—post route</h2>
+
+<p>Find the exported <code>author_delete_post()</code> controller method, and replace it with the following code.</p>
+
+<pre class="brush: js line-numbers language-js"><code class="language-js">// Handle Author delete on POST.
+exports.author_delete_post = function(req, res, next) {
+
+ async.parallel({
+ author: function(callback) {
+ Author.findById(req.body.authorid).exec(callback)
+ },
+ authors_books: function(callback) {
+ Book.find({ 'author': req.body.authorid }).exec(callback)
+ },
+ }, function(err, results) {
+ if (err) { return next(err); }
+ // Success
+ if (results.authors_books.length &gt; 0) {
+ // Author has books. Render in same way as for GET route.
+ res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } );
+ return;
+ }
+ else {
+ // Author has no books. Delete object and redirect to the list of authors.
+ Author.findByIdAndRemove(req.body.authorid, function deleteAuthor(err) {
+ if (err) { return next(err); }
+ // Success - go to author list
+ res.redirect('/catalog/authors')
+ })
+ }
+ });
+};</code></pre>
+
+<p>First we validate that an id has been provided (this is sent via the form body parameters, rather than using the version in the URL). Then we get the author and their associated books in the same way as for the <code>GET</code> route. If there are no books then we delete the author object and redirect to the list of all authors. If there are still books then we just re-render the form, passing in the author and list of books to be deleted.</p>
+
+<div class="note">
+<p><strong>Note:</strong> We could check if the call to <code>findById()</code><strong> </strong>returns any result, and if not,  immediately render the list of all authors.  We've left the code as it is above for brevity (it will still return the list of authors if the id is not found, but this will happen after <code>findByIdAndRemove()</code>).</p>
+</div>
+
+<h2 class="highlight-spanned" id="View">View</h2>
+
+<p>Create <strong>/views/author_delete.pug</strong> and copy in the text below.</p>
+
+<pre class="line-numbers language-html"><code class="language-html">extends layout
+
+block content
+ h1 #{title}: #{author.name}
+ p= author.lifespan
+
+ if author_books.length
+
+ p #[strong Delete the following books before attempting to delete this author.]
+
+ div(style='margin-left:20px;margin-top:20px')
+
+ h4 Books
+
+ dl
+ each book in author_books
+ dt
+ a(href=book.url) #{book.title}
+ dd #{book.summary}
+
+ else
+ p Do you really want to delete this Author?
+
+ form(method='POST' action='')
+ div.form-group
+ input#authorid.form-control(type='hidden',name='authorid', required='true', value=author._id )
+
+ button.btn.btn-primary(type='submit') Delete</code></pre>
+
+<p>The view extends the layout template, overriding the block named <code>content</code>. At the top it displays the author details. It then includes a conditional statement based on the number of <code><strong>author_books</strong></code> (the <code>if</code> and <code>else</code> clauses).</p>
+
+<ul>
+ <li>If there <em>are</em> books associated with the author then the page lists the books and states that these must be deleted before this <code>Author</code> may be deleted.</li>
+ <li>If there <em>are no</em> books then the page displays a confirmation prompt. If the <strong>Delete</strong> button is clicked then the author id is sent to the server in a <code>POST</code> request and that author's record will be deleted.</li>
+</ul>
+
+<h2 class="highlight-spanned" id="Add_a_delete_control">Add a delete control</h2>
+
+<p>Next we will add a <strong>Delete</strong> control to the<em> Author detail</em> view (the detail page is a good place from which to delete a record).</p>
+
+<div class="note">
+<p><strong>Note:</strong> In a full implementation the control would be made visible only to authorised users. However at this point we haven't got an authorisation system in place!</p>
+</div>
+
+<p>Open the <strong>author_detail.pug</strong> view and add the following lines at the bottom.</p>
+
+<pre class="brush: html line-numbers language-html"><code class="language-html">hr
+p
+ a(href=author.url+'/delete') Delete author</code></pre>
+
+<p>The control should now appear as a link, as shown below on the <em>Author detail</em> page.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14492/LocalLibary_Express_Author_Detail_Delete.png" style="border-style: solid; border-width: 1px; display: block; height: 202px; margin: 0px auto; width: 500px;"></p>
+
+<h2 class="highlight-spanned" id="What_does_it_look_like">What does it look like?</h2>
+
+<p>Run the application and open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Then select the <em>All authors </em>link, and then select a particular author. Finally select the <em>Delete author</em> link.</p>
+
+<p>If the author has no books, you'll be presented with a page like this. After pressing delete, the server will delete the author and redirect to the author list.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14494/LocalLibary_Express_Author_Delete_NoBooks.png" style="border-style: solid; border-width: 1px; display: block; height: 342px; margin: 0px auto; width: 600px;"></p>
+
+<p>If the author does have books, then you'll be presented with a view like the following. You can then delete the books from their detail pages (once that code is implemented!).</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14496/LocalLibary_Express_Author_Delete_WithBooks.png" style="border-style: solid; border-width: 1px; display: block; height: 327px; margin: 0px auto; width: 500px;"></p>
+
+<div class="note">
+<p><strong>Note:</strong> The other pages for deleting objects can be implemented in much the same way. We've left that as a challenge.</p>
+</div>
+
+<h2 id="Next_steps">Next steps</h2>
+
+<ul>
+ <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li>
+ <li>Proceed to the final subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Update_Book_form">Update Book form</a>.</li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/forms/index.html b/files/zh-tw/learn/server-side/express_nodejs/forms/index.html
new file mode 100644
index 0000000000..008d7ae4e8
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/forms/index.html
@@ -0,0 +1,274 @@
+---
+title: 'Express 教學 6: 使用表單'
+slug: Learn/Server-side/Express_Nodejs/forms
+translation_of: Learn/Server-side/Express_Nodejs/forms
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">在此教程中,我們會教你如何使用 Express ,並且結合 Pug 來實現 HTML 表單,並且如何從數據庫中創建、更新、和刪除文檔。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前提條件:</th>
+ <td>完成前面所有的教程,包括 Express 教程第5章: 展示圖書館數據。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>了解如何編寫表單獲取用戶信息,並且將這些數據更新到數據庫中。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p><a href="/zh-TW/docs/Web/Guide/HTML/Forms">HTML 表單</a>是網頁中由一個、或多個字段/小工具形成的一個組合,它被用來收集用戶的信息,並將信息上傳到服務器。表單作為一種用來收集用戶的機制,非常的靈活,因為有各種合適的輸入框,來接受各種類型的數據——文本框,複選框,單選按鈕,時間選擇器等。表單和服務器交互數據也相對安全,因為它使用<code>POST</code>請求發送數據,保護不受跨站點請求偽造攻擊(cross-site request forgery)的威脅。</p>
+
+<p>但是表單同樣也很複雜!開發者需要編寫給表單編寫 HTML,在服務器上驗證,並且正確去除有害的數據(瀏覽器上也可能需要),對於任何不合法的字段,需要傳給用戶相應的錯誤信息,當數據成功提交後,處理數據,並設法通知用戶提交成功。</p>
+
+<p>此教程將展示上述的操作,如何在 Express 中實現。在此過程中,我們將擴展 LocalLibrary 網站,以允許用戶創建、編輯、和刪除圖書館中的項目。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 我們還沒有考慮如何將特定路由,限制為經過身份驗證或授權的用戶,因此在這個時間點,任何用戶都可以對數據庫進行更改。</p>
+</div>
+
+<h3 id="HTML_表單">HTML 表單</h3>
+
+<p>首先簡要概述 <a href="/zh-TW/docs/Web/Guide/HTML/Forms">HTML 表單</a>。考慮一個簡單的 HTML 表單,其中包含一個文本字段,用於輸入某些 “團隊” 的名稱,及其相關標籤:</p>
+
+<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p>
+
+<p>表單在HTML中,定義為 <code>&lt;form&gt;...&lt;/form&gt;</code>標記內的元素集合,包含至少一個<code>type="submit"</code>的 <code>input</code>輸入元素。</p>
+
+<pre class="brush: html">&lt;form action="/team_name_url/" method="post"&gt;
+    &lt;label for="team_name"&gt;Enter name: &lt;/label&gt;
+    &lt;input id="team_name" type="text" name="name_field" value="Default name for team."&gt;
+    &lt;input type="submit" value="OK"&gt;
+&lt;/form&gt;</pre>
+
+<p>雖然這裡,我們只包含一個(文本)字段,用於輸入團隊名稱,但表單可能包含任意數量的其他輸入元素,及其相關標籤。字段的 <code>type</code> 屬性,定義將顯示哪種窗口小部件。該字段的名稱<code>name</code>和<code>id</code> ,用於標識JavaScript/CSS/HTML 中的字段,而 <code>value</code>定義字段首次顯示時的初始值。匹配團隊標籤使用 <code style="font-style: normal; font-weight: normal;">label </code>標籤,指定(請參閱上面的“輸入名稱” "Enter name"),其中 <code style="font-style: normal; font-weight: normal;">for</code> 字段,包含 <code style="font-style: normal; font-weight: normal;">input </code>相關輸入的 <code style="font-style: normal; font-weight: normal;">id</code>值。</p>
+
+<p>提交輸入(<code>submit</code>)將顯示為按鈕(默認情況下) - 用戶可以按此按鈕,將其他輸入元素包含的數據,上傳到服務器(在本例中,只有 <code>team_name</code>)。表單屬性,定義用於發送數據的HTTP <code>method</code>方法,和服務器上數據的目標(<code>action</code>):</p>
+
+<ul>
+ <li><code>action</code>: 提交表單時,要發送數據以進行處理的資源/ URL。如果未設置(或設置為空字符串),則表單將提交回當前頁面 URL。</li>
+ <li><code>method</code>: 用於發送數據的 HTTP 方法:<code>POST</code> 或 <code>GET</code>。
+ <ul>
+ <li><code>POST</code> 方法。如果數據將導致服務器數據庫的更改,則始終應該使用 <code>POST</code>方法,因為這更加可以抵抗跨站點偽造請求攻擊。</li>
+ <li><code>GET</code> 方法只應用於不更改用戶數據的表單(例如,搜索表單)。當您希望能夠為URL添加書籤或共享時,建議使用此選項。</li>
+ </ul>
+ </li>
+</ul>
+
+<h3 id="表單處理流程">表單處理流程</h3>
+
+<p>表單處理使用的技術,與我們學習過、用來顯示有關模型的信息的所有技術,是相同的:路由將我們的請求發送到控制器函數,該函數執行所需的任何數據庫操作,包括從模型中讀取數據,然後生成並返回 HTML 頁面。使事情變得更複雜的是,服務器還需要能夠處理用戶提供的數據,並在出現任何問題時,重新顯示帶有錯誤信息的表單。</p>
+
+<p>下面顯示了處理表單請求的流程圖,從包含表單的頁面請求開始(以綠色顯示):</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14478/Web%20server%20form%20handling.png" style="height: 649px; width: 800px;"></p>
+
+<p>如上圖所示,構成處理代碼所需要做的主要是:  </p>
+
+<ol>
+ <li>在用戶第一次請求時顯示默認表單。
+ <ul>
+ <li>表單可能包含空白字段(例如,如果您正在創建新記錄),或者可能預先填充了初始值(例如,如果您要更改記錄,或者俱有有用的默認初始值)。</li>
+ </ul>
+ </li>
+ <li>接收用戶提交的數據,通常是在HTTP <code>POST</code>請求中。</li>
+ <li>驗證並清理數據。</li>
+ <li>如果任何數據無效,請重新顯示表單 - 這次使用用戶填寫的任何值,和問題字段的錯誤消息。</li>
+ <li>如果所有數據都有效,請執行所需的操作(例如,將數據保存在數據庫中,發送通知電子郵件,返回搜索結果,上傳文件等)</li>
+ <li>完成所有操作之後,將用戶重定向到另一個頁面。</li>
+</ol>
+
+<p>表格處理代碼,通常使用 <code>GET</code>路由,以實現表單的初始顯示,以及 <code>POST</code>路由到同一路徑,以處理表單數據的驗證和處理。這是將在本教程中使用的方法!</p>
+
+<p>Express 本身不提供表單處理操作的任何特定支持,但它可以使用中間件,以處理表單中的 <code>POST</code>和 <code>GET</code>參數,並驗證/清理它們的值。</p>
+
+<h3 id="驗證和清理">驗證和清理</h3>
+
+<p>在儲存表單中的數據之前,必須對其進行驗證和清理:</p>
+
+<ul>
+ <li>驗證檢查輸入的值,適用於每個字段(範圍,格式等),並且已為所有必填字段提供了值。</li>
+ <li>數據中的字符,可能用於將惡意內容送到服務器,為其進行清理刪除/替換。</li>
+</ul>
+
+<p>在本教程中,我們將使用流行的 <a href="https://www.npmjs.com/package/express-validator">express-validator </a>模塊,來執行表單數據的驗證和清理。</p>
+
+<h4 id="安裝">安裝</h4>
+
+<p>通過在項目的根目錄中,運行以下命令,來安裝模塊。</p>
+
+<pre class="brush: bash">npm install express-validator
+</pre>
+
+<h4 id="使用_express-validator">使用 express-validator</h4>
+
+<div class="note">
+<p><strong>注意:</strong> Github上的 <a href="https://github.com/ctavan/express-validator#express-validator">express-validator</a> 指南,提供了API的良好概述。我們建議您閱讀該內容,以了解其所有功能(包括創建自定義驗證程序)。下面我們只介紹一個對 LocalLibrary 有用的子集。</p>
+
+<p> </p>
+
+<p> </p>
+</div>
+
+<p>要在我們的控制器中使用驗證器,我們必須從 'e<strong>xpress-validator/check</strong>'和'<strong>express-validator/filter</strong>'模塊中,導入我們想要使用的函數,如下所示:</p>
+
+<pre class="brush: js">const { body,validationResult } = require('express-validator/check');
+const { sanitizeBody } = require('express-validator/filter');
+</pre>
+
+<p>有許多可用的功能,允許您一次檢查和清理請求參數,正文,標頭,cookie 等數據,或所有數據。對於本教程,我們主要使用 <code>body</code>, <code>sanitizeBody</code>,和 <code>validationResult</code>(如上面 required 導入的 )。</p>
+
+<p>功能定義如下:</p>
+
+<ul>
+ <li><code><a href="https://github.com/ctavan/express-validator#bodyfields-message">body(fields[, message])</a></code>: 指定請求本文中的一組字段(<code>POST</code>參數)以及可選的錯誤消息,如果測試失敗,則可以顯示該字段。驗證標準以菊花鏈形式連接到 <code>body()</code>方法。例如,下面的第一個檢查測試,“name”字段不為空,如果不是,則設置錯誤消息“Empty name”。第二個測試,檢查age字段是否為有效日期,並使用<code>optional()</code>指定null和空字符串不會驗證失敗。
+
+ <pre class="brush: js">body('name', 'Empty name').isLength({ min: 1 }),
+body('age', 'Invalid age').optional({ checkFalsy: true }).isISO8601(),
+</pre>
+ 您還可以用菊花鍊式連接不同的驗證器,並添加前面驗證器為真時顯示的消息。
+
+ <pre class="brush: js">body('name').isLength({ min: 1 }).trim().withMessage('Name empty.')
+ .isAlpha().withMessage('Name must be alphabet letters.'),
+</pre>
+
+ <div class="note">
+ <p><strong>注意:</strong> 您還可以添加內聯清理器,如<code>trim()</code>,如上所示。但是,此處應用清理器,僅適用於驗證步驟。如果要對最終輸出進行消毒,則需要使用單獨的清理器方法,如下所示。</p>
+ </div>
+ </li>
+ <li><code><a href="https://github.com/ctavan/express-validator#sanitizebodyfields">sanitizeBody(fields)</a></code>: 指定一個正文要清理的字段。然後將清理操作,以菊花鏈形式連接到此方法。例如,下面的 <code>escape()</code>清理操作,會從名稱變量中,刪除可能在 JavaScript 跨站點腳本攻擊中使用的 HTML 字符。
+ <pre class="brush: js">sanitizeBody('name').trim().escape(),
+sanitizeBody('date').toDate(),</pre>
+ </li>
+ <li><code><a href="https://github.com/ctavan/express-validator#validationresultreq">validationResult(req)</a></code>: 運行驗證,以 <code>validation </code>驗證結果對象的形式,提供錯誤。這是在單獨的回調中調用的,如下所示:
+ <pre class="brush: js">(req, res, next) =&gt; {
+    // Extract the validation errors from a request.
+    const errors = validationResult(req);
+
+    if (!errors.isEmpty()) {
+        // There are errors. Render form again with sanitized values/errors messages.
+        // Error messages can be returned in an array using `errors.array()`.
+        }
+    else {
+        // Data from form is valid.
+    }
+}</pre>
+ 我們使用驗證結果的<code>isEmpty()</code>方法,來檢查是否存在錯誤,並使用其 <code>array()</code> 方法,來獲取錯誤消息集合。有關更多信息,請參閱驗證結果的 <a href="https://github.com/ctavan/express-validator#validation-result-api">Validation Result API</a>。</li>
+</ul>
+
+<p>驗證和清理鏈,是應該傳遞給 Express 路由處理程序的中間件(我們通過控制器,間接地執行此操作)。中間件運行時,每個驗證器/清理程序都按指定的順序運行。</p>
+
+<p>當我們實現下面的LocalLibrary表單時,我們將介紹一些真實的例子。</p>
+
+<h3 id="表單設計">表單設計</h3>
+
+<p>圖書館中的許多模型都是相關/依賴的 - 例如,一本書需要一個作者,也可能有一個或多個種類。這提出了一個問題,即我們應該如何處理用戶希望的情況:</p>
+
+<ul>
+ <li>在其相關對象尚不存在時,創建對象(例如,尚未定義作者對象的書)。<br>
+    </li>
+ <li>刪除另一個對象仍在使用的對象(例如,刪除仍有書本 <code>Book </code>使用的種類 <code>Genre</code>)。</li>
+</ul>
+
+<p>在這個項目,我們為了簡化實作,將聲明表單只能:</p>
+
+<ul>
+ <li>使用已存在的對象創建對象(因此用戶在嘗試創建任何 <code>Book</code>對象之前,必須創建任何所需的 <code>Author</code>和 <code>Genre</code>實例)。</li>
+ <li>如果對象未被其他對象引用,則刪除該對象(例如,在刪除所有關聯的 <code>BookInstance</code>對象之前,您將無法刪除該書)。</li>
+</ul>
+
+<div class="note">
+<p><strong>注意:</strong> 更“牢固”的實現,可能允許您在創建新對象時,創建依賴對象,並隨時刪除任何對象(例如,通過刪除依賴對象,或從數據庫中,刪除對已刪除對象的引用) 。</p>
+</div>
+
+<h3 id="路由">路由</h3>
+
+<p>為了實現我們的表單處理代碼,我們需要兩個具有相同 URL 模式的路由。</p>
+
+<p>第一個(<code>GET</code>)路由,用於顯示用於創建對象的新空表單。第二個路由(<code>POST</code>),用於驗證用戶輸入的數據,然後保存信息,並重定向到詳細信息頁面(如果數據有效),或重新顯示有錯誤的表單(如果數據無效)。</p>
+
+<p>我們已經在 <strong>/routes/catalog.js</strong>(在之前的教程中)為我們所有模型的創建頁面,創建了路徑。例如,種類路由如下所示:</p>
+
+<pre class="brush: js">// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
+router.get('/genre/create', genre_controller.genre_create_get);
+
+// POST request for creating Genre.
+router.post('/genre/create', genre_controller.genre_create_post);
+</pre>
+
+<h2 id="Express_表單子文件">Express 表單子文件</h2>
+
+<p>以下子文件,將帶我們完成向示例應用程序添加所需表單的過程。在進入下一個文件之前,您需要依次閱讀並解決每個問題。</p>
+
+<ol>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_genre_form">創建種類表單</a> — 定義我們的頁面以創建種類對象 <code>Genre </code>。</li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_author_form">創建作者表單</a> — 定義用於創建作者對象 <code>Author </code>的頁面。</li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_book_form">創建書本表單</a> — 定義頁面/表單以創建書本對象 <code>Book</code> 。</li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form">創建書本實例表單</a> — 定義頁面/表單以創建書本實例對象 <code>BookInstance</code> 。</li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form">刪除作者表單 </a>— 定義要刪除作者對象 <code>Author </code>的頁面。</li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Update_Book_form">更新書本表單</a> — 定義頁面以更新書本對象 <code>Book</code> 。</li>
+</ol>
+
+<h2 id="挑戰自我">挑戰自我</h2>
+
+<p>實現 <code>Book</code>, <code>BookInstance</code>, 和 <code>Genre</code>模型的刪除頁面,用跟我們的作者刪除頁面相同的方式,將它們與關聯的詳細信息頁面,鏈接起來。頁面應遵循相同的設計方法:</p>
+
+<ul>
+ <li>如果有來自其他對象的、對於對象的引用,則應顯示註釋,列出這些對象,並說明在刪除列出的對象之前,無法刪除此記錄。</li>
+ <li>如果沒有對該對象的其他引用,則視圖應提示刪除它。如果用戶按下“刪除”按鈕 <strong>Delete</strong>,則應刪除該記錄。</li>
+</ul>
+
+<p>一些提示:</p>
+
+<ul>
+ <li>刪除種類 <code>Genre</code>就像刪除作者<code>Author</code>一樣,因為兩個對像都是 <code>Book</code>的依賴項(因此在這兩種情況下,只有在刪除相關書本時,才能刪除對象)。</li>
+ <li>刪除書本 <code>Book</code>也很相似,但您需要檢查是否沒有關聯的書本實例 <code>BookInstances</code>。</li>
+ <li>刪除書本實例 <code>BookInstances</code>是最簡單的,因為沒有依賴對象。在這種情況下,您只需找到相關記錄並將其刪除即可。</li>
+</ul>
+
+<p>實現 <code>BookInstance</code>, <code>Author</code>, 和 <code>Genre</code>模型的更新頁面,以與我們的書本更新頁面相同的方式,將它們與關聯的詳細信息頁面,鏈接起來。</p>
+
+<p>一些提示:</p>
+
+<ul>
+ <li>我們剛剛實施的圖書更新頁面是最難的!相同的模式可用於其他對象的更新頁面。</li>
+ <li>作者<code>Author</code>的死亡日期和出生日期字段,以及書本實例<code>BookInstance</code> 的 due_date 字段,是輸入到表單上日期輸入字段的錯誤格式(它需要 “YYYY-MM-DD” 形式的數據)。解決此問題的最簡單方法,是為適當格式化的日期,定義新的虛擬屬性,然後在關聯的視圖模板中,使用此字段。</li>
+ <li>如果您遇到困難,此處示例中的更新頁面有一些示例<a href="https://github.com/mdn/express-locallibrary-tutorial">的連結。</a></li>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>Express, node, 與NPM上面的第三方套件,提供你需要的每樣東西 ,可用於新增表單到你的網站上。在本文中,您學習如何使用 Pug 創建表單,使用 express-validator 驗證和清理輸入,以及添加,刪除和修改數據庫中的記錄。</p>
+
+<p>你現在應該了解如何新增基本表單,以及表單處理代碼到你的 node 網站!</p>
+
+<h2 id="請參閱">請參閱</h2>
+
+<ul>
+ <li><a href="https://www.npmjs.com/package/express-validator">express-validator</a> (npm docs).</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<h2 id="本教程連結">本教程連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/index.html b/files/zh-tw/learn/server-side/express_nodejs/index.html
new file mode 100644
index 0000000000..c1c6e11ee5
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/index.html
@@ -0,0 +1,73 @@
+---
+title: Express web framework (Node.js/JavaScript)
+slug: Learn/Server-side/Express_Nodejs
+tags:
+ - Express
+ - Express.js
+ - Node
+ - node.js
+ - 介紹
+ - 伺服器端程式
+ - 初學者
+ - 學習
+translation_of: Learn/Server-side/Express_Nodejs
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">Express 是一個流行的web框架,使用JavsScript實現,執行在node.js環境上。本系列解釋Express的優點、如何設定開發環境、完成常見的web開發和佈署。</p>
+
+<h2 id="前置需求">前置需求</h2>
+
+<p>在開始前你需要了解什麼是伺服器端web程式和什麼是web框架,推薦閱讀<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/First_steps">伺服器端網站開發第一步</a>。建議了解基本的程式知識和<a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript">JavaScript</a>,但不需要知道核心概念。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 本網站有許多學習JavaScript應用在客戶端開發的有用資源,如:<a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript">JavaScript</a>、<a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide">JavaScript 指南</a>、<a href="https://developer.mozilla.org/zh-TW/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 基礎</a>、<a href="https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript">JavaScript</a> (learning)。使用Node.js開發伺服器端使用的JavaScript語言與概念和客戶端是一樣的。Node.js提供<a href="https://nodejs.org/dist/latest-v6.x/docs/api/">額外的APIs</a>以支援無瀏覽器環境,例如:建立HTTP服務和讀取檔案系統。但不支援DOM及瀏覽器相關的 JavaScript API。</p>
+
+<p>這份指南將提供一些使用Node.js和Express的資訊以及數個優秀的學習資源。部分連結由 <a href="http://stackoverflow.com/a/5511507/894359">How do I get started with Node.js</a>(StackOverflow) 與 <a href="https://www.quora.com/What-are-the-best-resources-for-learning-Node-js?">What are the best resources for learning Node.js?</a>(Quora) 提供。</p>
+</div>
+
+<h2 id="指南">指南</h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node 介紹</a></dt>
+ <dd>第一篇的系列文章中回答了「什麼是Node」和「什麼是Express?」並概略的說明為什麼Express web框架如此特別。此文章將重點放在主要的功能上,並展示一些Express應用常見的建構模塊(儘管此時你還沒有可供測試的開發環境)</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/development_environment">設定 Node (Express) 開發環境</a></dt>
+ <dd>現在你已經了解Express的目的了,接下來繼續說明如何設定和測試 Windows、Linux (Ubuntu)和Mac OS X上的Node/Express開發環境。不管你用的是什麼作業系統,你都能在本文中找到開發Express應用的入門需知。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express 教學(1): The Local Library website</a></dt>
+ <dd>在第一篇實務教學系列文章中將說明你將會學到什麼?以及提供範例網站local library的概覽,我們將在後續的文章中繼續改進它。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express 教學(2): 建構網站骨架</a></dt>
+ <dd>本文章展示如何建構網站的骨架,接著你可以自己添加路由、模板/畫面和資料庫。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/mongoose">Express 教學(3): 使用資料庫(以Mongoose為例)</a></dt>
+ <dd>本文簡短的介紹Node/Express如何使用資料庫。接下來展示LocalLibray網站如何透過<a href="http://mongoosejs.com/">Mongoose</a>進行資料庫的存取。說明物件綱要(object schema)和模型(models)如何宣告、the main field types和基本驗證。同時簡單的展示幾個讀取資料的主要方法。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/routes">Express 教學(4): 路由和控制器</a></dt>
+ <dd>在本教學中,我們將為LocalLibrary網站中的所有資源終端設定“虛擬”處理函數的路由(URL處理代碼)。 完成後,我們將為我們的路由處理程式提供模組化結構,以便我們可以在後續的教學中擴展真正的處理函數。 我們也將了解如何使用Express創建模組化路由。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express 教學(5): 顯示圖書館的資料</a></dt>
+ <dd>現在已經準備好新增頁面來展示館藏和其他資料了。這些頁面包括一個展示我們有多少種model 型態的首頁、所有models的列表和詳細資料頁面。透過本教學你可以得到從資料庫取得紀錄和使用模板的實務經驗。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/forms">Express 教學(6): 使用表單</a></dt>
+ <dd>本教學中展示如何使用Express的插件-Pug來使用HTML Forms,以及如何編寫表單來創造、更新和刪除資料庫的文件。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/deployment">Express 教學(7): 網站佈署</a></dt>
+ <dd>現在你完成了很棒的<em>LocalLibrary</em> 網站,你希望圖書館的員工和會員可以透過網路讀取它。本教學概略說明如何找到主機來佈署你的網站以及為了使你的網站正式上線所需做的準備。</dd>
+</dl>
+
+<h2 id="或許你也想看">或許你也想看</h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">在 PWS/Cloud Foundry上安裝LocalLibrary</a></dt>
+ <dd>本文展示如何在<a href="http://run.pivotal.io">Pivotal Web Services PaaS cloud</a>上安裝<em>LocalLibrary</em> ,PWS/Cloud Foundry是一個完整且開源的Heroku替代品,可使用於教學(7)。如果你正在尋找Heroku或其他PaaS的替代品或只是想玩點不同的東西,那PWS/Cloud Foundry絕對值得一試。</dd>
+</dl>
+
+<h2 id="新增其他教學">新增其他教學</h2>
+
+<div>
+<p>現在已經有了很多教學,但你可能會想寫其他有趣主題的模塊,包括:</p>
+
+<ul>
+ <li>Using sessions</li>
+ <li>使用者認證</li>
+ <li>使用者授權與權限</li>
+ <li>測試Express web應用</li>
+ <li>Express web 應用之安全性</li>
+</ul>
+
+<p>當然,如果能作個評估模塊就更好了!</p>
+</div>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html b/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html
new file mode 100644
index 0000000000..6fc3f0a98c
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/introduction/index.html
@@ -0,0 +1,522 @@
+---
+title: Express/Node introduction
+slug: Learn/Server-side/Express_Nodejs/Introduction
+tags:
+ - Express
+ - Node
+ - nodejs
+ - 伺服器端
+ - 初學者
+ - 學習
+translation_of: Learn/Server-side/Express_Nodejs/Introduction
+---
+<div>
+
+
+
+
+<p>{{LearnSidebar}}</p>
+
+<p>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</p>
+</div>
+
+<p class="summary">在這篇文章中回答了「什麼是Node?」和「什麼是Express」,同時概述是什麼讓Express框架如此特別。本文將概述主要特性、展示一些Express應用的主要建構模塊(雖然此時你還沒有能測試它的開發環境)</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置需求:</th>
+ <td>基本的電腦知識。 對<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">伺服器端網站程式設計</a>的基本了解,特別是網站中<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">客戶端 - 伺服器交互的機制</a>。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>提升對Express的了解、如何與Node搭配使用、提供的功能和Express應用的主要建構模塊。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="什麼是Express和Node">什麼是Express和Node?</h2>
+
+<p><a href="https://nodejs.org/">Node</a> (或者說<em>Node.js</em>) 是一個開源、跨平台和允許開發者使用<a href="https://developer.mozilla.org/en-US/docs/Glossary/JavaScript">Javascript</a>創造伺服器端工具和應用的執行環境。運行的目的是為了能在瀏覽器外使用,例如:直接執行在電腦或伺服器上。所以該環境捨棄了瀏覽器限定的JavaScript APIs並增加更多傳統OS APIs的支援,例如:HTTP和檔案系統的程式庫。</p>
+
+
+
+<p>從網站伺服器開發的觀點來看Node有幾項優點:</p>
+
+<ul>
+ <li>高效能!Node 旨在提升生產率和網頁應用的可擴充性。而且它非常適合網站開發常見的問題,例如:即時網站應用</li>
+ <li>使用舊版本的JavaScript進行程式編寫,這表示不用多花力氣在轉換瀏覽器和伺服器上的程式碼</li>
+ <li>與其他傳統的Web伺服器語言(例如Python,PHP等)相比,JavaScript是一種相對新的程式語言,它受益於語言設計的改進。許多其他新的和流行的語言都可以編譯/轉換成JavaScript,因此你還可以使用CoffeeScript, ClojureScript,Scala,LiveScript等</li>
+ <li>Node Package Manager(NPM) 提供數十萬個第三方套件,是最佳的依賴解決方案也可以用來自動化大部分構建工具鏈。</li>
+ <li>它是可移植的,能夠在Windows, OS x, Linux, Solaris, FreeBSD, OpenBSD, WebOS和NonStop OS上執行。許多web主機提供方也支援使用Node,通常會提供特定的基礎設施和文件</li>
+ <li>擁有非常活耀的第三方生態系統和開發者社群,許多人樂意提供幫助</li>
+</ul>
+
+<p>你可以只用Node的HTTP模組創造一個簡單的web伺服器來回應任何請求,如下所示。此教學不會告訴建議的檔案名稱或如何執行該檔案 ;-)</p>
+
+<p>這將創造一個伺服器並會監聽<code>http://127.0.0.1:8000/</code>上任何種類的HTTP請求,當接收到任何請求時回傳一個「Hello World」的純文字回應。</p>
+
+<pre class="brush: js">// 載入 HTTP 模組
+var http = require("http");
+
+// 創建 HTTP 伺服器並監聽8000 port
+http.createServer(function(request, response) {
+
+ // Set the response HTTP header with HTTP status and Content type
+ response.writeHead(200, {'Content-Type': 'text/plain'});
+
+ // Send the response body "Hello World"
+ response.end('Hello World\n');
+}).listen(8000);
+
+// Print URL for accessing server
+console.log('Server running at http://127.0.0.1:8000/');</pre>
+
+<p>Node並不原生支持其他常見的web開發任務,如果你想為不同的HTTP方法(例如:<code>GET</code>, <code>POST</code>, <code>DELETE</code>等)增加特定的處理、替不同的URL路徑提供靜態檔案、使用樣板或動態性的產生response,你需要自己完成相關的程式<strong>或者是</strong>避免重新造輪子 - 使用web框架!</p>
+
+<p><a href="https://expressjs.com/">Express</a> 是最受歡迎的Node web框架,還是其他許多流行的<a href="https://expressjs.com/en/resources/frameworks.html">Node web框架</a>的底層庫,它提供:</p>
+
+<ul>
+ <li>替不同HTTP Method、不同URL路徑的requests編寫不同的處理方法</li>
+ <li>透過整合「畫面」的渲染引擎來達到插入資料到樣板中產生response</li>
+ <li>設定常見的web應用設定,例如:連線用的port和產生response的樣板位置</li>
+ <li>在request的處理流程中增加額外的「中間層」進行處理</li>
+</ul>
+
+<p>雖然Express本身非常簡單,但開發者們已經創造相容的中間層套件來解決大部份web開發的問題,這些套件能處理cookies, sessions,登入,URL參數,POST資料,安全標頭等等,你能在<a href="http://expressjs.com/en/resources/middleware.html">Express Middleware</a>中找到這些套件的列表(以及其他流行的第三方套件)</p>
+
+<div class="note">
+<p><strong>注意:</strong> 這種靈活性是一把雙刃劍。有一些中間層套件能解決大部份的問題或需求,但使用正確的套件有時會是一個問題。也沒有「正確的方法」來創建應用,你在網路上找到的範例也並非都是最佳解或是只有開發上所需要做的一小部份。</p>
+</div>
+
+<h2 id="歷史">歷史</h2>
+
+<p>2009年Node在Linux平台上初次發佈. 2010年NPM套件管利器發佈, 2012年增加Windows的原生支援. 現在的LTS版本為Node v8.11.2,最新版本為Node v10.1.0。這只是它深厚歷史的一小片斷,欲知更多詳情請洽 <a href="https://en.wikipedia.org/wiki/Node.js#History">Wikipedia</a>。</p>
+
+<p>2010年11月Express初次發佈,現在的API版本為 4.16。你可以查閱<a href="https://expressjs.com/en/changelog/4x.html">更新紀錄</a>來了解此版本做了甚麼更改或是從<a href="https://github.com/expressjs/express/blob/master/History.md">GitHub</a>中了解詳細的歷史紀錄。</p>
+
+<h2 id="NodeExpress有多流行">Node/Express有多流行?</h2>
+
+<p>對於web 框架而言流行度很重要,這代表他會不會被繼續更新、文件、附加套件和技術支援方面有多少資源</p>
+
+<p>現在沒有一個明確的指標來評斷伺服器端框架的流行度,雖然有 <a href="http://hotframeworks.com/">Hot Frameworks</a>透過計算GitHub的專案數量和StackOverflow的問題來衡量流行度。更好的問題是,Node和Express是否「夠流行」以避免成為不流行的平台。有沒有持續進步?需要時是否能得到幫助?能不能找到Express相關的工作?</p>
+
+<p>從眾多使用Express的<a href="https://expressjs.com/en/resources/companies-using-express.html">公司</a>、貢獻程式碼的人數和那些提供免費/收費支援的人員來看,是的!Express是一個流行的框架。</p>
+
+<h2 id="Is_Express_opinionated">Is Express opinionated?</h2>
+
+<p>Web 框架通常自稱為 "opinionated" 或 "unopinionated".</p>
+
+<p>Opinionated指的是那些有「正確」方法解決特定問題的框架。在特定的需求上他們通常能快速開發,因為正確的方法通常易懂且有良好的文件,然而在面對其他問題時則會失去靈活性。這類型的框架通常傾向於提供較少的選擇和套件來解決問題。</p>
+
+<p>反過來說Unopinionated 框架,對於如何組合套件來解決問題尚有較少的限制,開發者可以更輕易的使用適當的套件來解決特定問題,儘管代價是你需要自己找到適合的套件。</p>
+
+<p>Express是Unopinionated 框架,你可以在request處理流程中使用任何相容套件,使用單一或複數個檔案來建構應用,有時候甚至會覺得擁有太多選擇了。</p>
+
+<h2 id="Express的程式碼長怎樣">Express的程式碼長怎樣?</h2>
+
+<p>傳統的資料驅動網站中,web應用程式會等待來自瀏覽器(或其他客戶端)的HTTP Request,接收到Request後根據URL和可能夾帶的<code>POST</code>/<code>GET</code>資料來決定需要回應什麼動作,根據需要可能對資料庫進行讀寫或執行滿足Request所需的其他任務。web應用程式會回應Response給瀏覽器,通常是藉由插入檢所到的資料到HTML 模板中動態產生HTML頁面讓瀏覽器顯示。</p>
+
+
+
+<p>Express provides methods to specify what function is called for a particular HTTP verb (<code>GET</code>, <code>POST</code>, <code>SET</code>, etc.) and URL pattern ("Route"), and methods to specify what template ("view") engine is used, where template files are located, and what template to use to render a response. You can use Express middleware to add support for cookies, sessions, and users, getting <code>POST</code>/<code>GET</code> parameters, etc. You can use any database mechanism supported by Node (Express does not define any database-related behaviour).</p>
+
+<p>The following sections explain some of the common things you'll see when working with <em>Express</em> and <em>Node</em> code.</p>
+
+<h3 id="Helloworld_Express">Helloworld Express</h3>
+
+<p>First lets consider the standard Express <a href="https://expressjs.com/en/starter/hello-world.html">Hello World</a> example (we discuss each part of this below, and in the following sections).</p>
+
+<div class="note">
+<p><strong>Tip:</strong> If you have Node and Express already installed (or if you install them as shown in the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">next article</a>), you can save this code in a text file called <strong>app.js</strong> and run it in a bash command prompt by calling:   </p>
+
+<p><strong><code>./node ./app.js</code></strong></p>
+</div>
+
+<pre class="brush: js">var express = require('express');
+var app = express();
+
+<strong>app.get('/', function(req, res) {
+ res.send('Hello World!');
+});</strong>
+
+app.listen(3000, function() {
+ console.log('Example app listening on port 3000!');
+});
+</pre>
+
+<p>The first two lines <code>require()</code> (import) the express module and create an <a href="https://expressjs.com/en/4x/api.html#app">Express application</a>. This object, which is traditionally named <code>app</code>, has methods for routing HTTP requests, configuring middleware, rendering HTML views, registering a template engine, and modifying <a href="https://expressjs.com/en/4x/api.html#app.settings.table">application settings</a> that control how the application behaves (e.g. the environment mode, whether route definitions are case sensitive, etc.)</p>
+
+<p>The middle part of the code (the three lines starting with <code>app.get</code>) shows a <em>route definition</em>. The <code>app.get()</code> method specifies a callback function that will be invoked whenever there is an HTTP <code>GET</code> request with a path (<code>'/'</code>) relative to the site root. The callback function takes a request and a response object as arguments, and simply calls <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> on the response to return the string "Hello World!"</p>
+
+<p>The final block starts up the server on port '3000' and prints a log comment to the console. With the server running, you could go to <code>localhost:3000</code> in your browser to see the example response returned.</p>
+
+<h3 id="Importing_and_creating_modules">Importing and creating modules</h3>
+
+<p>A module is a JavaScript library/file that you can import into other code using Node's <code>require()</code> function. <em>Express</em> itself is a module, as are the middleware and database libraries that we use in our <em>Express</em> applications.</p>
+
+<p>The code below shows how we import a module by name, using the <em>Express</em> framework as an example. First we invoke the <code style="font-style: normal; font-weight: normal;">require()</code> function, specifying the name of the module as a string (<code>'express'</code>), and calling the returned object to create an <a href="https://expressjs.com/en/4x/api.html#app">Express application</a>. We can then access the properties and functions of the application object.</p>
+
+<pre class="brush: js">var express = require('express');
+var app = express();
+</pre>
+
+<p>You can also create your own modules that can be imported in the same way.</p>
+
+<div class="note">
+<p><strong>Tip:</strong> You will <em>want </em>to create your own modules, because this allows you to organise your code into managable parts — a monolithic single-file application is hard to understand and maintain. Using modules also helps you manage your namespace, because only the variables you explicitly export are imported when you use a module.</p>
+</div>
+
+<p>To make objects available outside of a module you just need to assign them to the <code>exports</code> object. For example, the <strong>square.js</strong> module below is a file that exports <code>area()</code> and <code>perimeter()</code> methods:</p>
+
+<pre class="brush: js">exports.area = function(width) { return width * width; };
+exports.perimeter = function(width) { return 4 * width; };
+</pre>
+
+<p>We can import this module using <code>require()</code>, and then call the exported method(s) as shown:</p>
+
+<pre class="brush: js">var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension
+console.log('The area of a square with a width of 4 is ' + square.area(4));</pre>
+
+<div class="note">
+<p><strong>Note:</strong> You can also specify an absolute path to the module (or a name, as we did initially).</p>
+</div>
+
+<p>If you want to export a complete object in one assignment instead of building it one property at a time, assign it to <code>module.exports</code> as shown below (you can also do this to make the root of the exports object a constructor or other function):</p>
+
+<pre class="brush: js">module.exports = {
+ area: function(width) {
+ return width * width;
+ },
+
+ perimeter: function(width) {
+ return 4 * width;
+ }
+};
+</pre>
+
+<p>For a lot more information about modules see <a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs).</p>
+
+<h3 id="Using_asynchronous_APIs">Using asynchronous APIs</h3>
+
+<p>JavaScript code frequently uses asynchronous rather than synchronous APIs for operations that may take some time to complete. A synchronous API is one in which each operation must complete before the next operation can start. For example, the following log functions are synchronous, and will print the text to the console in order (First, Second).</p>
+
+<pre class="brush: js">console.log('First');
+console.log('Second');
+</pre>
+
+<p>By contrast, an asynchronous API is one in which the API will start an operation and immediately return (before the operation is complete). Once the operation finishes, the API will use some mechanism to perform additional operations. For example, the code below will print out "Second, First" because even though <code>setTimeout()</code> method is called first, and returns immediately, the operation doesn't complete for several seconds.</p>
+
+<pre class="brush: js">setTimeout(function() {
+ console.log('First');
+ }, 3000);
+console.log('Second');
+</pre>
+
+<p>Using non-blocking asynchronous APIs is even more important on Node than in the browser, because <em>Node</em> is a single threaded event-driven execution environment. "single threaded" means that all requests to the server are run on the same thread (rather than being spawned off into separate processes). This model is extremely efficient in terms of speed and server resources, but it does mean that if any of your functions call synchronous methods that take a long time to complete, they will block not just the current request, but every other request being handled by your web application.</p>
+
+<p>There are a number of ways for an asynchronous API to notify your application that it has completed. The most common way is to register a callback function when you invoke the asynchronous API, that will be called back when the operation completes. This is the approach used above.</p>
+
+<div class="note">
+<p><strong>Tip:</strong> Using callbacks can be quite "messy" if you have a sequence of dependent asynchronous operations that must be performed in order, because this results in multiple levels of nested callbacks. This problem is commonly known as "callback hell". This problem can be reduced by good coding practices (see <a href="http://callbackhell.com/">http://callbackhell.com/</a>), using a module like <a href="https://www.npmjs.com/package/async">async</a>, or even moving to ES6 features like <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>.</p>
+</div>
+
+<div class="note">
+<p><strong>Note:</strong> A common convention for Node and Express is to use error-first callbacks. In this convention the first value in your <em>callback functions</em> is an error value, while subsequent arguments contain success data. There is a good explanation of why this approach is useful in this blog: <a href="http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js">The Node.js Way - Understanding Error-First Callbacks</a> (fredkschott.com).</p>
+</div>
+
+<h3 id="Creating_route_handlers">Creating route handlers</h3>
+
+<p>In our <em>Hello World</em> Express example (see above), we defined a (callback) route handler function for HTTP <code>GET</code> requests to the site root (<code>'/'</code>).</p>
+
+<pre class="brush: js">app.<strong>get</strong>('/', function(req, res) {
+ res.send('Hello World!');
+});
+</pre>
+
+<p>The callback function takes a request and a response object as arguments. In this case the method simply calls <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> on the response to return the string "Hello World!" There are a <a href="https://expressjs.com/en/guide/routing.html#response-methods">number of other response methods</a> for ending the request/response cycle, for example you could call <code><a href="https://expressjs.com/en/4x/api.html#res.json">res.json()</a></code> to send a JSON response or <code><a href="https://expressjs.com/en/4x/api.html#res.sendFile">res.sendFile()</a></code> to send a file.</p>
+
+<div class="note">
+<p><strong>JavaScript tip:</strong> You can use any argument names you like in the callback functions; when the callback is invoked the first argument will always be the request and the second will always be the response. It makes sense to name them such that you can identify the object you're working with in the body of the callback.</p>
+</div>
+
+<p>The <em>Express application</em> object also provides methods to define route handlers for all the other HTTP verbs, which are mostly used in exactly the same way: <code>post()</code>, <code>put()</code>, <code>delete()</code>, <code>options()</code>, <code>trace()</code>, <code>copy()</code>, <code>lock()</code>, <code>mkcol()</code>, <code>move()</code>, <code>purge()</code>, <code>propfind()</code>, <code>proppatch()</code>, <code>unlock()</code>, <code>report()</code>, <code>mkactivity()</code>, <code>checkout()</code>, <code>merge()</code>, <code>m-</code><code>search()</code>, <code>notify()</code>, <code>subscribe()</code>, <code>unsubscribe()</code>, <code>patch()</code>, <code>search()</code>, and <code>connect()</code>.</p>
+
+<p>There is a special routing method, <code>app.all()</code>, which will be called in response to any HTTP method. This is used for loading middleware functions at a particular path for all request methods. The following example (from the Express documentation) shows a handler that will be executed for requests to <code>/secret</code> irrespective of the HTTP verb used (provided it is supported by the <a href="https://nodejs.org/api/http.html#http_http_methods">http module</a>).</p>
+
+<pre class="brush: js">app.all('/secret', function(req, res, next) {
+ console.log('Accessing the secret section ...');
+ next(); // pass control to the next handler
+});</pre>
+
+<p>Routes allow you to match particular patterns of characters in a URL, and extract some values from the URL and pass them as parameters to the route handler (as attributes of the request object passed as a parameter).</p>
+
+<p>Often it is useful to group route handlers for a particular part of a site together and access them using a common route-prefix (e.g. a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of <em>/wiki/</em>). In <em>Express</em> this is achieved by using the <code><a href="http://expressjs.com/en/guide/routing.html#express-router">express.Router</a></code> object. For example, we can create our wiki route in a module named <strong>wiki.js</strong>, and then export the <code>Router</code> object, as shown below:</p>
+
+<pre class="brush: js">// wiki.js - Wiki route module
+
+var express = require('express');
+var router = express.Router();
+
+// Home page route
+router.get('/', function(req, res) {
+ res.send('Wiki home page');
+});
+
+// About page route
+router.get('/about', function(req, res) {
+ res.send('About this wiki');
+});
+
+module.exports = router;
+</pre>
+
+<div class="note">
+<p><strong>Note:</strong> Adding routes to the <code>Router</code> object is just like adding routes to the <code>app</code> object (as shown previously).</p>
+</div>
+
+<p>To use the router in our main app file we would then <code>require()</code> the route module (<strong>wiki.js</strong>), then call <code>use()</code> on the <em>Express</em> application to add the Router to the middleware handling path. The two routes will then be accessible from <code style="font-style: normal; font-weight: normal;">/wiki/</code> and <code style="font-style: normal; font-weight: normal;">/wiki/about/</code>.</p>
+
+<pre class="brush: js">var wiki = require('./wiki.js');
+// ...
+app.use('/wiki', wiki);</pre>
+
+<p>We'll show you a lot more about working with routes, and in particular about using the <code>Router</code>, later on in the linked section<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes"> Routes and controllers .</a></p>
+
+<h3 id="Using_middleware">Using middleware</h3>
+
+<p>Middleware is used extensively in Express apps, for tasks from serving static files to error handling, to compressing HTTP responses. Whereas route functions end the HTTP request-response cycle by returning some response to the HTTP client, middleware functions <em>typically</em> perform some operation on the request or response and then call the next function in the "stack", which might be more middleware or a route handler. The order in which middleware is called is up to the app developer.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The middleware can perform any operation, execute any code, make changes to the request and response object, and it can<em> also end the request-response cycle</em>. If it does not end the cycle then it must call <code>next()</code> to pass control to the next middleware function (or the request will be left hanging).</p>
+</div>
+
+<p>Most apps will use <em>third-party</em> middleware in order to simplify common web development tasks like working with cookies, sessions, user authentication, accessing request <code>POST</code> and JSON data, logging, etc. You can find a <a href="http://expressjs.com/en/resources/middleware.html">list of middleware packages maintained by the Express team</a> (which also includes other popular 3rd party packages). Other Express packages are available on the NPM package manager.</p>
+
+<p>To use third party middleware you first need to install it into your app using NPM. For example, to install the <a href="http://expressjs.com/en/resources/middleware/morgan.html">morgan</a> HTTP request logger middleware, you'd do this:</p>
+
+<pre class="brush: bash"><code>$ npm install morgan
+</code></pre>
+
+<p>You could then call <code>use()</code> on the <em>Express application object</em> to add the middleware to the stack:</p>
+
+<pre class="brush: js">var express = require('express');
+<strong>var logger = require('morgan');</strong>
+var app = express();
+<strong>app.use(logger('dev'));</strong>
+...</pre>
+
+<div class="note">
+<p><strong>Note:</strong> Middleware and routing functions are called in the order that they are declared. For some middleware the order is important (for example if session middleware depends on cookie middleware, then the cookie handler must be added first). It is almost always the case that middleware is called before setting routes, or your route handlers will not have access to functionality added by your middleware.</p>
+</div>
+
+<p>You can write your own middleware functions, and you are likely to have to do so (if only to create error handling code). The <strong>only</strong> difference between a middleware function and a route handler callback is that middleware functions have a third argument <code>next</code>, which middleware functions are expected to call if they are not that which completes the request cycle (when the middleware function is called, this contains the <em>next</em> function that must be called).</p>
+
+<p>You can add a middleware function to the processing chain with either <code>app.use()</code> or <code>app.add()</code>, depending on whether you want to apply the middleware to all responses or to responses with a particular HTTP verb (<code>GET</code>, <code>POST</code>, etc). You specify routes the same in both cases, though the route is optional when calling <strong>app.use()</strong>.</p>
+
+<p>The example below shows how you can add the middleware function using both methods, and with/without a route.</p>
+
+<pre class="brush: js">var express = require('express');
+var app = express();
+
+// An example middleware function
+var a_middleware_function = function(req, res, <em>next</em>) {
+  // ... perform some operations
+  next(); // Call next() so Express will call the next middleware function in the chain.
+}
+
+// Function added with use() for all routes and verbs
+app.use(a_middleware_function);
+
+// Function added with use() for a specific route
+app.use('/someroute', a_middleware_function);
+
+// A middleware function added for a specific HTTP verb and route
+app.get('/', a_middleware_function);
+
+app.listen(3000);</pre>
+
+<div class="note">
+<p><strong>JavaScript Tip:</strong> Above we declare the middleware function separately and then set it as the callback. In our previous route handler function we declared the callback function when it was used. In JavaScript, either approach is valid.</p>
+</div>
+
+<p>The Express documentation has a lot more excellent documentation about <a href="https://expressjs.com/en/guide/using-middleware.html">using</a> and <a href="http://expressjs.com/en/guide/writing-middleware.html">writing</a> Express middleware.</p>
+
+<h3 id="Serving_static_files">Serving static files</h3>
+
+<p>You can use the <a href="http://expressjs.com/en/4x/api.html#express.static">express.static</a> middleware to serve static files, including your images, CSS and JavaScript (<code>static()</code> is the only middleware function that is actually <strong>part</strong> of <em>Express</em>). For example, you would use the line below to serve images, CSS files, and JavaScript files from a directory named '<strong>public'</strong> at the same level as where you call node:</p>
+
+<pre class="brush: js">app.use(express.static('public'));
+</pre>
+
+<p>Any files in the public directory are served by adding their filename (<em>relative</em> to the base "public" directory) to the base URL. So for example:</p>
+
+<pre><code>http://localhost:3000/images/dog.jpg
+http://localhost:3000/css/style.css
+http://localhost:3000/js/app.js
+http://localhost:3000/about.html
+</code></pre>
+
+<p>You can call <code>static()</code> multiple times to serve multiple directories. If a file cannot be found by one middleware function then it will simply be passed on to the subsequent middleware (the order that middleware is called is based on your declaration order).</p>
+
+<pre class="brush: js">app.use(express.static('public'));
+app.use(express.static('media'));
+</pre>
+
+<p>You can also create a virtual prefix for your static URLs, rather than having the files added to the base URL. For example, here we <a href="http://expressjs.com/en/4x/api.html#app.use">specify a mount path</a> so that the files are loaded with the prefix "/media":</p>
+
+<pre class="brush: js">app.use('/media', express.static('public'));
+</pre>
+
+<p>Now, you can load the files that are in the <code>public</code> directory from the <code>/media</code> path prefix.</p>
+
+<pre><code>http://localhost:3000/media/images/dog.jpg
+http://localhost:3000/media/video/cat.mp4
+http://localhost:3000/media/cry.mp3</code>
+</pre>
+
+<p>For more information, see <a href="Serving static files in Express">Serving static files in Express</a>.</p>
+
+<h3 id="Handling_errors">Handling errors</h3>
+
+<p>Errors are handled by one or more special middleware functions that have four arguments, instead of the usual three: <code>(err, req, res, next)</code>. For example:</p>
+
+<pre class="brush: js">app.use(function(err, req, res, next) {
+ console.error(err.stack);
+ res.status(500).send('Something broke!');
+});
+</pre>
+
+<p>These can return any content required, but must be called after all other <code>app.use()</code> and routes calls so that they are the last middleware in the request handling process!</p>
+
+<p>Express comes with a built-in error handler, which takes care of any remaining errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. If you pass an error to <code>next()</code> and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace.</p>
+
+<div class="note">
+<p><strong>Note:</strong> The stack trace is not included in the production environment. To run it in production mode you need to set the the environment variable <code>NODE_ENV</code> to '<code>production'</code>.</p>
+</div>
+
+<div class="note">
+<p><strong>Note:</strong> HTTP404 and other "error" status codes are not treated as errors. If you want to handle these, you can add a middleware function to do so. For more information see the <a href="http://expressjs.com/en/starter/faq.html#how-do-i-handle-404-responses">FAQ</a>.</p>
+</div>
+
+<p>For more information see <a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs).</p>
+
+<h3 id="Using_databases">Using databases</h3>
+
+<p><em>Express</em> apps can use any database mechanism supported by <em>Node</em> (<em>Express</em> itself doesn't define any specific additional behaviour/requirements for database management). There are many options, including PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.</p>
+
+<p>In order to use these you have to first install the database driver using NPM. For example, to install the driver for the popular NoSQL MongoDB you would use the command:</p>
+
+<pre class="brush: bash"><code>$ npm install mongodb
+</code></pre>
+
+<p>The database itself can be installed locally or on a cloud server. In your Express code you require the driver, connect to the database, and then perform create, read, update, and delete (CRUD) operations. The example below (from the Express documentation) shows how you can find "mammal" records using MongoDB.</p>
+
+<pre class="brush: js">//this works with older versions of mongodb version ~ 2.2.33
+var MongoClient = require('mongodb').MongoClient;
+
+MongoClient.connect('mongodb://localhost:27017/animals', function(err, db) {
+ if (err) throw err;
+
+ db.collection('mammals').find().toArray(function (err, result) {
+ if (err) throw err;
+
+ console.log(result);
+ });
+});
+
+
+//for mongodb version 3.0 and up
+let MongoClient = require('mongodb').MongoClient;
+MongoClient.connect('mongodb://localhost:27017/animals', function(err, client){
+ if(err) throw err;
+
+  let db = client.db('animals');
+  db.collection('mammals').find().toArray(function(err, result){
+ if(err) throw err;
+  console.log(result);
+  client.close();
+  });
+}
+</pre>
+
+
+
+
+
+
+
+<p>Another popular approach is to access your database indirectly, via an Object Relational Mapper ("ORM"). In this approach you define your data as "objects" or "models" and the ORM maps these through to the underlying database format. This approach has the benefit that as a developer you can continue to think in terms of JavaScript objects rather than database semantics, and that there is an obvious place to perform validation and checking of incoming data. We'll talk more about databases in a later article.</p>
+
+<p>For more information see <a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs).</p>
+
+<h3 id="Rendering_data_(views)">Rendering data (views)</h3>
+
+<p>Template engines (referred to as "view engines" by <em>Express</em>) allow you to specify the <em>structure</em> of an output document in a template, using placeholders for data that will be filled in when a page is generated. Templates are often used to create HTML, but can also create other types of documents. Express has support for <a href="https://github.com/expressjs/express/wiki#template-engines">a number of template engines</a>, and there is a useful comparison of the more popular engines here: <a href="https://strongloop.com/strongblog/compare-javascript-templates-jade-mustache-dust/">Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More</a>.</p>
+
+<p>In your application settings code you set the template engine to use and the location where Express should look for templates using the 'views' and 'view engines' settings, as shown below (you will also have to install the package containing your template library too!)</p>
+
+<pre class="brush: js">var express = require('express');
+var app = express();
+
+// Set directory to contain the templates ('views')
+app.set('views', path.join(__dirname, 'views'));
+
+// Set view engine to use, in this case 'some_template_engine_name'
+app.set('view engine', 'some_template_engine_name');
+</pre>
+
+<p>The appearance of the template will depend on what engine you use. Assuming that you have a template file named "index.&lt;template_extension&gt;" that contains placeholders for data variables named 'title' and "message", you would call <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code> in a route handler function to create and send the HTML response:</p>
+
+<pre class="brush: js">app.get('/', function(req, res) {
+ res.render('index', { title: 'About dogs', message: 'Dogs rock!' });
+});</pre>
+
+<p>For more information see <a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs).</p>
+
+<h3 id="File_structure">File structure</h3>
+
+<p>Express makes no assumptions in terms of structure or what components you use. Routes, views, static files, and other application-specific logic can live in any number of files with any directory structure. While it is perfectly possible to have the whole <em>Express</em> application in one file, typically it makes sense to split your application into files based on function (e.g. account management, blogs, discussion boards) and architectural problem domain (e.g. model, view or controller if you happen to be using an <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">MVC architecture</a>).</p>
+
+<p>In a later topic we'll use the <em>Express Application Generator</em>, which creates a modular app skeleton that we can easily extend for creating web applications.</p>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>恭喜,您已完成 Express / Node之旅的第一步!您現在應該了解 Express 和 Node 的主要優點,以及 Express 應用程序的主要部分(路由,中間件,錯誤處理和模板代碼)。您還應該明白,Express 是一個不固執己見的框架,您將這些組件組合在一起的方式以及您使用的函式庫,在很大程度上取決於您!</p>
+
+<p>當然,Express是一個非常輕量級的 Web 應用程序框架,它的許多好處和潛力來自第三方函式庫和功能。我們將在以下文章中更詳細地介紹這些內容。在下一篇文章中,我們將介紹如何設置 Node 開發環境,以便您可以開始查看一些 Express 代碼。</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://medium.com/@ramsunvtech/manage-multiple-node-versions-e3245d5ede44">Venkat.R - Manage Multiple Node versions</a></li>
+ <li><a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs)</li>
+ <li><a href="https://expressjs.com/">Express</a> (home page)</li>
+ <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li>
+ <li><a href="https://expressjs.com/en/guide/using-middleware.html">Using middleware</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/guide/writing-middleware.html">Writing middleware for use in Express apps</a> (Express docs)</li>
+ <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/starter/static-files.html">Serving static files in Express</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs)</li>
+</ul>
+
+<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html b/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html
new file mode 100644
index 0000000000..8541c1c37c
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/mongoose/index.html
@@ -0,0 +1,792 @@
+---
+title: 'Express 教學 3: 使用資料庫 ( Mongoose)'
+slug: Learn/Server-side/Express_Nodejs/mongoose
+translation_of: Learn/Server-side/Express_Nodejs/mongoose
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">本文簡短介紹數據庫,以及如何搭配 Node / Express 應用,使用數據庫。接下來會演示我們如何使用 <a href="http://mongoosejs.com/">Mongoose</a>,為本地圖書館提供數據庫存取。本文說明物件要求與模型如何宣告,主要的欄位型態,以及基本驗證。本文也簡短演示一些存取模型數據的主要方法。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置條件:</th>
+ <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express 教學 2: 創建一個骨架網站</a></td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>能夠使用Mongoose設計並創造自己的模型。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>圖書館職員會使用本地圖書館網站,存放書本和借書者<font><font>訊息</font></font>。圖書館使用者會用網站瀏覽與尋找書本,看看是否有可以藉閱的書本複本,然後預約或者藉閱。為了有效率地存放與取用<font><font>訊息</font></font>,我們將把它存放到數據庫。</p>
+
+<p>Express 應用可以使用許多不同的數據庫,並且有好幾種方法可以執行創建 <strong>C</strong>reate、讀取 <strong>R</strong>ead、更新 <strong>U</strong>pdate 和刪除 <strong>D</strong>elete (CRUD) 操作。本教程為一些可用的選項,提供簡短的概覽,然後接著詳細演示該選項的特定運行機制。</p>
+
+<h3 id="我可以使用什麼數據庫">我可以使用什麼數據庫?</h3>
+
+<p>Express 應用程序可以使用 Node 支持的任何數據庫(Express 本身不會為數據庫管理,定義任何特定的附加行為/要求)。有許多<a href="https://expressjs.com/en/guide/database-integration.html">流行的選項</a>,包括 PostgreSQL,MySQL,Redis,SQLite 和 MongoDB。</p>
+
+<p>在選擇數據庫時,您應該考慮時間 - 生產力/學習曲線,性能,易複製/備份,成本,社區支持等等。雖然沒有單一的 “最佳” 數據庫,但幾乎任何流行的解決方案,我們的本地圖書館這樣的中小型網站,應該都可以接受。</p>
+
+<p>有關選項的更多<font><font>訊息</font></font>,請參閱:<a href="https://expressjs.com/en/guide/database-integration.html">數據庫集成(Express docs)</a>。</p>
+
+<h3 id="與數據庫互動的最好方式是什麼">與數據庫互動的最好方式是什麼?</h3>
+
+<p>有兩種與數據庫互動的方法:</p>
+
+<ul>
+ <li>使用數據庫的原生查詢語言(例如SQL)</li>
+ <li>使用對像數據模型(“ODM”)/對象關係模型(“ORM”)。 ODM / ORM將網站的數據表示為JavaScript對象,然後將其映射到底層數據庫。一些ORM綁定到特定的數據庫,而另一些則提供了一個不特定數據庫的後端。</li>
+</ul>
+
+<p>通過使用 SQL 或數據庫支持的任何查詢語言,都可以獲得最佳性能。 ODM通常比較慢,因為它們使用翻譯代碼,在對象和數據庫格式之間進行映射,這可能不會使用最有效的數據庫查詢(尤其是如果ODM支持不同的數據庫後端,並且必須在各個數據庫所支持的功能方面,做出更大的折衷)。</p>
+
+<p>使用 ORM 的好處是,程序員可以繼續用 JavaScript 對象而不是數據庫語義來思考 — 如果您需要使用不同數據庫(在相同或不同的網站上),那麼尤其如此。他們還提供了一個明顯的地方來執行數據驗證和檢查。</p>
+
+<div class="note">
+<p><strong>提示:</strong>  使用ODM / ORM通常可以降低開發和維護成本!除非您非常熟悉本地查詢語言,或者性能對您至關重要,否則您應該強烈考慮使用 ODM。</p>
+</div>
+
+<h3 id="我應該使用哪個_ORMODM">我應該使用哪個 ORM/ODM ?</h3>
+
+<p>NPM 套件管理器站點上,有許多ODM / ORM 解決方案(查看 <a href="https://www.npmjs.com/browse/keyword/odm">odm</a> 和 <a href="https://www.npmjs.com/browse/keyword/orm">orm</a> 標籤的子集合!)。</p>
+
+<p>在撰寫本文時,受歡迎的幾種解決方案是:   </p>
+
+<ul>
+ <li><a href="https://www.npmjs.com/package/mongoose">Mongoose</a>: Mongoose 是一個 <a href="https://www.mongodb.org/">MongoDB</a>對象建模工具,用於在異步環境中工作。</li>
+ <li><a href="https://www.npmjs.com/package/waterline">Waterline</a>: 它是從基於Express的 Sails web 框架中提取的 ORM。它提供了一個統一的 API,來訪問眾多不同的數據庫,包括Redis,mySQL,LDAP,MongoDB 和 Postgres。</li>
+ <li><a href="https://www.npmjs.com/package/bookshelf">Bookshelf</a>: 提供基於 promise 和傳統回調的接口,提供事務支持,eager/嵌套 eager 關係加載,多態關聯以及對一對一,一對多和多對多關係的支持。適用於PostgreSQL,MySQL 和 SQLite3。</li>
+ <li><a href="https://www.npmjs.com/package/objection">Objection</a>: 以盡可能簡單的方式,使用 SQL 的全部功能,和底層數據庫引擎(支持SQLite3,Postgres 和 MySQL)。</li>
+ <li>
+ <p><a href="https://www.npmjs.com/package/sequelize">Sequelize</a> 是 Node.js 和 io.js 基於 promise 的 ORM。它支持以下數據庫方言,PostgreSQL,MySQL,MariaDB,SQLite 和 MSSQL,並具有可靠的事務支持,關係,唯讀複本等功能。</p>
+ </li>
+</ul>
+
+<p>一般來說,在選擇解決方案時,您應該考慮提供的功能和 “社區活動” (下載,貢獻,錯誤報告,文檔質量等)。在撰寫本文時,Mongoose 是迄今為止最受歡迎的 ODM,如果您將MongoDB 用於你的數據庫,那麼它是一個合理的選擇。</p>
+
+<h3 id="在本地圖書館使用_Mongoose_和_MongoDb">在本地圖書館使用 Mongoose 和 MongoDb</h3>
+
+<p>對於本地圖書館示例(以及本主題的其餘部分),我們將使用 <a href="https://www.npmjs.com/package/mongoose">Mongoose ODM </a>來訪問我們的圖書館數據。 Mongoose 是 <a href="https://www.mongodb.com/what-is-mongodb">MongoDB</a> 的前端,MongoDB 是一個使用面向文檔數據模型的開源 <a href="https://en.wikipedia.org/wiki/NoSQL">NoSQL</a> 數據庫。在 MongoDB 數據庫中,“文檔” 的 “集合” ,<a href="https://docs.mongodb.com/manual/core/databases-and-collections/#collections">類似於</a>關係數據庫中 “行” 的 “表”。</p>
+
+<p>這種 ODM 和數據庫的結合在 Node 社區中非常流行,部分原因是文檔存儲和查詢系統,看起來非常像 JSON,因此對 JavaScript 開發人員來說很熟悉。</p>
+
+<div class="note">
+<p><strong>提示:</strong> 使用 Mongoose 時,您不需要事先了解 MongoDB,但是如果您已經熟悉 MongoDB,<a href="http://mongoosejs.com/docs/guide.html">Mongoose documentation </a>文檔的一部分會更易於使用和理解。</p>
+</div>
+
+<p>本教程的其餘部分,將介紹如何為 本地圖書館網站示例,定義和訪問Mongoose 模式和模型。</p>
+
+<h2 id="設計本地圖書館的模型"><font><font>設計本地圖書館的模型</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在您開始編寫模型之前,花幾分鐘的時間思考,我們需要儲存的數據以及不同對象之間的關係。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們知道,我們需要儲存有關書籍的訊息(標題,摘要,作者,種類,國際標準書號),以及我們可能有多個副本可用(具有全域唯一ID,可用狀態等)。我們可能需要存儲有關作者的更多訊息,而不僅僅是他們的名字,並且可能有多個作者,具有相同或相似的名稱。我們希望能夠根據書名,作者,種類和類別對訊息進行分類。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在設計模型時,對於每個“對象”(相關訊息組)都有獨立的模型,是有意義的。在這種情況下,明顯的對像是書籍,書籍實例和作者。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>您可能還希望,使用模型來表示選擇列表選項(例如,選擇的下拉列表),而不是將選項硬編碼到網站本身— 在無法預先知道所有選項,或者可能更改時,更建議使用模型來表示。</font><font>很明顯的,書本類型是這種模型的可能人選(例如科幻小說,法國詩歌等)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>一旦我們決定了我們的模型和字段,我們就需要考慮它們之間的關係。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>考慮到這一點,下面的UML關聯圖,顯示了我們在這種情況下定義的模型(一個框對應一個模型)。</font><font>如上所述,我們創建了以下模型,圖書(本書的通用細節),書本實例(系統中可用圖書的特定實際副本的狀態)和作者。</font><font>我們還決定建立一個種類模型,以便可以動態創建它的值,而不是將下拉選項硬編碼。</font><font>我們已經決定不為書本實例:狀態</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>BookInstance:status</code><font><font>建立模型—我們將硬編碼可接受的值,因為我們不希望這些值發生變化。</font><font>在下圖每個框中,您可以看到模型名稱,字段名稱和類型,以及方法及其返回類型。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下圖還顯示了模型之間的關係,包括它們的多重性。</font><font>多重性是圖中顯示可能存在於關係中的每個模型的數量(最大值和最小值)的數字。</font><font>例如,框之間的連接線,顯示書本</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Book</code><font><font>和種類</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Genre</code><font><font>是相關的。</font><font>靠近書本</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Book</code><font><font>模型的數字,表明一本書必須有零個或多個種類(您想要多少都可以),而種類</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Genre</code><font><font>旁邊一行的數字,表明它可以有零個或多個相關書籍。</font></font></p>
+
+<div class="note">
+<p><strong>注意</strong>: <font><font>正如我們在下面的</font></font><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Mongoose入門</font></font></strong><font><font>中所討論的那樣,通常只需要在一個模型中定義文檔/模型之間關係的字段(通過在另一個模型中搜索相關的</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>_id</code><font><font>仍然可以找到反向關係)。</font><font>下面我們選擇在書本綱要(Book schema)中定義Book/Genre和Book/Author之間的關係,以及書本實例綱要(BookInstance Schema)中Book/BookInstance之間的關係。</font><font>這種選擇有點武斷—我們同樣可以在其他綱要中擁有該字段。</font></font></p>
+</div>
+
+<p><img alt="Mongoose Library Model with correct cardinality" src="https://mdn.mozillademos.org/files/15645/Library%20Website%20-%20Mongoose_Express.png" style="height: 620px; width: 737px;"></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>:下一節提供了一個基本的入門知識,解釋如何定義和使用模型。</font><font>在您閱讀它時,請想想我們將如何構建上圖中的每個模型。</font></font></p>
+</div>
+
+<h2 id="Mongoose入門"><font><font>Mongoose入門</font></font></h2>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>本節概述如何將Mongoose 連接到MongoDB 數據庫,如何定義模型綱要和模型,以及如何進行基本查詢。</span></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>本入門受到npm上的</font></font><a class="external external-icon" href="https://www.npmjs.com/package/mongoose" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>Mongoose快速入門</font></font></a><font><font>和</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/guide.html" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>Mongoose官方文檔</font></font></a><font><font>的“深度影響”。</font></font></p>
+</div>
+
+<h3 id="安裝Mongoose和MongoDB"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>安裝Mongoose和MongoDB</font></font></span></h3>
+
+<p><font><font>Mongoose像任何其他依賴項一樣,安裝在您的項目(</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>package.json</font></font></strong><font><font>)中—使用NPM。</font><font>要安裝它,請在項目文件夾中,使用以下命令:</font></font></p>
+
+<pre class="brush: bash notranslate"><code>npm install mongoose</code>
+</pre>
+
+<p><font><font>安裝Mongoose會添加所有依賴項,包括MongoDB數據庫驅動程序,但它不會安裝MongoDB 。</font><font>如果你想安裝一個MongoDB服務器,那麼你可以</font></font><a class="external external-icon" href="https://www.mongodb.com/download-center" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>從這裡下載</font></font></a><font><font>各種操作系統的安裝程序,並在本地安裝。</font><font>您還可以使用基於雲端的MongoDB實例。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>對於本教程,我們將使用基於mLab雲的數據庫,作為服務</font></font><a class="external external-icon" href="https://mlab.com/plans/pricing/" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>沙箱層</font></font></a><font><font>來提供數據庫。</font><font>這適用於開發,也對於本教程很有意義,因為它使“安裝”與操作系統無關(數據庫即服務,也是您可能會用於生產環境數據庫的一種方法)。</font></font></p>
+</div>
+
+<h3 id="連接到MongoDB"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>連接到MongoDB</font></font></span></h3>
+
+<p><font><font>Mongoose需要連接到MongoDB數據庫。</font><font>您可以</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>require()</code><font><font>並使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>mongoose.connect()</code><font><font>,以連接到本地託管的數據庫,如下所示。</font></font></p>
+
+<pre class="brush: js notranslate">//Import the mongoose module
+var mongoose = require('mongoose');
+
+//Set up default mongoose connection
+var mongoDB = 'mongodb://127.0.0.1/my_database';
+mongoose.connect(mongoDB);
+// Get Mongoose to use the global promise library
+mongoose.Promise = global.Promise;
+//Get the default connection
+var db = mongoose.connection;
+
+//Bind connection to error event (to get notification of connection errors)
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre>
+
+<p><font><font>您可以使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>mongoose.connection</code><font><font>獲取默認的</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Connection</code><font><font>對象。</font><font>一旦連接,在</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Connection</code><font><font>實例上,將觸發打開事件。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>提示:</font></font></strong><font><font>如果需要創建其他連接,可以使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>mongoose.createConnection()</code><font><font>。</font><font>這與</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>connect()</code><font><font>採用相同形式的數據庫URI(包含主機,數據庫,端口,選項等),並返回</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Connection</code><font><font>對象。</font></font></p>
+</div>
+
+<h3 id="定義並創建模型"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>定義並創建模型</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>模型使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Schema</code><font><font>接口進行定義。</font><font>Schema允許您定義存儲在每個文檔中的字段,及其驗證要求和默認值。</font><font>此外,您可以定義靜態和實例助手方法,以更輕鬆地處理數據類型,以及可以像其他任何字段一樣使用的虛擬屬性,但實際上並不存儲在數據庫中(我們稍後將討論)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>然後,綱要Schemas被</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>mongoose.model()</code><font><font>方法“編譯”為模型。</font><font>擁有模型後,您可以使用它來查找,創建,更新和刪除給定類型的對象。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>每個模型都映射到MongoDB數據庫中的文檔集合。</font><font>這些文檔將包含模型綱要</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Schema</code><font><font>中定義的字段/綱要型態。</font></font></p>
+</div>
+
+<h4 id="定義綱要Schemas" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>定義綱要Schemas</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面的代碼片段,顯示了您可以如何定義一個簡單的綱要。</font><font>首先</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>require()</code><font><font>mongoose,然後使用Schema構造函數,創建一個新的Schema實例,在構造函數的對象參數中,定義其中的各個字段。</font></font></p>
+
+<pre class="brush: js notranslate">//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+ a_string: String,
+ a_date: Date
+});
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在上面的例子中,我們只有兩個字段,一個字符串和一個日期。</font><font>在接下來的部分中,我們將展示一些其他的字段類型,驗證和其他方法。</font></font></p>
+
+<h4 id="創建模型" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>創建模型</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>mongoose.model()</code><font><font>方法從綱要創建模型:</font></font></p>
+
+<pre class="brush: js notranslate">// Define schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+ a_string: String,
+  a_date: Date
+});
+
+<strong>// Compile model from schema
+var SomeModel = mongoose.model('SomeModel', SomeModelSchema );</strong></pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>第一個參數,是將為模型創建的集合的單數名稱(Mongoose將為上面的SomeModel模型,創建數據庫集合),第二個參數,是您要在創建模型時使用的綱要Shema。</span></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>定義模型類後,可以使用它們來創建,更新或刪除記錄,並運行查詢,以獲取記錄的所有記錄,或特定子集。</font><font>我們將在以下“使用模型”部分,向您展示如何執行上述操作,以及當創建視圖時,如何執行此操作。</font></font></p>
+</div>
+
+<h4 id="綱要型態(字段)" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>綱要型態(字段)</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>綱要schema可以有任意數量的字段 — 每個字段代表存儲在MongoDB 文檔中的字段。</font><font>如下的示例綱要,顯示許多常見字段類型及其聲明方式。</font></font></p>
+
+<pre class="brush: js notranslate">var schema = new Schema(
+{
+ name: <strong>String</strong>,
+ binary: <strong>Buffer</strong>,
+ living: <strong>Boolean</strong>,
+ updated: { type: <strong>Date</strong>, default: Date.now },
+ age: { type: <strong>Number</strong>, min: 18, max: 65, required: true },
+ mixed: <strong>Schema.Types.Mixed</strong>,
+ _someId: <strong>Schema.Types.ObjectId</strong>,
+ array: <strong>[]</strong>,
+ ofString: [<strong>String</strong>], // You can also have an array of each of the other types too.
+ nested: { stuff: { type: <strong>String</strong>, lowercase: true, trim: true } }
+})</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>大多數綱要型態</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/schematypes.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>SchemaTypes</font></font></a><font><font>(“type:”之後或字段名稱之後的描述符)都是自解釋的。</font><font>例外情況是:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>ObjectId</code><font><font>:表示數據庫中模型的特定實例。</font><font>例如,一本書可能會使用它來表示其作者對象。</font><font>這實際上將包含指定對象的唯一ID (<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>_id</code><font><font>) 。</font><font>我們可以使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>populate()</code><font><font>方法,在需要時提取相關訊息。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="http://mongoosejs.com/docs/schematypes.html#mixed" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Mixed</font></font></a><font><font><span> </span>:任意綱要型態。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font face="Consolas, Liberation Mono, Courier, monospace"><font><font>[]</font></font></font><font><font><span> </span>:一個數組的項目。</font><font>您可以在這些模型上執行JavaScript數組操作(push,pop,unshift等)。</font><font>上面的例子,顯示了一個沒有指定類型的對像數組,和一個String對像數組,但是你可以有任何類型的對像數組。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該代碼還顯示了聲明一個字段的兩種方式:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>字段名稱和類型作為鍵值對(即是,像上面的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>name</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>binary<span> </span></code><font><font>and<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>living</code><font><font>)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>字段名稱後跟一個定義類型</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>type</code><font><font>的對象,以及該字段的任何其他選項。</font><font>選項包括如下內容:</font></font>
+ <ul style="font-style: normal !important; margin: 0px; padding: 6px 0px 0px 40px; border: 0px; max-width: 42rem;">
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>默認值。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>內置驗證器(例如最大/最小值)和自定義驗證功能。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>該字段是否為必要</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>是否應將字符串</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>String</code><font><font>字段自動設置為小寫,大寫或修剪(例如</font><font>)</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>{ type:<strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;">String</strong>, lowercase: true, trim: true }</code></li>
+ </ul>
+ </li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>有關選項的更多訊息,請參閱</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/schematypes.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>SchemaTypes</font></font></a><font><font>(Mongoose docs)。</font></font></p>
+
+<h4 id="驗證" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>驗證</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>Mongoose 提供內置和自定義驗證器,以及同步和異步驗證器。</font><font>它允許您在所有情況下,指定可接受的範圍或值,以及驗證失敗的錯誤消息。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>內置的驗證器包括:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>所有</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/schematypes.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>SchemaTypes</font></font></a><font><font>都具有內置的</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schematype_SchemaType-required" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>必需</font></font></a><font><font>驗證器。</font><font>這用於指定,是否必須提供該字段才能保存文檔。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema-number-js" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Numbers </font></font></a><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema-number-js" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>數字</font></font></a><font><font>有最小</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-min" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>min</font></font></a><font><font>和最大</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-max" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>max</font></font></a><font><font>驗證器。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema-string-js" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Strings</font></font></a><font><font>字符串有:</font></font>
+ <ul style="font-style: normal !important; margin: 0px; padding: 6px 0px 0px 40px; border: 0px; max-width: 42rem;">
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-enum" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>enum</font></font></a><font><font>枚舉:指定該字段的允許值集合。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-match" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>match</font></font></a><font><font><span> </span>:指定字符串必須匹配的正則表達式。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>字符串的最大長度</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-maxlength" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>maxlength</font></font></a><font><font>和最小長度</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-minlength" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>minlength</font></font></a></li>
+ </ul>
+ </li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面的示例(從Mongoose文檔稍微修改)顯示瞭如何指定一些驗證器類型和錯誤消息:</font></font></p>
+
+<pre class="brush: js notranslate"><code>
+ var breakfastSchema = new Schema({
+ eggs: {
+ type: Number,
+ min: [6, 'Too few eggs'],
+ max: 12
+ required: [true, 'Why no eggs?']
+ },
+ drink: {
+ type: String,
+ enum: ['Coffee', 'Tea', 'Water',]
+ }
+ });
+</code></pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>有關字段驗證的完整訊息,請參閱</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/validation.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>驗證</font></font></a><font><font>(Mongoose docs)。</font></font></p>
+
+<h4 id="虛擬屬性" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>虛擬屬性</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>虛擬屬性是您可以獲取和設置的文檔屬性,但不會持久保存到MongoDB。</font><font>getter 對格式化或組合字段非常有用,而setter 可用於將單個值分解為多個值,以進行存儲。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>文檔中的示例,從名字和姓氏字段構造(並解構)一個全名虛擬屬性,這比每次在模板中使用全名更簡單,更清晰。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>我們將使用庫中的虛擬屬性,來為每個使用路徑和記錄的<code>_id</code>值的模型記錄,定義唯一的URL。</font></font></p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>欲了解更多訊息,請參閱</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/guide.html#virtuals" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>虛擬</font></font></a><font><font>(Mongoose文檔)。</font></font></p>
+
+<h4 id="方法和查詢幫助" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>方法和查詢幫助</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>綱要schema也可以有</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/guide.html#methods" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>實例方法</font></font></a><font><font>,</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/guide.html#statics" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>靜態方法</font></font></a><font><font>和</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/guide.html#query-helpers" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>查詢助手</font></font></a><font><font>。</font><font>實例和靜態方法很相似,但有明顯的區別,即實例方法與特定記錄相關聯,並且可以訪問當前對象。</font><font>查詢助手允許您擴展mongoose的</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/queries.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>鍊式查詢構建器API</font></font></a><font><font>(例如,除了</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>find()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>findOne()</code><font><font>和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>findById()</code><font><font>方法外,還允許您添加一個“byName”查詢。</font></font></p>
+
+<h3 id="使用模型"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>使用模型</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>一旦創建了綱要,就可以使用它來創建模型。</font><font>該模型代表數據庫中可以搜索的文檔集合,而模型的實例代表您可以保存和檢索的單個文檔。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們在下面簡要介紹一下。有關更多訊息,請參閱:</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/models.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>模型</font></font></a><font><font>(Mongoose docs)。</font></font></p>
+
+<h4 id="創建和修改文檔" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>創建和修改文檔</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>要創建記錄,您可以定義模型的實例,然後調用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>save()</code><font><font>。</font><font>下面的例子假設,SomeModel是我們從綱要創建的模型(帶有單一字段“name” )。</font></font></p>
+
+<pre class="brush: js notranslate"><code>// Create an instance of model SomeModel
+var awesome_instance = new </code>SomeModel<code>({ name: 'awesome' });
+
+// Save the new model instance, passing a callback
+awesome_instance.save(function (err) {
+ if (err) return handleError(err);
+ // saved!
+});
+</code></pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>創建記錄(以及更新,刪除和查詢)是異步操作— 您提供在操作完成時調用的回調。</font><font>API使用錯誤優先參數約定,因此回調的第一個參數將始終為錯誤值(或null)。</font><font>如果API返回一些結果,則將作為第二個參數提供。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>您還可以使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>create()</code><font><font>,同時定義模型實例,並保存模型實例。</font><font>回調將為第一個參數返回錯誤,為第二個參數返回新創建的模型實例。</font></font></p>
+
+<pre class="brush: js notranslate">SomeModel<code>.create({ name: 'also_awesome' }, function (err, awesome_instance) {
+ if (err) return handleError(err);
+ // saved!
+});</code></pre>
+
+<p><font><font>每個模型都有一個關聯的連接(當您使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>mongoose.model()</code><font><font>時,這將成為默認連接)。</font><font>您創建一個新連接並調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>.model()</code><font><font>,以在另一個數據庫上創建文檔。</font></font></p>
+
+<p><font><font>您可以使用點語法訪問此新記錄中的字段,並更改值。</font><font>您必須調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>save()</code><font><font>或</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>update()</code><font><font>,將修改的值存回數據庫。</font></font></p>
+
+<pre class="brush: js notranslate">// Access model field values using dot notation
+console.log(<code>awesome_instance.name</code>); //should log '<code>also_awesome</code>'
+
+// Change record by modifying the fields, then calling save().
+<code>awesome_instance</code>.name="New cool name";
+<code>awesome_instance.save(function (err) {
+  if (err) return handleError(err); // saved!
+  });</code>
+</pre>
+
+<h4 id="尋找紀錄" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>尋找紀錄</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>可以使用查詢方法搜索記錄,將查詢條件指定為JSON 文檔。</font><font>下面的代碼片段,顯示瞭如何在數據庫中,找到所有參加網球運動的運動員,只返回運動員姓名和年齡的字段。</font><font>這裡我們只指定一個匹配的字段(運動 sport),但您可以添加更多條件,指定正則表達式標準,或完全刪除條件以返回所有運動員。</font></font></p>
+
+<pre class="brush: js notranslate"><code>var Athlete = mongoose.model('Athlete', yourSchema);
+
+// find all athletes who play tennis, selecting the 'name' and 'age' fields
+Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) {
+ if (err) return handleError(err);
+ // 'athletes' contains the list of athletes that match the criteria.
+})</code></pre>
+
+<p><font>如果您指定回調,如上所示,查詢將立即執行。</font><font>搜索完成後將調用回調。</font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font><span> </span>Mongoose中的所有回調,都使用此回調模式</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>callback(error, result)</code><font><font>。</font><font>如果執行查詢時發生錯誤,錯誤參數</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>error</code><font><font>將包含錯誤文檔,並且結果</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>result</code><font><font>將為null。</font><font>如果查詢成功,則</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>error</code><font><font>參數將為null,並且結果</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>result<span> </span></code><font><font>將被填充到查詢結果。</font></font></p>
+</div>
+
+<p><font><font>如果您未指定回調,則API將返回</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query-js" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>Query</font></font></a><font><font>類型的變量。</font><font>您可以使用此查詢對象來構建查詢,然後稍後使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>exec()</code><font><font>方法執行(使用回調)。</font></font></p>
+
+<pre class="brush: js notranslate"><code>// find all athletes that play tennis
+var query = Athlete.find({ 'sport': 'Tennis' });
+
+// selecting the 'name' and 'age' fields
+query.select('name age');
+
+// limit our results to 5 items
+query.limit(5);
+
+// sort by age
+query.sort({ age: -1 });
+
+// execute the query at a later time
+query.exec(function (err, athletes) {
+ if (err) return handleError(err);
+ // athletes contains an ordered list of 5 athletes who play Tennis
+})</code></pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>上面我們在</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>find()</code><font><font>方法中,定義了查詢條件。</font><font>我們也可以使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>where()</code><font><font>函數來執行此操作,並且我們可以使用點運算符( . )將查詢的所有部分鏈接在一起,而不是分別添加它們。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面的代碼片段,與我們上面的查詢相同,並有年齡的附加條件。</font></font></p>
+
+<pre class="notranslate"><code>Athlete.
+ find().
+ where('sport').equals('Tennis').
+ where('age').gt(17).lt(50). //Additional where query
+ limit(5).
+ sort({ age: -1 }).
+ select('name age').
+ exec(callback); // where callback is the name of our callback function.</code></pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query_Query-find" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>find()</font></font></a><font><font><span> </span> 方法獲取所有匹配的記錄,但通常你只想獲得一個匹配。</font><font>以下方法可以查詢單個記錄:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.findById" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findById()</a></code><font><font>:用指定的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>id<span> </span></code><font><font>查找文檔(每個文檔都有一個唯一的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>id</code><font><font>)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query_Query-findOne" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findOne()</a></code><font><font>: 查找與指定條件匹配的單個文檔。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findByIdAndRemove()</a></code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findByIdAndUpdate()</a></code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove" rel="noopener" style="font-style: normal !important; text-decoration: underline; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findOneAndRemove()</a></code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">findOneAndUpdate()</a></code><font><font>:通過</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>id<span> </span></code><font><font>或條件查找單個文檔,並更新或刪除它。</font><font>這些是用於更新和刪除記錄的有用便利功能。</font></font></li>
+</ul>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>還有一個</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.count" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">count()</a></code><font><font>方法,您可以使用它來獲取與條件匹配的項目數。</font><font>如果您想要在不實際提取記錄的情況下執行計數,這非常有用。</font></font></p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>查詢可以做更多的事情。有關更多訊息,請參閱:</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/queries.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>查詢</font></font></a><font><font>(Mongoose文檔)。</font></font></p>
+
+<h4 id="運用相關文檔—_population方法" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>運用相關文檔— population方法</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>您可以使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>ObjectId</code><font><font>綱要字段,從一個文檔/模型實例,創建一對一引用,或者使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>ObjectIds</code><font><font>數組,從一個文檔創建一對多的引用。</font><font>該字段存儲相關模型的ID。</font><font>如果需要關聯文檔的實際內容,可以在查詢中使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#query_Query-populate" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">populate()</a></code><font><font>方法,將id替換為實際數據。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>例如,以下綱要定義作者和故事。</font><font>每個作者可以有多個故事,我們將其表示為一個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>ObjectId</code><font><font>數組。</font><font>每個故事可以有一個作者。</font><font>綱要從“ref”(以粗體突出顯示)得知,可以分配給該字段的模型。</font></font></p>
+
+<pre class="brush: js notranslate"><code>var mongoose = require('mongoose')
+ , Schema = mongoose.Schema
+
+var authorSchema = Schema({
+ name : String,
+ stories : [{ type: Schema.Types.ObjectId, <strong>ref</strong>: 'Story' }]
+});
+
+var storySchema = Schema({
+ author : { type: Schema.Types.ObjectId, <strong>ref</strong>: 'Author' },
+ title : String
+});
+
+var Story = mongoose.model('Story', storySchema);
+var Author = mongoose.model('Author', authorSchema);</code></pre>
+
+<p><font><font>我們可以通過分配</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>_id</code><font><font>值,來保存對相關文檔的引用。</font><font>下面我們創建一個作者,然後創建一個故事,並將作者ID分配給我們的故事作者字段。</font></font></p>
+
+<pre class="brush: js notranslate"><code>var bob = new Author({ name: 'Bob Smith' });
+
+bob.save(function (err) {
+ if (err) return handleError(err);
+
+ //Bob now exists, so lets create a story
+ var story = new Story({
+ title: "Bob goes sledding",
+ author: bob._id // assign the _id from the our author Bob. This ID is created by default!
+ });
+
+ story.save(function (err) {
+ if (err) return handleError(err);
+ // Bob now has his story
+ });
+});</code></pre>
+
+<p><font><font>我們的故事文檔,現在有作者文檔ID引用的作者。為了在我們的故事結果中,獲取作者訊息,我們使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>populate()</code><font><font>,如下所示。</font></font></p>
+
+<pre class="brush: js notranslate"><code>Story
+.findOne({ title: 'Bob goes sledding' })
+.populate('author') //This populates the author id with actual author information!
+.exec(function (err, story) {
+ if (err) return handleError(err);
+ console.log('The author is %s', story.author.name);
+ // prints "The author is Bob Smith"
+});</code></pre>
+
+<div class="note">
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><strong style="border: 0px; font-style: normal; font-weight: 700; margin: 0px; padding: 0px;"><font><font>注意:</font></font></strong><font><font>敏銳的讀者會注意到,我們在故事中添加了作者,但我們沒有做任何事情,來將我們的故事添加到作者的故事</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>stories</code><font><font>數組中。</font><font>那麼我們怎樣才能得到特定作者的所有故事?</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><font><font>一種方法,是將作者添加到故事數組中,但這會導致我們需要在兩個地方,維護與作者和故事有關的訊息。更好的方法是獲取作者的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>_id</code><font><font>,然後使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>find()</code><font><font>,在所有故事的作者字段中搜索此內容。</font></font></p>
+
+<pre class="brush: js notranslate"><code>Story
+.find({ author : bob._id })
+.exec(function (err, stories) {
+ if (err) return handleError(err);
+ // returns all stories that have Bob's id as their author.
+});</code>
+</pre>
+</div>
+
+<p><font><font>這幾乎是您在本教程中,使用相關項目時,需要了解的所有內容。有關更多詳細訊息,請參閱</font></font><a class="external external-icon" href="http://mongoosejs.com/docs/populate.html" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>Population</font></font></a><font><font>(Mongoose docs)。</font></font></p>
+
+<h3 id="一個檔案對應一個綱要模型"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>一個檔案對應一個綱要/模型</font></font></span></h3>
+
+<p><font>雖然您可以使用任何喜歡的文件結構創建綱要和模型,但我們強烈建議在每個模型模塊(文件)中,定義每個模型綱要,導出方法以創建模型。</font><font>如下所示:</font></p>
+
+<pre class="brush: js notranslate"><code>// File: ./models/somemodel.js
+
+//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+ a_string : String,
+ a_date : Date,
+});
+
+<strong>//Export function to create "SomeModel" model class
+module.exports = mongoose.model('SomeModel', SomeModelSchema );</strong></code></pre>
+
+<p><font>然後,您可以在其他文件中,立即要求並使用該模型。</font><font>下面我們展示如何使用它,來獲取模型的所有實例。</font></p>
+
+<pre class="brush: js notranslate"><code>//Create a SomeModel model just by requiring the module
+var SomeModel = require('../models/somemodel')
+
+// Use the SomeModel object (model) to find all SomeModel records
+SomeModel.find(callback_function);</code></pre>
+
+<h2 id="架設MongoDB數據庫"><font><font>架設MongoDB數據庫</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>現在我們了解了Mongoose能做什麼,以及我們想如何設計我們的模型,現在該開始在LocalLibrary網站上工作了。我們想要做的第一件事,就是設置一個MongoDb數據庫,我們可以使用它來儲存我們的圖書館數據。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>本教程,我們將使用</font></font><a class="external external-icon" href="https://mlab.com/welcome/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>mLab</font></font></a><font><font>免費的雲託管的“<span> </span></font></font><a class="external external-icon" href="https://mlab.com/plans/pricing/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>沙盒</font></font></a><font><font><span> </span>”數據庫。</font><font>這個數據庫層不適合生產環境的網站,因為它沒有冗餘設計,但它對於開發和原型設計來說非常有用。我們在這裡使用它,是因為它免費且易於設置,並且因為作為數據庫服務供應商來說,mLab是流行的數據庫選擇之一,您可能會合理選擇您的生產環境數據庫(撰寫本文時,其他流行的選擇包括</font></font><a class="external external-icon" href="https://www.compose.com/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Compose</font></font></a><font><font>、</font></font><a class="external external-icon" href="https://scalegrid.io/pricing.html" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>ScaleGrid</font></font></a><font><font>和</font></font><a class="external external-icon" href="https://www.mongodb.com/cloud/atlas" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>MongoDB Atlas</font></font></a><font><font>)。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>如果您願意,可以下載並安裝</font></font><a class="external external-icon" href="https://www.mongodb.com/download-center" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>與系統相對應的二進製文件</font></font></a><font><font>,在本地設置MongoDb數據庫。</font><font>除了您在連接時指定的數據庫URL之外,本文中的其餘指令將很類似。</font></font></p>
+</div>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>您首先需要</font></font><a class="external external-icon" href="https://mlab.com/signup/" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>使用mLab創建一個賬戶</font></font></a><font><font>(這是免費的,只需要輸入基本聯繫訊息,並確認其服務條款)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>登錄後,您將進入</font></font><font><font><a class="external external-icon" href="https://mlab.com/home" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">mLab主</a>畫面</font></font><font><font>:</font></font></p>
+
+<ol>
+ <li><font><font>單擊</font></font><em><font><font>MongoDB Deployments</font></font></em><font><font>部分中的</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Create New。</font></font></strong><img alt="" src="https://mdn.mozillademos.org/files/14446/mLabCreateNewDeployment.png" style="height: 415px; width: 1000px;"></li>
+ <li><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>這將打開“雲提供商”Cloud Provider 選擇畫面。</span><br>
+ <img alt="MLab - screen for new deployment" src="https://mdn.mozillademos.org/files/15661/mLab_new_deployment_form_v2.png" style="height: 931px; width: 1297px;"><br>
+
+ <ul>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>從“計劃類型”Plan Type 部分中,選擇“SANDBOX(免費)”計劃。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>從“雲提供商”<span> </span></font></font><em><font><font>Cloud Provider</font></font></em><font><font>部分,選擇任意提供商。</font><font>不同的提供商,提供不同的地區(顯示在選定的計劃類型下面)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>單擊“繼續”<span> </span></font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Continue</font></font></strong><font><font>按鈕。</font></font></li>
+ </ul>
+ </li>
+ <li><font><font>這將打開“選擇區域”<span> </span></font></font><em><font><font>Select Region </font></font></em><font><font>畫面。</font></font>
+ <p><img alt="Select new region screen" src="https://mdn.mozillademos.org/files/15662/mLab_new_deployment_select_region_v2.png" style="height: 570px; width: 1293px;"></p>
+
+ <ul>
+ <li>
+ <p><font><font>選擇離您最近的地區,然後選擇繼續</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Continue</font></font></strong><font><font><span> </span>.</font></font></p>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>這將打開 Final Details </span><font><font>畫面</font></font><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>。</span><br>
+ <img alt="New deployment database name" src="https://mdn.mozillademos.org/files/15663/mLab_new_deployment_final_details.png" style="height: 569px; width: 1293px;"></p>
+
+ <ul>
+ <li>
+ <p><font><font>輸入新數據庫的名稱</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>local_library</code><font><font>,然後選擇繼續</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Continue</font></font></strong><font><font>。</font></font></p>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>這將打開訂單確認畫面。</span><br>
+ <img alt="Order confirmation screen" src="https://mdn.mozillademos.org/files/15664/mLab_new_deployment_order_confirmation.png" style="height: 687px; width: 1290px;"></p>
+
+ <ul>
+ <li>
+ <p><font><font>單擊“提交訂單”<span> </span></font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Submit Order</font></font></strong><font><font>以創建數據庫。</font></font></p>
+ </li>
+ </ul>
+ </li>
+ <li>
+ <p><font>您將返回到主</font><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>畫面</span><font>。單擊剛剛創建的新數據庫,以打開其詳細<font>訊息</font></font><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>畫面</span><font>。正如你所看到的,數據庫沒有集合(數據)。</font><br>
+ <img alt="mLab - Database details screen" src="https://mdn.mozillademos.org/files/15665/mLab_new_deployment_database_details.png" style="height: 700px; width: 1398px;"><br>
+  <font>您需要用來訪問數據庫的URL,顯示在上面的表單中(如上圖所示)。</font><font>為了使用它,您需要創建一個可以在URL中指定的數據庫用戶。</font></p>
+ </li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>單擊用戶</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Users</font></font></strong><font><font>選項卡,並選擇添加數據庫用戶按鈕</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Add database user</font></font></strong><font><font>。</font></font></li>
+ <li><font><font>輸入用戶名和密碼(兩次),然後按創建</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Create</font></font></strong><font><font>。</font><font>不要選擇只讀</font></font><em><font><font>read-only</font></font></em><font><font>。</font></font><br>
+ <img alt="" src="https://mdn.mozillademos.org/files/14454/mLab_database_users.png" style="height: 204px; width: 600px;"></li>
+</ol>
+
+<p><font><font>您現在已經創建了數據庫,並且有一個可以用來訪問它的URL(帶有用戶名和密碼)。</font><font>這看起來像是這樣的:</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library</code><font><font>.</font></font></p>
+
+<h2 id="安裝_Mongoose" style='font-style: normal; line-height: 1.2; margin: 103px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 2.5rem; position: relative; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>安裝 Mongoose</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開命令提示符,並到您創建</font></font><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Server-side/Express_Nodejs/skeleton_website" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>本地圖書館骨架網站</font></font></a><font><font>的目錄。</font><font>輸入以下命令,安裝Mongoose(及其依賴項),並將其添加到您的</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>package.json</font></font></strong><font><font>文件中,除非您在閱讀上述</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>Mongoose入門</font></font></strong><font><font>時,已經這樣做了。</font></font></p>
+
+<pre class="brush: bash notranslate">npm install mongoose
+</pre>
+
+<h2 id="連接到_MongoDB" style='font-style: normal; line-height: 1.2; margin: 103px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 2.5rem; position: relative; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>連接到 MongoDB</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/app.js</font></font></strong><font><font>(位於項目的根目錄),並在宣告Express應用程序對象的位置(在</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>var app = express();</code><font><font>之後)複製以下文本。</font><font>將數據庫url字符串('insert_your_database_url_here')替換為表示您自己的數據庫的位置URL(即是使用</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>來自上面mLab</font></font></strong><font><font>的訊息)。</font></font></p>
+
+<pre class="brush: js notranslate">//Set up mongoose connection
+var mongoose = require('mongoose');
+var mongoDB = '<em>insert_your_database_url_here</em>';
+mongoose.connect(mongoDB);
+mongoose.Promise = global.Promise;
+var db = mongoose.connection;
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre>
+
+<p><font><font>正如上面的</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Mongoose入門</font></font></strong><font><font>中所討論的,此代碼創建了與數據庫的默認連接,並綁定到錯誤事件(以便將錯誤打印到控制台)。</font></font></p>
+
+<h2 id="定義本地圖書館綱要" style='font-style: normal; line-height: 1.2; margin: 103px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 2.5rem; position: relative; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>定義本地圖書館綱要</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>如上所述,我們將為每個模型定義一個單獨的模塊。</font><font>首先在項目根目錄(</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/models</font></font></strong><font><font>)中,為我們的模型創建一個文件夾,然後為每個模型創建單獨的文件:</font></font></p>
+
+<pre class="notranslate">/express-locallibrary-tutorial //the project root
+ <strong>/models</strong>
+ <strong>author.js</strong>
+ <strong>book.js</strong>
+ <strong>bookinstance.js</strong>
+ <strong>genre.js</strong>
+</pre>
+
+<h3 id="作者模型"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>作者模型</font></font></span></h3>
+
+<p><font><font>複製下面顯示的</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Author</code><font><font>作者綱要代碼,並將其粘貼到</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>./models/author.js</font></font></strong><font><font>文件中。</font><font>該綱要定義了一個作者,具有</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>String</code><font><font>SchemaTypes的第一個名稱和家族名稱,這是必需的,最多有100個字符,</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Date</code><font><font>字段為出生和死亡日期。</font></font></p>
+
+<pre class="brush: js notranslate">var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var AuthorSchema = new Schema(
+ {
+ first_name: {type: String, required: true, max: 100},
+ family_name: {type: String, required: true, max: 100},
+ date_of_birth: {type: Date},
+ date_of_death: {type: Date},
+ }
+);
+
+<strong>// Virtual for author's full name
+AuthorSchema
+.virtual('name')
+.get(function () {
+ return this.family_name + ', ' + this.first_name;
+});</strong>
+
+// Virtual for author's URL
+AuthorSchema
+.virtual('url')
+.get(function () {
+ return '/catalog/author/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Author', AuthorSchema);
+
+</pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>我們還為AuthorSchema,聲明了一個名為“url”的虛擬屬性,它返回獲取模型的特定實例所需的絕對URL — 每當我們需要獲取指向特定作者的鏈接時,我們將在模板中使用該屬性。</span></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>在綱要中聲明我們的URL是虛擬的,這是一個好主意,因為一個項目的URL只需要在一個地方更改。</font><font>此時,使用此URL的鏈接將不起作用,因為我們還沒有任何路由,可以處理個別模型實例的代碼。</font><font>我們將在後面的文章中介紹這些內容!</font></font></p>
+</div>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>在模塊的最後,我們導出了模型。</span></p>
+
+<h3 class="highlight-spanned" id="書本模型" style='font-style: normal; line-height: 1.25; margin: 20px 0px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.5rem; background-color: rgb(255, 255, 255); color: rgb(51, 51, 51); font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>書本模型</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>複製下面顯示的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Book</code><font><font>綱要代碼,並將其粘貼到</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>./models/book.js</font></font></strong><font><font>文件中。</font><font>其中大部分與作者模型相似—我們已經聲明了一個具有多個字符串字段的綱要,以及一個虛擬屬性,用於獲取特定書籍記錄的URL,並且我們已經導出了模型。</font></font></p>
+
+<pre class="brush: js notranslate">var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookSchema = new Schema(
+ {
+ title: {type: String, required: true},
+ <strong> author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},</strong>
+ summary: {type: String, required: true},
+ isbn: {type: String, required: true},
+ <strong> genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]</strong>
+ }
+);
+
+// Virtual for book's URL
+BookSchema
+.virtual('url')
+.get(function () {
+ return '/catalog/book/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Book', BookSchema);
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>這裡的主要區別,是我們已經創建了兩個對其他模型的引用:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>作者是對單個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Author</code><font><font>作者模型對象的引用,並且是必要的。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>種類是對</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Genre</code><font><font>種類模型對像數組的引用。</font><font>我們還沒有宣告這個對象!</font></font></li>
+</ul>
+
+<h3 id="書本實例模型"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>書本實例模型</font></font></span></h3>
+
+<p><font><font>最後,複製下面顯示的</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>BookInstance</code><font><font>綱要代碼,並將其粘貼到</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>./models/bookinstance.js</font></font></strong><font><font>文件中。</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>BookInstance</code><font><font>表示某人可能藉閱的書籍的特定副本,並包含有關該副本是否可用,或預期返回日期的訊息,“印記”或版本詳細訊息。</font></font></p>
+
+<pre class="brush: js notranslate">var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookInstanceSchema = new Schema(
+ {
+ book: { type: Schema.Types.ObjectId, ref: 'Book', required: true }, //reference to the associated book
+ imprint: {type: String, required: true},
+ status: {type: String, required: true, <strong>enum: ['Available', 'Maintenance', 'Loaned', 'Reserved']</strong>, <strong>default: 'Maintenance'</strong>},
+ due_back: {type: Date, <strong>default: Date.now</strong>}
+ }
+);
+
+// Virtual for bookinstance's URL
+BookInstanceSchema
+.virtual('url')
+.get(function () {
+ return '/catalog/bookinstance/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('BookInstance', BookInstanceSchema);</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們在這裡展示的新東西,是字段選項:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>枚舉</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>enum</code><font><font>:這允許我們設置字符串的允許值。</font><font>在這種情況下,我們用它來指定我們書籍的可用性狀態(使用枚舉,意味著我們可以防止錯誤拼寫和任意值,成為我們的狀態)</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>默認值</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>default</code><font><font>:我們使用默認值,將新創​​ 建的書本實例的默認狀態,設置為維護,並將默認的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>due_back</code><font><font>日期,設置為現在</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>now</code><font><font>(請注意在設置日期時,如何調用Date函數!)</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>其他所有內容,大夥應該在前面教程裡邊已經熟悉了。</font></font></p>
+
+<h3 id="種類模型-自我挑戰!"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>種類模型-自我挑戰!</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開你的</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>./models/genre.js</font></font></strong><font><font>文件,並創建一個存儲類型的綱要(書本的類別,例如它是小說還是非小說,浪漫史或軍事歷史等)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該定義將與其他模型非常相似:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>該模型應該有一個名為</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>name</code><font><font>的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>String</code><font><font>SchemaType ,來描述種類。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>這個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>name</code><font><font>字段應該是必要的,並且有3到​​100個字符。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>為類型的URL聲明虛擬,名為</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>url</code><font><font>。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>導出模型。</font></font></li>
+</ul>
+
+<h2 id="測試—創建一些項目"><font><font>測試—創建一些項目</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>就是這樣。</font><font>我們現在已經為該網站建立了所有模型!</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>為了測試這些模型(並創建一些示例書籍,和其他項目以便於我們在後面文章使用),現在我們將運行一個獨立的腳本來創建每種類型的項目:</font></font></p>
+
+<ol>
+ <li><font><font>在express-locallibrary-tutorial目錄下(與</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>package.json</code><font><font>處於同一級別),下載(或以其他方式創建)文件</font></font><a class="external external-icon" href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>populatedb.js</font></font></a><font><font>。</font></font>
+
+ <div class="note">
+ <p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>您不需要知道</font></font><a class="external external-icon" href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>populatedb.js</font></font></a><font><font>的工作原理;它只是將示例數據添加到數據庫中。</font></font></p>
+ </div>
+ </li>
+ <li><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>在項目根目錄中,輸入以下命令,以安裝腳本所需的異步模塊(我們將在後面的教程中討論這一點)</span>
+ <pre class="brush: bash notranslate">npm install async</pre>
+ </li>
+ <li><font><font>在命令提示符下,使用node運行此腳本,傳遞MongoDB數據庫的URL(與之前在</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>app.js</code><font><font>中替換insert_your_database_url_here佔位符的那個相同):</font></font>
+ <pre class="brush: bash notranslate">node populatedb &lt;your mongodb url&gt;​​​​</pre>
+ </li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>該腳本應一路運行至完成,並在終端中創建它們時顯示各項目。</font></font></li>
+</ol>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>提示:</font></font></strong><font><font>至</font></font><a class="external external-icon" href="https://mlab.com/home" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>mLab</font></font></a><font><font>上的數據庫。</font><font>您現在應該可以深入到書本籍,作者,種類和書本實例的各個集合中,並查看單個文檔。</font></font></p>
+</div>
+
+<h2 id="總結"><font><font>總結</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>本文中我們學到了一點數據庫和Node/Express的ORMs,更多的是關於如何定義Mongoose綱要與模型。</font><font>然後我們使用這些知識,為本地圖書館網站設計並實作出書本</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Book</code><font><font>,書本實例</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>BookInstance</code><font><font>,作者</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Author</code><font><font>和種類</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Genre</code><font><font>模型。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>最後,我們創建一些實例,以測試模型(使用獨立運作的命令稿)。</font><font>下一篇文章,我們將關注於如何創建一些網頁,以呈現這些物件。</font></font></p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li>
+ <li><a href="http://mongoosejs.com/">Mongoose website</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/guide.html">Mongoose Guide</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/validation.html">Validation</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/schematypes.html">Schema Types</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/models.html">Models</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/queries.html">Queries</a> (Mongoose docs)</li>
+ <li><a href="http://mongoosejs.com/docs/populate.html">Population</a> (Mongoose docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<h2 id="本教程連結"><font><font>本教程連結</font></font></h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/routes/index.html b/files/zh-tw/learn/server-side/express_nodejs/routes/index.html
new file mode 100644
index 0000000000..f4549ec598
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/routes/index.html
@@ -0,0 +1,646 @@
+---
+title: 'Express 教學 4: 路由與控制器'
+slug: Learn/Server-side/Express_Nodejs/routes
+translation_of: Learn/Server-side/Express_Nodejs/routes
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">在本教程中,我們將為最終在 本地圖書館 網站中需要的所有資源端點,搭配 "空殼" 處理函式來配置路由 (URL handling code) 。完成後,我們的路由處理源碼將會有模組化結構,在接下來的文章中,我們可以用真實的處理函式加以擴充。我們也會對如何使用Express 創建模組化路由,有更好的理解。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先備知識:</th>
+ <td>閱讀 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node 介紹</a>。 完成先前教學主題 (包含 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express 教學 3: 使用資料庫 (Mongoose)</a>).</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td><font>理解如何創建簡易路由配置。</font><font>我們所有的URL端點。</font></td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在</font></font><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Server-side/Express_Nodejs/mongoose" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>上一篇教程文章</font></font></a><font><font>中,我們定義了Mongoose模型,以與數據庫互動,並使用(獨立)腳本創建一些初始庫記錄。</font><font>現在我們可以編寫代碼,向用戶展示這些信息。</font><font>我們需要做的第一件事,是確定我們希望能夠在頁面中顯示哪些信息,然後定義適當的URL,以返回這些資源。</font><font>然後我們將需要創建路由(URL處理程序)和視圖(模板)來顯示這些頁面。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下圖是作為處理HTTP請求/響應時,需要實現的主要數據流和事項的提醒。</font><font>除了視圖和路線之外,圖表還顯示“控制器” — 實際處理請求的函數,那些與路由請求分開的代碼。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>由於我們已經創建了模型,我們需要創建的主要內容是:</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>“路由”將支持的請求(以及請求URL中編碼的任何信息)轉發到適當的控制器功能。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>控制器用於從模型中獲取請求的數據,創建一個顯示數據的HTML頁面,並將其返回給用戶,以在瀏覽器中查看。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>視圖(模板)則由控制器用來呈現數據。</font></font></li>
+</ul>
+
+<p> </p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14456/MVC%20Express.png" style="height: 460px; width: 800px;"></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>最終,我們可能會有頁面顯示書籍,流派,作者和書籍的列表和詳細信息,以及用於創建,更新和刪除記錄的頁面。</font><font>對一篇文章來說,這是很多的內容。</font><font>因此,本文的大部分內容,都將集中在設置我們的路由和控制器,以返回“虛擬”內容。</font><font>我們將在後續文章中,擴展控制器方法,以使用模型數據。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面的第一部分,提供了關於如何使用</font></font><a class="external external-icon" href="http://expressjs.com/en/4x/api.html#router" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;"><font><font>Express Router</font></font></a><font><font>中間件的簡要“入門”。</font><font>當我們設置LocalLibrary路由時,我們將在後面的章節中使用這些知識。</font></font></p>
+
+<h2 id="路由入門" style='font-style: normal; line-height: 1.2; margin: 103px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 2.5rem; position: relative; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由入門</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由是Express代碼的一部分,它將HTTP動詞(</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>GET</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>POST</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>PUT</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>DELETE</code><font><font>等),URL路徑/模式和被調用來處理該模式的函數,相關聯起來。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>有幾種方法可以創建路線。</font><font>本教程將使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><a class="external external-icon" href="http://expressjs.com/en/guide/routing.html#express-router" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">express.Router</a></code><font><font>中間件,因為它允許我們將站點的特定部分的路由處理程序組合在一起,並使用通用的路由前綴訪問它們。</font><font>我們會將所有與圖書館有關的路由,保存在“目錄”模塊中,如果我們添加路由來處理用戶帳戶或其他功能,我們可以將它們分開保存。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>我們在</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Creating_route_handlers" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 243, 212);'><font><font>Express簡介&gt;創建路由處理程序</font></font></a><font><font>中,簡要討論了Express應用程序路由。</font><font>除了為模塊化提供更好的支持之外(如下面第一小節所述),使用Router非常類似於直接在Express應用程序對像上定義路由。</font></font></p>
+</div>
+
+<p><font><font>本節的其餘部分,概述瞭如何使用路由器</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Router</code><font><font>來定義路由。</font></font></p>
+
+<h3 id="定義和使用單獨的路由模塊"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>定義和使用單獨的路由模塊</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面的代碼提供了一個具體示例,說明我們如何創建路由模塊,然後在Express應用程序中使用它。</font><font>首先,我們在一個名為</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>wiki.js</font></font></strong><font><font>的模塊中創建一個wiki的路由。</font><font>代碼首先導入Express應用程序對象,使用它獲取一個</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Router</code><font><font>對象,然後使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>get()</code><font><font>方法向其添加一對路由。</font><font>所有模塊的最後一個導出路由器</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Router</code><font><font>對象。</font></font></p>
+
+<pre class="brush: js"><code>// wiki.js - Wiki route module.
+
+var express = require('express');
+var router = express.Router();
+
+// Home page route.
+router.get('/', function (req, res) {
+ res.send('Wiki home page');
+})
+
+// About page route.
+router.get('/about', function (req, res) {
+ res.send('About this wiki');
+})
+
+module.exports = router;</code>
+
+</pre>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>上面我們直接在路由器函數中定義路由處理程序回調。</font><font>在LocalLibrary中,我們將在一個單獨的控制器模塊中,定義這些回調。</font></font></p>
+</div>
+
+<p><font><font>要在主應用程序文件中使用路由器模塊,我們首先</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>require()</code><font><font>路由模塊(</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>wiki.js</font></font></strong><font><font>)。</font><font>然後,我們在Express應用程序上調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>use()</code><font><font>,將路由器添加到中間件處理路徑,並指定一個'wiki'的URL路徑。</font></font></p>
+
+<pre class="brush: js"><code>var wiki = require('./wiki.js');
+// ...
+app.use('/wiki', wiki);</code></pre>
+
+<p><font><font>然後可以從</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/wiki/</code><font><font>和</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/wiki/about/</code><font><font>,訪問我們的wiki路由模塊中定義的兩個路由。</font></font></p>
+
+<h3 id="路由函數"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>路由函數</font></font></span></h3>
+
+<p><font><font>我們上面的模塊,定義了幾個典型的路由功能。</font><font>使用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>Router.get()</code><font><font>方法定義“about”路由(在下面),該方法僅響應HTTP GET請求。</font><font>此方法的第一個參數是URL路徑,而第二個參數是一個回調函數,如果收到帶有路徑的HTTP GET請求,將會調用該函數。</font></font></p>
+
+<pre class="brush: js"><code>router.get('/about', function (req, res) {
+ res.send('About this wiki');
+})</code>
+</pre>
+
+<p><font><font>回調函數接受三個參數(通常如下所示命名:</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>req</code><font><font>,<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>res</code><font><font>,<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>next</code><font><font>),它將包含HTTP請求對象,HTTP響應,以及中間件鏈中的下一個函數。</font></font></p>
+
+<div class="note">
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><strong style="border: 0px; font-style: normal; font-weight: 700; margin: 0px; padding: 0px;"><font><font>注意:</font></font></strong><font><font>路由器功能是</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>Express中間件</font></font></a><font><font>,這意味著它們必須完成(響應)請求或調用鏈中的下一個功能</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>next</code><font><font>。</font><font>在上面的例子中,我們使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>send()</code><font><font>完成了請求,所以下一個參數</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem;'>next</code><font><font>沒有被使用(我們選擇不指定它)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><font><font>上面的路由器函數只需要一次回調,但您可以根據需要指定任意數量的回調參數,或一組回調函數。</font><font>每個函數都是中間件鏈的一部分,並且將按照添加到鏈中的順序調用(除非前面的函數完成請求)。</font></font></p>
+
+<p> </p>
+</div>
+
+<p><font><font>這裡的回調函數,在響應中調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><a class="external external-icon" href="https://expressjs.com/en/4x/api.html#res.send" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">send()</a></code><font><font>,當我們收到帶有路徑('<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/about'</code><font><font>)的GET請求時,返回字符串“About this wiki”。</font><font>有</font></font><a class="external external-icon" href="https://expressjs.com/en/guide/routing.html#response-methods" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>許多其他響應方法</font></font></a><font><font>,可以結束請求/響應週期。</font><font>例如,您可以調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><a class="external external-icon" href="https://expressjs.com/en/4x/api.html#res.json" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">res.json()</a></code><font><font>,來發送JSON響應,或調用</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; color: rgb(51, 51, 51); font-size: medium; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'><a class="external external-icon" href="https://expressjs.com/en/4x/api.html#res.sendFile" rel="noopener" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line;">res.sendFile()</a></code><font><font>來發送文件。</font><font>構建庫時,我們最常使用的響應方法是</font></font><a class="external external-icon" href="https://expressjs.com/en/4x/api.html#res.render" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>render()</font></font></a><font><font>,它使用模板和數據創建並返回HTML文件—我們將在後面的文章中,進一步討論這個問題!</font></font></p>
+
+<h3 id="HTTP_動詞"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font><span> </span>HTTP 動詞</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>上面的示例路由使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Router.get()</code><font><font>方法,響應具有特定路徑的HTTP GET請求。</font><font>路由器</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Router</code><font><font>還為所有其他HTTP動詞提供路由方法,這些方法多數以完全相同的方式使用:</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>post()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>put()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>delete()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>options()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>trace()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>copy()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>lock()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>mkcol()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>move()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>purge()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>propfind()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>proppatch()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>unlock()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>report()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>mkactivity()</code><font><font>​​​​​​,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>checkout()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>merge()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>m-</code><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>search()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>notify()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>subscribe()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>unsubscribe()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>patch()</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>search()</code><font><font>,和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>connect()</code><font><font>。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>例如,下面的代碼就像上一個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/about</code><font><font>路由一樣,但只響應HTTP POST請求。</font></font></p>
+
+<pre class="brush: js"><code>router.post('/about', function (req, res) {
+ res.send('About this wiki');
+})</code></pre>
+
+<h3 id="路由路徑"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>路由路徑</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由路徑定義可以進行請求的端點。</font><font>我們到目前為止看到的例子,都是字符串,並且完全按照字符串的寫法使用:'/','/ about','/ book','/any-random.path'。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由路徑也可以是字符串模式。</font><font>字符串模式使用正則表達式語法的子集,來定義將匹配的端點模式。</font><font>下面列出了子集(請注意,連字符(</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>-</code><font><font>)和點(</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>.</code><font><font>)由字符串路徑字面解釋):</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>? :端點在?號前面的那個字符,必須為0個或1個。</font><font>例如。</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>'/ab?cd'</code><font><font>的路徑路徑將匹配端點</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>acd<span> </span></code><font><font>或</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abcd</code><font><font>。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>+ :端點在+號前面的那個字符,必須為1個或多個。</font><font>例如,</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>'/ab+cd'</code><font><font>的路徑路徑將與端點</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abcd</code><font><font>,</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abbcd</code><font><font>,</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abbbcd</code><font><font>等匹配。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>* :端點在放置*字符的地方,可以代換為任意字符串。</font><font>例如。</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>'ab\*cd'</code><font><font>的路由路徑,將匹配端點</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abcd</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abXcd</code><font><font>,<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abSOMErandomTEXTcd</code><font><font>等。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><font><font>() :將一組字符進行匹配,以執行上面三個操作。</font><font>例如。</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>'/ab(cd)?e'</code><font><font>,表示以?</font><font>號對(cd)進行匹配-它會匹配</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abe</code><font><font>和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abcde</code><font><font>。</font><font>(譯註:即(cd)必須為0個或1個。若為0,匹配</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abe</code><font><font>。若為1,匹配</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>abcde</code><font><font>)</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由路徑也可以是</font></font><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions" style="font-style: normal !important; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px;"><font><font>JavaScript正則表達式</font></font></a><font><font>。</font><font>例如,下面的路由路徑將與鯰魚</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catfish<span> </span></code><font><font>和角鯊魚</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>dogfish</code><font><font>相匹配,但不包括鯰魚</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catflap</code><font><font>、鯰魚頭</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catfishhead</code><font><font>等。</font><font>請注意,正則表達式的路徑使用正則表達式語法(它不像以前那樣,是帶引號的字符串)。</font></font></p>
+
+<pre class="brush: js"><code>app.get(/.*fish$/, function (req, res) {
+ ...
+})</code></pre>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font><span> </span>LocalLibrary的大部分路由,都只使用字符串,而不是字符串模式和正則表達式。</font><font>我們還將使用下一節中討論的路由參數。</font></font></p>
+</div>
+
+<h3 id="路由參數"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>路由參數</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路徑參數是命名的URL段,用於捕獲在URL中的位置指定的值。</font><font>命名段以冒號為前綴,然後是名稱(例如</font><font>。捕獲的值,使用參數名稱作為鍵,存在</font><font>對像中(例如</font><font>)。</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/<strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;">:</strong>your_parameter_name/</code><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>req.params</code><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>req.params.your_parameter_name</code></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>例如,考慮一個編碼的URL,其中包含有關用戶和書本的信息:</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>http://localhost:3000/users/34/books/8989</code><font><font>。</font><font>我們可以使用</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>userId</code><font><font>和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>bookId</code><font><font>路徑參數,提取如下所示的信息:</font></font></p>
+
+<pre><code>app.get('/users/:userId/books/:bookId', function (req, res) {
+ // Access userId via: req.params.userId
+ // Access bookId via: req.params.bookId
+ res.send(req.params);
+})
+</code></pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>路由參數的名稱,必須由“單詞字符”(AZ,az,0-9和_)組成。</span></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font><span> </span>URL<span> </span></font></font><em><font><font>/book/create</font></font></em><font><font>將與</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/book/:bookId</code><font><font> 之類的路由匹配(它將提取要創建'<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>create</code><font><font>'的“bookId”值)。</font><font>將使用與傳入URL匹配的第一個路由,因此,如果要單獨處理</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/book/create</code><font><font>URL,則必須在</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/book/:bookId</code><font><font>路由之前,先定義其路由處理程序。</font></font></p>
+</div>
+
+<p><font><font>這就是您開始使用路由所需的全部內容-如果需要,您可以在Express文檔中找到更多信息:</font></font><a class="external external-icon" href="http://expressjs.com/en/starter/basic-routing.html" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>基本路由</font></font></a><font><font>和</font></font><a class="external external-icon" href="http://expressjs.com/en/guide/routing.html" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 255, 255);'><font><font>路由指南</font></font></a><font><font>。</font><font>以下部分顯示了我們如何為LocalLibrary設置路由和控制器。</font></font></p>
+
+<h2 id="本地圖書館需要的路由"><font><font>本地圖書館需要的路由</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下面列出了我們最終需要用於頁面的URL,其中object被替換為每個模型的名稱(book,bookinstance,genre,author),objects是對象的複數,id是默認情況下,為每個Mongoose模型實例指定的唯一實例字段(</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>_id</code><font><font>)。</font></font></p>
+
+<ul style='font-style: normal; margin: 0px 0px 24px; padding: 0px 0px 0px 40px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/</code><font><font><span> </span>— 主頁/索引頁面。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/&lt;objects&gt;/</code><font><font>—所有書本,書本實例,種類或作者的列表(例如/<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/books/</code><font><font>, /<span> </span></font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/genres/</code><font><font>等)</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/&lt;object&gt;/<em>&lt;id&gt;</em></code><font><font>—具有給定</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><em>_id</em></code><font><font>字段值的特定書本,書本實例,種類或作者的詳細信息頁面(例如</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/catalog/book/584493c1f4887f06c0e67d37</code><font><font>)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/&lt;object&gt;/create</code><font><font>—用於創建新的書本,書本實例,種類或作者的表單(例如</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/catalog/book/create</code><font><font>)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/&lt;object&gt;/<em>&lt;id&gt;</em>/update</code><font><font>—使用給定的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><em>_id</em></code><font><font>字段值更新特定書本,書本實例,種類或作者的表單(例如</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/catalog/book/584493c1f4887f06c0e67d37/update</code><font><font>)。</font></font></li>
+ <li style="font-style: normal !important; margin: 0px 0px 6px; padding: 0px; border: 0px;"><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>catalog/&lt;object&gt;/<em>&lt;id&gt;</em>/delete</code><font><font>—刪除具有給定</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><em>_id</em></code><font><font>字段值的特定書本,書本實例,種類或作者的表單(例如</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>/catalog/book/584493c1f4887f06c0e67d37/delete</code><font><font>)。</font></font></li>
+</ul>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>第一個主頁和列表頁面,不編碼任何其他信息。</font><font>雖然返回的結果,將取決於模型類型和數據庫中的內容,但為了獲取信息所運行的查詢,將始終相同(類似地,用於創建對象的代碼將始終類似)。</font><font>相反的,其他URL用於處理特定文檔/模型實例—這些將項目的標識編碼在URL中(如上面的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'><em>&lt;id&gt;</em></code><font><font>)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們將使用路徑參數,來提取編碼信息,並將其傳遞給路由處理程序(在稍後的文章中,我們將使用它來動態確定從數據庫獲取的信息)。</font><font>通過對我們的URL中的信息進行編碼,我們只需要一個路由,用於特定類型的每個資源(例如,一個路由來處理每個書本項目的顯示)。</font></font></p>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意</font></font></strong><font><font><span> </span>: Express允許您以任何方式構建URL -您可以在URL正文中編碼信息,就像上面一樣,或使用URL<span> </span></font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>GET</code><font><font>參數(例如</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/book/?id=6</code><font><font>)。</font><font>無論您使用哪種方法,URL都應保持乾淨,合理且可讀(請在此處查看</font></font><a class="external external-icon" href="https://www.w3.org/Provider/Style/URI" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>W3C建議</font></font></a><font><font>)。</font></font></p>
+</div>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>接下來,我們為所有上述URL,創建路由處理程序回調函數和路由代碼。</span></p>
+
+<h2 id="創建路由-handler回調函式"><font><font>創建路由-handler回調函式</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>在我們定義路由之前,我們將首先創建它們將調用的所有虛擬/骨架回調函數。</font><font>回調將存在Books,BookInstances,Genres 和Authors 的單獨“控制器” 模塊中(您可以使用任何文件/模塊結構,但這似乎是該項目的適當粒度)。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>首先在項目根目錄(</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/controllers</font></font></strong><font><font>)中,為我們的控制器創建一個文件夾,然後創建單獨的控制器文件/模塊,來處理每個模型:</font></font></p>
+
+<pre>/express-locallibrary-tutorial //the project root
+ <strong>/controllers</strong>
+ <strong>authorController.js</strong>
+ <strong>bookController.js</strong>
+ <strong>bookinstanceController.js</strong>
+ <strong>genreController.js</strong></pre>
+
+<h3 id="作者控制器"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>作者控制器</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/controllers/authorController.js</font></font></strong><font><font>文件,並複制以下代碼:</font></font></p>
+
+<pre class="brush: js">var Author = require('../models/author');
+
+// Display list of all Authors.
+exports.author_list = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author list');
+};
+
+// Display detail page for a specific Author.
+exports.author_detail = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id);
+};
+
+// Display Author create form on GET.
+exports.author_create_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author create GET');
+};
+
+// Handle Author create on POST.
+exports.author_create_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author create POST');
+};
+
+// Display Author delete form on GET.
+exports.author_delete_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author delete GET');
+};
+
+// Handle Author delete on POST.
+exports.author_delete_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author delete POST');
+};
+
+// Display Author update form on GET.
+exports.author_update_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author update GET');
+};
+
+// Handle Author update on POST.
+exports.author_update_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Author update POST');
+};
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該模塊首先導入我們稍後將使用的模型,來訪問和更新我們的數據。</font><font>然後它為我們希望處理的每個URL,導出函數(創建,更新和刪除操作使用表單,因此還有其他方法,來處理表單發布請求- 我們將在稍後的“表單文章” 中討論這些方法) 。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>所有函數都具有Express中間件函數的標準形式,如果方法沒有完成請求週期,則會調用請求,響應和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>next</code><font><font>下一個函數的參數(在所有這些情況下,它都會執行!)。</font><font>這些方法只返回一個字符串,表明尚未創建關聯的頁面。</font><font>如果期望控制器函數接收路徑參數,則在消息字符串中,輸出這些參數(參見上面的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>req.params.id</code><font><font>)。</font></font></p>
+
+<h4 id="書本實例控制器" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>書本實例控制器</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/controllers/bookinstanceController.js</font></font></strong><font><font>文件,並將其複製到以下代碼中(它遵循與</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Author</code><font><font>控制器模塊相同的模式):</font></font></p>
+
+<pre class="brush: js">var BookInstance = require('../models/bookinstance');
+
+// Display list of all BookInstances.
+exports.bookinstance_list = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance list');
+};
+
+// Display detail page for a specific BookInstance.
+exports.bookinstance_detail = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id);
+};
+
+// Display BookInstance create form on GET.
+exports.bookinstance_create_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance create GET');
+};
+
+// Handle BookInstance create on POST.
+exports.bookinstance_create_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance create POST');
+};
+
+// Display BookInstance delete form on GET.
+exports.bookinstance_delete_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance delete GET');
+};
+
+// Handle BookInstance delete on POST.
+exports.bookinstance_delete_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance delete POST');
+};
+
+// Display BookInstance update form on GET.
+exports.bookinstance_update_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance update GET');
+};
+
+// Handle bookinstance update on POST.
+exports.bookinstance_update_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: BookInstance update POST');
+};
+</pre>
+
+<h4 id="種類控制器" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>種類控制器</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/controllers/genreController.js</font></font></strong><font><font>文件,並複制以下文本(這與</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Author</code><font><font>和</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>BookInstance</code><font><font>文件的模式相同):</font></font></p>
+
+<pre class="brush: js">var Genre = require('../models/genre');
+
+// Display list of all Genre.
+exports.genre_list = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre list');
+};
+
+// Display detail page for a specific Genre.
+exports.genre_detail = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id);
+};
+
+// Display Genre create form on GET.
+exports.genre_create_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre create GET');
+};
+
+// Handle Genre create on POST.
+exports.genre_create_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre create POST');
+};
+
+// Display Genre delete form on GET.
+exports.genre_delete_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre delete GET');
+};
+
+// Handle Genre delete on POST.
+exports.genre_delete_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre delete POST');
+};
+
+// Display Genre update form on GET.
+exports.genre_update_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre update GET');
+};
+
+// Handle Genre update on POST.
+exports.genre_update_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Genre update POST');
+};
+</pre>
+
+<h4 id="書本控制器" style='font-style: normal; line-height: 1.2; margin: 30px 0px 20px; padding: 0px; border: 0px; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 1.375rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>書本控制器</font></font></h4>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/controllers/bookController.js</font></font></strong><font><font>文件,並複制以下代碼。</font><font>它遵循與其他控制器模塊相同的模式,但另外還有一個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>index()</code><font><font>函數,用於顯示站點歡迎頁面:</font></font></p>
+
+<pre class="brush: js">var Book = require('../models/book');
+
+<strong>exports.index = function(req, res) {
+ res.send('NOT IMPLEMENTED: Site Home Page');
+};</strong>
+
+// Display list of all books.
+exports.book_list = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book list');
+};
+
+// Display detail page for a specific book.
+exports.book_detail = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id);
+};
+
+// Display book create form on GET.
+exports.book_create_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book create GET');
+};
+
+// Handle book create on POST.
+exports.book_create_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book create POST');
+};
+
+// Display book delete form on GET.
+exports.book_delete_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book delete GET');
+};
+
+// Handle book delete on POST.
+exports.book_delete_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book delete POST');
+};
+
+// Display book update form on GET.
+exports.book_update_get = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book update GET');
+};
+
+// Handle book update on POST.
+exports.book_update_post = function(req, res) {
+ res.send('NOT IMPLEMENTED: Book update POST');
+};
+</pre>
+
+<h2 id="創建目錄路由模組"><font><font>創建目錄路由模組</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>接下來,我們為LocalLibrary 網站,創建所需全部URL 的路由,這將調用我們在上一節中定義的控制器功能。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>骨架網站已經有一個</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>./routes</font></font></strong><font><font>文件夾,其中包含索引和用戶的路由。</font><font>在此文件夾中,創建另一個路徑文件—<span> </span></font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>catalog.js</font></font></strong><font><font><span> </span>—如下圖所示。</font></font></p>
+
+<pre>/express-locallibrary-tutorial //the project root
+ /routes
+  index.js
+  users.js
+  <strong>catalog.js</strong></pre>
+
+<p><font><font>打開</font></font><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>/routes/<span> </span></font></font></strong><strong style='background-color: #ffffff; border: 0px; color: #333333; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>catalog.js</font></font></strong><font><font>,複製下面的代碼:</font></font></p>
+
+<pre class="brush: js"><strong>var express = require('express');
+var router = express.Router();
+</strong>
+// Require controller modules.
+var book_controller = require('../controllers/bookController');
+var author_controller = require('../controllers/authorController');
+var genre_controller = require('../controllers/genreController');
+var book_instance_controller = require('../controllers/bookinstanceController');
+
+/// BOOK ROUTES ///
+
+// GET catalog home page.
+router.get('/', book_controller.index);
+
+// GET request for creating a Book. NOTE This must come before routes that display Book (uses id).
+router.get('/book/create', book_controller.book_create_get);
+
+// POST request for creating Book.
+router.post('/book/create', book_controller.book_create_post);
+
+// GET request to delete Book.
+router.get('/book/:id/delete', book_controller.book_delete_get);
+
+// POST request to delete Book.
+router.post('/book/:id/delete', book_controller.book_delete_post);
+
+// GET request to update Book.
+router.get('/book/:id/update', book_controller.book_update_get);
+
+// POST request to update Book.
+router.post('/book/:id/update', book_controller.book_update_post);
+
+// GET request for one Book.
+router.get('/book/:id', book_controller.book_detail);
+
+// GET request for list of all Book items.
+router.get('/books', book_controller.book_list);
+
+/// AUTHOR ROUTES ///
+
+// GET request for creating Author. NOTE This must come before route for id (i.e. display author).
+router.get('/author/create', author_controller.author_create_get);
+
+// POST request for creating Author.
+router.post('/author/create', author_controller.author_create_post);
+
+// GET request to delete Author.
+router.get('/author/:id/delete', author_controller.author_delete_get);
+
+// POST request to delete Author.
+router.post('/author/:id/delete', author_controller.author_delete_post);
+
+// GET request to update Author.
+router.get('/author/:id/update', author_controller.author_update_get);
+
+// POST request to update Author.
+router.post('/author/:id/update', author_controller.author_update_post);
+
+// GET request for one Author.
+router.get('/author/:id', author_controller.author_detail);
+
+// GET request for list of all Authors.
+router.get('/authors', author_controller.author_list);
+
+/// GENRE ROUTES ///
+
+// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
+router.get('/genre/create', genre_controller.genre_create_get);
+
+//POST request for creating Genre.
+router.post('/genre/create', genre_controller.genre_create_post);
+
+// GET request to delete Genre.
+router.get('/genre/:id/delete', genre_controller.genre_delete_get);
+
+// POST request to delete Genre.
+router.post('/genre/:id/delete', genre_controller.genre_delete_post);
+
+// GET request to update Genre.
+router.get('/genre/:id/update', genre_controller.genre_update_get);
+
+// POST request to update Genre.
+router.post('/genre/:id/update', genre_controller.genre_update_post);
+
+// GET request for one Genre.
+router.get('/genre/:id', genre_controller.genre_detail);
+
+// GET request for list of all Genre.
+router.get('/genres', genre_controller.genre_list);
+
+/// BOOKINSTANCE ROUTES ///
+
+// GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id).
+router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get);
+
+// POST request for creating BookInstance.
+router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post);
+
+// GET request to delete BookInstance.
+router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get);
+
+// POST request to delete BookInstance.
+router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post);
+
+// GET request to update BookInstance.
+router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get);
+
+// POST request to update BookInstance.
+router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post);
+
+// GET request for one BookInstance.
+router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail);
+
+// GET request for list of all BookInstance.
+router.get('/bookinstances', book_instance_controller.bookinstance_list);
+
+<strong>module.exports = router;</strong>
+</pre>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>該模塊導入Express,然後使用它來創建一個</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>Router</code><font><font>對象。</font><font>路由都在路由器上設置完成,然後導出。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>路由是使用路由器對像上的</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>.get()</code><font><font>或</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>.post()</code><font><font>方法定義的。</font><font>所有路徑都是使用字符串定義的(我們不使用字符串模式或正則表達式)。</font><font>作用於某些特定資源(如書籍)的路由,則使用路徑參數從URL中獲取對象標識id。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>處理程序函數,都是從我們在上一節中,創建的控制器模塊導入的。</font></font></p>
+
+<h3 id="更新_index_路由模組"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;">更新 index 路由模組</span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們已經設置了所有新路由,但我們仍然有一個到原始頁面的路由。</font><font>讓我們將其重定向,到我們在路徑'/ catalog' 創建的新索引頁面。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>/routes/index.js</font></font></strong><font><font>並使用下面的函數,替換現有路由。</font></font></p>
+
+<pre class="brush: js">// GET home page.
+router.get('/', function(req, res) {
+ res.redirect('/catalog');
+});</pre>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>注意:</font></font></strong><font><font>這是我們第一次使用</font></font><a class="external external-icon" href="https://expressjs.com/en/4x/api.html#res.redirect" rel="noopener" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; white-space: pre-line; font-family: x-locale-heading-primary, zillaslab, Palatino, "Palatino Linotype", x-locale-heading-secondary, serif; font-size: 18px; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; background-color: rgb(255, 243, 212);'><font><font>redirect()</font></font></a><font><font>響應方法。</font><font>這會重定向到指定的頁面,默認情況下會發送HTTP狀態代碼“302 Found”。</font><font>您可以根據需要,更改返回的狀態代碼,並提供絕對路徑或相對路徑。</font></font></p>
+</div>
+
+<h3 id="更新app.js"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>更新app.js</font></font></span></h3>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>最後一步,是將路由,添加到中間件鏈。</font><font>我們在</font></font><code style='font-style: inherit; margin: 0px; padding: 0px 2px; border: 0px; font-weight: inherit; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word;'>app.js</code><font><font>這樣做。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>打開</font></font><strong style="border: 0px; font-style: normal !important; margin: 0px; padding: 0px;"><font><font>app.js</font></font></strong><font><font>,並要求其他路由下方的目錄路由(添加下面顯示的第三行,在其他兩個路由下面):</font></font></p>
+
+<pre class="brush: js">var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+<strong>var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site</strong></pre>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>接下來,將目錄路由,添加到其他路由下面的中間件堆棧(添加下面顯示的第三行,在其他兩行下面):</span></p>
+
+<pre class="brush: js">app.use('/', indexRouter);
+app.use('/users', usersRouter);
+<strong>app.use('/catalog', catalogRouter); // Add catalog routes to middleware chain.</strong></pre>
+
+<div class="note">
+<p><strong style='background-color: #fff3d4; border: 0px; color: #333333; font-family: x-locale-heading-primary,zillaslab,Palatino,"Palatino Linotype",x-locale-heading-secondary,serif; font-size: 18px; font-style: normal; font-weight: 700; letter-spacing: normal; margin: 0px; padding: 0px; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'><font><font>Note:</font></font></strong><font><font><span> </span>  我們已在路徑</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>'/catalog'</code><font><font>中添加了目錄模塊。</font><font>它預先添加到目錄模塊中定義的所有路徑。</font><font>例如,要訪問書本列表,URL將為:</font></font><code style='font-style: normal; margin: 0px; padding: 0px 2px; border: 0px; font-weight: 400; background-color: rgba(220, 220, 220, 0.5); border-radius: 2px; font-family: consolas, "Liberation Mono", courier, monospace; word-wrap: break-word; font-size: 1rem; color: rgb(51, 51, 51); letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; text-decoration-style: initial;'>/catalog/books/</code><font><font>。</font></font></p>
+</div>
+
+<p><font>就是這樣。</font><font>現在應該為我們最終在LocalLibrary 網站上支持的所有URL,啟用路由和框架功能。</font></p>
+
+<h3 id="測試路由"><span class="highlight-span" style="background-color: #333333; border: 0px; color: #ffffff; font-style: normal !important; font-weight: 400; line-height: 1.25; margin: 0px; padding: 0px 4px 0px 40px;"><font><font>測試路由</font></font></span></h3>
+
+<p><span style='background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: "Open Sans",arial,x-locale-body,sans-serif; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;'>要測試路由,首先使用您通常的方法啟動網站</span></p>
+
+<ul>
+ <li>預設方法
+ <pre class="brush: bash"><code>// Windows
+SET DEBUG=express-locallibrary-tutorial:* &amp; npm start
+
+// macOS or Linux
+DEBUG=express-locallibrary-tutorial:* npm start</code>
+</pre>
+ </li>
+ <li><font><font>如果您先前設置了</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website" style='font-style: normal; text-decoration: none; color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255);'><font><font>nodemon</font></font></a><font><font><span> </span>,則可以使用:</font></font>
+ <pre><code>// Windows
+SET DEBUG=express-locallibrary-tutorial:* &amp; npm <strong>run devstart</strong>
+
+// macOS or Linux
+</code>DEBUG=express-locallibrary-tutorial:* npm <strong style="font-family: inherit; font-size: 1rem;">run devstart</strong>
+</pre>
+ </li>
+</ul>
+
+<p><font>然後瀏覽一些上面的LocalLibrary URL,並驗證您沒有收到錯誤頁面(HTTP 404)。</font><font>為方便起見,下面列出了一小組網址:</font></p>
+
+<ul>
+ <li><a href="http://localhost:3000/">http://localhost:3000/</a></li>
+ <li><a href="http://localhost:3000/catalog">http://localhost:3000/catalog</a></li>
+ <li><a href="http://localhost:3000/catalog/books">http://localhost:3000/catalog/books</a></li>
+ <li><a href="http://localhost:3000/catalog/bookinstances/">http://localhost:3000/catalog/bookinstances/</a></li>
+ <li><a href="http://localhost:3000/catalog/authors/">http://localhost:3000/catalog/authors/</a></li>
+ <li><a href="http://localhost:3000/catalog/genres/">http://localhost:3000/catalog/genres/</a></li>
+ <li><a href="http://localhost:3000/catalog/book/5846437593935e2f8c2aa226/">http://localhost:3000/catalog/book/5846437593935e2f8c2aa226</a></li>
+ <li><a href="http://localhost:3000/catalog/book/create">http://localhost:3000/catalog/book/create</a></li>
+</ul>
+
+<h2 id="總結"><font><font>總結</font></font></h2>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>我們現在為網站創建了所有的路由,在稍後的教程,我們可以將實作完成的代碼,填入到空殼控制器函式。</font><font>以這樣的方式,我們學到了許多關於Express 路由的基本信息,以及一些組織路由和控制器的方式。</font></font></p>
+
+<p style='font-style: normal; margin: 0px 0px 24px; padding: 0px; border: 0px; max-width: 42rem; color: rgb(51, 51, 51); font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: medium; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-style: initial;'><font><font>下一篇文章,我們將使用視圖(模板) 和存在模型裡的信息,為網站創建一個合適的歡迎頁面。</font></font></p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li>
+ <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<p> </p>
+
+<h2 id="本教程連結">本教程連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html b/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html
new file mode 100644
index 0000000000..0139a30dd9
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/skeleton_website/index.html
@@ -0,0 +1,506 @@
+---
+title: 'Express 教學 2: 創建一個骨架網站'
+slug: Learn/Server-side/Express_Nodejs/skeleton_website
+translation_of: Learn/Server-side/Express_Nodejs/skeleton_website
+---
+<div>{{LearnSidebar}}</div>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<p class="summary">在 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express 教程</a>的第二篇文章,演示如何創建一個 "骨架" 網站項目,你可以接著在裡面加入網站特定的路由、模板/視圖、和數据庫調用。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置條件:</th>
+ <td><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">架設一個Node 開發環境</a>。回顧Express 教程。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>能夠使用<em>Express 應用產生器,</em>創建自己新的網頁項目。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>本文演示如何使用 <a class="external external-icon" href="https://expressjs.com/en/starter/generator.html" rel="noopener">Express 應用產生器</a> 工具,創建一個 "骨架" 網站,然後您可以使用特定於站點的路由,視圖/模板和數據庫調用來填充它們。在這個教程,我們將使用該工具,為我們的本地圖書館網站創建框架,我們稍後將添加該網站所需的所有其他代碼。該過程非常簡單,只需要在命令行上,用新項目名稱調用生成器,還可以指定站點的模板引擎和 CSS 生成器。</p>
+
+<p>以下部分向您展示如何調用應用程序生成器,並提供關於視圖或CSS的不同選項的一些解釋。我們還將解釋骨架網站的結構。最後,我們將展示如何運行網站,來驗證它是否有效。</p>
+
+<div class="note">
+<p><span style="line-height: 1.5;"><strong>注意</strong>: </span>Express Application Generator並非 Express 應用程序的唯一生成器,生成的項目不是構建文件和目錄的唯一可行方式。然而,生成的網站具有易於擴展和理解的模塊化結構。有關最小 Express 應用程序的信息,請參閱 <span style="line-height: 1.5;"><a href="https://expressjs.com/en/starter/hello-world.html">Hello world </a></span>示例(Express docs)。</p>
+</div>
+
+<h2 id="使用應用產生器">使用應用產生器</h2>
+
+<p>您應該已經安裝了生成器,作為設置 Node 開發環境的一部分。作為快速提醒,您可以使用 NPM 軟件包管理器,在整個站點安裝生成器工具,如下所示:</p>
+
+<pre class="brush: bash notranslate"><code>npm install express-generator -g</code></pre>
+
+<p>生成器有許多選項,您可以使用<code>--help</code>(或<code>-h</code>)命令,在命令行上查看它們:</p>
+
+<pre class="brush: bash notranslate">&gt; express --help
+
+  Usage: express [options] [dir]
+
+  Options:
+
+    -h, --help           output usage information
+        --version        output the version number
+    -e, --ejs            add ejs engine support
+        --pug            add pug engine support
+        --hbs            add handlebars engine support
+    -H, --hogan          add hogan.js engine support
+    -v, --view &lt;engine&gt;  add view &lt;engine&gt; support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
+    -c, --css &lt;engine&gt;   add stylesheet &lt;engine&gt; support (less|stylus|compass|sass) (defaults to plain css)
+        --git            add .gitignore
+    -f, --force          force on non-empty directory
+</pre>
+
+<p>您可以使用 Jade 視圖引擎和純 CSS 來指定 <code>express</code>,以在當前目錄中創建項目(如果指定目錄名,則項目將創建在具有該名稱的子文件夾中)。</p>
+
+<pre class="brush: bash notranslate"><code>express</code></pre>
+
+<p>您還可以使用<code>--view</code>選擇視圖(模板)引擎,並且/或者使用<code>--css</code>選擇 CSS 生成引擎。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 選擇模板引擎的其他選項(例如 <code>--hogan</code>, <code>--ejs</code>, <code>--hbs</code>等)已被棄用。請用 <code>--view</code> (或 <code>-v</code>)!</p>
+</div>
+
+<h3 id="我應該用哪個視圖引擎">我應該用哪個視圖引擎?</h3>
+
+<p>Express Application Generator 允許您配置許多流行的視圖/模板引擎,包括 <a href="https://www.npmjs.com/package/ejs">EJS</a>, <a href="http://github.com/donpark/hbs">Hbs</a>, <a href="https://pugjs.org/api/getting-started.html">Pug</a> (Jade), <a href="https://www.npmjs.com/package/twig">Twig</a>, 和 <a href="https://www.npmjs.com/package/vash">Vash</a>,但如果您沒有指定視圖選項,它會默認選擇Jade。 Express 本身也可以支持大量其他模板語言,是「<a href="https://github.com/expressjs/express/wiki#template-engines">開箱即可使用</a>」的。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 如果要使用生成器不支持的模板引擎,請參閱<a href="https://expressjs.com/en/guide/using-template-engines.html">在Express中使用模板引擎(Express文檔)</a>,並參閱目標視圖引擎的文檔。</p>
+</div>
+
+<p>一般來說,您應該選擇一種「可以提供您所需的所有功能」的模板引擎,<br>
+ 並使您能夠儘早提高生產力 - 換句話說,就像您選擇其他組件一樣!比較模板引擎時需要考慮的一些事項如下:</p>
+
+<ul>
+ <li>具備生產力之前所需要花費的時間 — 如果您的團隊已經有模板語言的經驗,那麼使用該語言可能會更快地提高生產力。如果不是,那麼你應該考慮候選模板引擎的相對學習曲線(即以投入時間與得到的生產力為XY座標所繪製的曲線)。</li>
+ <li>人氣和活躍 — 回顧引擎的普及程度以及它是否擁有活躍的社區。當您在網站的生命週期中遇到問題時,能夠獲得對引擎的支持非常重要。</li>
+ <li>風格 — 某些模板引擎使用特定的標記,來指示在 “普通” HTML內插入的內容,而其他模板引擎使用不同的語法(例如,使用縮進和區塊名稱)構造HTML。</li>
+ <li>性能/渲染時間。</li>
+ <li>特點 — 你應該考慮你看中的引擎是否具有以下功能:
+ <ul>
+ <li>佈局繼承:允許您定義基本模板,然後 “繼承” 它的一部分,使特定頁面可以有不同的呈現。比起通過包含大量必需組件,或每次從頭開始構建模板,這通常是更好的方式。</li>
+ <li>"Include" 支持:允許您通過包含其他模板,來構建模板。</li>
+ <li>簡潔的變量和循環控制語法。</li>
+ <li>能夠在模板級別過濾變量值(例如,將變量設置為大寫,或格式化日期值)。</li>
+ <li>能夠生成HTML以外的輸出格式(例如 JSON 或 XML)。</li>
+ <li>支持異步操作和流媒體。</li>
+ <li>可以在客戶端和服務器上使用。如果可以在客戶端上使用模板引擎,則允許提供數據,並有可能在客戶端完成所有渲染,或大部分渲染。</li>
+ </ul>
+ </li>
+</ul>
+
+<div class="note">
+<p><strong>提示:</strong> 互聯網上有許多資源,可幫助您比較不同的視圖/模板引擎選擇!</p>
+</div>
+
+<p>對於這個項目,我們將使用 <a href="https://pugjs.org/api/getting-started.html">Pug</a> 模板引擎(這是最近更名的 Jade 引擎),因為這是最流行的 Express / JavaScript 模板語言之一,並且應用發生器支持開箱即用。</p>
+
+<h3 id="我應該用哪個CSS樣式引擎">我應該用哪個CSS樣式引擎?</h3>
+
+<p>Express 應用生成器允許您創建一個項目,並配置最常見的 CSS 樣式表引擎:<a href="http://lesscss.org/">LESS</a>, <a href="http://sass-lang.com/">SASS</a>, <a href="http://compass-style.org/">Compass</a>, <a href="http://stylus-lang.com/">Stylus</a>。</p>
+
+<div class="note">
+<p><strong>注意: </strong>CSS有一些限制,使某些任務變得困難。 CSS 樣式表引擎允許您使用更強大的語法來定義您的 CSS,然後將定義編譯為純粹的舊式 CSS,以供瀏覽器使用。</p>
+</div>
+
+<p>與模板引擎一樣,您應該使用樣式表引擎,這樣可以讓您的團隊獲得最高生產力。對於這個項目,我們將使用普通的 CSS(默認值),因為我們的 CSS 要求不夠複雜,沒有必要使用其他任何東西。</p>
+
+<h3 id="我應該用哪個數據庫">我應該用哪個數據庫?</h3>
+
+<p>生成的代碼不使用/包含任何數據庫。 Express 應用程序可以使用 Node支持的任何<a href="https://expressjs.com/en/guide/database-integration.html">數據庫機制</a>(Express 本身並未針對數據庫管理,定義任何特定的附加行為/要求)。<br>
+ 我們將在後面的文章中,討論如何與數據庫集成。</p>
+
+<h2 id="創建項目">創建項目</h2>
+
+<p>對於我們要構建的示例 Local Library 應用程序,我們將使用 Pug 模板庫,創建一個名為 express-locallibrary-tutorial 的項目,並且不使用 CSS樣式表引擎。</p>
+
+<p>首先到要創建項目的位置,然後在命令提示符下,運行 Express 應用生成器,如下所示:</p>
+
+<pre class="brush: bash notranslate">express express-locallibrary-tutorial --view=pug
+</pre>
+
+<p>成器將創建(並列出)項目的文件。</p>
+
+<pre class="brush: bash notranslate"> create : express-locallibrary-tutorial
+ create : express-locallibrary-tutorial/package.json
+ create : express-locallibrary-tutorial/app.js
+ create : express-locallibrary-tutorial/public/images
+ create : express-locallibrary-tutorial/public
+ create : express-locallibrary-tutorial/public/stylesheets
+ create : express-locallibrary-tutorial/public/stylesheets/style.css
+ create : express-locallibrary-tutorial/public/javascripts
+ create : express-locallibrary-tutorial/routes
+ create : express-locallibrary-tutorial/routes/index.js
+ create : express-locallibrary-tutorial/routes/users.js
+ create : express-locallibrary-tutorial/views
+ create : express-locallibrary-tutorial/views/index.pug
+ create : express-locallibrary-tutorial/views/layout.pug
+ create : express-locallibrary-tutorial/views/error.pug
+ create : express-locallibrary-tutorial/bin
+ create : express-locallibrary-tutorial/bin/www
+
+ install dependencies:
+ &gt; cd express-locallibrary-tutorial &amp;&amp; npm install
+
+ run the app:
+ &gt; SET DEBUG=express-locallibrary-tutorial:* &amp; npm start</pre>
+
+<p>在輸出結束時,生成器提供關於「如何安裝依賴關係」的指示信息(如 <strong>package.json </strong>文件中所列),以及如何運行應用程序(上述說明適用於 Windows;在 Linux / macOS上,它們會略有不同)。</p>
+
+<h2 id="運行骨架網站">運行骨架網站</h2>
+
+<p>在這一時間點上,我們有一個完整的骨架項目。該網站實際上並沒有做太多工作,但運行它,能夠展示它是如何工作的。</p>
+
+<ol>
+ <li>首先安裝依賴項(<code>install</code>安裝命令,將獲取項目的 <strong>package.json </strong>文件中列出的所有依賴項包)。
+
+ <pre class="brush: bash notranslate">cd express-locallibrary-tutorial
+npm install</pre>
+ </li>
+ <li>然後運行該應用程序。
+ <ul>
+ <li>在Windows上,使用此命令:
+ <pre class="brush: bash notranslate">SET DEBUG=express-locallibrary-tutorial:* &amp; npm start</pre>
+ </li>
+ <li>在macOS 或 Linux,使用此命令:
+ <pre class="brush: bash notranslate">DEBUG=express-locallibrary-tutorial:* npm start
+</pre>
+ </li>
+ </ul>
+ </li>
+ <li>然後在瀏覽器中加載 <a href="http://localhost:3000/">http://localhost:3000/</a> ,以訪問該應用程序。</li>
+</ol>
+
+<p>你應該會看到一個瀏覽器頁面,就像這樣:</p>
+
+<p><img alt="Browser for default Express app generator website" src="https://mdn.mozillademos.org/files/14375/ExpressGeneratorSkeletonWebsite.png" style="display: block; height: 403px; margin: 0px auto; width: 576px;"></p>
+
+<p>你有一個能工作的 Express 應用了,讓它在 <a href="http://localhost:3000/">http://localhost:3000/ </a>服務。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 您也可以使用 <code>npm start</code>命令啟動應用程序。如下圖所示,指定 DEBUG 變量可啟用控制台日誌記錄/調試。例如,當你訪問上面的頁面時,你會看到像這樣的調試輸出:</p>
+
+<pre class="brush: bash notranslate">&gt;SET DEBUG=express-locallibrary-tutorial:* &amp; npm start
+
+&gt; express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial
+&gt; node ./bin/www
+
+ express-locallibrary-tutorial:server Listening on port 3000 +0ms
+GET / 200 288.474 ms - 170
+GET /stylesheets/style.css 200 5.799 ms - 111
+GET /favicon.ico 404 34.134 ms - 1335</pre>
+</div>
+
+<h2 id="讓伺服器在檔案更改時重新啟動">讓伺服器在檔案更改時重新啟動</h2>
+
+<p>在您重新啟動服務器之前,您對 Express 網站所做的任何更改,目前都不可見。每次進行更改時,必須停止並重新啟動服務器,很快變得非常煩人,因此值得花時間使服務器在需要時,自動重新啟動。</p>
+
+<p>這種工具中,最簡單的之一就是 <a href="https://github.com/remy/nodemon">nodemon</a>。這通常是全局安裝的(因為它是一個“工具”),但在這裡,我們將在本地安裝和使用它,作為開發人員依賴項,以便任何使用該項目的開發人員,在安裝應用程序時自動獲取它。在骨架項目的根目錄中,使用以下命令:</p>
+
+<pre class="brush: bash notranslate">npm install --save-dev nodemon</pre>
+
+<p>如果您打開項目的 <strong>package.json</strong> 文件,您現在將看到一個具有此依賴關係的新區段:</p>
+
+<pre class="brush: json notranslate"> "devDependencies": {
+ "nodemon": "^1.14.11"
+ }
+</pre>
+
+<p>由於該工具沒有全局安裝,我們無法從命令行啟動它(除非我們將其添加到路徑中),但是我們可以從 NPM 腳本中調用它,因為 NPM 知道所有關於安裝的軟件包的信息。找到你的 package.json 的腳本 scripts 區塊。我們更新 <code>scripts </code>區塊,最初的一行,以"<code>start</code>"開頭,在該行的末尾添加逗號,並添加 "<code>devstart</code>" 開頭的一行,如下所示:</p>
+
+<pre class="brush: json notranslate"> "scripts": {
+ "start": "node ./bin/www"<strong>,</strong>
+<strong> "devstart": "nodemon ./bin/www"</strong>
+ },
+</pre>
+
+
+
+<p>現在我們可以用與前面幾乎完全相同的方式,啟動服務器,但使用指定的 devstart 命令:</p>
+
+<ul>
+ <li>在 Windows,使用此命令:
+ <pre class="brush: bash notranslate">SET DEBUG=express-locallibrary-tutorial:* &amp; npm <strong>run devstart</strong></pre>
+ </li>
+ <li>在 macOS or Linux,使用此命令:
+ <pre class="brush: bash notranslate">DEBUG=express-locallibrary-tutorial:* npm <strong>run devstart</strong>
+</pre>
+ </li>
+</ul>
+
+<div class="note">
+<p><strong>注意:</strong> 現在,如果您編輯項目中的任何文件,服務器將重新啟動(或者您可以隨時在命令提示符下,鍵入<code>rs</code>來重新啟動它)。您仍需要重新加載瀏覽器,以刷新頁面。</p>
+
+<p>我們現在必須調用“<code>npm run &lt;scriptname&gt;</code>”而不是 <code>npm start</code>,因為“start”實際上是映射到指定腳本的 NPM 命令。我們可以在啟動腳本中替換該命令,但我們只想在開發期間使用 nodemon,因此創建新的腳本命令是有意義的。</p>
+</div>
+
+<h2 id="從產生器得到的項目">從產生器得到的項目</h2>
+
+<p>現在我們來看看我們剛剛創建的項目。</p>
+
+<h3 id="目錄結構">目錄結構</h3>
+
+<p>從產生器得到的生成項目,現在已經安裝了依賴項,具有以下文件結構 (<strong>不帶</strong>前綴 “/” 的項目,表示文件)。 <strong>package.json </strong>文件定義了應用程序依賴項,和其他信息。它還定義了一個啟動腳本,它將調用應用程序入口點 JavaScript 文件 <strong>/bin/www</strong>。這設置了一些應用程序的錯誤處理,然後加載 <strong>app.js</strong> ,來完成剩下的工作。應用程序路徑,存儲在 <strong>/routes </strong>目錄下的單獨模塊中。模板存儲在 <strong>/views</strong> 目錄下。</p>
+
+<pre class="notranslate">/express-locallibrary-tutorial
+ <strong>app.js</strong>
+ /bin
+  <strong>www</strong>
+ <strong>package.json</strong>
+ /node_modules
+  [about 4,500 subdirectories and files]
+ /public
+  /images
+  /javascripts
+  /stylesheets
+  <strong>style.css</strong>
+ /routes
+ <strong>index.js</strong>
+  <strong>users.js</strong>
+ /views
+  <strong>error.pug</strong>
+ <strong>index.pug</strong>
+  <strong>layout.pug</strong>
+
+</pre>
+
+<p>以下各節將詳細介紹這些文件。</p>
+
+<h3 id="package.json">package.json</h3>
+
+<p><strong>package.json </strong>文件定義了應用程序依賴關係,和其他訊息:</p>
+
+<pre class="brush: json notranslate">{
+  "name": "express-locallibrary-tutorial",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+  "dependencies": {
+    "body-parser": "~1.18.2",
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.16.2",
+    "morgan": "~1.9.0",
+    "pug": "~2.0.0-rc.4",
+    "serve-favicon": "~2.4.5"
+  },
+  "devDependencies": {
+    "nodemon": "^1.14.11"
+  }
+}
+</pre>
+
+<p>依賴關係包括 express 套件,和我們所選視圖引擎(pug)的套件。另外,我們還有以下的套件,在許多 Web 應用程序中很有用:</p>
+
+<ul>
+ <li><a href="https://www.npmjs.com/package/body-parser">body-parser</a>: 這解析傳入HTTP請求的正文 body 部分,並更容易提取包含信息的不同部分。例如,您可以使用它來讀取 <code>POST</code> 參數。</li>
+ <li><a href="https://www.npmjs.com/package/cookie-parser">cookie-parser</a>: 用於解析 cookie header 並填充 <code>req.cookies</code>(本質上提供了訪問 cookie 信息的便捷方法)。</li>
+ <li><a href="https://www.npmjs.com/package/debug">debug</a>: 一個小型 node 調試程序,仿照 node 核心的調試技術建立的。</li>
+ <li><a href="https://www.npmjs.com/package/morgan">morgan</a>: 搭配 node 使用的 HTTP 請求記錄器中間層軟件。</li>
+ <li><a href="https://www.npmjs.com/package/serve-favicon">serve-favicon</a>: 用於提供收藏圖標 <a href="https://en.wikipedia.org/wiki/Favicon">favicon</a> 的 node 中間層軟件(這是用於表示瀏覽器選項卡、書籤等網站內的圖標)。</li>
+</ul>
+
+<p>腳本部分,定義了一個“開始” "start" 腳本,當我們調用 <code>npm start</code> 來啟動服務器時,這就是我們所調用的腳本。從腳本定義中,您可以看到這實際上用 node 啟動了 JavaScript 文件 <strong>./bin/www</strong>。它還定義了一個“devstart” 腳本,我們在調用 <code>npm run devstart </code>時調用它。這將啟動相同的 <strong>./bin/www </strong>文件,但使用 nodemon 調用而不是 node 。</p>
+
+<pre class="brush: json notranslate"> "scripts": {
+ "start": "node ./bin/www",
+ "devstart": "nodemon ./bin/www"
+ },
+</pre>
+
+<h3 id="www_文件">www 文件</h3>
+
+<p>文件 <strong>/bin/www</strong> 是應用程序入口點!它做的第一件事是 <code>require()</code> “真正的” 應用程序入口點(即項目根目錄中的 app.js ),<strong>app.js </strong>會設置並返回 <code><a href="http://expressjs.com/en/api.html">express()</a></code>應用程序的對象。</p>
+
+<pre class="brush: js notranslate">#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+<strong>var app = require('../app');</strong>
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong> <code>require()</code> 是一個全局 node 函數,用於將模塊導入當前文件。這裡我們使用相對路徑指定 <strong>app.js</strong> 模塊,並省略可選的(<strong>.js</strong>)文件擴展名。</p>
+</div>
+
+<p>此文件中的其餘代碼,將設置一個node 運行的HTTP 服務器,並將應用app 設置為特定的端口(在環境變量中定義,如果變量未定義,則定義為3000),並開始監聽和報告服務器錯誤和連接。現在你並不需要知道代碼的其他內容(這個文件中的所有內容都是 “樣板文件” ),但如果你感興趣,可以隨時查看它。</p>
+
+<h3 id="app.js">app.js</h3>
+
+<p>此文件創建一個 <code>express</code> 應用程序對象(按傳統命名為 <code>app</code>),使用各種設置和中間件,以設置應用程序,然後從模塊導出應用程序。下面的代碼只顯示了文件的一部分,創建和導出應用程序對象的部分:</p>
+
+<pre class="brush: js notranslate"><code>var express = require('express');
+var app = express();
+...
+</code>module.exports = app;
+</pre>
+
+<p>回到上面的 <strong>www</strong> 入口點文件,它是在導入該文件時,提供給調用者的這個 <code>module.exports</code> 對象。</p>
+
+<p>讓我們詳細了解 <strong>app.js</strong> 文件。首先,我們使用 <code>require()</code>將一些有用的 node 庫導入到文件中,其中包括我們先前使用 NPM 為應用程序下載的 express,serve-favicon,morgan,cookie-parser 和body-parser;和path 庫,它是解析文件和目錄路徑的核心 node 庫。</p>
+
+<pre class="brush: js notranslate">var express = require('express');
+var path = require('path');
+var favicon = require('serve-favicon');
+var logger = require('morgan');
+var cookieParser = require('cookie-parser');
+var bodyParser = require('body-parser');
+</pre>
+
+<p>然後我們用 <code>require()</code>導入來自我們的路由目錄的模塊。這些模塊/文件包含用於處理特定的相關“路由”集合(URL路徑)的代碼。當我們擴展骨架應用程序,例如列出圖書館中的所有書籍時,我們將添加一個新文件,來處理與書籍相關的路由。</p>
+
+<pre class="brush: js notranslate">var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 此時我們剛剛導入了模塊;我們還沒有真正使用過它的路由(在文件的更下方一點將使用到路由)。</p>
+</div>
+
+<p>接下來,我們使用導入的 express 模塊​​,創建應用程序 <code>app</code> 對象,然後使用它來設置視圖(模板)引擎。引擎的設置有兩個部分。首先我們設置 '<code>views</code>' 值,來指定模板將被存儲的文件夾(在這種情況下是子文件夾<strong> /views</strong>)。然後我們設置 '<code>view engine</code>' 的值,來指定模板庫(在本例中為 “pug” )。</p>
+
+<pre class="brush: js notranslate">var app = express();
+
+// view engine setup
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'pug');
+</pre>
+
+<p>下一組函數調用 <code>app.use()</code>,將中間件的庫,添加到請求處理鏈中。除了我們之前導入的第三方庫之外,我們還使用 <code>express.static</code> 中間件,來使 Express 提供在項目根目錄下,<strong>/public</strong> 目錄中的所有靜態文件。</p>
+
+<pre class="brush: js notranslate">// uncomment after placing your favicon in /public
+//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
+app.use(logger('dev'));
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(cookieParser());
+<strong>app.use(express.static(path.join(__dirname, 'public')));</strong>
+</pre>
+
+<p>現在所有其他中間件都已設置完畢,我們將(先前導入的)路由處理代碼,添加到請求處理鏈中。導入的代碼,將為網站的不同部分定義特定路由:</p>
+
+<pre class="brush: js notranslate">app.use('/', indexRouter);
+app.use('/users', usersRouter);
+</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 上面指定的路徑 ('/' and '<code>/users</code>'),被視為定義在導入文件中的路由前綴。因此,例如,如果導入的用戶模塊 <strong>users</strong>為<code>/profile</code>定義了路由,則可以在 <code>/users/profile</code>中訪問該路由。我們將在後面的文章中,詳細討論路由。</p>
+</div>
+
+<p>文件中的最後一個中間件,為錯誤和 HTTP 404 響應添加了處理程序方法。</p>
+
+<pre class="brush: js notranslate">// catch 404 and forward to error handler
+app.use(function(req, res, next) {
+ var err = new Error('Not Found');
+ err.status = 404;
+ next(err);
+});
+
+// error handler
+app.use(function(err, req, res, next) {
+ // set locals, only providing error in development
+ res.locals.message = err.message;
+ res.locals.error = req.app.get('env') === 'development' ? err : {};
+
+ // render the error page
+ res.status(err.status || 500);
+ res.render('error');
+});
+</pre>
+
+<p>Express 應用程序對象(app)現已完全完成配置。最後一步,是將其添加到模塊導出(這允許它通過 <strong>/bin/www</strong> 導入)。</p>
+
+<pre class="brush: js notranslate">module.exports = app;</pre>
+
+<h3 id="路由">路由</h3>
+
+<p>路由文檔 <strong>/routes/users.js</strong> 如下所示(路由文件共享一個類似的結構,所以我們不需要也顯示 <strong>index.js</strong>)。首先加載 express 模塊​​,並使用它獲取<code> express.Router</code>對象。然後它在該對像上指定一個路由,最後從模塊中導出路由器(這就是允許將文件導入到 <strong>app.js</strong> 中的路由)。</p>
+
+<pre class="brush: js notranslate">var express = require('express');
+var router = express.Router();
+
+/* GET users listing. */
+<strong>router.get('/', function(req, res, next) {
+  res.send('respond with a resource');
+});</strong>
+
+module.exports = router;
+</pre>
+
+<p>該路由定義了一個回調,只要檢測到具有正確模式的HTTP <code>GET</code> 請求,就會調用該回調。匹配模式是模塊導入時指定的路由('<code>/users</code>'),加上('<code>/</code>')文件中定義的任何內容。換句話說,當收到<code>/users/</code>的 URL 時,將使用此路由。</p>
+
+<div class="note">
+<p><strong>提示:</strong> 嘗試運行帶有 node 的服務器,並在瀏覽器中訪問以下 URL: <a href="http://localhost:3000/users/">http://localhost:3000/users/</a>。您應該看到一條消息:'respond with a resource'。</p>
+</div>
+
+<p>上面有趣的事情是,回調函數有第三個參數 '<code>next</code>',因此是一個中間件函數,而不是簡單的路由回調。雖然代碼當前不使用 <code>next</code> 參數,但如果要在'<code>/</code>'根路由路徑中,添加多個路由處理程序,將來可能會有用。</p>
+
+<h3 id="視圖模板">視圖(模板)</h3>
+
+<p>視圖(模板)存儲在 <strong>/views</strong> 目錄中(如<strong> app.js</strong> 中指定的)並且被賦予文件擴展名<strong>.pug</strong>。方法 <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code>用於呈現指定的模板,以及在對像中傳遞的命名變量的值,然後將結果作為響應發送。在來自<strong> /routes/index.js </strong>的以下代碼中,您可以看到,該路由如何使用模板 "index" 傳遞模板變量 "title" ,以呈現響應。</p>
+
+<pre class="brush: js notranslate">/* GET home page. */
+router.get('/', function(req, res) {
+ res.render('index', { title: 'Express' });
+});
+</pre>
+
+<p>上面路由的相應模板在下面給出(<strong>index.pug</strong>)。我們稍後會詳細討論這個語法。您現在需要知道的是,標題變量 <code>title</code>(值為 '<code>Express</code>')將插入模板中指定的位置。</p>
+
+<pre class="notranslate">extends layout
+
+block content
+ h1= title
+ p Welcome to #{title}
+</pre>
+
+<h2 id="挑戰自己">挑戰自己</h2>
+
+<p>在 <strong>/routes/users.js </strong>中創建一個新路由,它將在 <code>/users/cool/</code>上顯示文本 “You're so cool”。通過運行服務器,並在瀏覽器中訪問 <a href="http://localhost:3000/users/cool/">http://localhost:3000/users/cool/</a> 來測試它。</p>
+
+<ul>
+</ul>
+
+<h2 id="總結">總結</h2>
+
+<p>你現在為 本地圖書館 創建了一個骨架網站項目,並且用 node 驗證了它能夠運行。最重要的,你也理解了項目的結構,因此你也明白了我們需要為本地圖書館加上路由和視圖。</p>
+
+<p>接下來我們將開始修改骨架,讓它能像一個圖書館網站一樣運作。</p>
+
+<h2 id="參閱">參閱</h2>
+
+<ul>
+ <li><a href="https://expressjs.com/en/starter/generator.html">Express application generator</a> (Express docs)</li>
+ <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p>
+
+
+
+<h2 id="本教程連結">本教程連結</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html b/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html
new file mode 100644
index 0000000000..6804ef3742
--- /dev/null
+++ b/files/zh-tw/learn/server-side/express_nodejs/tutorial_local_library_website/index.html
@@ -0,0 +1,91 @@
+---
+title: 'Express 教學 1: 本地圖書館網站'
+slug: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website
+translation_of: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</div>
+
+<p class="summary">我們實作教程系列的第一篇文章,會說明將學到什麼東西,並提供「本地圖書館」範例網站的概述 。我們將在接下來的文章中一步一步完成這個網站。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">前置條件:</th>
+ <td>閱讀 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express 介紹。</a> 在底下的教程,你將需要 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">架設一個 Node 開發環境。</a></td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>介紹本教程的範例應用,讓讀者理解包含哪些主題。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概覽">概覽</h2>
+
+<p>歡迎來到 MDN "本地圖書館" Express (Node) 教程,我們將開發一個網站,用於管理本地圖書館的目錄。</p>
+
+<p>本系列教程文章中,你將會:</p>
+
+<ul>
+ <li>使用 <em>Express 應用產生器工具,創建一個骨架網站與應用</em></li>
+ <li>起動和停止Node 網頁伺服器</li>
+ <li>使用數据庫存放應用的數据</li>
+ <li>創建路由用以要求不同的信息,創建模板 ("視圖") 以HTML的形式在瀏覽器中呈現數据</li>
+ <li>使用表單</li>
+ <li>部署應用到生產環境</li>
+</ul>
+
+<p>這些主題中,有一部分你可能已經學過了,或者曾經簡短的接觸過。在本列系教程的最後,你應該知道的夠多,能夠自己開發簡單的 Express 應用。</p>
+
+<h2 id="本地圖書館網站">本地圖書館網站</h2>
+
+<p><em>我們接下來將創建,並隨著本系列教程發展的網站,名字是本地圖書館。如同你的預測,此網站的目的,是為一間小型本地圖書館,提供一個線上目錄,使用者能夠瀏覽可取得的書本</em>,並管理他們的帳号。</p>
+
+<p>本範例經過細心地考慮,因為它的規模可以放大或縮小,以配合我們的需要,演示盡可能多或少的細節。並且可以用來演示幾乎所有的 Express 特性。更重要的,它允許我們提供一條引導路徑,演示你在任何網站都會需要的功能:</p>
+
+<ul>
+ <li>在教程一開始,我們將定義一個簡單的、只能瀏覽的圖書館,圖書館成員能夠用來找到可以借的書。這允許我們找出,幾乎每個網站都會使用的共同操作: 從數据庫讀取並呈現內容。</li>
+ <li>跟隨教程的進展,圖書館的例子會一步一步擴充,以演示更高級的網站特征。比如我們會擴充圖書館,允許新書能夠被創建,並用這個來演示如何使用表單,並支持使用者授權。</li>
+</ul>
+
+<p>即使這是一個具備相當擴充性的範例,它被叫做<strong>本地</strong>圖書館是有原因的 — 我們希望呈現給你最少的信息,能夠盡快幫助你上手並運行Express。因此,我們將會存放書本、複本、作者、和其它關鍵信息。然而,我們不會存放其它圖書館可能用到的有關信息,或者提供支持多個圖書館網站的架構,又或者其它 "大型圖書館" 的特性。</p>
+
+<h2 id="我被卡住了,哪裡可以得到原始碼">我被卡住了,哪裡可以得到原始碼?</h2>
+
+<p>當你使用本教程,我們將在每個知識點,提供適當的代碼片段,讓你複制貼上,同時有些代碼,我們希望你能自己擴充 (會有一些指引)。</p>
+
+<p>如果你被卡住了,你可以在 <a class="external external-icon" href="https://github.com/mdn/express-locallibrary-tutorial" rel="noopener">Github 的這裡</a>,找到本地圖書館網站已經開發完成的版本。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 在本教程中,指定版本的 node、Express、還有其它模組,都經過測試,並列出在專案項目的 <a class="external external-icon" href="https://github.com/mdn/express-locallibrary-tutorial/blob/master/package.json" rel="noopener">package.json</a> 檔案中。</p>
+</div>
+
+<h2 id="總結Edit">總結<a class="button section-edit only-icon" href="https://developer.mozilla.org/zh-CN/docs/learn/Server-side/Express_Nodejs/Tutorial_local_library_website$edit#總結" rel="nofollow, noindex"><span>Edit</span></a></h2>
+
+<p>現在,你對本地圖書館網站以及將要學習的東西,有更多一點的認識,是時候開始創建一個 <a href="https://developer.mozilla.org/zh-TW/docs/Learn/Server-side/Express_Nodejs/skeleton_website">骨架項目</a>,以存放我們的範例。</p>
+
+<p> </p>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</p>
+
+<p> </p>
+
+<p> </p>
+
+<h2 id="本系列教學">本系列教學</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/zh-tw/learn/server-side/first_steps/index.html b/files/zh-tw/learn/server-side/first_steps/index.html
new file mode 100644
index 0000000000..2afd7bb1d4
--- /dev/null
+++ b/files/zh-tw/learn/server-side/first_steps/index.html
@@ -0,0 +1,41 @@
+---
+title: 伺服器端程式設計起步走
+slug: Learn/Server-side/First_steps
+translation_of: Learn/Server-side/First_steps
+---
+<div>{{LearnSidebar}}</div>
+
+<p>在我們的伺服器端程式設計模組內,我們會回答一些關於伺服器端編程的問題──「那是什麼?」、「它和用戶端程式設計有何不同?」、還有「為什麼它有用?」。接著,我們會比較各大熱門框架、並佐以一些如何選擇最適合框架的指引。最後,我們還會提供關於伺服器安全的進階介紹性文章。</p>
+
+<p>(譯者 iigmir 註:你可能常常聽到網路開發有前端與後端。在網路開發的脈落下,這裡講的伺服器端程式設計,就是俗稱的後端。)</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>在開始本模組前,你不需要擁有任何與伺服器端、或其他種類的程式設計相關知識。</p>
+
+<p>你必須知道「網路如何運作」。關於此,我們推薦以下主題:</p>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/What_is_a_web_server">何謂網路伺服器</a></li>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/What_software_do_I_need">我需要什麼軟體來建立網站?</a></li>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/Upload_files_to_a_web_server">如何把檔案上傳到網路伺服器?</a></li>
+</ul>
+
+<p>有了基本理解後,你就可以透過本章節的模組來完成工作。</p>
+
+<h2 id="指引">指引</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/First_steps/Introduction">介紹伺服器端</a></dt>
+ <dd>歡迎來到 MDN 初學者的伺服器端程式設計課程!在這首篇文章中,我們將以很高的角度回答諸如「這是什麼?」、「它和用戶端程式設計有何不同?」、還有「為什麼它有用?」之類的問題。讀完以後,你會明白很多關於伺服器端程式設計的知識。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/First_steps/Client-Server_overview">用戶端概覽</a></dt>
+ <dd>現在你知道了伺服器端程式設計的目標與益處,而我們現在要檢驗一些細節:當伺服器從瀏覽器那邊收到「動態請求」的時候,究竟發生了什麼事。因為大多數網站都用相近的方法處理請求與回應,所以這一點會幫助你理解自己在撰寫程式碼的時候要幹什麼。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/First_steps/Web_frameworks">伺服器端網路框架</a></dt>
+ <dd>最後一篇文章介紹了伺服器端網路程式,為了回應來自瀏覽器的請求,究竟需要些什麼。現在,我們會告訴你網路框架如何簡化那些工作,並幫助你選定自己的第一個網路程式,要用上什麼樣的框架。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/First_steps/Website_security">網站安全</a></dt>
+ <dd>網站安全,有賴網頁設計時的高度警覺。這篇概要性的文章不是要讓你變成網站安全大神,而是幫你理解在強化網路程式免受大多數威脅時,第一要務為何。</dd>
+</dl>
+
+<h2 id="評估">評估</h2>
+
+<p>這份「概覽」模組不做任何評估,因為我們還沒有給你看過任何程式碼。我們希望到了這裡,你可以對伺服器端程式設計能提供什麼東西,有者良好的理解;我們也希望你能在建立第一個網站時要用什麼框架的方面,能夠下好決定。</p>
diff --git a/files/zh-tw/learn/server-side/first_steps/介紹/index.html b/files/zh-tw/learn/server-side/first_steps/介紹/index.html
new file mode 100644
index 0000000000..a0919697ee
--- /dev/null
+++ b/files/zh-tw/learn/server-side/first_steps/介紹/index.html
@@ -0,0 +1,225 @@
+---
+title: 伺服器端的介紹
+slug: Learn/Server-side/First_steps/介紹
+translation_of: Learn/Server-side/First_steps/Introduction
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</div>
+
+<p class="summary"><span class="seoSummary">歡迎來到MDN伺服器端程式設計的初學者課程 !在第一篇文章中,我們會用較為抽象的角度來探討 server-side programming,並且為你解答「這是什麼?」「這個和用戶端的程式有什麼不同?」以及「這個有什麼用?」 。在讀完這篇文章後,你將能明白如何透過 server-side coding 來為你的網站增添力量。</span></p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決條件:</th>
+ <td>基本電腦知識、對網路伺服器有基本了解。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>認識伺服器端的程式設計、它可以做什麼、它和用戶端的程式有什麼不一樣?</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>大多數的大型網站使用伺服器端程式(server-side code)來動態地顯示各種所需的資料,普遍的做法為從伺服端的資料庫中取出資料,並送至用戶端,再透過一些 code 來顯示它們(例如:HTML 與 JavaScript)。</p>
+
+<p>也許,使用伺服器端程式的最大好處是為不同的瀏覽者量身打造網頁內容。動態網站根據使用者的偏好設定及興趣提供更為相關的內容,也可以儲存個人設定及資訊讓網站更易於使用 — 例如重複使用已儲存的信用卡資料來使付款流程更為順暢。</p>
+
+<p>它也能讓網站透過信件或其他方式來和使用者互動,如發送通知與更新。這一切的一切都讓網站更能牢牢抓住使用者的心。</p>
+
+<h2 id="何謂伺服器端網站程式開發?">何謂伺服器端網站程式開發?</h2>
+
+<p>網頁瀏覽器使用超文本傳輸協定(<strong>H</strong>yper<strong>T</strong>ext <strong>T</strong>ransfer <strong>P</strong>rotocol, {{glossary("HTTP")}})與網頁伺服器(<a href="/zh-TW/docs/Learn/Common_questions/What_is_a_web_server">web servers</a>)溝通。當您點選網頁上的連結、送出表單,或者執行搜尋,一段<strong> HTTP 請求</strong>(<strong>request</strong>)會由您的瀏覽器送至目標伺服器。</p>
+
+<p>該請求(request)包含一個用來指定受影響資源的 URL、一個定義行為的請求方法(例如對資源進行get、delete或post)與當進行<a href="/zh-TW/docs/Web/HTTP/Methods/POST">HTTP POST方法</a>時可能包含編碼於URL參數中的額外資訊(經由一段<a href="https://en.wikipedia.org/wiki/Query_string">查詢字串</a>送出的各個鍵值對),或是在關聯的{{glossary("Cookie", "cookies")}}中。</p>
+
+<p>網頁伺服器等待用戶端的請求訊息、獲得後處理它們,並以一個<strong>HTTP回應</strong>(<strong>response</strong>)訊息回覆至網頁瀏覽器。該回應包含一個狀態訊息說明本次請求是否達成(例如:"HTTP/1.1 200 OK"表示成功)。</p>
+
+<p>成功對應於一個請求的回應主體(response body)應包含請求的資源(例如:一份新的HTML頁面或一張圖片等),這些可能將被用來顯示在網頁瀏覽器中。</p>
+
+<h3 id="靜態網站">靜態網站</h3>
+
+<p>以下的靜態網站(static site)圖展示一個基本的網頁伺服器架構,其中靜態網站意謂當無論何時有個特定資源的請求,伺服器始終回傳相同的硬編碼內容(hard-coded content)。當一個使用者想要引導到一個網頁時,瀏覽器送出的HTTP "GET" 請求指的就是該資源的URL。</p>
+
+<p>此伺服器從它的檔案系統取回被請求的文件,並回傳一個包含此文件以及<a href="/zh-TW/docs/Web/HTTP/Status#成功回應">成功狀態碼</a>(通常為200 OK)的HTTP回應。若檔案因某些原因無法被取回,則回傳一個錯誤狀態(參見 <a href="/zh-TW/docs/Web/HTTP/Status#用戶端錯誤回應">用戶端錯誤回應</a> 與 <a href="/zh-TW/docs/Web/HTTP/Status#伺服器端錯誤回應">伺服器端錯誤回應</a>)。</p>
+
+<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png" style="height: 223px; width: 800px;"></p>
+
+<h3 id="動態網站">動態網站</h3>
+
+<p>一個動態網站的回應內容是當需要時<em>動態</em>產生的。在一個動態網站的HTML網頁通常是經由資料庫取得並插入資料至HTML範本的佔位符(placeholders)中而創造出來(相較於靜態網站,這對於儲存大量內容而言,這是一種相當有效率的做法)。 </p>
+
+<p>一個動態網站可以根據使用者或已存偏好設定提供的URL資訊回傳不同的資料,也可以以其他的作用方式呈現回應(例如:發送通知)。</p>
+
+<p>用來支援一個動態網站的大部分的程式碼必須在伺服器執行。建立程式碼的方式稱為"<strong>伺服端程式設計(server-side programming)</strong>"或"<strong>後端腳本(back-end scripting)</strong>"。</p>
+
+<p>下圖為<em>動態網站</em>(<em>dynamic website</em>)的基本架構。如同先前的圖說,瀏覽器發送HTTP請求至伺服器,接著伺服器處理請求後,回傳合適的HTTP回應。</p>
+
+<p>對於<em>靜態</em>資源的請求處理方式如同靜態網站的方式(靜態資源為任何不會改變的檔案 — 通常為CSS、JavaScript、圖片、預產生的PDF檔案等)。 </p>
+
+<p><img alt="A simplified diagram of a web server that uses server-side programming to get information from a database and construct HTML from templates. This is the same diagram as is in the Client-Server overview." src="https://mdn.mozillademos.org/files/13839/Web%20Application%20with%20HTML%20and%20Steps.png"></p>
+
+<p>對於動態資源的請求方式則為轉送(2)至伺服端程式碼(如圖中的<em>網頁應用程式 Web Application</em>)。對於"動態請求",伺服器解釋該請求、從資料庫讀取所需資訊(3)、與HTML範本結合取得的資料(4),最後送回一個包含已產生HTML的回應(5,6)。</p>
+
+<div>
+<h2 id="伺服端與用戶端程式設計是相同的嗎?">伺服端與用戶端程式設計是相同的嗎?</h2>
+</div>
+
+<p>讓我們把注意力集中在伺服端與用戶端的程式設計吧!在以下的每個案例中,程式碼完全不一樣:</p>
+
+<ul>
+ <li>他們有不同的目的與考量。</li>
+ <li>一般而言,他們不使用相同的程式語言(除了JavaScript可以使用在伺服端與用戶端以外)。</li>
+ <li>他們在不同的作業系統環境下執行。</li>
+</ul>
+
+<p>執行在瀏覽器的程式碼被稱為<strong>用戶端程式碼</strong>(<strong>client-side code</strong>),它主要用來改善一個渲染的網頁外觀與行為。這包含選取與設定UI元件樣式、建立佈局、導覽、表格驗證等。相對的,伺服端網站程式設計大量涉及要回傳<em>哪些內容</em>給瀏覽器做為對請求的回應。伺服端程式碼處理驗證已提交的資料與請求、使用資料庫儲存及取得資料,和按需求發送正確的資料給用戶等任務。</p>
+
+<p>用戶端程式碼以<a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>與<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a>撰寫 — 它執行在網頁瀏覽器內,並且僅有或無訪問底層的作業系統(包含對檔案系統的有限存取)。</p>
+
+<p>網頁開發者不能控制使用者可能使用何種瀏覽器來檢視一個網站 — 瀏覽器與用戶端程式有著不同層度的相容性,並且用戶端程式的挑戰之一是如何妥善地處理瀏覽器支援的差異。</p>
+
+<p>伺服端程式碼可以為任何程式語言 — 例如有名的伺服端網頁語言包括PHP、Python、Ruby、C#與NodeJS(JavaScript)。該伺服端程式碼擁有完整的作業系統存取權限,而且開發者能夠選擇他們想要的程式語言(以及特定版本)。</p>
+
+<p>開發者們通常使用<strong>網頁框架</strong>(<strong>web frameworks</strong>)撰寫程式碼。網頁框架為功能函式、物件、規則與其他程式碼的集合,旨在解決常見問題、加速開發並簡化在特定域中面臨到的不同類型的任務。</p>
+
+<p>再者,儘管用戶端與伺服端程式碼都使用框架,但會因為非常不同的域,而使得框架也不同。用戶端網頁框架簡化佈局與呈現的任務,而伺服端網頁框架則提供大量"通用"的網頁伺服器功能,否則你可能必須要自己實現(例如:對sessions的支援、對使用者認證的支援、簡易資料庫存取、樣板庫等)。</p>
+
+<div class="note">
+<p><strong>Note</strong>: Client-side frameworks are often used to help speed up development of client-side code, but you can also choose to write all the code by hand; in fact, writing your code by hand can be quicker and more efficient if you only need a small, simple web site UI.</p>
+
+<p>In contrast, you would almost never consider writing the server-side component of a web app without a framework — implementing a vital feature like an HTTP server is really hard to do from scratch in say Python, but Python web frameworks like Django provide one out of the box, along with other very useful tools.</p>
+</div>
+
+<div>
+<h2 id="在伺服端,你能做什麼?">在伺服端,你能做什麼?</h2>
+
+<p>伺服端程式設計是非常有用的,因為它讓我們有效地遞送替單個使用者量身訂做的資訊,從而創造更棒的使用者體驗。</p>
+</div>
+
+<p>如Amazon這樣的公司使用伺服端程式設計來建構產品搜尋結果、根據顧客偏好與過往購物習慣提供針對性的產品建議、簡化購物過程等。</p>
+
+<p>銀行使用伺服端程式設計來儲存帳號資訊,並讓已授權用戶檢視與進行交易。其他服務如Facebook、Twitter、Instagram與Wikipedia使用伺服端程式設計來突顯、分享與控制使用者存取到感興趣的內容。</p>
+
+<p>一些常見的伺服端程式設計使用案例與效益列舉如下。您將會注意到這當中會有些重疊的部分!</p>
+
+<h3 id="高效率資訊儲存與遞送">高效率資訊儲存與遞送</h3>
+
+<p>想像一下,在Amazon可以找到多少產品,或者說在Facebook上有多少文章?對各個產品或文章建立各別的靜態網頁完全是不切實際的。</p>
+
+<p>伺服端程式設計反而是可以讓我們將資訊儲存至資料庫,並且動態建構及回傳HTML與其他型態的檔案(例如:PDF、圖片等)。它也可以藉由合適的用戶端網頁框架(利用這個方式可以降低在伺服器的處理負擔,亦減少需要被送出的大量資料)僅回傳資料({{glossary("JSON")}}、{{glossary("XML")}}等)來進行畫面渲染。</p>
+
+<p>伺服器並不侷限於從資料庫發送資訊,還可以回傳軟體工具的結果或是來自通訊服務的資料。這些內容甚至可以針對到收到它的用戶裝置類型。</p>
+
+<p>由於資訊存在於資料庫中,它可以輕易地與其他商業系統進行分享與更新(例如:當產品在線上或在店家中售完,店家可能會更新該產品的庫存資料庫)。</p>
+
+<div class="note">
+<p><strong>Note</strong>: Your imagination doesn't have to work hard to see the benefit of server-side code for efficient storage and delivery of information:</p>
+
+<ol>
+ <li>Go to <a href="https://www.amazon.com">Amazon</a> or some other e-commerce site.</li>
+ <li>Search for a number of keywords and note how the page structure doesn't change, even though the results do. </li>
+ <li>Open two or three different products. Note again how they have a common structure and layout, but the content for different products has been pulled from the database.</li>
+</ol>
+
+<p>For a common search term ("fish", say) you can see literally millions of returned values. Using a database allows these to be stored and shared efficiently, and it allows the presentation of the information to be controlled in just one place.</p>
+</div>
+
+<h3 id="客製化的使用者體驗">客製化的使用者體驗</h3>
+
+<p>伺服器能保存及使用關於用戶的資訊,來提供一個方便且量身訂做的使用者體驗。例如,許多網站儲存信用卡資料讓這些資料無須再重新輸入。網站如Google Maps能使用已儲存或目前位置來提供導航資訊與搜尋或旅行歷史紀錄,以便於搜尋結果中突顯在地店家。</p>
+
+<p>一個使用者習慣更深層的分析,可以使用在預測他的興趣以及更進一步客製回應與提醒,例如在地圖中提供你可能想去看得過去遊歷過的或是熱門的地點列表。</p>
+
+<div class="note">
+<p><strong>Note: </strong><a href="https://maps.google.com/">Google Maps</a> saves your search and visit history. Frequently visited or frequently searched locations are highlighted more than others.</p>
+
+<p>Google search results are optimized based on previous searches.</p>
+
+<ol>
+ <li> Go to <a href="https:\\google.com">Google search</a>.</li>
+ <li> Search for "football".</li>
+ <li> Now try typing "favourite" in the search box and observe the autocomplete search predictions.</li>
+</ol>
+
+<p>Coincidence? Nada!</p>
+</div>
+
+<h3 id="控制內容存取">控制內容存取</h3>
+
+<p>伺服器端程式設計允許網站限制僅能由已授權的使用者存取,並提供資訊給那些只被允許觀看的使用者。</p>
+
+<p>真實世界案例包括:</p>
+
+<ul>
+ <li>社交網路如Facebook允許使用者全權控制他們自己的資料,但是只有允許他們的朋友檢視或評論資料。該使用者決定誰能看到他們的資料,並推廣到他們的動態中會呈現誰的資料 —  授權是使用者體驗的核心部分!</li>
+ <li>
+ <p>你正所在的網站控制內容的存取:文章可被任何人看見,但是只有使用者登入才能編輯該內容。若要試試看,點擊本頁面上方的<strong>編輯</strong>按鈕 — 如果你已登入,你將會顯示編輯視窗;如果你沒有登入,你將會被導到註冊頁面。</p>
+ </li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: Consider other real examples where access to content is controlled. For example, what can you see if you go to the online site for your bank? Log in to your account — what additional information can you see and modify? What information can you see that only the bank can change?</p>
+</div>
+
+<h3 id="儲存sessionstate資訊">儲存session/state資訊</h3>
+
+<p>伺服器端程式設計允許開發者利用<strong>sessions</strong> — 基本上,就是一個機制讓伺服器儲存目前的使用者資訊,並且基於這些資訊發送不同的回應。</p>
+
+<p>例如,這允許網站了解一個使用者先前已登入過,以及將訂購歷史紀錄在他們的電子郵件中顯示連結,或者也許會儲存一個基本的遊戲狀態,讓使用者能再次回到網站的同時,拿回他們留在網站的資訊。</p>
+
+<div class="note">
+<p><strong>Note</strong>: Visit a newspaper site that has a subscription model and open a bunch of tabs (e.g. <a href="http://www.theage.com.au/">The Age</a>). Continue to visit the site over a few hours/days. Eventually, you will start to be redirected to pages explaining how to subscribe, and you will be unable to access articles. This information is an example of session information stored in cookies.</p>
+</div>
+
+<h3 id="提醒與溝通">提醒與溝通</h3>
+
+<p>伺服器能透過網站本身或經由電子郵件、SMS、即時通訊、影像或其他通訊服務,發送提醒訊息給一般或特定使用者。</p>
+
+<p>一些範例包括:</p>
+
+<ul>
+ <li>Facebook與Twitter發送電子郵件與SMS訊息等新的通訊來提醒你。</li>
+ <li>Amazon定期發送產品電子郵件來提供相近於曾經已購買或你可能有興趣瀏覽的產品。</li>
+ <li>一個網頁伺服器可能會發送警告訊息給網站管理員,以警示伺服器的記憶體過低或有嫌疑的使用者型為。</li>
+</ul>
+
+<div class="note">
+<p><strong>Note</strong>: The most common type of notification is a "confirmation of registration". Pick almost any large site that you are interested in (Google, Amazon, Instagram, etc.) and create a new account using your email address. You will shortly receive an email confirming your registration, or requiring acknowledgment to activate your account.</p>
+</div>
+
+<h3 id="資料分析">資料分析</h3>
+
+<p>一個網站可能會收集很多包括使用者的資料:他們所搜尋的、他們所買的、他們所推薦的、他們在每個網頁停留的時間。伺服器端程式設計能根據資料分析以完善回應。</p>
+
+<p>例如,Amazon與Google都根據過往搜尋(與購買)紀錄來廣告產品。</p>
+
+<div class="note">
+<p><strong>Note</strong>: If you're a Facebook user, go to your main feed and look at the stream of posts. Note how some of the posts are out of numerical order - in particular, posts with more "likes" are often higher on the list than more recent posts.</p>
+
+<p>Also look at what kind of ads you are being shown — you might see ads for things you looked at on other sites. Facebook's algorithm for highlighting content and advertising can be a bit of a mystery, but it is clear that it does depend on your likes and viewing habits!</p>
+</div>
+
+<h2 id="總結">總結</h2>
+
+<p>恭喜,你已經到達關於伺服器端程式設計的第一篇文章的結尾。 </p>
+
+<p>現在你已經學到伺服器端程式碼運作於網頁伺服器,他的主要任務是控制<em>哪些</em>資訊要發送給使用者(而用戶端程式碼主要掌握資料的結構與呈現給使用者)。</p>
+
+<p>你也應該了解這是很有用的,當你身為伺服器端開發者時,因為它允許我們創建<em>有效</em>散播客製訊息與有些你可能會去做的好點子給單個使用者的網站。</p>
+
+<p>最後,你應該了解伺服器端程式碼可以用很多種程式語言來撰寫,以及你應該使用網頁框架來讓整個程序變得更簡便。 </p>
+
+<p>在未來的文章,我們將協助你選擇最佳的網頁框架,做為你的第一個網站;接著,我們將帶你更詳細了解主要的用戶端-伺服端的互動。</p>
+
+<p>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li>
+</ul>
diff --git a/files/zh-tw/learn/server-side/index.html b/files/zh-tw/learn/server-side/index.html
new file mode 100644
index 0000000000..c62f4e8aba
--- /dev/null
+++ b/files/zh-tw/learn/server-side/index.html
@@ -0,0 +1,59 @@
+---
+title: 伺服端網站程式設計
+slug: Learn/Server-side
+tags:
+ - Beginner
+ - CodingScripting
+ - Intro
+ - Landing
+ - Learn
+ - NeedsTranslation
+ - Server
+ - Server-side programming
+ - Topic
+ - TopicStub
+translation_of: Learn/Server-side
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary"><strong><em>動態網站</em></strong>–<em><strong>伺服端網站程式設計</strong></em>是一連串有關如何建立動態網站的模塊:動態網站可以針對 HTTP 請求,發送客製化的資訊。這些模塊將介紹伺服端網站程式設計:還有以初學者的角度,來教你怎麼使用 Django (Python) 與 Express (Node.js/JavaScript) 來架設基本的動態網路程式。</p>
+
+<p>大多數主流網站會使用伺服端技術,以根據需要呈現動態資料。例如說,來想想亞馬遜(Amazon)上架多少商品、還有臉書(Facebook)貼了多少動態。如果都用靜態頁面來呈現這些內容,開發就會毫無效率可言。因此,我們會使用靜態技術(<a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a>)來顯示靜態模板;並在需要時,動態更新模板內的資料。一如你在逛亞馬遜時,看著五花八門的產品一般。</p>
+
+<p>在當今的 Web development 的世界,我們強烈建議學習怎麼開發伺服端網站程式。</p>
+
+<h2 id="學習路徑">學習路徑</h2>
+
+<p>學習伺服端網站程式設計通常比用戶端網站程式設計簡單,因為動態網站比較傾向執行多次相似的操作(像是從資料庫擷取資料並放到頁面上、驗證用戶輸入的資料並存到資料庫、檢查登入用戶權限之類的)、使用框架建立網站能讓上述操作、以及其他常見操作變得簡單許多。</p>
+
+<p>基本的程式概念(或是理解特定的語言)會很有用,但不是必須的。同樣地,精於用戶端網站程式設計不是必須,但它能在前端開發時,幫你做得更好。</p>
+
+<p>首先你要知道「web 是怎麼作動的」。我們建議先看看這些文章:</p>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/What_is_a_web_server">何謂網路伺服器?</a></li>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/What_software_do_I_need">建立網站需要什麼軟體?</a></li>
+ <li><a href="/zh-TW/docs/Learn/Common_questions/Upload_files_to_a_web_server">如何把檔案傳到伺服器?</a></li>
+</ul>
+
+<p>有了基本觀念後,就可以開始去學習模塊章節的東西了。</p>
+
+<h2 id="模塊">模塊</h2>
+
+<p>本章節包含了以下模塊。你首先要從第一個模塊開始,再循序漸進,學習接下來的模塊。這些模塊將告訴你如何與訪間最熱門的其中兩個伺服器端框架共事。</p>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/First_steps">伺服器端程式設計起步走</a></dt>
+ <dd>本模塊會提供與技術無關的伺服器資訊,像是「那什麼?」、「和用戶端有啥不同?」、「有用嗎?」之類的。本模塊也會概述一些比較熱門的伺服器端 web 框架、並告訴你如何選擇。最後,我們還會概述有關伺服器服務的安全性問題。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Django">Django 網站框架 (Python)</a></dt>
+ <dd>Django 以 Python 寫成,是個非常熱門的伺服器端 web 框架。本模塊會講解 Django 是好框架的理由、如何建立開發環境、還有如何處理常見工作。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Express_Nodejs">Express web framework (Node.js/JavaScript)</a></dt>
+ <dd>Express 以 JavaScript 寫成、並在 node.js 執行環境執行。它也是個非常熱門的伺服器端 web 框架。本模塊會講解一些有關本框架的重要優點、也同樣會講解如何建立開發環境、還有如何處理常見工作。</dd>
+</dl>
+
+<h2 id="參見">參見</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Server-side/Node_server_without_framework">不用框架的 Node 伺服器</a></dt>
+ <dd>如果不想用框架的話,這篇文章會告訴你如何使用純 Node.js 提供簡易的靜態檔案。</dd>
+</dl>
diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html
new file mode 100644
index 0000000000..89c677beac
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/index.html
@@ -0,0 +1,130 @@
+---
+title: 理解 JavaScript 前端框架
+slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks
+translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">JavaScript 框架在前端開發佔有重要的地位:它能讓前端工程師透過千錘百鍊的工具,建立擴展性高、互動性強的網路程式。多數公司也視 JavaScript 框架為重要的前端工具。因此多數前端工程師,會需要擁有前端框架的技能。</p>
+
+<p class="summary">身為一位富有抱負的前端工程師,學習前端框架時,可能很難確定要從哪裡開始:五花八門的框架可供選擇、隨時還有新的框架出現。儘管大多數框架用途類似,但實作方法千變萬化。而在使用框架時,也需要考慮無數情形。</p>
+
+<p class="summary">在這裡,我們旨在理解前端框架方面,提供舒適的學習曲線:我們不會詳細說明 React/ReactDOM 或 Vue 亦或其他特定框架的資訊。框架開發團隊早就針對這方面,寫出了詳細的文件。相反地,我們想先著重回答更基本的問題:</p>
+
+<ul>
+ <li class="summary">為什麼要用框架?它能解決什麼問題?</li>
+ <li class="summary">選用框架時要考慮哪些問題?或甚至,我需要框架嗎?</li>
+ <li class="summary">框架擁有什麼功能?一般來說他們怎麼作動,或實作方面有哪些不同?</li>
+ <li class="summary">這些框架與「Vanilla JavaScript」(譯註:Vanilla JavaScript 是指原生 JavaScript)或 HTML 有什麼關係?</li>
+</ul>
+
+<p class="summary">之後,我們將針對坊間主要框架提供教學,以便提供足夠鑽研下去的背景資訊。我們希望以務實且不忘基本實做(如無障礙)的方法,來理解框架這回事。</p>
+
+<p class="summary"><strong><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">從「前端框架簡介」開始吧。</a></strong></p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>在理解前端框架前,你需要對 web 核心技術:<a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、以及最重要的<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a>,擁有基本程度的理解。</p>
+
+<p>如果理解構建框架的 Web 技術,你的程式會更豐富(richer)且更專業,同時也能更有信心地除錯。</p>
+
+<h2 id="概觀性教學">概觀性教學</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">1. 前端框架介紹</a></dt>
+ <dd>我們從整體概述來探討框架、提供 JavaScript 與框架的簡要歷史、框架存在的理由、他們提供什麼東西、如何決定選擇哪個框架、以及前端框架的的替代方案。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">2. 框架的主要功能</a></dt>
+ <dd>大多數主要的 JavaScript 前端框架在更動 DOM、處理瀏覽器事件、還有提供良好的開發體驗方面,使出了不同的方法。這篇文章將探討「四大框架」的主要功能、看看他們如完成高層次工作、以及這四個框架的相異之處。</dd>
+</dl>
+
+<h2 id="React_教學">React 教學</h2>
+
+<div class="blockIndicator note">
+<p><strong>注</strong>:最近一次測試成功的 React 教學在 2020 年五月。版本為 React/ReactDOM 16.13.1 與 create-react-app 3.4.1。</p>
+
+<p>如果想看看最新的程式,可以從我們的 <a href="https://github.com/mdn/todo-react">todo-react repository</a> 或互動性的 <a href="https://mdn.github.io/todo-react-build/">https://mdn.github.io/todo-react-build/</a> 看。</p>
+</div>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">1. 開始學 React</a></dt>
+ <dd>在這裡我們將開始與 React 打招呼。我們將探索其背景和用途的一些細節、在自己的電腦建立 React 全家桶、還有建立與把玩簡單的程式,以理解 React 是怎麼跑的。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">2. 建立我們的 React todo list</a></dt>
+ <dd>我們的任務是驗證 React 的概念(proof-of-concept):我們將建立一個能讓使用者添加、編輯、刪除需要的工作,同時在不刪除工作的情況下,將它們標記為完成。本文將完成 <code>App</code> 組件的基本架構與樣式,以便為下個文章將探討的組件定義與響應性做準備。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">3. 把 React app 組件化</a></dt>
+ <dd>現在,我們的 app 整個黏在一起了。在做其他事情前,最好把這個程式切成一個個能管理,描述性也好的組件(component)。React 本身對組件的定義不多:那是取決於你的考量!我們將展示如何以聰明的方法,把程式切成一個個組件。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">4. 響應性 React:事件與狀態</a></dt>
+ <dd>在組件化以後,現在開始把原本靜態的 UI,能開始與我們實際互動,並修改資料吧。在這裡除了做這件事以外,我們還會深入探討事件和狀態。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">5. 響應性 React:編輯、過濾、條件式過濾</a></dt>
+ <dd>在初學 React 之路即將結束前(至少從現在來說),我們將在 Todo list app 裡面,添加畫龍點睛的主要功能:包括編輯已存在的工作、透過給定條件過濾全部、已完成、或未完成的工作。我們將不斷探討條件式 UI 渲染。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">6. React 無障礙</a></dt>
+ <dd>在教學最後,我們將削除最後的障礙:像是能增進可用性,同時降低鍵盤與螢幕報讀用戶困惑的 focus 管理。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">7. React 的資源</a></dt>
+ <dd>最後的最後,我們將提供鑽研 React 所需的資源。</dd>
+</dl>
+
+<h2 id="Ember_教學">Ember 教學</h2>
+
+<div class="blockIndicator note">
+<p><strong>注</strong>:最近一次測試成功的 Ember 教學在 2020 年五月。版本為 Ember/Ember CLI 3.18.0。</p>
+
+<p>如果想看看最新的程式,可以從我們的 <a href="https://github.com/NullVoxPopuli/ember-todomvc-tutorial/tree/master/steps/00-finished-todomvc/todomvc">ember-todomvc-tutorial repository</a> 或互動性的 <a href="https://nullvoxpopuli.github.io/ember-todomvc-tutorial/">https://nullvoxpopuli.github.io/ember-todomvc-tutorial/</a> 看。注意:部分功能沒有放在教學裡面。</p>
+</div>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">1. 開始學 Ember</a></dt>
+ <dd>首先我們將探討 Ember 的原理與用途,還有如何安裝 Ember 全家桶,建立簡單的 app,最後還有完成開發環境。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">2. Ember app 架構與組件</a></dt>
+ <dd>In this article we'll get right on with planning out the structure of our TodoMVC Ember app, adding in the HTML for it, and then breaking that HTML structure into components.</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">3. 響應性 Ember:事件、類別、狀態</a></dt>
+ <dd>此時,我們將開始給 app 添加一些響應性,從而能夠添加和顯示新的待辦事項。在此過程中,我們將研究如何在 Ember 中使用事件,創建組件類以包含用於控制交互功能的 JavaScript 程式,以及設置服務來跟踪應用程序的資料狀態。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">4. 響應性 Ember:Footer 功能、條件式渲染</a></dt>
+ <dd>現在是時候開始處理我們應用程序中的 Footer 功能了。在這裡,我們將更新待辦事項計數器,以顯示仍需完成的正確待辦事項數量,並將樣式正確應用於已完成待辦事項(即已選中復選框的位置)。我們還將連接「清除完成」按鈕。在此過程中,我們將學習在模板中使用條件式渲染的知識。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">5. Ember 的路由</a></dt>
+ <dd>在本文中,我們學習了路由,有時也稱為基於 URL 的過濾。我們將使用它為三個Todo視圖(「全部」、「活動」、「已完成」)中的每個視圖提供唯一的 URL。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">6. Ember 的資源與除錯</a></dt>
+ <dd>最後的最後,我們將提供鑽研 Ember 所需的資源,以及好用的相關資訊。</dd>
+</dl>
+
+<h2 id="Vue_教學">Vue 教學</h2>
+
+<div class="blockIndicator note">
+<p><strong>注</strong>:最近一次測試成功的 Vue 教學在 2020 年五月。版本為 Vue 2.6.11。</p>
+
+<p>如果想看看最新的程式,可以從我們的 <a href="https://github.com/mdn/todo-vue">todo-vue repository</a> 或互動性的 <a href="https://mdn.github.io/todo-vue/dist/">https://mdn.github.io/todo-vue/dist/</a> 看。</p>
+</div>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">1. 開始學 Vue</a></dt>
+ <dd>我們首先來介紹 Vue 吧。首先我們將聊聊 Vue 的背景、理解如何安裝新的專案、研究專案的整體架構與單一組件、如何讓專案在自己的電腦執行、並準備好建立一個新範例。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">2. 建立第一個 Vue 組件</a></dt>
+ <dd>現在來開始鑽研 Vue 並建立第一個組件吧:我們將給 todo list 的各個單元建立獨立的組件。在此同時,我們將學習一些重要概念:比如說在組件內使用組件、透過 prop 傳送資料、還有儲存資料的狀態。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">3. 渲染 Vue 組件的列表</a></dt>
+ <dd>現在我們已經有了一個能動的組件;現在將要給我們的 App 添加 <code>ToDoItem</code> 這個組件了。在這裡,我們將專精於如何給 <code>App.vue</code> 組件,添加一組 todo 的資料,接著使用 <code>v-for</code> 指令(directive)讓 <code>ToDoItem</code> 透過迴圈顯示出來。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">4. 寫一個 todo 表單:Vue 的事件、方法、model</a></dt>
+ <dd>我們已經放了一些資料,同時也透過迴圈把 <code>ToDoItem</code> 渲染出來了。接下來,我們將讓使用者輸入 todo 項目、同時需要文字 <code>&lt;input&gt;</code>、submit 之後的事件觸發、還有能控制資料的 model。這些就是我們會探討的重點。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">5. 透過 CSS 樣式化 Vue 組件</a></dt>
+ <dd>我們的程式看起來終於要漂亮一點了。我們將探討如何透過 CSS 樣式化 Vue 組件。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">6. 使用 Vue 的計算屬性</a></dt>
+ <dd>在這裡我們將使用 Vue 的計算(computed)屬性,加上一個 counter 已便顯示完成工作的數量。計算屬性的功能與 methods 類似,但它只會在資料更新時變動資料。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">7. Vue 的條件式渲染:編輯已存在的待辦</a></dt>
+ <dd>現在來添加一個還沒探討到的重要功能吧:那就是編輯已經存在的項目。要完成這件事,我們將借用 Vue 在條件式渲染的長才——也就是 <code>v-if</code> 與 <code>v-else</code>——在現有 todo 項目視圖間切換,同時編輯能更新的視圖。我們還會探討如何添加刪除待辦的功能。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">8. 重點管理 Vue ref</a></dt>
+ <dd>我們快講完 Vue 了。最後要看的功能是 focus 管理,或者換句話說,如何消除鍵盤用戶的障礙。我們會看看怎麼透過 Vue ref 完成這件事:這是一項能透過虛擬 DOM、或組件的內部 DOM 結構,直接訪問 DOM 節點的進階功能。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">9. Vue 的資源</a></dt>
+ <dd>最後的最後,我們將提供鑽研 Vue 所需的資源,以及有用的資訊。</dd>
+</dl>
+
+<h2 id="該選什麼框架?">該選什麼框架?</h2>
+
+<p>我們在最初發布的文章集,主要介紹了 React/ReactDOM、Ember、Vue。之所以選中這三個框架是因為:</p>
+
+<ul>
+ <li>它們在一段時間內,依舊是最受歡迎的選擇:如同多數軟體工具一般,選擇持續開發中、不太可能下星期就棄掉、還有可能藉由這份技能來找工作的軟體,才是明智的選擇。</li>
+ <li>它們都擁有活躍的社群與良好的文件。在剛開始理解複雜的概念時,這方面至關重要。</li>
+ <li>我們不可能把<em>所有的</em>框架都寫進來。因為你沒辦法在前端日新月異的情況下即時更新。</li>
+ <li>初學者在選擇需要理解的概念方面,會是個蠻麻煩的問題。因此,盡可能精簡會對初學者的幫助很大。</li>
+</ul>
+
+<p>先講一下:我們選什麼框架<strong>並不是</strong>因為他們最棒,而是因為我們認同他們:這些框架在較吻合以上的考量要點。</p>
+
+<p>我們以本來希望在一開始包含更多框架,但最後決定先發布,之後再追加其它教學,而非延後。如果屬意的框架沒放進去、而你也想幫忙的話,來和我們聊聊吧!透過 <a href="https://wiki.mozilla.org/Matrix">Matrix</a>、<a href="https://discourse.mozilla.org/c/mdn">Discourse</a>、或 <a href="mailto:mdn-admins@mozilla.org">mdn-admins list</a> 與我們聯繫。</p>
diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html
new file mode 100644
index 0000000000..d13116582d
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/introduction/index.html
@@ -0,0 +1,387 @@
+---
+title: 前端框架簡介
+slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction
+translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{NextMenu("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</div>
+
+<p class="summary">我們從整體概述來探討框架、提供 JavaScript 與框架的簡要歷史、框架存在的理由、他們提供什麼東西、如何決定選擇哪個框架、以及前端框架的的替代方案。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決條件:</th>
+ <td>熟悉 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 這些核心技術。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>理解 JavaScript 前端框架存在的理由、他們解決的問題、可用的替代方案、還有決定選擇的方法。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="一段簡短的歷史">一段簡短的歷史</h2>
+
+<p>在 JavaScript 誕生的 1996,它的作用就只有針對網頁,提供些許的互動和興奮。但之後網路漸漸從<em>拿來看</em>,變成<em>拿來用</em>了。JavaScript 慢慢地紅了起來,JavaScript 開發者也開始針對自己碰上的問題,寫出了能解決問題的工具、接著包成能複用的工具包。他們就能把這個被稱為<strong>函式庫</strong>(library)的東西,拿去與他人共享。共享的函式庫生態,也有助於塑造網路的增長趨勢。</p>
+
+<p>目前 JavaScript 已經是網路的必需品了,<a href="https://w3techs.com/technologies/details/cp-javascript">大約 95% 的網站都又在使用 JavaScript</a>,網路也成了當今生活的必須。使用者可以透過文字與影像,來寫論文、聽音樂、看電影、與人遠距離交流。曾經只能透過裝在電腦內的原生軟體所完成的事情,現在也能網路上做到。這種現代化、複雜度高、還有各種互動的網站,被稱為<strong>網路應用程式</strong>(web applications)。</p>
+
+<p>當代 JavaScript 框架的問世,讓構建高度動態的互動式應用,變得簡單許多。<strong>框架</strong>是個針對軟體構建,提供完整解決方案的函式庫。這些選項能讓應用程式,開始能預測和同質化。可預測性讓軟體能擴展到巨大的規模時依舊能維護;可預測性和可維護性則對軟體的健康和長壽至關重要。</p>
+
+<p>JavaScript 框架能構建常用的網站裡,許多令人印象深刻的軟體。目前你正在看的 MDN Web Docs 網站,也是用 React/ReactDOM 作為前端支援的。</p>
+
+<h2 id="那有什麼框架?">那有什麼框架?</h2>
+
+<p>有很多框架,不過主要有以下「四大框架」。</p>
+
+<h3 id="Ember">Ember</h3>
+
+<p><a href="https://emberjs.com/">Ember</a> 在 2011 年 12 月發行。這個框架始於 <a href="https://en.wikipedia.org/wiki/SproutCore">SproutCore</a> 的內部專案。這是個比較老的框架:與 React 或 Vue 之類的替代方案相比,其用戶數比較少,不過在穩定性、社區支持、和一些巧妙的編碼原則方面,仍然享譽無數。</p>
+
+<h3 id="Angular">Angular</h3>
+
+<p><a href="https://angular.io">Angular</a> 是個由 Google 內部的 Angular Team 與其他社群所開發的開源專案。這個專案是同一群人由 <a href="https://angularjs.org/">AngularJS</a> 所重寫的專案。該專案於2016年9月14日發行。</p>
+
+<p>Angular 是基於組件、並使用指令式 HTML 樣板的框架。在構建時,框架的編譯器會將模板,轉換為優化的 JavaScript 程式。Angular 使用了 JavaScript 超集(superset)的 <a href="https://www.typescriptlang.org/">TypeScript</a>。我們將在下一章中詳細介紹它。</p>
+
+<h3 id="Vue">Vue</h3>
+
+<p>尤雨溪在維護並理解前述的 <a href="https://angularjs.org/">AngularJS</a> 專案後,於 2014 年發表了 <a href="https://vuejs.org/">Vue</a>。Vue 是四大框架裡面最年輕的,但成了近年來的當紅炸子雞。</p>
+
+<p>Vue 除了與 Angular 一樣,使用了一些自定義的 HTML 以外,大部分還是使用現代化的標準 JavaScript。</p>
+
+<h3 id="React">React</h3>
+
+<p>Facebook 於 2013 年發表了 <a href="https://reactjs.org/">React</a>。在發表當時 Facebook 內部早已使用 React 解決許多內部問題。技術上來說 React <em>並不是</em>框架,而是一個用來渲染 UI 組件的函式庫。React 通常會配合<em>其他</em>函式庫來建立應用程式:例如 React 搭配 <a href="https://reactnative.dev/">React Native</a> 建立手機程式、React 與 <a href="https://reactjs.org/docs/react-dom.html">ReactDOM</a> 建立網路程式...等等。</p>
+
+<p>由於 React 與 ReactDOM 通常會搭在一起用,React 在通俗上會被理解為 JavaScript 框架。在閱讀本模塊時,我們將以這種通俗理解為基礎。</p>
+
+<p>React 使用一種很像是 HTML 的 JavaScript 語法:<a href="https://reactjs.org/docs/introducing-jsx.html">JSX</a>。</p>
+
+<h2 id="為什麼有框架?">為什麼有框架?</h2>
+
+<p>我們已經討論了啟發框架建立的環境,但那不是開發人員<em>為什麼</em>要製造它們的理由。要探索原因,首先需要首先檢查開發軟體所碰上的挑戰。</p>
+
+<p>來看看一個常見的例子吧:一個能建立待辦事項程式,我們將會用待辦事項程式為例子,來介紹不同的框架。這個應用程序要能讓使用者執行諸如渲染事項列表,添加新任務和刪除任務之類的操作;還要能可靠地跟踪並更新程式所依賴的資料在軟體開發中,此這些資料稱為狀態(state)。</p>
+
+<p>每個目標分開來看,理論上都很簡單:我們能遍歷需要渲染的資料、建立新的工作物件、還能用標識符來查詢、編輯或刪除工作。然而,當我們要求程式,讓用戶在瀏覽器完成<em>這一切</em>的話,麻煩就來了。<strong>問題在於:更動狀態時,也同時需要更動 UI 的顯示。</strong></p>
+
+<p>讓我們藉由待辦事項程式的<em>一個功能</em>來看看這個問題有多難搞:把工作清單渲染出來。</p>
+
+<h2 id="DOM_的冗長變化">DOM 的冗長變化</h2>
+
+<p>建立 HTML 元素並在瀏覽器上渲染,會需要驚人數量的程式碼。假設我們的狀態,是一個由多個物件組成的陣列:</p>
+
+<pre class="brush: js notranslate">const state = [
+ {
+ id: 'todo-0',
+ name: 'Learn some frameworks!'
+ }
+]</pre>
+
+<p>我們如何對用戶顯示工作?我們想將每個工作,都表示為一個列表項目:結構為無序列表元素 <code><a href="/zh-TW/docs/Web/HTML/Element/ul">&lt;ul&gt;</a></code> 內,含有一定數量的 <code><a href="/zh-TW/docs/Web/HTML/Element/li">&lt;li&gt;</a></code> 元素。怎麼做呢?看起來就像這樣:</p>
+
+<pre class="brush: js notranslate">function buildTodoItemEl(id, name) {
+ const item = document.createElement('li');
+ const span = document.createElement('span');
+ const textContent = document.createTextNode(name);
+
+ span.appendChild(textContent)
+
+ item.id = id;
+ item.appendChild(span);
+ item.appendChild(buildDeleteButtonEl(id));
+
+ return item;
+}</pre>
+
+<p>我們在這裡用上了 <code><a href="/zh-TW/docs/Web/API/Document/createElement">document.createElement()</a></code> 方法建立了 <code>&lt;li&gt;</code>、還有一些程式碼來建立需要的屬性與子元素。</p>
+
+<p>程式的第十行引用了另一個構建函式:<code>buildDeleteButtonEl()</code>。它與用於構建列表元素的模式很像:</p>
+
+<pre class="brush: js notranslate">function buildDeleteButtonEl(id) {
+ const button = document.createElement('button');
+ const textContent = document.createTextNode('Delete');
+
+ button.setAttribute('type', 'button');
+ button.appendChild(textContent);
+
+ return button;
+}</pre>
+
+<p>這個按鈕還派不上用場,但稍後我們會用它來實做刪除功能。這渲染程式,會讓頁面看起來像這樣:</p>
+
+<pre class="brush: js notranslate">function renderTodoList() {
+ const frag = document.createDocumentFragment();
+ state.tasks.forEach(task =&gt; {
+ const item = buildTodoItemEl(task.id, task.name);
+ frag.appendChild(item);
+ });
+
+ while (todoListEl.firstChild) {
+ todoListEl.removeChild(todoListEl.firstChild);
+ }
+ todoListEl.appendChild(frag);
+}</pre>
+
+<p><em>光是</em>為了弄 UI 我們就寫了大約三十行左右的程式:這樣就<em>只是</em>為了能讓清單在 DOM 渲染而已喔。更別提之後還需要添加方便樣式化的 class。</p>
+
+<p>像範例這樣直接操作 DOM 的話,會需要理解很多 DOM 的東西:像是 DOM 的原理、如何建立元素、更改屬性、巢狀排列……<em>同時</em>還要把他們都呈現出來。這些程式甚至還沒有處理與用戶的互動或工作。在增加功能的時候,我們需要在正確的時間、用正確的方法,來更新我們的 UI。</p>
+
+<p>JavaScript 框架旨在使這類工作更加輕鬆:他們會提供更好的<em>開發體驗</em>。框架本身並沒有給 JavaScript 提供新功能;而是用更容易的方案,建立當代的網站。</p>
+
+<p>如果想查看本節中的程式碼範例,請參閱 <a href="https://codepen.io/dengeist/pen/XWbPNmw">CodePen 的程式</a>:這網站同樣允許用戶添加和刪除新任務。</p>
+
+<p>閱讀本節中使用的 JavaScript 資訊:</p>
+
+<ul>
+ <li><code><a href="/zh-TW/docs/Web/API/Document/createElement">document.createElement()</a></code></li>
+ <li><code><a href="/zh-TW/docs/Web/API/Document/createTextNode">document.createTextNode()</a></code></li>
+ <li><code><a href="/zh-TW/docs/Web/API/Document/createDocumentFragment">document.createDocumentFragment()</a></code></li>
+ <li><code><a href="/zh-TW/docs/Web/API/EventTarget/addEventListener">eventTarget.addEventListener()</a></code></li>
+ <li><code><a href="/zh-TW/docs/Web/API/Node/appendChild">node.appendChild()</a></code></li>
+ <li><code><a href="/zh-TW/docs/Web/API/Node/removeChild">node.removeChild()</a></code></li>
+</ul>
+
+<h2 id="建立_UI_的另一種方法">建立 UI 的另一種方法</h2>
+
+<p>JavaScript 框架都會提供一種能更加<em>宣告性</em>撰寫介面的方法。也就是說,框架能讓你描述 UI 看起來要怎麼樣、然後在 DOM 的背後完成這一切。</p>
+
+<p>原生 JavaScript 試圖重複建立新 DOM 元素的方法,很難一眼理解。相反地,來看看 Vue 的程式碼會怎麼完成吧:</p>
+
+<pre class="brush: html notranslate">&lt;ul&gt;
+ &lt;li v-for="task in tasks" v-bind:key="task.id"&gt;
+ &lt;span&gt;\{{task.name\}}&lt;/span&gt;
+ &lt;button type="button"&gt;Delete&lt;/button&gt;
+ &lt;/li&gt;
+&lt;/ul&gt;</pre>
+
+<p>就這樣啦。原本大約三十多行的程式,現在只要六行。如果不太熟悉大括號和 <code>v-</code> 屬性的話,沒關係;那些語法會在 Vue 模塊學到。這裡只是要講說與原生 JavaScript 對比,框架的程式碼看起來更像是實際呈現的 UI。</p>
+
+<p>也因為有 Vue,我們再也不用自己寫針對 UI 呈現的函式;整個框架會幫我們用最優化、最效率的方法完成這件事。我們只要告訴 Vue 整個排版要怎麼排就好。熟悉 Vue 的開發者,也可以盡快參與我們的專案、搞清楚整個專案到底怎麼做的。不過並不是只有 Vue 這樣:使用框架本身,就可以提高團隊與個人的工作效率。</p>
+
+<p>要在原生 JavaScript 做<em>類似的</em>事是可以的。<a href="/zh-TW/docs/Web/JavaScript/Reference/Template_literals">樣板文字</a>就能在編寫 HTML 字串的同時,也表示最終元素的外觀。就算是待辦事項列表應用,這樣簡單的事情,這可能是一個有用的想法,但是對於管理成千上萬條數據記錄、並且要在用戶界面中呈現盡可能多唯一元素的大型應用程序而言,這樣子是很難維護的。</p>
+
+<h2 id="框架給我們的其他東西">框架給我們的其他東西</h2>
+
+<p>讓我們看看框架賦予的其他優勢。正如之前提,你可以透過原生 JavaScript 實現框架,但是使用框架可以消除自行解決這些問題所需要的認知負擔。</p>
+
+<h3 id="工具">工具</h3>
+
+<p>本模塊提到的幾個框架,背後都有著龐大而活躍的社群;這些社群形成了各種生態圈、並提供能增進開發體驗的工具:像是確保功能正常的測試、或著維持程式一致性的 linting。</p>
+
+<div class="blockIndicator note">
+<p><strong>註</strong>:如果對這方面的概念有興趣,請看看 <a href="/zh-TW/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview">Client-side tooling overview</a>。</p>
+</div>
+
+<h3 id="切分">切分</h3>
+
+<p>大多數框架鼓勵開發者把介面的各部份,封裝成各種<em>組件</em>(components):也就是一個個可維護、可互通、還可重用的程式碼塊(chunks of code)。與該組件相關連的程式,可獨立為一個、或數個獨立的程式。在原生 JavaScript 裡面要這麼做的話,開發者就必須靠自己的慣例,才能在高效、可擴展的情況下,實現這個目標。但大多數的 JavaScript 開發者,最後會讓 UI 相關的所有程式,都分散在整個文件中。</p>
+
+<h3 id="路由">路由</h3>
+
+<p>web 最重要的功能之一,就是頁面之間的導航:畢竟它就是相互連接文件的網路。在你點選網站上的連結時,瀏覽器會與伺服器溝通、並獲取新內容以便顯示給你看。也因為這樣,地址欄中的 URL 就會更改。你可以保存這個新的 URL 並稍後回來、或與其他人分享該 URL,以便他們輕鬆地找到同一個頁面。你的瀏覽器會記住這個導航歷史記錄,也能在頁面之間來回導航。這就叫<strong>伺服器端路由</strong>(server-side routing)。</p>
+
+<p>現代的網路應用程式通常不獲取和渲染新的 HTML 文件:它們通常載入單個 HTML Shell,並不斷更新其中的 DOM 同時,不導航用戶到新地址(這被稱為<strong>單頁應用</strong>、<strong>single page apps</strong>、<strong>SPA</strong>)。每個新的虛擬網頁通常稱為 <em>視圖</em>(view),一般來說也不執行路由。</p>
+
+<p>在 SPA 複雜到一定的程度、也有渲染出足夠獨特的視圖時,給應用程式導入路由功能,就變得很重要:人們習慣在應用程式中,透過連結導航到特定頁面,在導航歷史記錄中前進和後退等,而當這些標準的 Web 功能被破壞時,他們的體驗也會受到影響。如果導航功能以用戶端程式提供,這就叫做<strong>用戶端路由</strong>(server-side routing)。</p>
+
+<p>你<em>可以</em>透過原生 JavaScript 實做路由功能。但比較活躍的框架都有相對應的函式庫,讓路由功能在開發過程中更加直觀。</p>
+
+<h2 id="使用框架時要考慮的事情">使用框架時要考慮的事情</h2>
+
+<p>想成為一位高效的網路開發,意味著你需要選擇最合適的工具:JavaScript 框架能讓前端開發變簡單,但它並不是萬能仙丹。我們回在這個章節探討選擇框架需要考慮的事情。請注意,你可能完全不需要框架。不要為了用框架而用框架。</p>
+
+<h3 id="熟悉工具">熟悉工具</h3>
+
+<p>如同原生 JavaScript,框架也需要理解它們各自的特性。在選好框架前,確保有足夠的時間熟悉框架,以便讓它成為開發的墊腳石,而不是絆腳石。同時,也要確保你的同事們能接受它。</p>
+
+<h3 id="過度工程化">過度工程化</h3>
+
+<p>一個 web 專案如果是個只有數個個人頁面、還幾乎沒有交互功能的話,你完全不需要 JavaScript 框架、甚至 JavaScript 本身也不需要。也就是說,框架並不是整體式的,其中一些可能更適合於小型專案。一篇在 Smashing Magazine 的文章中,作者 Sarah Drasner 寫了一篇<a href="https://www.smashingmagazine.com/2018/02/jquery-vue-javascript/">怎麼用 Vue 取代 jQuery 的文章</a>、讓網頁的一小部分具有交互性。</p>
+
+<h3 id="更大的程式庫和抽象化">更大的程式庫和抽象化</h3>
+
+<p>框架能寫出宣告式程式、有時候還會<em>少寫</em>程式。這一切都是透過框架在背後處理 DOM 互動所達成的。這種抽象化給開發者提供了相當棒的體驗,但這並不是免費的。為了把編寫的程式變成能與 DOM 互動的玩意,框架必須執行自己的程式;而這反過來又會讓專案變大,執行演算的開銷也更高昂。</p>
+
+<p>不可避免地,這會產生一些額外的程式;而儘管一個支持 tree-shaking(刪除在構建過程中未實際用到的程式)的框架,會讓應用程式保持小巧,但在考慮性能時,這將是必須牢記在心的因素之一,尤其是在受網路/儲存空間受限的設備上(像是手機)。</p>
+
+<p>框架的抽象化不僅影響你的 JavaScript、它也會影響你對與網絡本質的關係:無論如何構建 Web,最後與用戶交流的都是 HTML。用 JavaScript 編寫整個程式,會讓你看不到 HTML 本身、以及各標籤的用途,最後會生出不語義、且有障礙的 HTML 文件。實際上,你甚至能寫出一個完全依賴 JavaScript,沒有它就完全動不了的脆弱應用程式。</p>
+
+<p>框架不是問題的根源。如果優先事項設錯了,<em>任何</em>應用程式都會變得脆弱、腫大、且障礙多舛。不過,框架確實擴大了我們作為開發人員的優先事項。如果想做出一個很複雜的 Web 程式,這當然能作到;但如果優先事項無法確保性能與無障礙的話,框架將放大這方面的問題。現在的 Web 不再是一個健壯的,內容優先的文件網絡,而是常將 JavaScript 放在首位,用戶體驗則放在最後。</p>
+
+<h2 id="框架網站的無障礙議題">框架網站的無障礙議題</h2>
+
+<p>讓我們以上一節的內容為基礎,並進一步討論無障礙問題。消除用戶界面的障礙總是需要點思考與努力,而框架會使該過程複雜化。你通常要用上進階的框架 API 來訪問本機瀏覽器功能,例如 ARIA <a href="/zh-TW/docs/Web/Accessibility/ARIA/ARIA_Live_Regions">live region</a> 或 focus 管理。</p>
+
+<p>在某些情況下,框架應用程式會發生在傳統網站不存在的障礙。最明顯的例子,就是前述的客戶端路由。</p>
+
+<p>使用傳統(伺服器端)路由瀏覽 Web 會出現可預測的結果。瀏覽器知道將焦點設置在頁面頂部、輔助技術將宣布頁面標題。在導航到新頁面時,這些事情都一定會發生。</p>
+
+<p>使用客戶端路由時,瀏覽器不會加載新頁面,因此它不知道要自動調整焦點、或宣告新的頁面標題。框架作者會花費大量時間和精力,來編寫可重現這些功能的 JavaScript,但沒有一個框架能做到如此完美。</p>
+
+<p>結論是,<em>所有的</em> Web 專案一開始,就要應該考慮無障礙問題。如果專案使用抽象的框架、又不考慮無障礙問題的話,未來衍生的無障礙問題會更嚴重。</p>
+
+<h2 id="如何選擇框架">如何選擇框架</h2>
+
+<p>不同模塊的框架,會採用不同的方法。來開發 Web 應用程式。框架都會定期變化、也都有其優缺點。選擇哪個框架的過程,是與團隊及專案息息相關的。你需要透過研究,來找出合適的需求。換句話說,我們已經找出了一些能有效地研究出選擇的問題:</p>
+
+<ol>
+ <li>框架支援哪些瀏覽器?</li>
+ <li>框架使用哪個特定領域語言(domain-specific language)?</li>
+ <li>框架有夠大的社群與夠好的文件(或其他東西)支援嗎?</li>
+</ol>
+
+<p>接下來我們退提供一個表格,來展示各大框架的<em>瀏覽器支援</em>、還有能用的<strong>特定領域語言</strong>。</p>
+
+<p>一般來說,特定領域語言(domain-specific language, <strong>DSL</strong>)是一種與的特定領域軟體開發相關的程式語言。以框架的脈絡來說,DSL 是能讓開發更簡單的 JavaScript 或 HTML 變體。最重要的是,沒有哪個框架<em>要求</em>開發者使用某種特定領域語言,但框架們在挑選 DSL 方面,早已心有所屬了。選擇不採用該框架的首選 DSL,可能就會失去本可增添開發人員體驗的功能。</p>
+
+<p>在為任何新專案做出選擇時,你需要認真考慮框架的支持矩陣(support matrix)和 DSL。瀏覽器要是不支援,會成為用戶的障礙;而 DSL 要是不支援,則會你和你開發團隊的障礙。</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">框架</th>
+ <th scope="col">瀏覽器支援</th>
+ <th scope="col">首選的 DSL</th>
+ <th scope="col">支援的 DSL</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Angular</td>
+ <td>IE9+</td>
+ <td>TypeScript</td>
+ <td>基於 HTML; TypeScript</td>
+ </tr>
+ <tr>
+ <td>React</td>
+ <td>當代瀏覽器(IE9+ 含有 Polyfill)</td>
+ <td>JSX</td>
+ <td>JSX; TypeScript</td>
+ </tr>
+ <tr>
+ <td>Vue</td>
+ <td>IE9+</td>
+ <td>基於 HTML</td>
+ <td>基於 HTML, JSX, Pug</td>
+ </tr>
+ <tr>
+ <td>Ember</td>
+ <td>當代瀏覽器(IE9+ 直到 2.18 為止)</td>
+ <td>Handlebars</td>
+ <td>Handlebars, TypeScript</td>
+ </tr>
+ </tbody>
+</table>
+
+<div class="blockIndicator note">
+<p><strong>注</strong>:「基於 HTML」的 DSL 並沒有官方名字。雖然它們不完全是 DSL,但也不是標準的 HTML,所在我們在此附帶一題。</p>
+</div>
+
+<p>表格的引用來源:</p>
+
+<ul>
+ <li><a href="https://reactjs.org/docs/react-dom.html#browser-support">React browser support: official docs</a></li>
+ <li><a href="https://blog.emberjs.com/2018/02/14/ember-3-0-released.html">Ember browser support: Ember 3.0 release announcement</a></li>
+ <li><a href="https://guides.emberjs.com/v3.3.0/templates/handlebars-basics/">Ember templating language (official docs)</a></li>
+</ul>
+
+<h3 id="框架有堅實的社區嗎?">框架有堅實的社區嗎?</h3>
+
+<p>這大概是最難評估的,因為社區沒辦法用什麼數字直接估算。你或許可以用 GitHub 的星星、或是 npm 的下載量來看,但有時最好的辦法,是找看看一些論壇、或和其他開發者聊聊看。這不只是社區大小的問題而已,你還需要看看社區多麼熱情和包容、以及文件多好讀。</p>
+
+<h3 id="Web_的看法">Web 的看法</h3>
+
+<p>在選框架這件事,不要只聽我們的話:網路上也有不少的討論。例如說,維基媒體基金會最近就選了 Vue 作為他們的前端框架,還發表了<a href="https://phabricator.wikimedia.org/T241180">相關的請求意見稿</a>。請求意見稿的作者 Eric Gardner 花了不少時間,概述維基媒體基金會的需求、還有為什麼他認為這個框架,對開發團隊有益。這個請求意見稿,是你在研究要使用什麼框架時,需要考量什麼的一個好例子。</p>
+
+<p><a href="https://stateofjs.com/">State of JavaScript survey</a> 也是有用的 JavaScript 開發者反饋集合。它包含了很多 JavaScript 相關的要點、包括有關框架使用情況、還有開發者對各框架看法的數據。網站也有數年的可用數據,以便了解框架的消長。</p>
+
+<p>Vue 的開發團隊也寫了<a href="https://vuejs.org/v2/guide/comparison.html">有關 Vue 與其他框架的詳盡比較</a>。如同他們自知,這種比較可能會有一些偏見,但這仍然是一種寶貴的資源。</p>
+
+<h2 id="前端框架的替代">前端框架的替代</h2>
+
+<p>如果在尋找能夠加速開發的工具、卻又發現專案不需要前端 JavaScript 框架的話,可以試試其他用於構建 Web 的解決方案:</p>
+
+<ul>
+ <li>內容管理系統(content management system)</li>
+ <li>伺服器渲染(Server-side rendering)</li>
+ <li>靜態網站產生器(static site generator)</li>
+</ul>
+
+<h3 id="內容管理系統">內容管理系統</h3>
+
+<p><strong>內容管理系統</strong>( Content Management System, <strong>CMS</strong>)是能讓用戶在不自己寫程式的情況下,創建內容的工具。針對大型專案,尤其是撰寫者不熟悉程式、或者開發者想省時間的情況下,內容管理系統是個相當不錯的解決方案。不過,內容管理系統也需要費神去設定。使用 CMS 也同時意味著你會在最終輸出的控制方面,做出一定程度的退讓。比方說,如果 CMS 不太著墨在無障礙方面,那你也很難在這方面有所改進。</p>
+
+<p>坊間常見的內容管理系統有 <a href="https://wordpress.com/">Wordpress</a>、<a href="https://www.joomla.org/">Joomla</a>、<a href="https://www.drupal.org/">Drupal</a>。</p>
+
+<h3 id="伺服器渲染">伺服器渲染</h3>
+
+<p><strong>伺服器端渲染</strong>(Server-side rendering, <strong>SSR</strong>)是由<em>伺服器</em>負責渲染單頁應用的程式架構,與構建 JavaScript 程式中最常見,最直接的<em>用戶端渲染</em>(client-side rendering)相對。伺服器端渲染只單純傳送 HTML 檔案,所以對用戶端更友善;但設置起來就比用戶端渲染程式難得多。</p>
+
+<p>本模塊的所有用戶端渲染框架,都有相對應的伺服器端渲染。像是 React 的 <a href="https://nextjs.org/">Next.js</a>、Vue 的 <a href="https://nuxtjs.org/">Nuxt.js</a>(對這的確很教人困惑,不過兩者沒有關係)、Ember 的 <a href="https://github.com/ember-fastboot/ember-cli-fastboot">FastBoot</a>、Angular 的 <a href="https://angular.io/guide/universal">Angular Universal</a>。</p>
+
+<div class="blockIndicator note">
+<p><strong>註</strong>:某些伺服器端渲染的解決方案,是由社區編寫和維護;但也有「官方」的解決方案,是由框架維護者提供的。</p>
+</div>
+
+<h3 id="靜態網站產生器">靜態網站產生器</h3>
+
+<p>靜態網站產生器是個可以給網站生成多個網頁的程式──這包括相對應的 CSS 或 JavaScript──以便在任何地方發布。發布主機可以是 GitHub pages 分支、或著 Netlify 實體、抑或著是私人的伺服器。這種方法有很多優點,主要是性能方面(用戶端收到網頁時,已經載入了整個網頁,所以不需要執行 JavaScript)與安全性(靜態網站的攻擊因為變少了)。靜態網站還是能在需要時用上 JavaScript,但靜態網站並不<em>依賴</em> JavaScript。一如其他工具,靜態網站產生器需要點時間去搞懂。這可能是開發過程的障礙。</p>
+
+<p>靜態網站的獨立網頁,要多少就能有多少。如同框架能加快開發用戶端 JavaScript 程式一般,靜態網站產生器也能快速產生 HTML 檔案(要不然,你本來要自己寫的)。靜態網站產生器也像框架一樣,能允許用戶給網頁撰寫組件;並在最後建立頁面時,把組件都結合起來。以靜態網站產生器而言,組件被稱為<strong>樣板</strong>(template)。靜態網站產生器構建的網頁,甚至可以作為框架應用程式的宿主:比方說你可以完成「如果希望用戶造訪某個特定頁面時,啟動 React 程式」這樣的需求。</p>
+
+<p>靜態網站產生器已經存在好一段時間了,但他們最近在 Web 歷史中再度復興起來。現在有一些強大的選擇,像是 <a href="https://gohugo.io/">Hugo</a>、<a href="https://jekyllrb.com/">Jekyll</a>、<a href="https://www.11ty.dev/">Eleventy</a>、<a href="https://www.gatsbyjs.org/">Gatsby</a>。</p>
+
+<p>如果想深入理解靜態網站產生器的概念,看一下 Tatiana Mac 的 <a href="https://tatianamac.com/posts/beginner-eleventy-tutorial-parti/">Beginner's guide to Eleventy</a>。在該系列的第一篇文章中,她解釋了什麼是靜態網站生成器,以及它與發布 Web 內容的其他方式之間的關係。</p>
+
+<h2 id="結論">結論</h2>
+
+<p>我們終於把框架介紹完了。我們還沒有教任何程式,但我們希望提供了有用的背景知識,說明為什麼要使用框架,如何選擇框架,還有燃起想要學習的興趣!</p>
+
+<p>我們的下一篇文章,將探討更底層的東西,著眼於框架傾向於提供的特定種類的功能,以及它們為什麼能動。</p>
+
+<p>{{NextMenu("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</p>
+
+<h2 id="在本模塊">在本模塊</h2>
+
+<ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">前端框架介紹</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">框架的主要功能</a></li>
+ <li>React
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">開始學 React</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">建立我們的 React 待辦清單</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">把 React app 組件化</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">響應性 React:事件與狀態</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">響應性 React:編輯、過濾、條件式過濾</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">React 無障礙</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React 的資源</a></li>
+ </ul>
+ </li>
+ <li>Ember
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">開始學 Ember</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember app 架構與組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">響應性 Ember:事件、類別、狀態</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">響應性 Ember:Footer 功能、條件式渲染</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Ember 的路由</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember 的資源與除錯</a></li>
+ </ul>
+ </li>
+ <li>Vue
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">開始學 Vue</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">建立第一個 Vue 組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">渲染 Vue 組件的列表</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">寫一個 todo 表單:Vue 的事件、方法、model</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">透過 CSS 樣式化 Vue 組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">使用 Vue 的計算屬性</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue 的條件式渲染:編輯已存在的待辦</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">重點管理 Vue ref</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue 的資源</a></li>
+ </ul>
+ </li>
+</ul>
diff --git a/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html
new file mode 100644
index 0000000000..a76fb04f60
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/client-side_javascript_frameworks/react_todo_list_beginning/index.html
@@ -0,0 +1,614 @@
+---
+title: Beginning our React todo list
+slug: >-
+ Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning
+tags:
+ - Accessibility
+ - App
+ - CSS
+ - React
+ - component
+ - 初學者
+ - 前端框架
+ - 框架
+ - 無障礙
+translation_of: >-
+ Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</div>
+
+<div>我們被賦予做出一個React原型app的任務--這個app將允許使用者新增、編輯、刪除任務;且可以標記任務完成而不被刪除。</div>
+
+<div>文章將會與您一起完成一個基本 <code>App</code> component 的結構與畫面,以便稍後與其他 component 互動。</div>
+
+<div class="blockIndicator note">
+<p class="summary"><strong>小提示:如果您需要檢查自己的程式碼與範例之間的差異,可以連到</strong> <a href="https://github.com/mdn/todo-react">todo-react repository</a>,這裡有我們完整的程式碼。 Todo list 作品示範:<a href="https://mdn.github.io/todo-react-build/">https://mdn.github.io/todo-react-build/</a>。</p>
+</div>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">預備知識:</th>
+ <td>
+ <p>知道 <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>與<a href="/en-US/docs/Learn/JavaScript">JavaScript</a>的核心語法、操作基本終端機指令 <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line">terminal/command line</a>.</p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">實作目標:</th>
+ <td>介紹待辦事項清單案例研究,並掌握基本<code>App</code>結構和樣式。</td>
+ </tr>
+ </tbody>
+</table>
+
+<p><br>
+ 在軟體開發中,user story 透過使用者觀點傳達開發目標。動手開發前先定義好user stories可以幫助我們專注於需要工作的項目,而我們這個案例中的app需要實現以下功能:</p>
+
+<p>使用者可以...</p>
+
+<ul>
+ <li>讀取任務清單</li>
+ <li>可以用滑鼠或鍵盤給清單增加新任務</li>
+ <li>可以用滑鼠或鍵盤為任務標記完成</li>
+ <li>可以用滑鼠或鍵盤刪除任務</li>
+ <li>可以用滑鼠或鍵盤編輯任務</li>
+ <li>可以分類查看特定子群組:全部任務、待處理任務、已完成任務</li>
+</ul>
+
+<p>我們將一一處理這些使用者故事。</p>
+
+<h2 id="專案開始前,先清理一下">專案開始前,先清理一下</h2>
+
+<p>終端機指令 <code>create-react-app</code> 會產生一些我們這個專案用不到的檔案,讓我們來清理一下。</p>
+
+<ul>
+ <li>我們不需要個別component的樣式表,所以首先請刪除<code>App.js</code>檔案上方的<code>import './App.css'</code></li>
+ <li>我們也不需使用 <code>logo.svg</code>,請一並刪除這項import</li>
+</ul>
+
+<p>接著,請複製貼上以下終端機指令,以刪除專案中不需要的檔案;刪除前請確認您在專案的根目錄中!</p>
+
+<pre class="brush: bash notranslate"># 移動到專案中的src資料夾
+cd src
+# 刪除一些檔案
+rm -- App.test.js App.css logo.svg serviceWorker.js setupTests.js
+# 回到專案上一層
+cd ..</pre>
+
+<p>小提示:</p>
+
+<ul>
+ <li>刪除的檔案之中包含兩個測試檔,這個練習中不會涵蓋測試教學。</li>
+ <li>如果您停止server以便在終端機中刪除上述檔案,請記得使用<code>npm start</code>指令再次連上server</li>
+</ul>
+
+<h2 id="專案起點">專案起點</h2>
+
+<p>作為專案起始點 starting point ,我們會提供兩件事:一個新的 <code>App()</code> function 來取代原生預設,以及一些 CSS 美化我們的app。</p>
+
+<h3 id="The_JSX">The JSX</h3>
+
+<p>複製以下片段貼到 <code>App.js</code> 中取代原先的 <code>App()</code> function:</p>
+
+<pre class="brush: js notranslate">function App(props) {
+ return (
+ &lt;div className="todoapp stack-large"&gt;
+ &lt;h1&gt;TodoMatic&lt;/h1&gt;
+ &lt;form&gt;
+ &lt;h2 className="label-wrapper"&gt;
+ &lt;label htmlFor="new-todo-input" className="label__lg"&gt;
+ What needs to be done?
+ &lt;/label&gt;
+ &lt;/h2&gt;
+ &lt;input
+ type="text"
+ id="new-todo-input"
+ className="input input__lg"
+ name="text"
+ autoComplete="off"
+ /&gt;
+ &lt;button type="submit" className="btn btn__primary btn__lg"&gt;
+ Add
+ &lt;/button&gt;
+ &lt;/form&gt;
+ &lt;div className="filters btn-group stack-exception"&gt;
+ &lt;button type="button" className="btn toggle-btn" aria-pressed="true"&gt;
+ &lt;span className="visually-hidden"&gt;Show &lt;/span&gt;
+ &lt;span&gt;all&lt;/span&gt;
+ &lt;span className="visually-hidden"&gt; tasks&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;button type="button" className="btn toggle-btn" aria-pressed="false"&gt;
+ &lt;span className="visually-hidden"&gt;Show &lt;/span&gt;
+ &lt;span&gt;Active&lt;/span&gt;
+ &lt;span className="visually-hidden"&gt; tasks&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;button type="button" className="btn toggle-btn" aria-pressed="false"&gt;
+ &lt;span className="visually-hidden"&gt;Show &lt;/span&gt;
+ &lt;span&gt;Completed&lt;/span&gt;
+ &lt;span className="visually-hidden"&gt; tasks&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;/div&gt;
+ &lt;h2 id="list-heading"&gt;
+ 3 tasks remaining
+ &lt;/h2&gt;
+ &lt;ul
+ role="list"
+ className="todo-list stack-large stack-exception"
+ aria-labelledby="list-heading"
+ &gt;
+ &lt;li className="todo stack-small"&gt;
+ &lt;div className="c-cb"&gt;
+ &lt;input id="todo-0" type="checkbox" defaultChecked={true} /&gt;
+ &lt;label className="todo-label" htmlFor="todo-0"&gt;
+ Eat
+ &lt;/label&gt;
+ &lt;/div&gt;
+ &lt;div className="btn-group"&gt;
+ &lt;button type="button" className="btn"&gt;
+ Edit &lt;span className="visually-hidden"&gt;Eat&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;button type="button" className="btn btn__danger"&gt;
+ Delete &lt;span className="visually-hidden"&gt;Eat&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;/div&gt;
+ &lt;/li&gt;
+ &lt;li className="todo stack-small"&gt;
+ &lt;div className="c-cb"&gt;
+ &lt;input id="todo-1" type="checkbox" /&gt;
+ &lt;label className="todo-label" htmlFor="todo-1"&gt;
+ Sleep
+ &lt;/label&gt;
+ &lt;/div&gt;
+ &lt;div className="btn-group"&gt;
+ &lt;button type="button" className="btn"&gt;
+ Edit &lt;span className="visually-hidden"&gt;Sleep&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;fbutton type="button" className="btn btn__danger"&gt;
+ Delete &lt;span className="visually-hidden"&gt;Sleep&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;/div&gt;
+ &lt;/li&gt;
+ &lt;li className="todo stack-small"&gt;
+ &lt;div className="c-cb"&gt;
+ &lt;input id="todo-2" type="checkbox" /&gt;
+ &lt;label className="todo-label" htmlFor="todo-2"&gt;
+ Repeat
+ &lt;/label&gt;
+ &lt;/div&gt;
+ &lt;div className="btn-group"&gt;
+ &lt;button type="button" className="btn"&gt;
+ Edit &lt;span className="visually-hidden"&gt;Repeat&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;button type="button" className="btn btn__danger"&gt;
+ Delete &lt;span className="visually-hidden"&gt;Repeat&lt;/span&gt;
+ &lt;/button&gt;
+ &lt;/div&gt;
+ &lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;/div&gt;
+ );
+}
+</pre>
+
+<p>再來,請打開 <code>public/index.html</code> 改掉 <code><a href="/en-US/docs/Web/HTML/Element/title">&lt;title&gt;</a></code> 元素中的文字,將文字改為 <code>TodoMatic</code>,這樣才能對應到上述 <code><a href="/en-US/docs/Web/HTML/Element/Heading_Elements">&lt;h1&gt;</a></code> 的文字。</p>
+
+<pre class="notranslate">&lt;title&gt;TodoMatic&lt;/title&gt;</pre>
+
+<p>當您更新瀏覽器,您應該可以看到以下畫面:</p>
+
+<p><img alt="todo-matic app, unstyled, showing a jumbled mess of labels, inputs, and buttons" src="https://mdn.mozillademos.org/files/17253/unstyled-app.png" style="border-style: solid; border-width: 1px; height: 743px; width: 838px;"></p>
+
+<p>畫面醜醜的對吧,而且還沒有實際功能,沒關係讓我們馬上來美化它。</p>
+
+<p>在此之前,回頭複習一下我們的JSX,以及它與用戶故事的對應關係:</p>
+
+<ul>
+ <li>我們有一個 <code><a href="/en-US/docs/Web/HTML/Element/form">&lt;form&gt;</a></code> 元素,其中包含可以寫入新任務的 <code><a href="/en-US/docs/Web/HTML/Element/input/text">&lt;input type="text"&gt;</a></code> 以及一個button來送出表單。</li>
+ <li>我們還有一個<code>&lt;button&gt;</code>陣列,用以過濾不同任務狀態(全部、待辦、完成)。</li>
+ <li>下方接著一個標題告訴我們擁有多少任務</li>
+ <li>我們有3個預設任務寫在無序清單<code>&lt;ul&gt;</code>元素中,其中包含的各項單一任務都是使用<code><a href="/en-US/docs/Web/HTML/Element/li">&lt;li&gt;</a></code>。 並且在各項任務下方增加 <code><a href="/en-US/docs/Web/HTML/Element/input/text">&lt;input type="checkbox"&gt;</a></code>來勾選此任務是否完成,以及編輯、刪除按鈕<code>&lt;button&gt;</code>。</li>
+</ul>
+
+<p>這個表單<code><a href="/en-US/docs/Web/HTML/Element/form">&lt;form&gt;</a></code> 允許我們新增、管理任務, <code>&lt;button&gt;</code>幫助我們篩選任務狀態,<code>&lt;ul&gt;&lt;li&gt;</code> 則負責展示任務清單。接著由於缺乏編輯任務的UI,讓我們開始來處理畫面美化的部分吧。</p>
+
+<h3 id="Accessibility_features_無障礙設定">Accessibility features 無障礙設定</h3>
+
+<p>您可能已經注意到一些不常見的屬性,例如:</p>
+
+<pre class="brush: html notranslate">&lt;button type="button" className="btn toggle-btn" aria-pressed="true"&gt;
+ &lt;span className="visually-hidden"&gt;Show &lt;/span&gt;
+ &lt;span&gt;all&lt;/span&gt;
+ &lt;span className="visually-hidden"&gt; tasks&lt;/span&gt;
+&lt;/button&gt;</pre>
+
+<p><code>aria-pressed</code> 元素可以跟輔助工具對話(像是螢幕閱讀器),這個button 總是處於: <code>pressed</code> 或 <code>unpressed</code>其中之一的狀態。可以想像它們如同 <code>on</code> 與 <code>off</code>。設定 <code>true</code> 代表這個button預設開啟<code>pressed</code>。</p>
+
+<p>class <code>visually-hidden</code> 在我們加入CSS前還不會有作用;當我們加入樣式後,這個class會對一般使用者隱藏,因為視覺使用者不需要這些文字;而仰賴閱讀器的使用者則可以聽到更多輔助文字來提高的讀取理解與體驗。</p>
+
+<p>您還可以發現 <code><a href="/en-US/docs/Web/HTML/Element/ul">&lt;ul&gt;</a></code> 元素中:</p>
+
+<pre class="brush: html notranslate">&lt;ul
+ role="list"
+ className="todo-list stack-large stack-exception"
+ aria-labelledby="list-heading"
+&gt;</pre>
+
+<p><code>role</code> 屬性會向科技輔具說明各種元素分別代表什麼用途。雖然瀏覽器預設<code>&lt;ul&gt;</code> 為清單,但是由於樣式表會破壞這個功能,因此需要使用<code>role</code> 屬性保留 "list" 清單這個意思。如果您想了解更多<code>role</code> 屬性的重要性,請參照<a href="https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html">Scott O'Hara’s article, “Fixing Lists”</a>。</p>
+
+<p><code>aria-labelledby</code> 屬性告訴科技輔具,我們將清單標題list heading 設為label,以描述下方的程式碼片段;將這些關聯設定好會幫助使用科技輔具的朋友更好的理解前因後果。</p>
+
+<p>最後,我們清單中的labels 與 inputs對JSX而言將會有些特別的屬性:</p>
+
+<pre class="brush: html notranslate">&lt;input id="todo-0" type="checkbox" defaultChecked={true} /&gt;
+&lt;label className="todo-label" htmlFor="todo-0"&gt;
+ Eat
+&lt;/label&gt;</pre>
+
+<p><code>&lt;input/ &gt;</code>中的 <code>defaultChecked</code> 屬性會讓 React 預設勾選某項目。假如我們同一般寫HTML一樣使用 <code>checked</code>,React 會紀錄一些:handling events on the checkbox警告到瀏覽器console中,而這些是我們想避免的。不過先別擔心,我們在稍後討論事件的章節會教大家解決這個問題。</p>
+
+<p><code>htmlFor</code> 屬性對應HTML中的 <code>for</code> 屬性 ,我們不能在JSX中使用<code>for</code> 屬性因為 <code>for</code> 是保留字,因此React 使用 <code>htmlFor</code> 取代 <code>for</code>。</p>
+
+<p>備註:</p>
+
+<ul>
+ <li>在JSX屬性使用boolean值 :<code>true</code> 與 <code>false</code>, 必須將之包在<code>{ }</code>中,如果只寫 <code>defaultChecked="true"</code>,這個值將是 <code>"true"</code> — 一個字串 string literal。 請記得 — 這是JavaScript,不是HTML!</li>
+ <li><code>aria-pressed</code> 屬性在我們稍早寫的程式碼片段中有一個 <code>"true"</code> 的值,因為<code>aria-pressed</code> 不像<code>checked</code>真的是一個布林值屬性。</li>
+</ul>
+
+<h3 id="Implementing_our_styles_實作CSS美化">Implementing our styles 實作CSS美化</h3>
+
+<p>將以下的CSS貼進 <code>src/index.css</code> 取代原本的預設內容:</p>
+
+<pre class="brush: css notranslate">/* RESETS */
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+*:focus {
+ outline: 3px dashed #228bec;
+ outline-offset: 0;
+}
+html {
+ font: 62.5% / 1.15 sans-serif;
+}
+h1,
+h2 {
+ margin-bottom: 0;
+}
+ul {
+ list-style: none;
+ padding: 0;
+}
+button {
+ border: none;
+ margin: 0;
+ padding: 0;
+ width: auto;
+ overflow: visible;
+ background: transparent;
+ color: inherit;
+ font: inherit;
+ line-height: normal;
+ -webkit-font-smoothing: inherit;
+ -moz-osx-font-smoothing: inherit;
+ -webkit-appearance: none;
+}
+button::-moz-focus-inner {
+ border: 0;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ font-size: 100%;
+ line-height: 1.15;
+ margin: 0;
+}
+button,
+input {
+ overflow: visible;
+}
+input[type="text"] {
+ border-radius: 0;
+}
+body {
+ width: 100%;
+ max-width: 68rem;
+ margin: 0 auto;
+ font: 1.6rem/1.25 Arial, sans-serif;
+ background-color: #f5f5f5;
+ color: #4d4d4d;
+}
+@media screen and (min-width: 620px) {
+ body {
+ font-size: 1.9rem;
+ line-height: 1.31579;
+ }
+}
+/*END RESETS*/
+/* GLOBAL STYLES */
+.form-group &gt; input[type="text"] {
+ display: inline-block;
+ margin-top: 0.4rem;
+}
+.btn {
+ padding: 0.8rem 1rem 0.7rem;
+ border: 0.2rem solid #4d4d4d;
+ cursor: pointer;
+ text-transform: capitalize;
+}
+.btn.toggle-btn {
+ border-width: 1px;
+ border-color: #d3d3d3;
+}
+.btn.toggle-btn[aria-pressed="true"] {
+ text-decoration: underline;
+ border-color: #4d4d4d;
+}
+.btn__danger {
+ color: #fff;
+ background-color: #ca3c3c;
+ border-color: #bd2130;
+}
+.btn__filter {
+ border-color: lightgrey;
+}
+.btn__primary {
+ color: #fff;
+ background-color: #000;
+}
+.btn-group {
+ display: flex;
+ justify-content: space-between;
+}
+.btn-group &gt; * {
+ flex: 1 1 49%;
+}
+.btn-group &gt; * + * {
+ margin-left: 0.8rem;
+}
+.label-wrapper {
+ margin: 0;
+ flex: 0 0 100%;
+ text-align: center;
+}
+.visually-hidden {
+ position: absolute !important;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
+ clip: rect(1px 1px 1px 1px);
+ clip: rect(1px, 1px, 1px, 1px);
+ white-space: nowrap;
+}
+[class*="stack"] &gt; * {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.stack-small &gt; * + * {
+ margin-top: 1.25rem;
+}
+.stack-large &gt; * + * {
+ margin-top: 2.5rem;
+}
+@media screen and (min-width: 550px) {
+ .stack-small &gt; * + * {
+ margin-top: 1.4rem;
+ }
+ .stack-large &gt; * + * {
+ margin-top: 2.8rem;
+ }
+}
+.stack-exception {
+ margin-top: 1.2rem;
+}
+/* END GLOBAL STYLES */
+.todoapp {
+ background: #fff;
+ margin: 2rem 0 4rem 0;
+ padding: 1rem;
+ position: relative;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
+}
+@media screen and (min-width: 550px) {
+ .todoapp {
+ padding: 4rem;
+ }
+}
+.todoapp &gt; * {
+ max-width: 50rem;
+ margin-left: auto;
+ margin-right: auto;
+}
+.todoapp &gt; form {
+ max-width: 100%;
+}
+.todoapp &gt; h1 {
+ display: block;
+ max-width: 100%;
+ text-align: center;
+ margin: 0;
+ margin-bottom: 1rem;
+}
+.label__lg {
+ line-height: 1.01567;
+ font-weight: 300;
+ padding: 0.8rem;
+ margin-bottom: 1rem;
+ text-align: center;
+}
+.input__lg {
+ padding: 2rem;
+ border: 2px solid #000;
+}
+.input__lg:focus {
+ border-color: #4d4d4d;
+ box-shadow: inset 0 0 0 2px;
+}
+[class*="__lg"] {
+ display: inline-block;
+ width: 100%;
+ font-size: 1.9rem;
+}
+[class*="__lg"]:not(:last-child) {
+ margin-bottom: 1rem;
+}
+@media screen and (min-width: 620px) {
+ [class*="__lg"] {
+ font-size: 2.4rem;
+ }
+}
+.filters {
+ width: 100%;
+ margin: unset auto;
+}
+/* Todo item styles */
+.todo {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+}
+.todo &gt; * {
+ flex: 0 0 100%;
+}
+.todo-text {
+ width: 100%;
+ min-height: 4.4rem;
+ padding: 0.4rem 0.8rem;
+ border: 2px solid #565656;
+}
+.todo-text:focus {
+ box-shadow: inset 0 0 0 2px;
+}
+/* CHECKBOX STYLES */
+.c-cb {
+ box-sizing: border-box;
+ font-family: Arial, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ font-weight: 400;
+ font-size: 1.6rem;
+ line-height: 1.25;
+ display: block;
+ position: relative;
+ min-height: 44px;
+ padding-left: 40px;
+ clear: left;
+}
+.c-cb &gt; label::before,
+.c-cb &gt; input[type="checkbox"] {
+ box-sizing: border-box;
+ top: -2px;
+ left: -2px;
+ width: 44px;
+ height: 44px;
+}
+.c-cb &gt; input[type="checkbox"] {
+ -webkit-font-smoothing: antialiased;
+ cursor: pointer;
+ position: absolute;
+ z-index: 1;
+ margin: 0;
+ opacity: 0;
+}
+.c-cb &gt; label {
+ font-size: inherit;
+ font-family: inherit;
+ line-height: inherit;
+ display: inline-block;
+ margin-bottom: 0;
+ padding: 8px 15px 5px;
+ cursor: pointer;
+ touch-action: manipulation;
+}
+.c-cb &gt; label::before {
+ content: "";
+ position: absolute;
+ border: 2px solid currentColor;
+ background: transparent;
+}
+.c-cb &gt; input[type="checkbox"]:focus + label::before {
+ border-width: 4px;
+ outline: 3px dashed #228bec;
+}
+.c-cb &gt; label::after {
+ box-sizing: content-box;
+ content: "";
+ position: absolute;
+ top: 11px;
+ left: 9px;
+ width: 18px;
+ height: 7px;
+ transform: rotate(-45deg);
+ border: solid;
+ border-width: 0 0 5px 5px;
+ border-top-color: transparent;
+ opacity: 0;
+ background: transparent;
+}
+.c-cb &gt; input[type="checkbox"]:checked + label::after {
+ opacity: 1;
+}</pre>
+
+<p>儲存並更新瀏覽器後,您的app應當會有對應的美化。</p>
+
+<h2 id="小結">小結</h2>
+
+<p>現在我們的待辦清單app終於比較像真正的app了!問題是它還沒真正提供功能,我們將在下一章解決這個問題。</p>
+
+<p>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</p>
+
+<h2 id="在本模塊">在本模塊</h2>
+
+<ul>
+ <li><a href="https://wiki.developer.mozilla.org/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">前端框架簡介</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">框架的主要功能</a></li>
+ <li>React
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">開始學 React</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">建立我們的 React 待辦清單</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">把 React app 組件化</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">響應性 React:事件與狀態</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">響應性 React:編輯、過濾、條件式過濾</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">React 無障礙</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React 的資源</a></li>
+ </ul>
+ </li>
+ <li>Ember
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">開始學 Ember</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember app 架構與組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">響應性 Ember:事件、類別、狀態</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">響應性 Ember:Footer 功能、條件式渲染</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Ember 的路由</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember 的資源與除錯</a></li>
+ </ul>
+ </li>
+ <li>Vue
+ <ul>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">開始學 Vue</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">建立第一個 Vue 組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">渲染 Vue 組件的列表</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">寫一個 todo 表單:Vue 的事件、方法、model</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">透過 CSS 樣式化 Vue 組件</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">使用 Vue 的計算屬性</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue 的條件式渲染:編輯已存在的待辦</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">重點管理 Vue ref</a></li>
+ <li><a href="/zh-TW/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue 的資源</a></li>
+ </ul>
+ </li>
+ <li>Svelte
+ <ul>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started">開始學Svelte</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning">寫一個Svelte待辦清單(todp list app)</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props">Svelte中的動態行為:變數與props</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility">進階Svelte:Reactivity、元件生命週期、網頁無障礙設定</a></li>
+ <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores">Working with Svelte stores</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript">Svelte中的TypeScript</a></li>
+ <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next">部署與下一步</a></li>
+ </ul>
+ </li>
+</ul>
diff --git a/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html
new file mode 100644
index 0000000000..59126f3334
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/automated_testing/index.html
@@ -0,0 +1,372 @@
+---
+title: 自動化測試介紹
+slug: Learn/Tools_and_testing/Cross_browser_testing/Automated_testing
+translation_of: Learn/Tools_and_testing/Cross_browser_testing/Automated_testing
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Feature_detection", "Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment", "Learn/Tools_and_testing/Cross_browser_testing")}}</div>
+
+<p class="summary">每天在好幾個瀏覽器與設備上,運行手動測試數次,既乏味又浪費時間。要有效率的處理這種事,就要開始熟悉自動化工具。我們會在這篇文章看看有哪些可用的工具、如何使用它們、以及如何使用如 Sauce Labs 與 Browser Stack 的商業化瀏覽器測試程式之基本講述。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先決條件:</th>
+ <td>熟悉 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 核心語言的基本;<a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">跨瀏覽器測試的重要原則</a>。</td>
+ </tr>
+ <tr>
+ <th scope="row">目標:</th>
+ <td>提供理解自動化測試的需求、它如何讓你生活變得簡單、還有如何透過一些商業產品令事情更簡易。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="自動化讓事情變簡單">自動化讓事情變簡單</h2>
+
+<p>在這個模組中,我們詳細介紹了不同的方式,來測試你的網站和應用程序,並解釋了跨瀏覽器測試工作應該在哪些瀏覽器上進行測試、輔助功能要點……等等。聽來要做很多事呢,不是嗎?</p>
+
+<p>我們同意手動測試前述的一切,真的很累。幸好有很多工具,可以讓我們不用這麼累。有兩個主要方法,可以自動執行我們討論過的測試:</p>
+
+<ol>
+ <li>使用如 <a href="http://gruntjs.com/">Grunt</a> 或 <a href="http://gulpjs.com/">Gulp</a> 或 <a href="http://gulpjs.com/">Gulp</a> 或 <a href="https://docs.npmjs.com/misc/scripts">npm scripts</a> 之類的任務執行器(task runner)來跑測試,並在組建過程中清理你的程式碼。這個方法很適合如清理並最小化程式碼、增加 CSS 前輟或最大化跨瀏覽器的 transpiling nascent JavaScript 功能...之類的任務。</li>
+ <li>使用如 <a href="http://www.seleniumhq.org/">Selenium</a> 之類的瀏覽器自動化系統,在安裝好的瀏覽器跑指定測試並傳回結果,並在瀏覽器出問題的時候警告你。諸如 <a href="https://saucelabs.com/">Sauce Labs</a> 與 <a href="https://www.browserstack.com/">Browser Stack</a> 之類的商業跨瀏覽器測試程式都是基於 Selenium,但能讓你用簡單的介面,遠端訪問他們設好的東西,如此一來,就能省下自己架設測試系統的心力。</li>
+</ol>
+
+<p>我們會在下一篇文章,專注於如何設定基於 Selenium 的個人測試系統。這篇文章則會專注於如何設定任務執行器,並簡單與系統化地,使用前述的商業系統。</p>
+
+<div class="note">
+<p><strong>注意</strong>:這兩件事情並不互斥。我們可以用任務執行器來訪問服務。例如,你可以用 Sauce Labs 的 API 來跑跨瀏覽器測試,並顯示結果。我們會在下面解釋這件事。</p>
+</div>
+
+<h2 id="使用任務執行器以自動化測試工具">使用任務執行器以自動化測試工具</h2>
+
+<p>如同前述,你可以透過任務執行器運行在組建功能中,所有想要自動化的常見任務,例如在每次存檔,或其他時候,清理並壓縮程式碼。在這個章節,我們將專注於如何用對初學者友善的選項,透過 Node 與 Gulp 執行自動化任務。</p>
+
+<h3 id="設定_Node_與_npm">設定 Node 與 npm</h3>
+
+<p>今日,此類工具大都基於 {{Glossary("Node.js")}}。所以,你需要從 <a href="https://nodejs.org/">nodejs.org</a> 安裝它:</p>
+
+<ol>
+ <li>從上面的網站下載安裝程式。</li>
+ <li>如同安裝其他程式般地安裝它。注意 Node 還會安裝 <a href="https://www.npmjs.com/">Node Package Manager</a>(npm),它能讓你輕易安裝套件(package)、分享你自己寫的套件、還有在你的專案運行腳本。</li>
+ <li>安裝完成後,請輸入以下指令以測試 node 是否已安裝到電腦裡面,它會回傳 Node 與 npm 的版本:
+ <pre class="brush: bash">node -v
+npm -v</pre>
+ </li>
+ <li>如果已經安裝過 Node/npm,你應該更新它們到最新版本。要更新 Node 的最可行方法,是從上述網站下載並安裝更新的軟體包。要更新 npm,請在文字介面輸入以下指令:
+ <pre class="brush: bash">npm install npm@latest -g</pre>
+ </li>
+</ol>
+
+<div class="note">
+<p><strong>注意</strong>:如果因為權限問題而失敗,<a href="https://docs.npmjs.com/getting-started/fixing-npm-permissions">Fixing npm permissions</a> 應該對你有所幫助。</p>
+</div>
+
+<p>要在專案裡面使用 node/npm 套件,你需要把專案所在目錄設為 npm 專案。它很簡單。</p>
+
+<p>例如說,先來做個 test 目錄,以便不操心自己搞壞什麼。</p>
+
+<ol>
+ <li>選個合適的地方建立目錄。可以在檔案管理員的 UI 完成,或是輸入以下指令:
+ <pre class="brush: bash">mkdir node-test</pre>
+ </li>
+ <li>要把這目錄變成 npm 專案,就要到 test 把此目錄初始化。請輸入:
+ <pre class="brush: bash">cd node-test
+npm init</pre>
+ </li>
+ <li>第二個指令(<code>npm init</code>)會問你幾個問題,以便取得專案所需的資訊。你可以把一切都以預設帶過。</li>
+ <li>問完所有問題後,它會問你是否對設定滿意。輸入 <code>yes</code> 並按下 <kbd>Enter</kbd> 鍵,npm 就會在目錄產生一個稱為 <code>package.json</code> 的檔案。</li>
+</ol>
+
+<p>這個檔案基本上就是個專案的設定檔。你可以之後再來設定,但目前它大概長成這個樣子:</p>
+
+<pre class="brush: json">{
+ "name": "node-test",
+ "version": "1.0.0",
+ "description": "Test for npm projects",
+ "main": "index.js",
+ "scripts": {
+ "test": "test"
+ },
+ "author": "Chris Mills",
+ "license": "MIT"
+}</pre>
+
+<p>有了這個檔案,你已經可以開始了。</p>
+
+<h3 id="設定_Gulp_自動化">設定 Gulp 自動化</h3>
+
+<p>來看看怎麼用 Gulp 設定一些測試工具的自動化。</p>
+
+<ol>
+ <li>要開始的話,得先建立一個 test npm 專案。使用的程式會在下面的章節提到。</li>
+ <li>接著,你需要有些簡單的 HTML、CSS、JavaScript 來測試系統:你可以複製我們的 <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/automation/index.html">index.html</a>、<a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/automation/main.js">main.js</a>、<a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/automation/style.css">style.css</a> 到專案裡面,一個稱為 <code>src</code> 的目錄。現在你可以隨意嘗試測試內容,不過請注意這些工具不會直接在 JS/CSS 裡面運作:你需要外部的檔案。</li>
+ <li>首先,你要下這個指令,以全域(意思是說,它能在所有專案使用)的形式安裝 gulp:
+ <pre class="brush: bash">npm install --global gulp-cli</pre>
+ </li>
+ <li>接著在 npm 專案輸入以下指令,以便專案將 gulp 認定為安裝所須:
+ <pre class="brush: bash">npm install --save-dev gulp</pre>
+ </li>
+ <li>在專案裡面建立一個叫 <code>gulpfile.js</code> 的檔案。這個檔案能運行所有我們需要做的任務。在檔案裡面加這個指令:
+ <pre class="brush: js">var gulp = require('gulp');
+
+gulp.task('default', function() {
+ console.log('Gulp running');
+});</pre>
+ 這檔案需要我們之前安裝過的 <code>gulp</code> 模組,接著會跑些只顯示訊息的基本任務:它至少讓我們知道 Gulp 可以動。每個 gulp task 的基本格式都一樣——<code>gulp</code> 會執行 <code>task()</code> 方法,並給出兩個參數——任務的名稱、還有指示如何完成任務的回傳函式。</li>
+ <li>現在你可以跑 gulp task 了——輸入這個指令吧:
+ <pre class="brush: bash">gulp
+</pre>
+ </li>
+</ol>
+
+<h3 id="讓_Gulp_做些實際的工作">讓 Gulp 做些實際的工作</h3>
+
+<p>要讓 Gulp 真的能幹些事情,就得先想想我們想要它做什麼。我們的專案想要做這些合理的基本功能:</p>
+
+<ul>
+ <li>用 html-tidy、css-lint、js-hint 來 lint、報告、修理 HTML/CSS/JS 的常見錯誤(請參見 <a href="https://www.npmjs.com/package/gulp-htmltidy/">gulp-htmltidy</a>、<a href="https://www.npmjs.com/package/gulp-csslint/">gulp-csslint</a>、<a href="https://www.npmjs.com/package/gulp-jshint/">gulp-jshint</a>)。</li>
+ <li>用 Autoprefixer 掃描我們的 CSS 並在需要時增加 vendor prefixes(請參見 <a href="https://www.npmjs.com/package/gulp-autoprefixer/">gulp-autoprefixer</a>)</li>
+ <li>用 babel 把新式的 JavaScript 語法轉換為能在老舊瀏覽器運作的語法(請參見 <a href="https://www.npmjs.com/package/gulp-babel/">gulp-babel</a>)</li>
+</ul>
+
+<p>請詳見上面我們使用的 gulp 套件連結,以獲取完整指引。</p>
+
+<p>要用套件的話,要先透過 npm 安裝之,之後在 <code>gulpfile.js</code> 上面引用需要的套件,再接著到下面加入想測試的東西,最後把你的任務命名為 <code>default</code>。</p>
+
+<p>在往下一步開始進發以前,把 default task 改成:</p>
+
+<pre class="brush: js">gulp.task('default', [ ]);</pre>
+
+<p>在陣列裡面寫下所有想在命令列輸入 <code>gulp</code> 後,希望 Gulp 運作的命令。</p>
+
+<h4 id="html-tidy">html-tidy</h4>
+
+<ol>
+ <li>輸入以下指令安裝:
+ <pre class="brush: bash"><span class="text"><span>npm install --save-dev gulp-htmltidy</span></span>
+</pre>
+
+ <div class="note">
+ <p><strong>注意</strong>:<code>--save-dev</code> 會把此套件加到開發相依設定中。如果去看專案的 <code>package.json</code> 檔,你會在 <code>devDependencies</code> 屬性看到它被放在裡面。</p>
+ </div>
+ </li>
+ <li class="line">在 <code>gulpfile.js</code> 增加這個相依:
+ <pre class="brush: js">var htmltidy = require('gulp-htmltidy');</pre>
+ </li>
+ <li>在 <code>gulpfile.js</code> 的底部加入以下測試:
+ <pre class="brush: js">gulp.task('html', function() {
+ return gulp.src('src/index.html')
+ .pipe(htmltidy())
+ .pipe(gulp.dest('build'));
+});</pre>
+ </li>
+ <li>在 <code>default</code> 任務的陣列裡面加入 <code>'html'</code> 項目。</li>
+</ol>
+
+<p>在這裡我們抓到了 <code>index.html</code> 開發檔:<code>gulp.src()</code> 讓我們抓取需要完成事情所需的原始檔。</p>
+
+<p>我們接著會用 <code>pipe()</code> 函式以通行另一個執行用的指令。我們可以應自己需求,把盡可能多的指令連接起來。在原始碼裡面,我們先執行能修復錯誤的 <code>htmltidy()</code> 函式。第二個 <code>pipe()</code> 函式會寫出 HTML 檔案的輸出至 <code>build</code> 目錄。</p>
+
+<p>在 input 版本的檔案內,你可能發現到我們放了空白的 {{htmlelement("p")}} 元素,htmltidy 會在這個輸出檔創建後移除。</p>
+
+<h4 id="Autoprefixer_與_css-lint">Autoprefixer 與 css-lint</h4>
+
+<ol>
+ <li>輸入以下指令安裝:
+ <pre class="brush: bash">npm install --save-dev gulp-autoprefixer
+npm install --save-dev gulp-csslint</pre>
+ </li>
+ <li>在 <code>gulpfile.js</code> 增加這個相依:
+ <pre class="brush: js">var autoprefixer = require('gulp-autoprefixer');
+var csslint = require('gulp-csslint');</pre>
+ </li>
+ <li>在 <code>gulpfile.js</code> 的底部加入以下測試:
+ <pre class="brush: js">gulp.task('css', function() {
+ return gulp.src('src/style.css')
+ .pipe(csslint())
+ .pipe(csslint.formatter('compact'))
+ .pipe(autoprefixer({
+ browsers: ['last 5 versions'],
+ cascade: false
+ }))
+ .pipe(gulp.dest('build'));
+});</pre>
+ </li>
+ <li>在 <code>default</code> 任務的陣列裡面加入 <code>'css'</code> 項目。</li>
+</ol>
+
+<p>我們在此選定了 <code>style.css</code> 檔案,對它執行了 csslint(它會在終端機上面列出所有 CSS 的錯誤),接著透過運行 autoprefixer 來增加所有為了在舊瀏覽器運行所需要的前輟修飾子。在 pipe chain 的最後面,我們把已經 modified prefixed CSS 輸出到 build 目錄。注意,這只有在 csslint 沒有找到錯誤的時候才能動──試著把 CSS 檔案內的大括弧移掉,看看會發生什麼事!</p>
+
+<h4 id="js-hint_與_babel">js-hint 與 babel</h4>
+
+<ol>
+ <li>輸入以下指令安裝:
+ <pre class="editor editor-colors">npm install --save-dev gulp-babel babel-preset-es2015
+<span class="shell source"><span>npm install jshint gulp-jshint --save-dev</span></span>
+</pre>
+ </li>
+ <li>在 <code>gulpfile.js</code> 增加這個相依:
+ <pre class="editor editor-colors">var babel = require('gulp-babel');
+<span class="js source"><span class="js storage type"><span>var</span></span><span> jshint </span><span class="assignment js keyword operator"><span>=</span></span><span> </span><span class="function-call js meta"><span class="function js support"><span>require</span></span><span class="js meta"><span class="begin definition js punctuation round"><span>(</span></span><span class="js quoted single string"><span class="begin definition js punctuation string"><span>'</span></span><span>gulp-jshint</span><span class="definition end js punctuation string"><span>'</span></span></span><span class="definition end js punctuation round"><span>)</span></span></span></span><span class="js punctuation statement terminator"><span>;</span></span></span>
+</pre>
+ </li>
+ <li class="line">在 <code>gulpfile.js</code> 的底部加入以下測試:
+ <pre class="brush: js">gulp.task('js', function() {
+    return gulp.src('src/main.js')
+        .pipe(jshint())
+        .pipe(jshint.reporter('default'))
+        .pipe(babel({
+            presets: ['es2015']
+        }))
+        .pipe(gulp.dest('build'));
+});</pre>
+ </li>
+ <li>在 <code>default</code> 任務的陣列裡面加入 <code>'js'</code> 項目。</li>
+</ol>
+
+<p>我們在這裡抓了 <code>main.js</code> 檔案,對其運行 <code>jshint</code> 並使用 <code>jshint.reporter</code> 對終端機輸出結果;我們接著把檔案 pass 到 babel,它將其轉換至舊語法並將結果輸出至 <code>build</code> 目錄。我們原本的程式碼包含了 <a href="/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions">fat 箭頭函式</a>,babel 會將其編寫為舊語法。</p>
+
+<h4 id="進一步的點子">進一步的點子</h4>
+
+<p>把一切都設定好後,在專案目錄內用運行 <code>gulp</code> 指令,你應該能看到像這樣的輸出:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14227/gulp-output.png" style="display: block; height: 478px; margin: 0px auto; width: 697px;"></p>
+
+<p>你可以試著把自動任務產生的檔案放在 <code>build</code> 目錄,並從瀏覽器的 <code>build/index.html</code> 觀察之。</p>
+
+<p>如果出了問題,檢查下是不是加了上面寫的所有相依套件與測試,也請試著把 HTML/CSS/JavaScript 程式碼通通註解掉、接著執行 gulp 以便檢查能否忽略出錯的地方。</p>
+
+<p>Gulp 還有個 <code>watch()</code> 函式能監視,並在每次存檔完就跑測試。例如,你可以試著在 <code>gulpfile.js</code> 底下增加以下程式碼:</p>
+
+<pre class="brush: js">gulp.task('watch', function(){
+ gulp.watch('src/*.html', ['html']);
+ gulp.watch('src/*.css', ['css']);
+ gulp.watch('src/*.js', ['js']);
+});</pre>
+
+<p>現在來輸入 <code>gulp watch</code> 指令。Gulp 會開始監視目錄,並在儲存 HTML、CSS、JavaScript 檔的時候,運行適當的任務。</p>
+
+<div class="note">
+<p><strong>註</strong>:<code>*</code> 是通配字符(wildcard character)--這裡的意思是「當任何檔案被儲存的時候,執行這些任務」。你也可以在主要任務內使用通配,例如 <code>gulp.src('src/*.css')</code> 會抓取所有的 CSS 檔案並執行 piped task。</p>
+</div>
+
+<div class="note">
+<p><strong>註</strong>:在我們的 watch 指令有個問題,那就是我們的 CSSLint/Autoprefixer combination throws full-blown errors when a CSS error is encountered, which stops the watch working. You'll have to restart the watch once a CSS error is encountered, or find another way to do this.</p>
+</div>
+
+<p>你還可以用 Gulp 做很多事情。<a href="http://gulpjs.com/plugins/">Gulp plugin directory</a> 收錄了近千個可搜尋的套件。</p>
+
+<h3 id="其他任務執行器">其他任務執行器</h3>
+
+<p>其實還有很多任務執行器能用。我們不會說 Gulp 是最好的解決方案,但它對我們而言很好用、而且也對新手友善。你可以嘗試這些解決方案:</p>
+
+<ul>
+ <li>Grunt 與 Gulp 很像,不過它依靠的是事先指定的設定檔,而不是 JavaScript 檔。請參見 <a href="http://gruntjs.com/getting-started">Getting started with Grunt</a> 以獲取詳情。</li>
+ <li>你也可以在不安裝任何任務執行器的情況下,直接使用 <code>package.json</code> 內的 npm 腳本。它行得通的前提,是 Gulp 之類的套件基本上靠著命令列工具運作。所以如果你知道如何透過命令列工具跑工具,你就可以透過 npm 腳本運行。這麼做會更麻煩點,但對那些懂命令列的來說這很值得。<a href="https://css-tricks.com/why-npm-scripts/">Why npm scripts?</a> 有進一步的介紹。</li>
+</ul>
+
+<h2 id="使用_Sauce_Labs_加快瀏覽器測試">使用 Sauce Labs 加快瀏覽器測試</h2>
+
+<p>有很多商業化的瀏覽器測試系統可供選擇,不過在這裡我們會探討 Sauce Labs。這並不是說它是可用工具裡面最好的,而是說它對初學者而言,是其中一個好上手的。</p>
+
+<p>這種程式的基本前提,是存在一家擁有很多伺服器的公司,以便跑很多不同的測試。在使用服務的時候,你會給服務一個需要測試的 URL,還有諸如什麼瀏覽器需要測試之類的資訊。程式接著會設置擁有指定作業系統的虛擬機,並回傳螢幕截圖、視頻、日誌文件,文字之類的測試結果。</p>
+
+<p>You can then step up a gear, using an API to access functionality programmatically, which means that such apps can be combined with task runners, your own local Selenium environments, etc., to create automated tests.</p>
+
+<h3 id="開始用_Sauce_Labs">開始用 Sauce Labs</h3>
+
+<p>來透過 Sauce Labs Trial 開始熟悉吧。</p>
+
+<ol>
+ <li>建立 <a href="https://saucelabs.com/signup/trial">Sauce Labs trial 帳號</a>。</li>
+ <li>登入。通常在驗證電子郵件後,就能自動登入。</li>
+</ol>
+
+<h3 id="基本的手動測試">基本的手動測試</h3>
+
+<p><a href="https://saucelabs.com/beta/dashboard/manual">Sauce Labs dashboard</a> 有很多可用選項。現在,先確認是否位於 <em>Manual Tests</em> tab。</p>
+
+<ol>
+ <li>點選 <em>Start a new manual session</em>。</li>
+ <li>在下個螢幕,輸入想測試的 URL(像是本例中要輸入 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html">http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html</a>)接著透過不同的按鈕與清單,選擇想測試的瀏覽器/作業系統組合。如你所見,有很多很多的組合! <img alt="" src="https://mdn.mozillademos.org/files/14229/sauce-manual-session.png" style="border-style: solid; border-width: 1px; display: block; height: 636px; margin: 0px auto; width: 600px;"></li>
+ <li>When you click Start session, a loading screen will then appear, which spins up a virtual machine running the combination you chose.</li>
+ <li>When loading has finished, you can then start to remotely test the web site running in the chosen browser. <img alt="" src="https://mdn.mozillademos.org/files/14231/sauce-test-running.png" style="display: block; height: 390px; margin: 0px auto; width: 800px;"></li>
+ <li>From here you can see the layout as it would look in the browser you are testing, move the mouse around and try clicking buttons, etc. The top menu allows you to:
+ <ul>
+ <li>Stop the session</li>
+ <li>Give someone else a URL so they can observe the test remotely.</li>
+ <li>Copy text/notes to a remote clipboard.</li>
+ <li>Take a screenshot.</li>
+ <li>Test in full screen mode.</li>
+ </ul>
+ </li>
+</ol>
+
+<p>Once you stop the session, you'll return to the Manual Tests tab, where you'll see an entry for each of the previous manual sessions you started. Clicking on one of these entries shows more data for the session. In here you can for example download any screenshots you took, watch a video of the session, and view data logs for the session.</p>
+
+<div class="note">
+<p><strong>註</strong>:This is already very useful, and way more convenient than having to set all these emulators and virtual machines by yourself.</p>
+</div>
+
+<h3 id="進階:The_Sauce_Labs_API">進階:The Sauce Labs API</h3>
+
+<p>Sauce Labs 有個能允許程式化檢索帳號與現有測試詳情的 <a href="https://wiki.saucelabs.com/display/DOCS/The+Sauce+Labs+REST+API">restful API</a>,並講解測試與進一步細節,如手動測試無法錄製的 pass/fail 狀態。For example, you might want to run one of your own Selenium tests remotely using a Sauce Labs, to test a certain browser/OS combination, and then pass the test results back to Sauce Labs.</p>
+
+<p>It has a number of clients available to allow you to make calls to the API using your favourite environment, be it PHP, Java, Node.js, etc.</p>
+
+<p>Let's have a brief look at how we'd access the API using Node.js and <a href="https://github.com/danjenkins/node-saucelabs">node-saucelabs</a>.</p>
+
+<ol>
+ <li>First, set up a new npm project to test this out, as detailed in {{anch("Setting up Node and npm")}}. Use a different directory name than before, like <code>sauce-test</code> for example.</li>
+ <li>使用以下指令安裝 Node Sauce Labs wrapper:
+ <pre>npm install saucelabs</pre>
+ </li>
+ <li>在專案根目錄下建立個稱作 <code>call-sauce.js</code> 的新檔案。寫入以下內容:
+ <pre class="brush: js">var SauceLabs = require('saucelabs');
+
+var myAccount = new SauceLabs({
+ username: "your-sauce-username",
+ password: "your-sauce-api-key"
+});
+
+myAccount.getAccountDetails(function (err, res) {
+  console.log(res);
+ myAccount.getServiceStatus(function (err, res) {
+  // Status of the Sauce Labs services
+  console.log(res);
+  myAccount.getJobs(function (err, jobs) {
+    // Get a list of all your jobs
+    for (var k in jobs) {
+      if ( jobs.hasOwnProperty( k )) {
+        myAccount.showJob(jobs[k].id, function (err, res) {
+        var str = res.id + ": Status: " + res.status;
+          if (res.error) {
+            str += "\033[31m Error: " + res.error + " \033[0m";
+          }
+        console.log(str);
+        });
+      }
+    }
+  });
+  });
+});</pre>
+ </li>
+ <li>You'll need to fill in your Sauce Labs username and API key in the indicated places. These can be retrieved from your <a href="https://saucelabs.com/beta/user-settings">User Settings</a> page. Fill these in now.</li>
+ <li>Make sure everything is saved, and run your file like so:
+ <pre class="brush: bash">node call-sauce</pre>
+ </li>
+</ol>
+
+<h3 id="進階:自動化測試">進階:自動化測試</h3>
+
+<p>我們會在下一章覆蓋實際運行的 Sauce Lab 自動化測試。</p>
+
+<h2 id="總結">總結</h2>
+
+<p>這是一切都還蠻簡單的,但我想你能看到自動化工具,在測試方面提供了很大的幫助。</p>
+
+<p>下篇文章我們來關注怎麼用 Selenium 設定你自己的區域自動化系統,並與 Sauce Labs 做結合。</p>
+
+<p>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Feature_detection", "Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment", "Learn/Tools_and_testing/Cross_browser_testing")}}</p>
diff --git a/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html
new file mode 100644
index 0000000000..2158e7ec3a
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/cross_browser_testing/index.html
@@ -0,0 +1,33 @@
+---
+title: 跨瀏覽器測試
+slug: Learn/Tools_and_testing/Cross_browser_testing
+translation_of: Learn/Tools_and_testing/Cross_browser_testing
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">此模組專注於測試網路專案的跨瀏覽器領域。在此,我們會辨認你的目標閱聽者(例如你最該對什麼樣的用戶、瀏覽器、還有設備操心?)如何做測試、不同類型的程式碼會碰上的主要問題、如何解決/減輕這些問題、哪些工具最能幫你測試和修復問題、還有如何用自動化加速測試。</p>
+
+<h2 id="先決條件">先決條件</h2>
+
+<p>在使用文章所述的工具前,你應該確實理解 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 核心語言的基本。</p>
+
+<h2 id="指引">指引</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">跨瀏覽器測試介紹</a></dt>
+ <dd>這篇文章將透過給予跨瀏覽器測試概覽重點、回答諸如「何謂跨瀏覽器測試?」、「你最有可能碰上什麼問題?」、「測試、找出、並解決錯誤的主要方法有哪些?」的問題,以作為模組的開頭。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">測試進行策略</a></dt>
+ <dd>接著,我們將針對測試執行深入研究、確定目標受眾(像是什麼瀏覽器、設備、或其他需要確認的地方)、低測試策略(low fi testing strategies,讓自己取得需要的設備、虛擬機、還有 adhoc 測試)、進階測試策略(自動化以及使用專用工具)、還有用戶群組間的測試。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">處理常見的 HTML 與 CSS 問題</a></dt>
+ <dd>在這裡,我們將關注可能遇上的,常見跨瀏覽器 HTML 與 CSS 程式相關問題,還有能預防或修復淺在問題的工具。這裡面會有語法標示(linting code)、CSS 前輟處理、使用瀏覽器工具找出問題、使用 polyfill 支援瀏覽器、處理響應式網頁問題...等等。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">處理常見的 JavaScript 問題</a></dt>
+ <dd>我們會開始觀察常見的跨瀏覽器 JavaScript 程式問題,以及修復的辦法。使用瀏覽器工具追蹤並解決問題、使用 Polyfill 與函式庫解決問題、在老舊瀏覽器實作新功能...等等。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">處理常見的無障礙問題</a></dt>
+ <dd>我們要關注無障礙網頁,並提供常見問題的資訊、如何簡易測試、還有使用檢測/自動化工具,以排查無障礙問題。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">功能檢測實做</a></dt>
+ <dd>功能檢測牽涉到確定瀏覽器是否支持某個程式碼,是否依賴他執行不同的程式碼,以便部分瀏覽器能提供可執行的體驗,而不是直接崩潰/錯誤。本文詳細介紹如何編寫自己的簡單功能檢測,如何使用函式庫來加速實現,以及用於功能檢測的本機功能,例如 <code>@supports</code>。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">自動化測試介紹</a></dt>
+ <dd>每天在好幾個瀏覽器與設備上,運行手動測試數次,既乏味又浪費時間。要有效率的處理這種事,就要開始熟悉自動化工具。我們會在這篇文章看看有哪些可用的工具、如何使用它們、以及如何使用如 Sauce Labs 與 Browser Stack 的商業化瀏覽器測試程式之基本講述。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">設定你的自動化測試環境</a></dt>
+ <dd>我們會在這篇文章教你如何安裝自己的自動化測試環境、並透過 Selenium/WebDriver 以及 Node 的測試函式庫如 selenium-webdriver 來跑你的測試。我們還會講測試環境如何與上篇文章所講述的商業軟體做整合。</dd>
+</dl>
diff --git a/files/zh-tw/learn/tools_and_testing/index.html b/files/zh-tw/learn/tools_and_testing/index.html
new file mode 100644
index 0000000000..23c9d3f335
--- /dev/null
+++ b/files/zh-tw/learn/tools_and_testing/index.html
@@ -0,0 +1,31 @@
+---
+title: 工具與測試
+slug: Learn/Tools_and_testing
+translation_of: Learn/Tools_and_testing
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary">當你開始對網路核心技術(如 HTML、CSS、JavaScript)感到熟悉、累積經驗、閱讀更多資源、學到更多技巧和竅門時,你會碰上一大堆的工具,從 CSS 與 JavaScript 開始,到測試並自動化程式、還有一堆眉眉角角。等到你網路專案變得龐大而複雜時,你可能會想要用上某些工具、並針對你的程式碼,撰寫些可信賴的測試計劃。學習專區的這一區,旨在給你做出明智抉擇的所需。</p>
+
+<p>網路產業的職場令人興奮,但也並非全無弊病。當今用於建置網站的核心技術已相當成熟,然新功能日益漸增、而方便使用,並由那些技術為基礎的新工具也不斷問世。最重要的是,我們還要把跨瀏覽器支援銘記於心,並確保我們的程式碼遵循專案的最佳做法,以確保它們能在不同用戶使用的瀏覽器和設備上運行,身心障礙人士亦可使用。</p>
+
+<p>決定該用什麼工具可能是個困難的過程,因此我們寫了這幾篇文章,來告訴你可以使用什麼樣的工具、它們能為你做什麼,以及如何針對產業的偏好利用之。</p>
+
+<div class="note">
+<p><strong>注意</strong>:因為隨時都會有新工具問世、舊工具退出,我們刻意把內容寫得盡可能中立:我們希望先關注這些工具所能完成,最重要的一般類型的任務,並最小化特定工具。很明顯,我們要示範工具使用,以展示具體技術,但請注意我們不一定推薦這些工具為最佳或唯一辦法:大多數情況下其實有其他方法,但我們希望為你提供一個清晰的工作方法論。</p>
+</div>
+
+<h2 id="學習途徑">學習途徑</h2>
+
+<p>在使用文章所述的工具前,你應該確實理解 <a href="/zh-TW/docs/Learn/HTML">HTML</a>、<a href="/zh-TW/docs/Learn/CSS">CSS</a>、<a href="/zh-TW/docs/Learn/JavaScript">JavaScript</a> 核心語言的基本。比方說,在你開始處理複雜的程式碼錯誤前,要知道這些語言的基本原理、如何活用 JavaScript 函式庫、或是使用 test runner 給你的程式碼寫測試……等等。</p>
+
+<p>最少,你需要扎實的基礎。</p>
+
+<h2 id="模組">模組</h2>
+
+<dl>
+ <dt>現實世界的網路開發工具(TBD)</dt>
+ <dd>在此模組,我們會探索許多可用的網路開發工具。這包括檢查想解決的最常見任務類型,它們如何合併到工作流程中,以及目前可用於執行這些任務的最佳工具。</dd>
+ <dt><a href="/zh-TW/docs/Learn/Tools_and_testing/Cross_browser_testing">跨瀏覽器測試</a></dt>
+ <dd>此模組專注於測試網路專案的跨瀏覽器領域。在此,我們會辨認你的目標閱聽者(例如你最該對什麼樣的用戶、瀏覽器、還有設備操心?)如何做測試、不同類型的程式碼會碰上的主要問題、如何解決/減輕這些問題、哪些工具最能幫你測試和修復問題、還有如何用自動化加速測試。</dd>
+</dl>