diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:43:23 -0500 |
commit | 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 (patch) | |
tree | a9ef8ac1e1b8fe4207b6d64d3841bfb8990b6fd0 /files/zh-tw/learn/tools_and_testing | |
parent | 074785cea106179cb3305637055ab0a009ca74f2 (diff) | |
download | translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.gz translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.bz2 translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.zip |
initial commit
Diffstat (limited to 'files/zh-tw/learn/tools_and_testing')
6 files changed, 1567 insertions, 0 deletions
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><input></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"><ul></a></code> 內,含有一定數量的 <code><a href="/zh-TW/docs/Web/HTML/Element/li"><li></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><li></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 => { + 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"><ul> + <li v-for="task in tasks" v-bind:key="task.id"> + <span>\{{task.name\}}</span> + <button type="button">Delete</button> + </li> +</ul></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 ( + <div className="todoapp stack-large"> + <h1>TodoMatic</h1> + <form> + <h2 className="label-wrapper"> + <label htmlFor="new-todo-input" className="label__lg"> + What needs to be done? + </label> + </h2> + <input + type="text" + id="new-todo-input" + className="input input__lg" + name="text" + autoComplete="off" + /> + <button type="submit" className="btn btn__primary btn__lg"> + Add + </button> + </form> + <div className="filters btn-group stack-exception"> + <button type="button" className="btn toggle-btn" aria-pressed="true"> + <span className="visually-hidden">Show </span> + <span>all</span> + <span className="visually-hidden"> tasks</span> + </button> + <button type="button" className="btn toggle-btn" aria-pressed="false"> + <span className="visually-hidden">Show </span> + <span>Active</span> + <span className="visually-hidden"> tasks</span> + </button> + <button type="button" className="btn toggle-btn" aria-pressed="false"> + <span className="visually-hidden">Show </span> + <span>Completed</span> + <span className="visually-hidden"> tasks</span> + </button> + </div> + <h2 id="list-heading"> + 3 tasks remaining + </h2> + <ul + role="list" + className="todo-list stack-large stack-exception" + aria-labelledby="list-heading" + > + <li className="todo stack-small"> + <div className="c-cb"> + <input id="todo-0" type="checkbox" defaultChecked={true} /> + <label className="todo-label" htmlFor="todo-0"> + Eat + </label> + </div> + <div className="btn-group"> + <button type="button" className="btn"> + Edit <span className="visually-hidden">Eat</span> + </button> + <button type="button" className="btn btn__danger"> + Delete <span className="visually-hidden">Eat</span> + </button> + </div> + </li> + <li className="todo stack-small"> + <div className="c-cb"> + <input id="todo-1" type="checkbox" /> + <label className="todo-label" htmlFor="todo-1"> + Sleep + </label> + </div> + <div className="btn-group"> + <button type="button" className="btn"> + Edit <span className="visually-hidden">Sleep</span> + </button> + <fbutton type="button" className="btn btn__danger"> + Delete <span className="visually-hidden">Sleep</span> + </button> + </div> + </li> + <li className="todo stack-small"> + <div className="c-cb"> + <input id="todo-2" type="checkbox" /> + <label className="todo-label" htmlFor="todo-2"> + Repeat + </label> + </div> + <div className="btn-group"> + <button type="button" className="btn"> + Edit <span className="visually-hidden">Repeat</span> + </button> + <button type="button" className="btn btn__danger"> + Delete <span className="visually-hidden">Repeat</span> + </button> + </div> + </li> + </ul> + </div> + ); +} +</pre> + +<p>再來,請打開 <code>public/index.html</code> 改掉 <code><a href="/en-US/docs/Web/HTML/Element/title"><title></a></code> 元素中的文字,將文字改為 <code>TodoMatic</code>,這樣才能對應到上述 <code><a href="/en-US/docs/Web/HTML/Element/Heading_Elements"><h1></a></code> 的文字。</p> + +<pre class="notranslate"><title>TodoMatic</title></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"><form></a></code> 元素,其中包含可以寫入新任務的 <code><a href="/en-US/docs/Web/HTML/Element/input/text"><input type="text"></a></code> 以及一個button來送出表單。</li> + <li>我們還有一個<code><button></code>陣列,用以過濾不同任務狀態(全部、待辦、完成)。</li> + <li>下方接著一個標題告訴我們擁有多少任務</li> + <li>我們有3個預設任務寫在無序清單<code><ul></code>元素中,其中包含的各項單一任務都是使用<code><a href="/en-US/docs/Web/HTML/Element/li"><li></a></code>。 並且在各項任務下方增加 <code><a href="/en-US/docs/Web/HTML/Element/input/text"><input type="checkbox"></a></code>來勾選此任務是否完成,以及編輯、刪除按鈕<code><button></code>。</li> +</ul> + +<p>這個表單<code><a href="/en-US/docs/Web/HTML/Element/form"><form></a></code> 允許我們新增、管理任務, <code><button></code>幫助我們篩選任務狀態,<code><ul><li></code> 則負責展示任務清單。接著由於缺乏編輯任務的UI,讓我們開始來處理畫面美化的部分吧。</p> + +<h3 id="Accessibility_features_無障礙設定">Accessibility features 無障礙設定</h3> + +<p>您可能已經注意到一些不常見的屬性,例如:</p> + +<pre class="brush: html notranslate"><button type="button" className="btn toggle-btn" aria-pressed="true"> + <span className="visually-hidden">Show </span> + <span>all</span> + <span className="visually-hidden"> tasks</span> +</button></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"><ul></a></code> 元素中:</p> + +<pre class="brush: html notranslate"><ul + role="list" + className="todo-list stack-large stack-exception" + aria-labelledby="list-heading" +></pre> + +<p><code>role</code> 屬性會向科技輔具說明各種元素分別代表什麼用途。雖然瀏覽器預設<code><ul></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"><input id="todo-0" type="checkbox" defaultChecked={true} /> +<label className="todo-label" htmlFor="todo-0"> + Eat +</label></pre> + +<p><code><input/ ></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 > 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 > * { + flex: 1 1 49%; +} +.btn-group > * + * { + 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"] > * { + margin-top: 0; + margin-bottom: 0; +} +.stack-small > * + * { + margin-top: 1.25rem; +} +.stack-large > * + * { + margin-top: 2.5rem; +} +@media screen and (min-width: 550px) { + .stack-small > * + * { + margin-top: 1.4rem; + } + .stack-large > * + * { + 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 > * { + max-width: 50rem; + margin-left: auto; + margin-right: auto; +} +.todoapp > form { + max-width: 100%; +} +.todoapp > 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 > * { + 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 > label::before, +.c-cb > input[type="checkbox"] { + box-sizing: border-box; + top: -2px; + left: -2px; + width: 44px; + height: 44px; +} +.c-cb > input[type="checkbox"] { + -webkit-font-smoothing: antialiased; + cursor: pointer; + position: absolute; + z-index: 1; + margin: 0; + opacity: 0; +} +.c-cb > 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 > label::before { + content: ""; + position: absolute; + border: 2px solid currentColor; + background: transparent; +} +.c-cb > input[type="checkbox"]:focus + label::before { + border-width: 4px; + outline: 3px dashed #228bec; +} +.c-cb > 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 > 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> |