--- title: 深入淺出 JavaScript --- # 深入淺出 JavaScript #### tags: `課程` `JavaScript` `Prototype` `Web Design` `App Design` :::info - **開課日期:** 2021/11/27 - **課程時間:** 09:00~12:00 - 13:00~17:00 - **開課時數:** 49小時 - **講師資訊** - **姓名:** 江星誌 - **電子信箱:** iffyart@icloud.com - **聯絡電話:** 0971025397 - **官網連結:** https://www.i-noby.com/ - **課程目標** - 網頁程式基礎概念學習 - 暸解 JavaScript 基礎語法與如何操作 - 使用純 JavaScript 來進行網頁特效互動與操作 - 學習如何使用階層式樣式表(CSS)來改變網頁樣式 - 使用 JavaScript 的開源 Library 進行網頁設計 - 學習如何使用 React 進行新世代的網站開發 - 暸解 JSON 與資料結構及應用 - 初步暸解API概念以及與後端進行互動設計 ::: <br> # 課程大綱 | 日期 | 課程內容 | 課程時間 | |:------------------:|:------------------------------------------------------------------------------ |:-----------------------:| | 第一週 110/11/27(星期六) | JavaScript 語言基本介紹 | 第一節 <br/>(09:00~12:00) | | | 實務範例操作練習 | 第二節 <br/>(13:00~17:00) | | 第二週 110/12/04(星期六) | JavaScript Libraries 與 Frameworks 介紹 | 第三節 <br/>(09:00~12:00) | | | jQuery 基本效果學習 | 第四節 <br/>(13:00~17:00) | | 第三週 110/12/11(星期六) | 商務形象網站設計開發 - 1/3 | 第五節 <br/>(09:00~12:00) | | | 商務形象網站設計開發 - 2/3 | 第六節 <br/>(13:30~17:30) | | 第四週 110/12/25(星期六) | 商務形象網站設計開發 - 3/3 | 第七節 <br/>(09:00~12:00) | | | Github 上傳網站以及架設連結 | 第八節 <br/>(13:30~17:30) | | 第五週 111/01/08(星期六) | React.js Framework 與 MVVM 基本介紹 | 第九節 <br/>(09:00~12:00) | | | JavaScript ES6 語法學習與操作 | 第十節 <br/>(13:30~17:30) | | 第六週 111/01/15(星期六) | 使用React.js 創建一個基本的 TodoList 專案 | 第十一節 <br/>(09:00~12:00) | | | 使用React.js 創建動態前端網頁應用 1/2 | 第十二節 <br/>(13:30~17:30) | | 第七週 111/01/22(星期六) | 使用React.js 創建動態前端網頁應用 2/2 | 第十三節 <br/>(09:00~12:00) | | | 課程結語與課後補充 | 第十四節 <br/>(13:30~17:30) | <br> # 課程內容 ## 開發環境基本設置 下載網址:https://code.visualstudio.com/ :::info * Visual Studio Code 軟體下載 * 輔助套件下載 * 程式環境架設(JavaScript放置於HTML位置中的區別) * 外接JavaScript檔案建置 ::: 課程套件下載: * [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) 前端開發套件推薦下載: * [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) * [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) * [indent-rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow) * [JavaScript (ES6) code snippets](https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets) * [Import Cost](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost) ```json= { "prettier.singleQuote": true, "prettier.jsxSingleQuote": true, "prettier.trailingComma": "all", "csscomb.preset": "zen", "editor.tabSize": 2, "editor.insertSpaces": false, "editor.formatOnType": true, "editor.formatOnSave": true, "editor.minimap.enabled": false, "editor.renderWhitespace": "boundary", "html.format.wrapAttributes": "force-aligned", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "emmet.triggerExpansionOnTab": true, "css.validate": true, "less.validate": false, "scss.validate": true, "liveServer.settings.donotVerifyTags": true, "liveServer.settings.donotShowInfoMsg": true, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[jsonc]": { "editor.defaultFormatter": "vscode.json-language-features" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[scss]": { "editor.defaultFormatter": "michelemelluso.code-beautifier" }, "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode", }, "liveSassCompile.settings.formats": [ { "format": "expanded", "savePath": "/assets/css", "extensionName": ".css" } ], "workbench.iconTheme": "material-icon-theme", "bracketPairColorizer.depreciation-notice": false, "window.zoomLevel": 2, } ``` --- ## 網頁設計基礎學習 ### HTML5 基礎知識學習 在網頁設計當中,我們的頁面是藉由所謂的 HTML(Hyper Text Markup Language) 所組織起來的,同時 HTML 也被簡單地稱之為標籤式程式語言,原先的用意其實是為了進行學術資料的交互傳遞而誕生,也可以說資料清晰地傳遞就是他本質的工作,而隨著經年累月的發展,在經歷了過於繁瑣的 XHTML(XML嚴格設計)失敗之後,在 2014 由W3C(World Wide Web Consortium,全球資訊網協會)完成設計標準,我們目前主流所使用的 HTML5 就此誕生. 以下就讓我們來看一下最基本的網頁結構吧! ```html // 定義文件類型為 HTML <!DOCTYPE html> <html lang="en"> <head> // 指定字元編碼 <meta charset="UTF-8" /> <title>Document</title> </head> <body> 我們網頁的內容 </body> </html> ``` > 在上方的範例中,我們其實可以清晰地看到標籤式程式語言的結構,而標籤類型主要可以分成兩種,這邊就讓我們繼續往下看吧! 基本上 HTML 的本職就是進行資料的傳遞,而下方兩種標籤類型其實可以理解成,若沒有需要子項目的存在,就會以單標籤的形式進行設計,這類型的標籤通常功能單一,或是與文件設定以及資源引入為主,相反則是作為內容包覆的容器使用 ```html // 單標籤結構(單一元素) <meta charset="UTF-8" /> // 首尾標籤結構(容器元素) <title>Document</title> // 單標籤範例 <br /> <hr /> <img src="" /> // 首尾標籤範例 <div></div> <body></body> ``` ### 開發規範建議 - 盡可能採用有意義的 Tag 進行開發設計,包括組件 UI > 雖然可以藉由 div 與 class 或 id 的搭配,來完成我們網站的樣式賦予及設計,但那將對程式的可讀性造成不可挽回的打擊,並且完全違背了「 語易化 」這個最根本的設計準則,因此在建置的過程中,使用 HTML5 與原先就有著「富有意義」的 Tag 進行撰寫,就成為了非常重要的課題,並且這在一定程度上,也會幫助瀏覽器的讀取以及 SEO 的建立. #### 常用 HTML5 標籤一覽 - `<header>` 網頁頁首,經常包含 logo、標題、導航列或介紹文字 - `<nav>` 網站操作導航列 - `<aside>` 跟主要內文沒有直接聯繫的側欄,常用來做功能按鈕設計與輔助說明文字 - `<main>` 主要內容 - `<article>` 主要文章 - `<section>` 段落 - `<footer>` 網頁結尾,經常包含版權資訊、聯絡方式 > 雖然很多人都將 HTML5 標籤作為主要切版結構進行設計,但在實務將其溶入頁面組件等開發也可以協助我們的語易化更加順暢 #### 常用內容標籤一覽 - `<div>` : 分組用 ( block ) - 盡可能少用 - `<ul>` 有序清單 & `<ol>` 無序清單 - 底下清單都是 `<li>` - 去除清單預設樣式 CSS:`list-style-type: none` 常用標籤 - 文字內容 - `<h1>` ~ `<h6>` 網頁標題 - `<p>` 網頁內文 - 假文產生字: [Lorerm ipsum](https://loremipsum.io/) - 也可以用塊級字體取代: [blokkfont](http://www.blokkfont.com/)、[Rdacted-Font](https://github.com/christiannaths/Redacted-Font) - `<span>` 分組用 ( inline ) - 通常放在 `<p>` 裡面 - `<em>` 強調文字 - `<strong>` 重要文字 - `<blockquote>` 表示引用自其他內容 - `<a>` 超連結 or 錨點 - 超連結: - `href` 填 網址 - `target` 內連 or 外連 - `_self` 在同一個標籤頁跳轉 - `_blank` 另開標籤頁 - 錨點: - `href` 填 `#id` - 例如網頁要跳到 `h1` - `<h1 id="title">標題</h1>` - `<a href="#title">跳到標題</a>` - `<pre>` 保留格式 - 因為在瀏覽器解析裡,不管內文有多少空白,都只會顯示成 1 個空白,也不會換行。所以如果要換行可以使用 `<br>` 標籤 - `<code>` 放程式碼 - `<time>` 日期與時間 - `<hr/>` <單標籤>分隔線 - `<br/>` <單標籤>換行 常用標籤 - 內容 - `<img/>` <單標籤>圖片 - `src` 圖片網址 - `title` 鼠標停留在圖片上的提示文字 - `alt` 圖片連結失效的替代文字 - `<figcaption>` 圖片說明文字 #### 範例程式 ```html <!-- 不良好的操作 --> <body> <div class="header"></div> <div class="nav"></div> <div class="main"></div> <div class="article"> <div class="section"></div> </div> <div class="footer"></div> </body> <!-- 良好的操作 --> <body> <header></header> <nav></nav> <main> <article> <section></section> </article> </main> <footer></footer> </body> ``` 備註:HTML 的 Tag 並不是唯一存在的值,實際上除了最底層的 body 以外,其他的標籤都能在遵守頁面「 語易化 」的情況下,重複的使用於 LAYOUT 中 #### 盡可能完善 meta 標籤 > Meta 標籤相當與網頁的身份定義,他負責在第一個時間告訴瀏覽器相關的資訊,並且還有部分設定將影響功能本身的操作,此外的標籤也肩負完善 SEO 的使命 > #### 基本標籤 ```html <!-- 網站編碼 --> <meta charset="UTF-8"> <!-- 負責將 IE 瀏覽器提升至可用最新版本 --> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- 告訴頁面需依照頁面尺寸進行畫面切換 - RWD 基本標籤 --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> ``` #### 盡可能完善部分標籤子屬性 > 許多 HTML Tag 會有著一些子屬性的定義值,如圖片就具有 alt 這個當圖片沒有獲取到資源時,負責代替顯示的文字,因此補齊這些所需的相關資料便尤為重要(且對 SEO 與無障礙網站等也會有所影響). > #### 基本標籤 ```html <!-- 網站編碼 --> <img src="peraonAvatar.png" alt="人物頭像" title="人物頭像" /> ``` <br/> ### CSS 基礎語法學習 階層式樣式表 CSS(Cascading Style Sheets),是建立在 HTML 的基礎上所設計的樣式表,原本僅為了將傳遞資訊的 HTML 添上色彩與註解等,而隨著時間的流逝,我們對於網頁美觀與互動的需求日益提升,具有更高變化性的 CSS3 在 2011 年被制訂出來,同時也成為了我們設計網頁所使用的最佳能手. ### 為什麼我們要使用 CSS? CSS 作為一個簡易的樣式表,在原生的效能上具有非常優秀的發揮,同時他也可以協助我們改善網頁結構,並縮短製作與維護 HTML 的時間,同時目前作為必備的 RWD 響應式網頁設計,也少不了設計與規劃. --- ### CSS 使用方式 #### 行內樣式(inline-style) 直接在 HTML 的標籤中將 CSS 寫入 Style 的屬性內,這將直接改動 HTML 元素的樣式 ```html= <header style="background-color: red"></header> ``` #### 內部樣式表載入 使用建立在網頁內的樣式表進行設置,通常均是使用放在 head 內的 style ```html= <head> <style> .red-bg{ background-color:red; } <style/> </head> <body> <header class="red-bg"></header> </body> ``` #### 外部樣式表載入 ```html= <head> // 使用 link 標籤載入樣式表 <link rel="stylesheet" href="style.css"> // 使用 CSS 提供的 @import 進行載入 <style> @import url('style.css') <style/> </head> <body> <header class="red-bg"></header> </body> ``` ### CSS 基本語法 CSS 的語法結構,是藉由選擇器與宣告所組成的,而宣告內部會帶有複數的屬性與數值. <br/> ![](https://i.imgur.com/HD3QI1b.png) #### 選擇器 用來指定這個樣式所要影響 HTML 位置 #### 宣告 定義這個選擇器將會套用哪些樣式 #### 範例 在下方的範例中 選擇器是 .red-bg,會給擁有 red-bg 這個 class 的目標元素宣告中的屬性 background-color 是宣告中的屬性,指的是背景顏色 red 是宣告中的值,代表想要想要給予的參數 ```css= <style> .red-bg{ background-color:red; } <style/> ``` ### CSS 基本選擇器一覽 #### 全域選擇器 可以選到頂部階層以下全部的 HTML 元素,預設頂部階層是 html ```css= *{color:red} ``` #### 元素選擇器 可以直接選擇 HTML 的標籤名稱,如 h1 或是 body、div等 ```css= body{color:red} ``` #### class 選擇器 可以選擇到在 HTML 中 class 的屬性值內有包含定義值得元素 ```css= .red-text{color:red} ``` #### id 選擇器 可以選擇到在 HTML 中 id 的屬性值內有包含定義值得元素 ```css= #red-text{color:red} ``` <br/> ### 常用虛擬類別選擇器 - `:hover` 滑鼠滑入時的樣式  - `:not(選擇器名稱)` 不符合選擇器名稱的元素 - `:first-child` 第一個元素 - `:last-child` 最後一個元素 - `:only-child` 只有一個元素 - `:nth-child(參數)` 較為複雜的選擇器 - `:nth-child(數字)` 選擇第幾個元素 - `:nth-child(2n)` 選擇2的倍數的元素,n代表乘機可做復合運算 - `:nth-child(odd)` 選擇奇數元素 - `:nth-child(even)` 選擇偶數元素 - `:nth-last-child(數字)` 選擇從後面數過來第幾個元素 ### 常用偽元素 - `::before` 加入在元素前內容並套用樣式,需搭配 content 屬性使用 - `::after` 加入在元素後內容並套用樣式,需搭配 content 屬性使用 <br/> ### 組合選擇器 #### 後代選擇器 只要是選擇器內 子項目的目標均會受到影響 <br> ![](https://i.imgur.com/kdTlCN2.png) ```css= body p{color:red} ``` #### 子選擇器 只有選擇器內下一層子項目的目標會受到影響 <br> ![](https://i.imgur.com/bSSeMnf.png) ```css= body > p{color:red} ``` <br/> ### 選擇器的套用順序 #### 後面的設定會勝過前面的 在同樣的結構之下,後面撰寫的樣式將會擁有較高的優先級 #### 選擇器的明確精度越高會先行套用 所謂的明確度具有兩個面向 1.複雜的選擇器被認為是精度高的表現,因此優先權重會較高 2.選擇器具有優先排序 id選擇器 > class 選擇器 > 元素選擇器 > 全域選擇器 #### !important優先套用 只要在屬性後面加入「!important」及會擁有最高優先級,但也可被其他 !important 取代(若其他優先級高) 屬性參考與學習: http://www.w3big.com/zh-TW/css/default.html http://tympanus.net/codrops/css_reference/ ### 建置規範建議 #### 兩個單字以上的字串以 - 進行連接 > 雖然 CSS 選擇器的規則並無特別規定,但大部分工程師均遵守著這個規定,此方法可避免與 JavaScript 中的小駝峰產生撞名問題,也可方便區隔字串內容. > #### 範例程式 ```html <!-- 不良好的操作 --> <body> <header class="headerBanner"></header> </body> <!-- 良好的操作 --> <body> <header class="header-banner"></header> </body> ``` #### 盡可能使用百分比或相對值進行開發 > CSS 中有許多單位可以使用,在這邊建議盡可能使用 em、rem、% 等進行開發,因為頁面很常因尺寸變動而有異常,因此將版面或是文字大小等寫死並不會是一個很好的實行方案. > ```css // 不良好的操作 body { font-size: 18px; } // 良好的操作 body { font-size: 1.15rem; } ``` ### 使用 BEM 結構進行開發 > CSS 作為一個有著權重概念的語言,很容易產生一些無可避免的搶權問題,並且在大多數的案例中,我們都會看到撞名等問題產生,而 BEM 的撰寫方法,則可以有效的從根本解決這類型的問題. > BEM 的設計模式是以區塊開發為主(與可以理解為組建開發) - BLOCK - 區塊本身的跟節點 - ELEMENT - 區塊內部的元素(並不會疊加) - MODIFIER - 區塊所使用的額外裝飾 ### 範例程式 ```html <nav class="navbar"> <article class="navbar__container navbar__container--full"> <h1 class="navbar__title">JavaScript Course</h1> <ul class="navbar__link"> <li> <a class="line-btn" href="#"></a> </li> </ul> </article> </nav> </nav> ``` ```css // 過往 (除了產生權重外,偶爾也會因為命名失誤導致如 container 等常用字被重複定義樣式) .navbar {} .navbar .container {} .navbar .container.full {} .navbar .title {} .navbar .link {} // BEM 結構 (單一階層使權重成本均降至最低) .navbar {} .navbar__container {} .navbar__container--full {} .navbar__title {} .navbar__link {} ``` ### 基礎結構設計範例 #### HTML ```htmlmixed= <body> <nav class="navbar"> <a class="navbar__logo" href="index.html">Mockup Company</a> <ul class="navbar__link"> <li><a href="#">Link</a></li> <li><a href="#">Link</a></li> <li><a href="#">Link</a></li> </ul> <ul class="navbar__button"> <li><a href="#">Log in</a></li> <li><a href="#">Get Started</a></li> </ul> </nav> <header class="header-home"> <h1 class="header-home__title">Page Title</h1> <p class="header-home__container"> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequuntur blanditiis deleniti quod sunt nulla eos autem magnam, </p> </header> </body> ``` #### (Base)reset.css ```css= html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } ``` #### (Layout)body.css ```css= @import url('https://fonts.googleapis.com/css2?family=Exo:wght@300;400&family=Noto+Sans+TC:wght@300;400;500;700&display=swap'); body { font-family: 'Exo', sans-serif; font-family: 'Noto Sans TC', sans-serif; } ``` #### (Component)header.css ```css= .header-home { position: relative; display: flex; align-items: center; flex-direction: column; justify-content: center; height: 80vh; background-image: url('../../images/dog.jpeg'); background-position: center; background-size: cover; } .header-home::before { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: white; content: ''; opacity: 0.6; } .header-home > * { position: relative; } .header-home__title { font-size: 2.5rem; margin-bottom: 1rem; color: blueviolet; } .header-home__container { max-width: 40em; text-align: center; } ``` [課程範例參考](https://github.com/IffyArt/web-effect) --- ## JavaScript 語言基本介紹 ### 什麼是 JavaScript? JavaScript 是個跨平台、物件導向(OOP)、函式導向(FP)、輕小型的腳本語言。 他有著半編譯的特性,以及獨特的執行模式,因其的自由度極高,進而延伸出了各種不同的相關技術練,像是撇除最基礎的網頁特效互動操作外,有著像後端與伺服器的Node.js,特化網頁前端操作的框架如React.js以及Angular等等,而本次課程所使用的編輯器VS Code所使用的Electron,而對於手機應用程式而言,除了較舊的jQuery UI所設計的簡易手機應用外,現在也有了原生開發類型的React Native,以及優化Web View處理器的其他架構等等,可說是一個涵蓋量最大的程式語言. 當 HTML 建立了網站的架構,CSS 完善了頁面得樣式之後,就該輪到 JavaScirpt 來添加互動了,基本上在網頁設計中,關於 UI 的複雜操作與資料的串接均離不開 JavaScript,即使在現代的 HTML 與 CSS 的交互協做之下,任何複雜的頁面都得以設計,但始終均僅停留在「畫面」這個概念上,因此若希望網站本身能有真正的功能的話,學習 JavaScript 確實是一條無可厚非的道路。 <br/> ### 註解你的 JavaScirpt Code 雖然大部分的人比較不在意註解這件事情,但實際上註解就跟你在程式中的筆記一樣,它可以幫助下一次看到程式時,可以更加明確的知道自己之前做了什麼,並且好的註解在協同作業時,也可以讓其他的開發者有更直觀的參考點. ```javascript= // 以下宣告變數並且給值 var courseName = '深入淺出 JavaScript' // 課程名稱 /* const courseInstructor ='IFFY' console.log(courseInstructor) */ // 單行註解 /* 多行 註解 */ ``` <br/> ### 顯示你的 JavaScirpt Code 在 JavaScript 的設計當中,我們很常使用到 console.log 來對資料進行輸出展示,而除了 console.log 外,也有像是直接在網頁中輸入文字的 write(),以及彈出視窗 alert() 等等,而該使用何種方式來進行程式輸出展示,其實都取決於開發時的作業需求,不過因為 console.log 在程式輸出上,是使用網頁的開發者工具,因此不太會遭遇如 write() 當頁面過長時的找尋問題,以及 alert() 將會導致其餘頁面無法互動的問題,並且可以將開發環境與 DOM 進行分割,以利開發者更好找到問題的所在. ```javascript= // 在網頁中直接寫入 document.write('標題') // 在網頁中觸發彈出視窗(注意:彈出視窗將會將網站其他操作完全暫停) alert('我是被觸發的彈出視窗') // 在網站開發工具內被顯示 console.log('Hello Console'); ``` <br/> ### 定義一個 JavaScript 變數 ```javascript= // 賦值操作 var name = 'IFFY'; // 更改變數內容 name = '你的名字' ``` > 變數設計是一個既簡單又複雜的東西,說他簡單是因為他的入手難易度非常低,而且大部分的情況下並不會過於複雜,但也因為他是一切的基本,所以關於他的延展可說是屬之不盡,下面將會列舉大部分會用到的操作與關鍵字,同學們可以當作是一個參考來看就好,不需要去記憶,只要在需要時來查看就好. > JavaScript 許多基本語法借鑒自 Java,C或是C++,但亦受 Awk、Perl 和 Python 的影響。 | 類型 | 描述 | 範例 | | -------- | -------- | -------- | | var | 宣告一個隨時可以變動的變數 | var title = 'JavaScript 課程' | | let | (ES6)宣告一個可隨時變動的「區塊」「區域」變數 | let title = 'JavaScript 課程' | | const | (ES6)宣告一個只可讀取不可變動的常數 | const title = 'JavaScript 課程' | 在 JavaScript 中,變數必須使用字母(letter)、下底線( _)、錢號($)作為開頭;後面的字員組成可以包含數字(0-9)。JavaScript 是區分大小寫(case secsitive)的,大寫字母('A' ~ 'Z')和小寫字母('a' ~ 'z')皆可使用且不相等。 > 雖然我們有個高彈性的命名規則,但在實務上開發者均習慣使用小駝峰來命名變數 > 如:const titleName = 'JavaScript 課程' ### 變數可建立的型別 六種基本型別(純值):undefined、null、boolean、number、string、symbol(ES6 新規範,幾乎沒看到有人使用) | 類型 | 描述 | 範例 | | -------- | -------- | -------- | | Undefined | 未宣告的變數,或宣告過卻沒有初始化的變數 | var text,text2; <br>此時的兩個變數值便為Undefined,記住JavaScript允許將變數從新定義為Undefined,但我們會盡量避免他的發生<br>var text= 1234;<br>var text = undefined; | | String | 字串 | var text='JS'text2='JS2'; | | Number | 64bits浮點數 | var text = 123; | | Boolean | 布林值 | var text = true, text2 = false; | | Null | 當物件不再食用時可宣告為Null | var text = null; | | (物件型別)Function | 函數 | var text = function(){}; | | (物件型別) Object | 物件 | var text = {},text2 = {key1:1}; | | (物件型別) Array | 擁有多筆資料的變數 | var text = [],text2 =[1,2,3]; | ### 基本語法操作 | 種類 | 描述 | 運算符 | 運算元 | 結果值 | | -------- | -------- | -------- | -------- |-| | 算術運算式 | 四則運算符號 | + - * / % ++ -- | Number | Number| | 位元運算式 | 提供快速且低階的運算 | & | ~ ^ << >> >>> | Number | Number| | 比較運算式 | 測試真假值 | > < >= == != === !== | Boolean | Boolean| | 邏輯運算式 | 測試真假值 | && || ! | Boolean | Boolean| | 字串運算式 | 將字元合併 | + | String | String| | 賦值運算式 | 為變數賦值 | = += -= *= /= &= <<= |= >>= >>>= ^= | * | * | | 函數運算式 | 執行函數 | () | Function | * | #### 基本型別操作練習 > 下方範例可以將 log 出來的值進行 +1 的處理,會因為 JavaScript 自動型別轉換的特性獲得結果(沒有實質定義的類別),也可以將變數前面加上 !,已將其轉換成布林 ```javascript= var iAmUndefined; var iAmString = '我是一個字串'; var iAmNumber = 10; var iAmBoolean = true; var iAmNull = null; console.log(iAmUndefined); console.log(iAmString); console.log(iAmNumber); console.log(iAmBoolean); console.log(iAmNull); ``` #### 物件型別操作練習 > 物件型別有很多東西可以變化,他的可延展性也讓整個網站操作有了更多可能性 ```javascript= var addNumber = function (x, y) { return x + y; }; function numberFunction(x, y) { if (x === 0) { console.log('x 不可以是 0'); return; } return x + y / 2 + 3; } console.log(addNumber(1, 2)); console.log(numberFunction(0, 5)); console.log(numberFunction(addNumber(1, 2), 5)); ``` #### 百用不膩 BMI 範例 ```javascript= // // BMI 計算 BMI值計算公式: BMI = 體重(公斤) / 身高*身高(公尺) var BMI = {}; // var BMI = new Object(); 不建議這樣寫,只會讓行數新增且需要額外的閱讀 BMI.getBMI = function (weight, height) { var bmi = weight / ((height / 100) * (height / 100)); return bmi; }; // 可將函式寫入其餘物件內 console.log(BMI.getBMI(87, 175)); ``` #### 基礎練習項目 ```javascript= // 1、賦予變數資料使用 "=" ,同時因為 JavaScript 特性,將會自動轉為被賦予型態 var str = 'hello'; // 2、算式運算符包括 +(加法) -(減法) *(乘法) /(除法) %(取餘數) var number = 10; // console.log(number + 3); // console.log(number - 3); // console.log(number * 3); // console.log(number / 3); // console.log(number % 3); // 3、對變數進行單獨加法操作 var i = 3; // i = i + 1; // i++; // ++i; // alert(i); // 4、對變數進行單獨減法操作 var i = 3; // i--; // --i; // alert(i); // 5、將運算式放置於前後的差別,在於賦值的的順序問題 // console.log(i--); // console.log(--i); // <額外提示>先賦予 a=10,再執行加法操作 => b=16,最後才是a=11 ,此處可更改 ++ 前後改變結果 var a = 10; var b = a++ + 6; // console.log(a); // console.log(b); // 6、常用關系運算符簡略 (< <= > >= == != ===) var num1 = 3; var num2 = 4; var str3 = '3'; // <範例說明>相對等於範例 == // if (num1 == num2) { // console.log("相等"); // } else { // console.log("不相等");; // } // <改良寫法>改為條件 (三元) 運算子 // num1 == num2 ? console.log("相等") : console.log("不相等") // <改良寫法>設計包覆函式 var equal = function () { console.log('相等'); }; var notEqual = function () { console.log('不相等'); }; // num1 == str3 ? equal() : notEqual(); // <範例說明>絕對等於範例 === ,此處判斷將判別型別 // num1 === str3 ? equal() : notEqual() // num1 === str3++ ? equal() : notEqual() // num1 === --num2 ? equal() : notEqual() // <範例說明>不等於 != // num1 != --num2 ? equal() : notEqual() // 7、常用邏輯運算式 並且(&&) 或者(||) 相反(!) var person = { name: 'Alex', age: '22', sex: 'man', }; // person.age > 30 && person.sex == 'man' ? equal() : notEqual() // <範例說明>大於25 並且 小於三十 // person.age > 25 && person.age < 30 ? equal() : notEqual() // <範例說明>大於25 或者 小於三十 // person.age > 25 || person.age < 30 ? equal() : notEqual() // <範例說明> !將會反轉資料的布林值,同樣使用兩個將會再次反轉 // console.log(!true); // console.log(!!true); // console.log(!!person); // <額外補充>藉由型別轉換實現簡易條件判斷 var shopCart = []; // console.log(shopCart.length); // shopCart.length ? console.log('有內容') : console.log('無內容'); // shopCart.push('apple') // console.log(shopCart.length); // shopCart.length ? console.log('有內容') : console.log('無內容'); ``` <br/> ### 進階討論 #### 變數都去哪了? > 變數會被處存到你所依賴的環境上,說白話文就是被存在記憶體裡,在更簡單的來說,就是 JavaScript 會將他放在一個方便找尋且操作的地方,雖然大部分時間,這其實不是我們關心的事,但很多時候這個冷漠,就會將我們帶入永劫不復的深淵(物理上),因此在這邊就讓我們稍微了解一下吧! ```javascript= var name = 'Me'; // 印出整個 window 物件 console.log(window); console.log(window.name); // Me ``` 上面的範例是將整個網站的內容列印出來(整個網站就是一個巨大的物件),可以在這之中發現我們所定義的變數,但這裡其實只是因為 var 的性質,他的定義方式與 Window 物件相互掛鉤,導致他在最外層被設定成全域變數,實際上他的實體會在記憶體當中(其實理論上全部的東西都在記憶體)。 #### 賦值操作 > 有時我們會喜歡進行一些複雜的設計,此時我們將很常把一個變數賦予另一個變數,已達成我們想要的功能,而此時就會出現兩種不同的情況,我們可以在下面的範例中一探究竟。 ##### 基本型別(純值) - 傳值(pass by value) ```javascript= // 賦值操作 var name = 'IFFY'; var noName = name; name = 'No name'; console.log(noName); // IFFY console.log(name); // No name ``` > 當我們使用六個基本型別進行變數宣告的時候,JavaScript 均會直接將數值傳過去,因此新的變數就不會有舊的資料有任何關聯了 ##### 物件型別 - 傳址(pass by reference) ```javascript= // 賦值操作 var nameArray = ['Iffy', 'Alex']; var newNameArray = nameArray; newNameArray.push('Eva'); console.log(nameArray); //['Iffy', 'Alex', 'Eva'] ``` > 但當我們使用物件型別的時候,事情就開始不一樣了,因為物件的結構可能會非常複雜,因此他會將「記憶體位置」傳送過去,因此用此方法實作之後,兩個 Array 之間會互相影響。 ### 條件判斷與迴圈 #### <常用條件判斷式> 如果是否則(if ... else) ```javascript= // if (condition) { // } else { 可以不加 else 條件 // } var number = 12; // 是 if (number > 10) { console.log(true); } // 是否 if (number > 10) { console.log(true); }else{ console.log(false) } // 多條件 if (number > 10) { console.log('大於10'); } else if (number > 5) { console.log('小於等於10大於5'); } else { console.log('其他'); } ``` #### <常用條件判斷式> 依照條件判斷內容(switch ... case) ```javascript= // switch (key) { // case value: // break; 沒有加 break 的話將會持續下方條件 // default: // break; // } var week = 2; switch (week) { case 1: console.log('星期一'); break; case 2: console.log('星期二'); break; case 3: console.log('星期三'); break; default: console.log('請輸入 1 - 3'); break; } ``` #### <常用條件判斷式> 條件滿足前執行(do ... while) ```javascript= // do { // } while (condition); var i = 2; do { document.write(i); console.log(i); i++; } while (i <= 10); ``` #### <常用條件判斷式> 符合條件前執行(while) ```javascript= // while (condition) { // } var i = 2; while (i <= 10) { document.write(i); document.write("<br/>"); i++; } ``` #### <差異解釋> (do ... while) 與 (while) ```javascript= var whileNumber = 21; // var whileNumber = 20 while (whileNumber >= 20) { console.log('條件達成即結束循環'); whileNumber-- } do { console.log('不管如何都先進行一次操作,之後才判斷是否完成條件') whileNumber-- } while (whileNumber >= 20); ``` #### <常用迴圈> for & forEach 固定次數的迴圈操作 為每個實體提供函式 ```javascript= // for (let index = 0; index < array.length; index++) { // const element = array[index]; // } var array = ['apple', 'banana', 'orange']; for (let index = 0; index < array.length; index++) { const element = array[index]; console.log(element); } array.forEach(function (element) { console.log(element); }); ``` #### <常用迴圈> Map 固定次數的迴圈操作 會建立一個新個陣列,並執行提供的操作 ```javascript= var array = ['apple', 'banana', 'orange']; array.map(function (element){ document.write(element); }) console.log(array); const array1 = [1, 4, 9, 16]; const map1 = array1.map(x => x * 2); const map1 = array1.map(function (x) { return x * 2; }); console.log(array1); console.log(map1); ``` <br/> ## 實務範例操作練習 ### <練習案例-01> 在網站上新增多個隨機變數 ```javascript= var str = '產出亂碼 - '; function getRandomInt(max) { return Math.floor(Math.random() * max); } for (var i = 1; i <= 10; i++) { if (i <= 9) { str = str + getRandomInt(100) + '、' } else { str = str + getRandomInt(100) } } document.write(str); ``` ### <練習案例-02> 日薪為 1000 的員工,以每年增長 2% 的比例提高薪資,持續工作 30 年後的薪資 ```javascript= var salary = 1000; for (var i = 1; i <= 30; i++) { salary = salary * 1.02; } document.write(salary); ``` ### <練習案例-03> 輸出 100 以內能被固定數字整除的數字 ```javascript= for (let i = 0; i < 100; i++) { if (i % 7 == 0) { document.write(i); document.write("<br />"); } } var startNumber = 1; while (startNumber * 7 < 100) { document.write(startNumber * 7); document.write("<br />"); startNumber++; } for (var i = 1; i <= parseInt(100 / 7); i++) { console.log(i);// 會給出被 7 整除後餘數為零的數值 document.write(i * 7); document.write("<br />"); } ``` ### <練習案例-04> 條件判斷與迴圈應用 ```javascript= for (var i = 1; i <= 5; i++) { if (i == 3) { //可操作的條件 break; } document.write(i); document.write("<br />"); } document.write("break 會跳出 for"); arrayBlock = [ { name: '王大明', age: 23 }, { name: '王小明', age: 17 }, { name: '王鐘銘', age: 20 }, ]; arrayBlock.forEach(function (element) { if (element.age >= 18) { console.log(element.name); } }); ``` ### <練習案例-05> 計算 100 - 300 之間能被 12 或者 17 整除的數值 ```javascript= for (var i = 100; i <= 300; i++) { if (i % 12 == 0 || i % 17 == 0) { // 可將 || 改成 && document.write(i); document.write("<br />"); } } ``` ### <練習案例-06> 顯示下列圖型 ```javascript= /* * 第1行,1个* **  第2行,2个* ** 第3行,3个* **** 第4行,4个* ***** 第5行,5个* ****** 第6行,6个* ... 第n行,n个* */ var rows = 20; for (var i = 1; i <= rows; i++) { // i代表行數 // 要求第幾行,輸出幾個'*'' for (var col = 0; col < i; col++) { document.write('*'); } document.write('<br />'); } for (let index = 20; index > 0; index--) { for (var col = 0; col < index; col++) { document.write('*'); } document.write('<br />'); } for (var i = 1; i <= rows; i++) { // i代表行數 console.log(i); // 要求第幾行,輸出幾個'*'' for (var col = 0; col < i; col++) { document.write('*'); } document.write('<br />'); } ``` <br/> ### JavaScript Libraries(函式庫) 與 Frameworks(框架) 介紹 ### 關於定義那些小事 其實名詞的定義大多時候並不重要,同時也不需特別認真的進行區分,程式語言畢竟終究是達成目的的工具,大多時我們不需要太過執著於通往的過程,當然這是暫時撇出效能與可讀性等所說的話,但相信我,在學習的過程中矯枉過正帶來的只有累贅。 以直觀的角度而言,所謂的函式庫(Libraries)其實就是可額外引用的資源,許多語言也都會存在自己不同的函示庫,他誕生於程式語言開發的過程中,並不會將其都囊跨其中的操作,打個比方而言,以過往的範例「在網站上新增多個隨機變數」舉例,這類型的函示運算我們需要自行處理,若想要重複利用還需要另外撰寫成 Function,試想一下如果他是語言的原生函示的話,我們可能就能用單行解決程式了,但想必大家也注意到了,有這需求的人可說是鳳毛菱角,因此許多開發者就不約而同的開始將自己所用的功能額外包出,並建立成了所謂的 Libraries(函式庫)。 當然,真正會需要額外建立的,通常都是比較複雜的邏輯,但以概念而言,我們自己包的小功能也可以被稱之為 Libraries,而 Frameworks 則是有點像是這些函式庫的集結,他會建立在一個程式語言上,並且整合設計一個高可用性的骨架供人使用. > 以火鍋來舉例的話,Libraries 就像是已經整理好的高湯塊,非常容易在任何地方使用,而 Frameworks 就是整鍋都處理好讓你自己按照喜好往裡面加東西的整鍋火鍋. ### 大多數的 JavaScript Libraries 跟 Frameworks 在做些什麼 其實大部分時候在前端網站開發時,多數的 Libraries 與 Frameworks 都拿來處理著複雜的 DOM 操作,同時也有許多像是輪播功能與動畫等額外的小功能,講白了也就是協助 HTML、CSS 與 JavaScript 的相互配合,而要了解為什麼需要這樣處理,我們就需要先看一下 DOM 是什麼存在了。 ### The HTML DOM (Document Object Model) 操作 下方是 W3CShool 所提供的圖,他簡單跟我們頗析了網頁的結構,就跟我們之前的課程所提過的一樣,Web 本質上就是一個巨大的 Object,因此操作 DOM 的意思,其實就是用程式運行的方式,動態控制著這個網頁所發生的一切。 ![The HTML DOM Tree of Objects](https://i.imgur.com/6SJZKZ4.gif) #### 修改 DOM 中的 title ```javascript= <script> document.title = '我是新的標籤'; </script> ``` > 在上方的案例中,我們很輕鬆的改變了網站上的 title,doucment 作為我們文件的主體,是很常拿來進行操作的物件,大家不妨用 console.log(document),來查看這個物件裡面有什麼可以改吧! #### 簡單的操作範例 ```javascript= <body> <button onclick="myFunction()">點擊我</button> <div id="myDiv">This is my DIV element.</div> </body> <script> // 取得物件實體 var myDiv = document.getElementById('myDiv'); // 可以看到這個實體內的「文字內容」 console.log(myDiv.textContent); // 建立一個用於互動的函示 function myFunction() { if (myDiv.style.display === 'none') { myDiv.style.display = 'block'; } else { myDiv.style.display = 'none'; } } // 改個寫法並用三元運算式 // const myFunction = function(){ // myDiv.style.display === 'none' // ? (myDiv.style.display = 'block') // : (myDiv.style.display = 'none'); // } </script> ``` ### 加上樣式的 DOM 操作 從上面的練習中我們不難看出,實際上 JavaScript 在操作 DOM 時是相對直覺的,但網頁設計終究不是一個單體,這次就讓我們搭配起 CSS 來呈現畫面吧! ```javascript= <style> .height-line { border-bottom: 1px solid #ffccee; } </style> <body> <button onclick="addColor()">點擊我修改顏色</button> <button onclick="addClass()">點擊我新增樣式類別</button> <div id="myDiv">This is my DIV element.</div> <span id="mySpan">This is my SPAN element.</span> </body> <script> // 建立實體物件 var myDiv = document.getElementById('myDiv'); var mySpan = document.getElementById('mySpan'); // 新增顏色功能 var addColor = function () { myDiv.style.color = 'red'; }; // 新增樣式功能 var addClass = function () { myDiv.className = 'height-line'; mySpan.className = 'height-line'; }; // 帶入變數的顏色修改 // var addColor = function (color) { // myDiv.style.color = color; // }; </script> ``` > 上方的範例也可以帶入多個變數進行複雜的操作,例如像下面那樣給複數的參數,先動態建立目標實體後,在進行額外的操作。 > > 小叮嚀: 物件的 style 屬性可以操作 CSS 的大部分特性 ```javascript= var changeTargetColor = function (target, color) { var targetElement = document.getElementById(target); targetElement.style.color = color; }; changeTargetColor('mySpan','blue') ``` 上面的範例基本上均為練習操作,而現在我們已經擁有足夠的練習量,是時候該來製作一個常用 UI 出來了! ### 作為 DOM 基礎練習的尾聲,我們來做一個標籤切換吧! 在實作之前,我們先思考一下我們目標是什麼,這是寫程式開發非常重要的一環,因此等等在實作的過程中,我們也會將 HTML、CSS、JavaScript 的部分先進行分離,首先讓我們開始思考,我們要結構要長得的怎麼樣吧! ```html= <body> <article> <ol> <li>標籤一</li> <li>標籤二</li> <li>標籤三</li> </ol> <section>標籤項目一</section> <section>標籤項目二</section> <section>標籤項目三</section> </article> </body> ``` > 符合大家的預期嗎?這邊的設計是思考說作為一個可以切換的功能,應該要有一個包覆在最外面的主層,而子項目會有兩個分支,一個是標籤的按鈕列,另外一個是內容的呈現頁,當然這裡也可以做一層額外的包覆,但這類型本身就是見仁見智的設計方式. 接下來讓我們思考一下樣式的問題吧!儘管這麼說,但可惜的是我們是以 JavaScript 為主的課程,不過下方的樣式還是能大概說明一下的,我們首先對 Body 做了定義,但這只是為了讓之後的內容置中好查看而已,之後就是對 tab-box 本身進行設計,還另外設計了當 tab 被點擊時會產生的效果,另外各位同學也要記得,要把這些樣式加到我們的 HTML 上才有用喔! ```css== <style> body { display: flex; align-items: center; justify-content: center; min-height: 100vh; } .tab-box { display: flex; flex-direction: column; width: 400px; } .tab-box section { padding: 1rem; min-height: 5rem; background-color: bisque; } .tab-box__header { display: flex; padding-left: 0; list-style: none; } .tab-box__header > li { margin-right: 10px; } .tab-box__header > li.active { color: blueviolet; } </style> <body> <article class="tab-box"> <ol class="tab-box__header"> ... ``` 終於來到最後的重頭戲了,為了方便學習我們會設計兩個版本出來,一個是以上面作為基礎延伸的版本,另外一個是藉由 「程式」 特性實作的版本,那就先嚷我們從簡單的開始吧! ```html= <style> body { display: flex; align-items: center; justify-content: center; min-height: 100vh; } .tab-box { display: flex; flex-direction: column; width: 400px; } .tab-box section { padding: 1rem; min-height: 5rem; background-color: bisque; } .tab-box__header { display: flex; padding-left: 0; list-style: none; } .tab-box__header > li { margin-right: 10px; cursor: pointer; } .tab-box__header > li.active { color: blueviolet; } </style> </head> <body> <article class="tab-box" id="tab-box"> <ol class="tab-box__header"> <li onclick="triggerSection(event,'targetOne')" id="defaultOpen"> 標籤一 </li> <li onclick="triggerSection(event,'targetTwo')">標籤二</li> <li onclick="triggerSection(event,'targetThree')">標籤三</li> </ol> <section id="targetOne">標籤項目一</section> <section id="targetTwo">標籤項目二</section> <section id="targetThree">標籤項目三</section> </article> </body> <script> // 取得全部需要使用的 UI var tabBox = document.getElementById('tab-box'); var tabBoxTab = document.querySelectorAll('li'); var tabBoxSection = document.querySelectorAll('section'); var triggerSection = function (event, target) { // 消除全部的 Section 顯示 tabBoxSection.forEach(function (element) { element.style.display = 'none'; }); // 取得目標實體 var targetElement = document.getElementById(target); // 顯示目標 targetElement.style.display = 'block'; // 清除 tab 上的樣式並且將目前點擊的目標加上 active tabBoxTab.forEach(function (element) { element.classList = ''; }); event.currentTarget.className += ' active'; }; // 預設出發此名稱的點擊事件 document.getElementById('defaultOpen').click(); </script> ``` > 相對直覺的程式對吧!除了使用 forEach 來處理 DOM 元素以外,基本上都是我們老生常談的東西了,當然當中也有像是點擊事件傳入,以及預設點擊操作這種行為,但其實都還算好理解的範圍,但現今這樣做其實是有弊端的,各位可以看到我們與 DOM 本身的牽扯性極強,包括需要給予很多 ID 這點,對於一個可重複利用與需要額外擴充的 UI 都非常不良,因此下面就讓我們用程式的思維,來解決這過於土法煉鋼的問題吧! ```html= <style> body { display: flex; align-items: center; justify-content: center; min-height: 100vh; } .tab-box { display: flex; flex-direction: column; width: 400px; } .tab-box section { padding: 1rem; min-height: 5rem; background-color: bisque; } .tab-box__header { display: flex; padding-left: 0; list-style: none; } .tab-box__header > li { margin-right: 10px; cursor: pointer; } .tab-box__header > li.active { color: blueviolet; } </style> <body> <article class="tab-box" id="tab-box"> <ol class="tab-box__header"> <li>標籤一</li> <li>標籤二</li> <li>標籤三</li> </ol> <section>標籤項目一</section> <section>標籤項目二</section> <section>標籤項目三</section> </article> </body> <script> var tabBox = document.getElementById('tab-box'); // 在已經搜尋出的 DOM 物件內在進行搜尋 var tabBoxTab = tabBox.querySelectorAll('li'); var tabBoxSection = tabBox.querySelectorAll('section'); var triggerTab = function (tabNumber) { tabBoxSection.forEach(function (element, index) { element.style.display = 'none'; // 使用 forEach 自帶的 index,同時對 tabBoxTab 進行同樣的處理 tabBoxTab[index].className = ''; }); tabBoxSection[tabNumber].style.display = 'block'; tabBoxTab[tabNumber].className = 'active'; }; tabBoxTab.forEach(function (element, index) { element.onclick = function () { triggerTab(index); }; }); triggerTab(0); </script> ``` > 所謂的變數以及參數,其實有著許多我們可以額外操作的細節空間,在這個範例中,我們藉由陣列的特性將原先兩次的 forEach 合併處理,並且同時處理了原先綁定在 UI 上的操作,讓程式的延展性提供,雖然以目前的結果而言都是好處居多,但其實大家應該不難看出,當我們與 HTML 進行分離的同時,整個設計其實也開始愈發抽象了。 ### 進階討論 (倒數計時專案) ```javascript= <body> <p id="downDate"></p> </body> <script> // 定義倒計時目標時間 var countDownDate = new Date('July 15, 2022 16:10:25').getTime(); // 新增每秒更新時間的函示 var x = setInterval(function () { // 取得今日的日期 var now = new Date().getTime(); // 找出現在和倒計時日期之間的時間 var distance = countDownDate - now; //天、小時、分鐘和秒的時間計算 var days = Math.floor(distance / (1000 * 60 * 60 * 24)); var hours = Math.floor( (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60), ); var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((distance % (1000 * 60)) / 1000); // 在 id="downDate" 的元素中顯示結果 document.getElementById('downDate').innerHTML = days + 'DAY ' + hours + 'h ' + minutes + 'm ' + seconds + 's '; // 如果倒計時結束的話,就顯示一些預設文字 if (distance < 0) { clearInterval(x); document.getElementById('downDate').innerHTML = '倒數已結束'; } // console.log(parseInt(Math.random() * 10)); }, 1000); </script> ``` ### 最後讓我們來稍微討論一下十種目前流行的 JavaScirpt 寫法吧! ``` <body> <ul id="todos"></ul> <form> <input name="todo" type="password" /> <input type="submit" value="Add Todo" /> </form> </body> ``` ``` <script> // Get DOM elements const form = document.querySelector('form'); const input = document.querySelector("[name='todo']"); const todoList = document.getElementById('todos'); // Side Effects / Lifecycle const todoData = []; function addTodo(todoText) { todoData.push(todoText); const li = document.createElement('li'); li.innerHTML = todoText; todoList.appendChild(li); input.value = ''; } // Events form.onsubmit = (event) => { event.preventDefault(); addTodo(input.value); }; </script> ``` [10-javascript-frameworks ](https://github.com/IffyArt/10-javascript-frameworks) | 開發架構名稱 | 簡略介紹 | | -------- | -------- | | Vanilla JS | 不借助任何外力的基礎 JavaScript 開發,擁有最高的可控性 | | React | Facebook 所開源的專案,主要特點為虛擬 DOM 的設計跟坐擁最廣大的社群,但因為寫法過於自由,以至於沒有一個良好的統一規範,本身雖然作為只管理 View 的 Libraries,但擁有著數個完整的 Framework,同時也以最小的架構著稱 | | Angular | Google 所開源的框架,以高可維護性以及嚴謹著稱,對專案架構有自己的一套做法,官方文件異常齊全,但因為他採用 TypeScript 進行開發,因此需要付出的學習成本特別高 | | Vue | 中國開發者所發佈的開源專案,以輕量級以及方便使用的特性著稱,本身融合了上方兩個的各自優點,但均未抵達同等水平,為各方面最為平均的框架,另外也坐擁廣大的社群 | | Svelte | 近年來廣受好評的開源專案,運作原理是將原先在瀏覽器上的運算拉到編譯階段處理,以達到最低成本的文件傳輸,需要非常理解 webpack 的運作 | | Lit | Google 所贊助的專案,專注在 Web Component 的開發,作為 Web 的標準,可以設計出許多可跨框架以及平台的組建,但 Web Compeont 可是出了名的難開發(即使有了這套也不好操作) | | Alpine | Ionic 團隊所設計出的手機組件創建框架,初衷是要將它引回 ionic 的設計中,但目前支援度一直都有在陸續提升 | | Solid | 基本上他就像是 React 一樣,不同的是他並不會見虛擬 DOM ,但轉換為實體 DOM 並進行優化的操作,使他的效能一直有直著優秀的發揮 | | Stencil | 目前 jQuery 的流行替代品,本身體積非常輕(4kb)且提供了 html 本身語法的擴增 | | Mithril | 與 React 一樣使用虛擬 DOM 進行開發,但本身非常輕量化且狀態管理方式有所不同 | <br/> ## jQuery 基本效果學習 [學習用網頁](https://iffyart.github.io/JavaScript-Course/Chapter-03/) [你不需要 jQuery](https://youmightnotneedjquery.com/) <br/> <br/> ## JavaScript ES6 語法學習與操作 ES6(ES2015) 是目前最新的官方版本,因其標準在 2015 年中才定案,因此該時間前開發的瀏覽器版本會出現部分不支援的問題,而過往普遍所使用的 JavaScript 版本 ES5(ECMAScript 5) 則是在 2009 年底發行的,這時間跨度其實相當的大,而當中的 ECMAS 是指歐洲計算機製造協會(European Computer Manufactures Association),其中設立的 TC39 負責了該標準的討論與走向. 其實上方的名稱定義與歷史定位等,並不會是我們需要認真探討的點,我們需要知道的是因為發布時間的關係,導致像 IE11 等瀏覽器可能會出現對 ES6 語法不支援的問題,而這也是前端工程師所面對的世紀難題. ### 從宣告開始學習 ES6 語法 在之前的課程中我們有稍微提過變數宣告的部分,在 ES6 中新增了兩個夥伴,以下就讓我們從宣告再次開始吧! ```javascript= // 這是變數宣告有可能看到的方式,但除了最後一個外基本上都是在 window 上建立全域變數 a = 10 this.a = 10 window.a = 10 var a = 10 ``` 需要先介紹上方操作的原因是,JavaScript 是一套非常自由的語言,以上均可使程式正常運行,並達成相同的結果,也就是說 var 本身其實在某方面而言是非必要的. 會有上方的操作的原因,是因為 var 是所謂的函示作用域(function scope),而現在要開始介紹的 let 與 const 則不同,他們屬於區塊作用域(Block scope),雖然說起來還蠻抽象的,但其實我們實際看 code 的時候,結果是非常一目瞭然的. ```javascript= // 使用 var 進行的宣告會以 function 做為分隔區塊 function test(){ var a = 10 } if(true){ var b = 20 } console.log(a) // a is not defined console.log(b) // 20 ``` ```javascript= // 使用 let 或 const 進行的宣告會以 「區塊」 做為分隔區塊 function test(){ let a = 10 } if(true){ const b = 20 } console.log(a) // a is not defined console.log(b) // b is not defined ``` 在上方的範例中,大家應該會發現第二種的行為操作更加合理,因為實際上 function scope 很容易造成部分變數作用的混淆,並且在觀看上也相對不直覺,且大多的撰寫操作中,也會盡量在程式開頭就先完成 var 的操作,雖然理論上是在建立全域變數,但追根究底其實就是在 window object 上建立變數存取而已. 下方範例就是很明顯的操作,使用 var 的 for 將會在 window object 建立 index 這個變數,這很有可能會跟其他的變數互相影響從而導致錯誤 ```javascript= for (var index = 0; index < 3; index++) {} console.log(index); // 取得 3 for (let index = 0; i < 6; i++) {} console.log(i); // i is not defined ``` 那介紹完了作用域,接下來就讓我們從兩個宣告所使用的方式與地方著手吧! ### const const 其實就是常數的意思,真正的含義其實就是固定的值,以下方的案例為例,這樣操作就會導致程式出錯. ```javascript= const a = 1 a = 2 // 錯誤訊息 ``` 以上的操作有一個核心重點,是常數本身不可被變更,但在 JavsScript 中是存在 「傳址」 這個概念的,因此如果將常數定義為物件型別(array、object等)而非純值的話,他還是可以進行修改的,只是若給予他一個全新的 地址 的話,他還是會發生錯誤 ```javascript= const a = {}; a.foo = 2; console.log(a); a = { b: 1 }; // 錯誤訊息 ``` ### let let 其實就沒有那麼多額外的規則了,他與 const 的差別只有他作為一個變數,可以任意的修改與刪除,現在慣用的操作方式均拿他來取代 var 進行變數定義,因為再如 for 的迴圈中,使用 var 很容易造成相互影響的錯誤 ### 提升(Hoistion) 在之前的範例中,我們可能習慣了使用為賦值的變數將出現 undefined 的標語,但在使用 let 與 const 時這會直接錯誤,但原因其實並非他們沒有進行提升,而是因為一個名為時間死區的機制(Temporal Dead Zone),簡單來說就是在賦值成功並進入到作用域之前,為了防止有任進行操作而設置的保護機制 ```javascript= let x = 'outer scope'; (function(){ console.log(x) // let x = 'inner scope' // 這行將導致錯誤 })() ``` > 設計規範:以目前最流行的設計指南而言,我們會將物件類型以及常數使用 const 進行宣告,而變數類型使用 let 宣告,而 var 的部分則幾乎不會使用 ### typeof typeof 雖然不是 ES6 才推出的方法,但他是一個讓我們很好判斷變數型態的一個操作,但要注意的是他對 null 的判斷會以 object 為回傳 ```javascript= var iAmUndefined; var iAmString = '我是一個字串'; var iAmNumber = 10; var iAmBoolean = true; var iAmNull = null; var iAmFUnction = function () {}; console.log(typeof iAmUndefined); //undefined console.log(typeof iAmString); // string console.log(typeof iAmNumber); // number console.log(typeof iAmBoolean); //boolean console.log(typeof iAmNull); // object console.log(typeof iAmFUnction); // function ``` ### 箭頭函示 在 ES6 中新增了一個函式的撰寫方式,也就是這邊要探討的 Arrow Function,要注意的是他並不是過去 function 的縮寫語法,而是一個經過改良並重新設計的新語法,最主要的功能是在沒有 {} 包覆功能時,將會自動 return 右方的內容(這在 React 中很常用),且不在需要 function 關鍵字 ```javascript= // ES5 var x = function(x, y) { return x * y; } // ES6 const x = (x, y) => x * y; ``` 需要注意的地方 + Arrow Function 並不會被提升,因此需要在使用前宣告 + 建議使用 const 進行宣告 + 若函式使用 {} 進行包覆,則不會自動 return 任何東西 #### 基本函示定義語法(概念補充) 其實在函示定義中,存在著所謂的匿名函示,通常用在指定給一個識別名或是單次的操作功能 ```javascript= // 匿名函示 function(){} // 有名字的函示 function foo(){} (function(){ console.log('匿名函示範例') })() ``` ### 函示預設值 在 ES5 的標準中,我們定義函示的預設值其實相對不方便,我們需要藉由額外的判斷來處理,但在 ES6 中,我們有了更簡便的方式 ```javascript= // 過去寫法 function myFunction(x, y) { var x = x || 10 var y = y || 10 return x + y; } myFunction(5); function myFunction(x=10, y = 10) { return x + y; } myFunction(5); ``` ### 短路求值(小技巧) 上方的操作有一個小技巧叫做短路求值,他是藉由 || 與 && 的回傳特性而實現的操作,簡單的說就是一個簡易的邏輯判斷式 ```javascript= let a = 1 && 2 let b = 0 && 2 && 3 // 0 等於是 false 將會直接回傳 let c = true && false let d = true || 'test' let e = false || 'test' console.log(a); // 2 console.log(b); // 0 console.log(c); // false console.log(d); // true console.log(e); // test ``` ### 展開運算式 展開運算值是 ES6 中非常好用的一個操作,他可以藉由將其他 array 展開在內容的方式,去複製其他陣列的內容,原理上跟各自進行 push 一樣,且會是完全新的資料,不會觸發淺複製的問題 ```javascript= const arrayA = [1,2,3] const arrayB = [1,2,3,...arrayA] console.log(arrayB) //[1, 2, 3, 1, 2, 3] ``` 在函示參數裡協助展開 ```javascript= const sum=(a,b,c)=> a + b + c const arrayA = [1,2,3] console.log(sum(...arrayA)) // 6 ``` 也可以將字串展開 ```javascript= const arrayA = [1,2,3] console.log(...arrayA) // 1 2 3 ``` ### 解構賦值 解構賦值其實正確來說應該是解構並且指定值,只是在網路上中文都流傳為解構賦值,他是拿來提取固定指定值的一個操作,在 React 中會非常平凡的出現,這邊就先讓我們看一下基本的範例吧! #### 陣列操作 ```javascript= // 基本操作 const [a,b]=[1,2] // a=1 b=2 // 若需先建立變數 let a,b; const [a,b]=[1,2] // a=1 b=2 // 可以跳過某值 const [a,,b]=[1,2,3] // a=1 b=2 // 其餘運算式 const [a,...b]=[1,2,3] // a=1 b=[2,3] ``` > 基本上可以理解為鏡像對照,且可以進行多維或複雜的操作 #### 物件操作 ```javascript= // 基本操作 const {user:x}={user:5} // x=5 // 失敗操作 const {user2:x}={user:5} // x=undefined 因為前綴名稱不同 // 賦予新的變數名稱 const {prop:x,prop2:y} = {prop:10,prop2:20} // x=10 y =20 // 屬性賦值寫法 const {prop:prop,prop2:prop2}={prop:5,prop:10} // prop=5 prop2=10 // 簡短語法 const {prop,prop2}={prop:5,prop:10} // prop=5 prop2=10 // 若需使用 let 先宣告 let a,b ({a,b}={a:1,b:2}) // a=1,b=2 // 需要額外操作的原因是{}雖然是物件宣告的方法,但同時也是 function 的區塊,因此這邊需要額外設計 ``` ### 這樣做會更好 ```javascript= const turtle = { name: '鑽石 🐢', legs: 4, shell: true, type: '北美鑽紋龜', meal: 10, diet: '生魚片?' } function feed(animal) { return `餵食 ${animal.name} ${animal.meal} 小片 ${animal.diet}`; } // 更良好的解答 // function feed({ name, meal, diet }) { // return `餵食 ${name} ${meal} 小片 ${diet}`; // } // 或者 // function feed(animal) { // const { name, meal, diet } = animal; // return `餵食 ${name} ${meal} 小片 ${diet}`; // } console.log(feed(turtle)) ``` <br/> ## React.js Framework 與 MVVM 基本介紹 ### 前端工程師 早期的網頁前端與後端沒有明確得分工,因為當時沒有行動裝置的出現,而現今為了應對RWD(Responsive Web Design)網頁設計,也就是所謂的響應式網頁(依據使用裝置而變換顯示樣式,如手機版本等),專案的架構複雜度越來越龐大,因此前後端的分工才逐漸受到重視,前端工程師的工作就像是橋樑,需要跟UI、UX設計師與後端工程師進行緊密的搭配. ### MVC(Model-View-Controller)架構 MVC三個英文字母所代表的意思: * 模型(Model):程式的功能模組等,接手控制器(Controller)的工作進行處理. * 介面(View):使用者可以看到的畫面,也就是我們所謂的DOM(Document Object Model) * 控制器(Controller):負責轉發請求、控制流程等,並且針對各項請求進行處理. > 簡單來說,MVC是將專案的各個部分功能進行抽象化,使其相互存在關聯性同時保有獨立性,好處是無論你再修改哪一端的程式時,都能確保另外兩端部用做任何修改,後端人員就能專注於模型(Model)的設計,功能的製作與演算邏輯等等就好,而介面(View)就直接交由介面設計師處理,最後再利用控制器(Controller)串接整個專案. MVC架構示意圖架構 --- ![](https://i.imgur.com/AXTp37L.jpg) > * Route(網頁連結等):以網頁來說若沒有連結則出現404,成功便會對Controller發出請求 * Controller :控制器會去與Model和View發送請求與接收資訊,為雙方溝通的橋樑 * Model:負責演算資料與DB取得資料等事宜,再將處理好的資料給Controller傳回給View * View:負責在接受資料來呈現畫面等,也就是user interface * User:使用者介面,會將資料丟回Controller並傳回給Model等 * DB:資料庫,負責存儲資料 ### MVVM(Model-View-ViewModel) MVVM架構示意圖架構 --- ![](https://i.imgur.com/M62dvYP.jpg) > * Route(網頁連結等):以網頁來說若沒有連結則出現404,成功便會對Controller發出請求 * ViewModel :控制器會去與Model和View發送請求與接收資訊,為雙方溝通的橋樑 * Model:負責演算資料與DB取得資料等事宜,再將處理好的資料給Controller傳回給View * View:負責在接受資料來呈現畫面等,也就是user interface * User:使用者介面,會將藉由操作 View 觸發 ViewModel * DB:資料庫,負責存儲資料 > MVVM是MVC架構的延伸版本,其設計概念是將UI端從Server端抽離(前後端分離),而在架構的設計上,則是將MVC中的控制器(Controller)轉換成了ViewModel,最大的區別在使用者在使用軟體時,是直接與介面(View)互動,當介面或模型(Model)產生變動時ViewModel會自動反應,並將結果同步在界面或模組上,因此它比較容易採用雙向資料流(data-binding)的概念,而MVC則偏向單向資料流的設計. ### 前端熱門框架介紹 * Angula(angularjs.org) - 適合後端工程師學習 * Vue(vuejs.org) - 零基礎可學習 * React(reactjs.com) - 需盡可能有 JavaScript 開發經驗或基礎 [範例查看](https://github.com/IffyArt/10-javascript-frameworks) --- ### React.js 介紹 React 是 Faecbook 所發布的一套前端開源專案,主要的功能是拿來進行 View 的開發,在架構上其實就是 MVC 的 V,因此這套函式庫具有非常輕薄且高效能的特點,但同時也因其並非作為 MVVM 架構中的 ViewModel 誕生,因此在整體功能面上需要依賴大量外部開源專案輔助,才能完成一個良好的 MVVM 專案. 另外 React 有一個宗旨,也就是在他官網上的 Learn Once, Write Anywhere (學一次就可以寫在任何地方),其原因是他另外一個名為 React Native(https://reactnative.dev/) 的開源專案,可以用來開發接近原生的 iOS 與 Android 專案,使用的方法是接近轉換編譯的做法,樣式撰寫也偏向 CSS 的方式. #### 特色 * 單向式的資料流(One-way data flow) * 虛擬 DOM 設計(Virtual DOM) * JSX 語法糖 * 提倡 元件(Component) 開發模式 ```javascript= // 有 JSX 的寫法,並建立 Virtual DOM class HelloMessage extends React.Component { render() { return ( <div> Hello {this.props.name} </div> ); } } ReactDOM.render( <HelloMessage name="Taylor" />, // 單向資料流的傳入 document.getElementById('hello-example') ); // 原先的寫法 class HelloMessage extends React.Component { render() { return React.createElement( "div", null, "Hello ", this.props.name ); } } ReactDOM.render(React.createElement(HelloMessage, { name: "Taylor" }), document.getElementById('hello-example')); ``` 上面這個範例看起來非常抽象,那讓我們來引入他們程式來做看看吧! ```javascript= // 在 body 中貼入,並建立 Root 節點 <div id="root"></div> // 引入需要使用的函式庫,需注意這是開發模式的函示庫 <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin ></script> // 開始撰寫這令人困惑的東西 <script> class Hello extends React.Component { render() { return React.createElement('div', null, 'Hello '); } } ReactDOM.render( React.createElement(Hello), document.getElementById('root'), ); </script> ``` 各位撰寫完之後覺得很困惑是正常的,因為我們目前的範例是 React 最複雜的撰寫方法,同時也是最原始的操作方式,實際上在 React 16.8 推出 Hook 這項新功能之後(2018年),class 的寫法就逐漸減少了,但這邊要注意的是他並不是消失,在一些較舊的專案或是需要較強掌控力的組件中,class 還是具有一定的優勢. 下面就讓我們來看一下較新的寫法吧!基本上我們會使用 Function 的方式去建立組件,在 16.8 的版本推出之前這其實也是很常在使用的,但我們統一將其稱為 Pure Component 也就是純的組件,原因是在 Hook 推出之前,Pure Component 並不具備狀態管理等操作,而是僅能藉由單向資料流來顯示固定資料. ```html= <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello World</title> <script src="https://unpkg.com/react@17/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <!-- 不要使用他在正式的專案上 --> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> </head> <body> <div id="root"></div> <script type="text/babel"> function Hello() { return <h1>Hello, world!</h1>; } ReactDOM.render(<Hello />, document.getElementById('root')); </script> </body> </html> ``` 以上就是 React 的基本介紹與範例演示,但這裡其實只能算是牛刀小試的內容了,同時在實際開發上,我們也不會傾向使用這種 CDN 載入的方式進行開發,這邊我們主要的學習目的,只是帶大家稍微看一下 React 大概的撰寫方式,一個以 JavaScript 為主導,使用名為 JSX 的語法糖進行語意化,並採納單向數據流的一個 SPA (single-page application) 函式庫. > 注意: React 是一套撰寫起來十分自由的語言,以上的寫法均能使程式正常運作,並且居有優缺點,因此很多新手的學習時很容易頻繁碰壁,另外其本質其實就是藉由 JavaScript 進行驅動操作的函示庫,因此 JavaScript 的熟悉程度也會影響對 React 的暸解,但 JavaScript 也很自由就是另外的議題了... ```htmlmixed= <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello World</title> <script src="https://unpkg.com/react@17/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <!-- 不要使用他在正式的專案上 --> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> </head> <body> <div id="root"></div> <script type="text/babel"> const { useState } = React; const Hello = () => { const [isOpen, setIsOpen] = useState(true); return ( <h1> {isOpen && <div>Is Open</div>} <button onClick={() => setIsOpen(!isOpen)}>Click Me!</button> </h1> ); }; ReactDOM.render(<Hello />, document.getElementById('root')); </script> </body> </html> ``` > 學習基本 hook 操作 ```htmlmixed= <script type="text/babel"> const { useState } = React; const App = () => { const [page, setPage] = useState('1'); return ( <main> <Navbar page={page} setPage={setPage} /> <Header page={page} /> </main> ); }; const Navbar = ({ page, setPage }) => { const router = [ { name: 'link1', link: '1', }, { name: 'link2', link: '2', }, { name: 'link3', link: '3', }, { name: 'lin3', link: '4', }, ]; return ( <nav className='test'> <ul> {router.map(({ name, link }) => ( <li key={name}> <a onClick={() => setPage(link)}>{name}</a> </li> ))} </ul> </nav> ); }; const Header = ({ page }) => { return <h1>{page}</h1>; }; const Hello = () => { const [isOpen, setIsOpen] = useState(true); return ( <h1> {isOpen && <div>Is Open</div>} <button onClick={() => setIsOpen(!isOpen)}>Click Me!</button> </h1> ); }; ReactDOM.render(<App />, document.getElementById('root')); </script> ``` <br/> ## React 當中我們可能會遇到的 class 概念 ### 從令人困惑的 this 開始學習 this 是 JavaScript 當中一個非常容易讓人困惑的關鍵字,他是一個特殊的識別關鍵字(identifier keyword),會自動定自在每個函式的範疇(scope)內,但實際上要搞清楚他究竟參考了(refers)什麼,是個連資深的開發者都會感到頭疼的問題。 因為我們僅是要稍微了解 ES6 中 class 對 this 的操作,因此在這邊並不會對 this 做太多筆墨的琢磨,各位同學可以有個最基本的認知,就是 this 所綁定的地方,為該觸發環境中的堆疊階層,簡單來說就是在電腦執行緒中被呼叫的位子,我們將使用以下的範例進行簡單的介紹 ```javascript= console.log(this); // 會顯示 window 是因為他在 window 上觸發 function CallMe(name) { this.name = name; console.log(this); } // 使用 function 去動態建立一個物件 var me = new CallMe('Iffy'); // 建立時 會觸發 console.log(this) 的功能,並列印該物件本身(因為是該物件觸發) ``` > 在上方的範例中,我們使用了一個 new 的方法,去進行動態物件的建立,會需要這樣做的原因,是因為在物件導向的語言當中,我們往往會去繼承與依賴提他的物件,而在 JavaScript 中的物件導向也是如此,但他的傳統做法實在上很常令人感到困惑。 ```javascript= function CallMe(name) { this.name = name; } CallMe.prototype.print = function(){ this.name = name; } // 若需要 function 綁定需額外撰寫 prototype var me = new CallMe('Iffy'); me.print(); ``` > 這邊有一個特點需要注意,當我們在建立這種可以重複利用的「類別」時,將採用大駝峰命名 #### 嚴格模式 JavaScript 在設計上特別設置了一個嚴格模式,他使得 this 在沒有觸發堆疊時,不會自動進行 window 的綁定,但要注意的是該設置基本上應該會影響怎麼運行,需注意在 引入 JavaScript 其他的函示庫後的使用。 ```javascript= 'use strict'; // 定義 JavaScript 為 嚴格模式,使 this 不會自動綁定 window (function () { console.log(this); })(); ``` 在上方的範例中我們不難看出,JavaScript 在進行物件導向的設計時,會因為各種細節處理而導致使用起來不如預期,究其原因,是 JavaScript 在 ES6 之前並沒有所謂 類(class) 的設計,這使得我們儘管在操作行為與實作上接近物件導向,但實際在撰寫上卻沒有那麼方便,而這裡就讓我們從範例看所謂的 class 是什麼吧! ```javascript= // 建立類別 class CallMe { constructor(name) { this.name = name; } print() { console.log(this); } } // 建立物件實體 const iffyCall = new CallMe('Iffy'); // 顯示物件內容(會發現與之前一樣在 prototype 中有建立 point function) console.log(iffyCall); // 操作物件功能 iffyCall.print(); ``` 其實 class 的概念就像是藍圖,各位可以把它想像成零件的設計圖,而 new 則是建立這個藍圖為實體的方法,而藍圖的重點基本可以往重複利用以及方向閱讀的方面設想,也就是組件化元件的概念,同時也可以讓多張藍圖堆疊組成如以下範例。 ```javascript= class Book { constructor(title) { this.title = title; } getTitle() { return this.title; } } class EBook extends Book { constructor(title, link) { super(title); // 用來呼叫執行父母類別的建構式(constructor) this.link = link; } getLink() { return this.link; } } const myBook = new EBook('書本名稱', '書本連結'); console.log(myBook); console.log(myBook.getTitle()); ``` <br/> ## 開始建立 React 基本專案 ### 從安裝 Node.js 開始 Node.js 是沒有瀏覽器的 JavaScript,他是用於建構完整 JavaScript 應用程式的執行環境. Node 是開源的軟體,可以安裝在 Windows、macOS、Linux 與其他平台上,同時目前在 JavaScript 的全端開發中,他也負責了後端程式的開發,常用的架構是 Express。 使用 React 時其實不需要使用 Node,但必須使用 Node package manager(npm)來安裝相依檔案以及管理環境,他會在安裝 Node 時自動安裝。 [Node 官網安裝](https://nodejs.org/en/) > 若不確定在機器上是否有安裝 Node.js,可以在 終端機或命令視窗中輸入,若是沒有安裝的話,應該會顯示 Command not found ``` node -v ``` ### 從零到有搭建 React 專案 其實 React 官方提供了我們非常快捷且便利的方法,那就是 create react app 的指令操作,那為什麼這邊還要特意從零到有尼?究其原因是在使用 Create React App 建構專案之後,其實會有蠻大量用不到的東西被引入到你的專案中,且因為 React 其實作為一個蠻輕巧的函示庫,並沒有那麼多複雜的額外綁定,因此自己建立一下也可以當作是在學習 npm 與 package 的操作。 #### 官方提供方法 (嘗試使用並開啟專案) [官方操作連結](https://zh-hant.reactjs.org/docs/create-a-new-react-app.html) Create React App 是一個適合學習 React 的環境,而且也是使用 React 建立一個全新的 single-page 應用程式的最佳方法。 > 它會為你設定好開發環境,以便你能夠使用最新的 JavaScript 特性,提供良好的開發者體驗,並且為線上環境最佳化你的應用程式。你需要在你的機器上安裝 Node >= 14.0.0 and npm >= 5.6。要建立項目,請執行: ``` npx create-react-app my-app cd my-app npm start ``` 透過這些簡單的指令應該可以很簡單的搭建出 React App,雖然能如此輕鬆其實是因為 npx 的關係,但在學習階段又何嘗不可尼? #### 開始搭建自己的專案(可嘗試操作) 其實 npm 是一個非常輕鬆使用的東西,各位同學不妨從頭到尾自己嘗試一下,當然也可以使用目前有的範例檔案,直接運行 npm install [起始範例檔案](https://github.com/IffyArt/React-Project-Demo/tree/feature/first-project) 那就讓我們先來稍微介紹一下專案結構吧!最簡單的是會需要建立一個 src 進行開發內容的存放,建立一個 public 配置我們的靜態檔案,最後在專案目錄放置一個 package.json,其實就大功告成拉! ``` - src App.js index.js - public index.html package.json ``` 基本專案結構是否簡單到符合預期尼?當然還有內容需要填入,同時在專案運行時也會自動安裝其他套件等,但不可否認的是我們的基本結構可與複雜兩個字沒有任何關係尼 #### 填入專案內容 package.json 說白了其實就是專案的設定擋,裡面可以定義任何你想定義的東西,不過這裡的關鍵是在 dependencies(依賴關係) 中將 react 的運作引入,讓我們可以自由的使用他們 ```json= { "name": "react-app", "version": "0.1.0", "private": true, "scripts": { "start": "react-scripts start", "build": "react-scripts build" }, "dependencies": { "react": "^17.0.1", "react-dom": "^17.0.1", "react-scripts": "4.0.2" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ``` App.js 當中會放置我們的主要開發節點,各位可以想像是 「畫面」 的根目錄 ```javascript= function App() { return ( <div> <h1>Home Page</h1> </div> ); } export default App; ``` index.js 其實就是我們 src 這個資料夾的最終集結點,並且會最終經過編譯提供一版可運作的 JavaScript 給 public 中的 index.html 進行引入。 ```javascript= import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root')); ``` > 作為目標集結點,App 這個組件本身當然也可以在本檔案中進行建立,這邊會額外做引入的原因,只是為了讓整個開發環境更加整潔 index.html 就是單純存放我們的靜態頁面內容,同時也可以進行 SEO 的基礎設計 ```htmlembedded= <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="description" content="Web site created using create-react-app" /> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html> ``` > 在當中有用到所謂的 import 與 export,這其實也是 ES6 所提供的寫法,功能是將組建或功能等進行匯入與分享,需注意的是如果 export 後面沒有特別帶 default(預設匯出),那在 import 時則需要使用 import {App} from './App' 的方式 在建立完專案的現在,我們在理論上只需要用 npm install 就可以將專案的依賴下載下來了,package 會透過 npm 自動下載所設定的內容,但因為可能會遇到環境與套件安裝等問題,因此可能還需要額外進行一些排錯處理,若真的無法正常操作的同學,可以先使用 npx create-react-app 進行操作 ### 建立我們第一個有功能的專案(Todo list) 在這一個範例中,我們將先使用 class 來建立我們的應用程式,已達到練習的目的,之後會再將練習的功能進行改寫,用更新的撰寫方法實作 修改 App.js ```javascript= import React from 'react'; // 建立一個單純顯示 UI 的純組件 class TodoList extends React.Component { render() { return ( <ul> {this.props.items.map((item) => ( <li key={item.id}>{item.text}</li> ))} </ul> ); } } class App extends React.Component { constructor(props) { super(props); this.state = { items: [], text: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } // 改變輸入匡內容 handleChange(e) { this.setState({ text: e.target.value }); } // 送出輸入匡內容 handleSubmit(e) { //取消表單預設事件 e.preventDefault(); if (this.state.text.length === 0) { return; } const newItem = { text: this.state.text, id: Date.now(), }; // class 需要透過 setState 才能修改 constructor 的內容 this.setState((state) => ({ items: state.items.concat(newItem), text: '', })); } // render 是宣染畫面用的操作,最終的 UI 將藉由 return 回程,有時會在該函式內進行資料整理 render() { return ( <div> <h3>TODO</h3> <TodoList items={this.state.items} /> <form onSubmit={this.handleSubmit}> <label htmlFor='new-todo'>What needs to be done?</label> <input id='new-todo' onChange={this.handleChange} value={this.state.text} /> <button>Add #{this.state.items.length + 1}</button> </form> </div> ); } } export default App; ``` 經歷了上方的寫法,大家應該會發現這樣的開發體驗並不是很理想吧!雖然 React.Component 實際上提供給了我們非常完整的狀態管理機制,但在直觀的體驗上著實不是那麼的舒暢,雖然在後端的角度來看這類型的物件導向沒有什麼大問題,但在有高自由的度的前端來看,這樣有些冗長的程式也一度勸對很多了,不過之前也不是一定要使用 class 的寫法,在 hook 推出的版本(16.8版)前,所謂的 prue componet 就非常盛行,以下方的 TodoList 為例,在沒有狀態管理的需求下,子層的組件其實是沒有必要使用這麼多語法的,但同時他也一度失去了狀態管理的能力。 ```javascript= function TodoList(props) { return ( <ul> {props.items.map((item) => ( <li key={item.id}>{item.text}</li> ))} </ul> ); } ``` ### 使用 useState 重新設計我們的 Todo list 在下方的程式碼中,我們會發現我們的程式少了非常多,但這其實不是因為 function component 的設計更加優秀,而只是他更加輕便而已,而 hook 帶給我們的便利,即是在狀態管理上提供了一個非常優秀的操作,他就如同字面意義上的掛鉤,與 function 本身建立連結,並且支援了異動時重新 render 的機制(建立 let 等變數異動時不會觸發 render),讓我們可以用更加直觀的方式進行應用程式的開發 ```javascript= import { useState } from 'react'; const TodoList = ({ todoList }) => { return ( <ul> {todoList.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> ); }; const App = () => { const [text, setText] = useState(''); const [todoList, setTodoList] = useState([]); const handleSubmit = (e) => { e.preventDefault(); if (!text.trim()) { setText(''); return; } setTodoList([...todoList, text]); setText(''); }; return ( <div> <h3>TODO</h3> <TodoList todoList={todoList} /> <form onSubmit={handleSubmit}> <label htmlFor='new-todo'>What needs to be done?</label> <input id='new-todo' onChange={(e) => setText(e.target.value)} value={text} /> <button>Add</button> </form> </div> ); }; export default App; ``` ### 使用 useEffect 操作生命週期 在已經擁有了狀態管理的能力之後,我們就只剩下生命週期管理需要在意了!實在話在使用 hook 時其實無論如何,都無法達到 class 所提供的狀態管理強度(所繼承的 React.Component 對組建的生命週期有進行很完整的設計),但大多時候我們並沒有需要用到那麼複雜的生命週期,因此可以在下方使用我們的 useEffect 稍微進行一些操作看看! ```javascript= import { useState, useEffect } from 'react'; useEffect(() => { // 將在組件載入以及組建更新觸發 console.log('show'); // 將在組建消失或是發生異動重新建立觸發 return () => { console.log('clear'); }; // 下方的 array 中的值是拿來監控的,當其中的數值發生變化,將會觸發 useEffect 異動 }, [text]); ``` <br/> # 課程額外資源 ## 資源庫 ### [Frontend Development](https://github.com/codingknite/frontend-development) > 眾多開發者在 github 上所貢獻出的資源彙整,幾乎涵蓋了目前所有主流開發的資源 ### [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) > Airbnb 開出的 JavaScript 撰寫規範 --- ## 圖庫下載 ### [illustrationkit](https://illustrationkit.com/) > 簡單的開源插圖,提供 SVG 下載以利配合動畫與特效的設計. ### [BGJar](https://bgjar.com/) > 多元的背景資源庫,並有著動態的隨機產生功能,以方面工程師獲取資源. ### [Unsplash](https://unsplash.com/) > 全球等級的開源圖庫,來至於全網共同新增的成果,著作權使用部分均會寫在圖片下載的細項裡。 --- ## HTML5 標籤式程式語言 ### [HTML5 Reference by MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) > HTML5 Tag的大集合,使開發者不必再牢記每個不同的tag,開發時只需上去尋找相關內容即可. ### [HTML Entity Reference by CSS-Tricks](https://css-tricks.com/snippets/html/glyphs/) > 整理多項特殊符號的顯示與字符,並提供了多種可供使用的編碼,是非常好的工具. ### [HTML Cheat Sheet](https://websitesetup.org/html5-cheat-sheet/) > 網上開源的html備忘清單,並提供了多種觀看方式. --- ## CSS 階層式樣式表 ### [CSS3 Reference by MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference) > CSS Property的大集合,有幾乎全部的相關資料可以供人參考. ### [CSS3 Reference by Codrops](http://tympanus.net/codrops/css_reference/) > 另一個Property的大集合,但相對整潔乾淨並且有進行分類,是個查閱屬性的不二之選. ### [Can I Use?](http://caniuse.com/) > 提供每項Property的快速查詢,能夠迅速暸解屬性對各項瀏覽器與裝置的支援度. ### [Clippy](http://bennettfeely.com/clippy/) > 一個簡單並好操作的clip-path應用工具,讓開發者可以直覺的進行屬性設計. ### [Cubic-bezier function generator](http://cubic-bezier.com/#.17,.67,.83,.67) > 貝茲曲線的產生器,能幫助動畫以及轉變有更加良好的體驗. ### [CSS easing functions ](http://easings.net/) > 除了單純的動畫以及轉變應用外,還多支援了漸層以及Function的實作,適合拿來處理一些特殊效果. --- ### JavaScript 網頁動態語言 ### [w3schools](https://www.w3schools.com/js/default.asp) > JavaScript語法的大集合,Function,開發時只需上去尋找相關內容即可. ### [JavaScript Reference by MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) > JavaScript語法的大集合,Function,開發時只需上去尋找相關內容即可. ### [You might not need jQuery](http://youmightnotneedjquery.com/) > 純JavaScript與jQuery進入後的程式差異,包括了動態效果以及後端API串接的範例 ### [ECMAScript 發展史與可用性](https://kangax.github.io/compat-table/es6/) > 涵蓋近期ECMAScript發展之歷史,以及相對應的語法等等 ### [JavaScript MDN指南 - 繁體中文版](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide) > JavaScript語法的大集合,Function,開發時只需上去尋找相關內容即可. --- ## 配色平台 ### [Colorhunt Palettes](http://www.colorhunt.co/) > 多種不同配色可以直接選擇,以一組四種顏色為單位,可以直接選擇主色、輔助色、強調色等. ### [UI Gradients](http://uigradients.com/) > 多款優質且可直接使用的漸層顏色,並可以從漸層色中選擇強調色與輔助系使用 ### [Paletton](http://paletton.com/) > 非常流行的配色工具,同時具有多項顏色調和選項,並能直接模擬簡易網頁與相關配色 ### [Adobe Color](https://color.adobe.com/zh/create/color-wheel) > Adobe推出的色彩搭配器,除了具有多項調色規則可採用外,也可以使用圖片擷取顏色與漸層使用. ### [NIPPON COLORS - 日本の伝統色](https://nipponcolors.com/) > 主打日系傳統配色,在傳統藝術以及文化相關網站有卓越的發揮. ### [Coolors](https://coolors.co/) > 強大的色票產生器,並提供了多種色彩可供選擇. >