Angular 超入門學前幼幼班(二)
上一篇在最後已經建立了一個新專案,這邊就來稍微深入了解一下 Angular 專案究竟長什麼樣。
開啟專案資料夾後,根目錄長相如下:
其中「e2e」資料夾是與測試有關檔案,「node_modules」裡面則是 npm 下載回來並安裝好的套件包們,而其他檔案則是基本設定、測試框架、說明文件等等沒事不太會去碰的東西。
所以以上都讓它們繼續安靜躺在那裡,然後展開「src」資料夾看到如下畫面:
好的,這層的檔案基本上也都不太需要管它。
等等!?這層不是有個很重要的網頁首頁「index.html」嗎?還有「style.css」也在這裡耶?
但是啊,人家 Angular 是分工詳細的大企業,像「index.html」這種頂層角色都嘛只偶爾在董事會議出席,平常很少有機會看到,而像是「test.ts」這種管理測試程式碼的企業顧問,很可能你從進公司到畢業都不曾見過咧。
而這也是 Angular 實現軟體工程中設計模式(design pattern)其中一部份概念,也就是盡量拆解並讓工作單元能獨立運作的實際體現。
透過這樣詳細的分工方式,可以讓我們從茫茫程式海中解脫。想像一下如果是像電商網站那樣版面複雜的網頁,要從 5000 行程式碼中找出其中一行的<li>
,添加個 id 之後,打開另一個有 10000 行程式碼的 JS 檔案開始撰寫,這樣反覆下去還沒寫完一個專案應該就想摔鍵盤了。
那麼 Angular 究竟是怎麼分工的呢?首先來看看「index.html」長什麼樣子吧。
你切換畫面看了一下瀏覽器......嗯是個正常的網頁沒錯,但這個「index.html」也太簡短了吧?除了<head>
還有些東西之外,<body>
裡面根本就只有<app-root>
而已啊?
沒錯啊,人家董事長本來就是只抓大方向,剩下的都嘛交給總經理負責就好,而<app-root>
就是整個 Angular 專案的總經理, Angular 真正的執行工作,就是以這個<app-root>
為源頭往下延伸。
這裡應該很容易發現,<app-root>
是以 HTML 標籤的形式存在。好的,請關掉 Google 搜尋頁面,網路上所有介紹與說明 HTML 的文章都找不到這個東西的。
因為<app-root>
是 Angular 自訂的 HTML 標籤。
...啊?
<app-root>
是 Angular 自訂的 HTML 標籤。
對齁,HTML5 可以自己寫客製化標籤了,不過整個網頁能靠一個標籤就寫出來嗎?
要解開 Angular 所變的魔術,這裡先來展開「app」資料夾。
這個資料夾裡會看到有許多檔名相似的東西,首先打開「app.component.ts」這個檔案,然後在這裡找到了剛才見過的「app-root」。
除此之外,同樣被@Component({})
包起來的,還有./app.component.html
和./app.component.css
,而左邊的目錄中,在跟「app.component.ts」同層的資料夾裡也能找到這兩個檔案,顯然它們彼此是有關聯的。
這裡就先來看看熟悉的html檔案,打開「/app.component.html」後,終於出現看起來好像認得的東西了。
首先跳過預設範本中開頭那一大串<style>
,往下拉到標示 Toolbar 開始的地方。
現在再試著回頭對照瀏覽器開啟的範例網站...還好還好,果然是這個檔案沒有開錯。
接著再往下拉一段,一直看到<span>{{ title }} app is running!</span>
這行程式碼:
嗯...但網頁上的文字顯示的是「my-app app is running!」耶?
這時不要緊張,冷靜地回到「app.component.ts」檔案,找到下面這段程式碼:
export class AppComponent {
title = 'my-app';
}
喔...好像有點頭緒了,總之這東西就跟 JS 一樣,可以寫一些變數然後在 HTML 裡顯示對吧?
沒錯,這裡來試著將變數title
更改成title = 'My First Angular App'
,存檔後讓網頁重載之後,網頁上的文字果然跟著改變了。
目前為止能夠理解,「.ts」檔案跟在「.js」裡面一樣能夠進行計算以及宣告和綁定變數。但事實上,整個<app-root>
標籤裡面的東西,都是從「app.component.ts」檔案編譯過來的。
呃...?好吧,這大概就跟用 JS 產生 HTML 和 CSS 的概念一樣?不過還是搞不懂是怎麼辦到的耶?
這裡首先就來說說,Angular 架構的基本核心──「Component」吧!
Component 介紹
Component 在中文圈又被譯為元件、組件,每個 Component 在 Angular 中可視為跟<div>
、<img>
、<video>
一樣的 HTML 標籤元件。每個元件就像是積木,將它們組合起來才能成為一整個網頁,但元件本身也是一個單獨的個體,裡面包含了自己完整的功能。
哇...才說組起來才是一整個,又說自己單獨也是完整的,搞得我有點亂啊?
這裡稍微舉個例子:<img src="https://example.jpg" alt="example picture" title="我是範例">
上面這行 HTML 語法會自己在瀏覽器中跑出一張圖片,而游標滑過時會出現「我是範例」的提示,並在圖片失效時自動顯示「example picture」的文字。以上這些都是包含在<img>
裡面的功能,完全不需要再撰寫其他任何程式碼。
而 Angular 的 Component 就是讓開發者自訂 HTML 標籤,只要在「component.ts」檔案裡寫好希望它包含的所有功能,就可以直接在網頁裡使用這個 Component。
像最一開始的<app-root>
其實就是這個網頁中最大的元件,硬要舉例的話在架構上和<wrap>
標籤的意義有些類似,但所有的內容已經被包裝在整個元件裡面,所以在「index.html」中,只要像置入<img>
標籤一樣,只要簡單地置入一個<app-root>
就可以跑出這個元件蘊含的所有東西。
最後的「index.html」看起來清清爽爽,這就是 Component 的魔力啊!
在理解 Component 的強大之處後,接著就來看看它的詳細運作原理吧。
Component 檔案組成
Angular 的每個 Component 裡包含了以下東西:
元件名稱.component.ts
(必須)元件名稱.component.html
(非必須)元件名稱.component.css
(非必須,視初始設定後綴也可能是「.scss」或「.sass」)元件名稱.component.spec
(非必須)
可以看到,每個 Component 檔案名稱後綴有兩個,.ts
跟.html
等就是一般所稱的副檔名,.component
則表示這個檔案屬於某某元件,而同樣名稱的.component
檔案加起來才是一個完整的元件。
其中 ts 是 TypeScript 檔案,如果不認識這東西,簡單來說它就是 JavaScript 的進階版,如果不會用/沒興趣用這啥能吃嗎 的話就先當成 JavaScript 來寫就好。
spec 則是撰寫測試檔用,簡單來說就是寫檢驗用的程式碼測試這個元件有沒有正常運作,但反正沒寫測試網頁還是能跑 目前都先不用管 spec 檔案,嫌佔位置的話直接刪掉就好。
另外特別的一點是,每個 Component 的 html 和 css 是「只屬於這個 Component 的」,某個元件的 html 不會出現在別的元件裡。但就像<div>
裡面可以放<h1>
或<p>
一樣,Angular 也可以用同樣的方法把一個元件嵌入另一個元件中。
與 HTML 不同的是,某個 Component 的 CSS 效果只會套用在該 Component 身上,不會對其他元件,即便是包在該元件裡面的子元件產生影響。
所以才會說同樣名稱的 .component 檔案是一整個完整的元件。
耶?但是上面的清單除了.ts
之外都寫非必須,像 HTML、CSS 這些檔案沒有也沒關係嗎?
這是因為,就像在 HTML 中可以用<style>
和<script>
直接撰寫 CSS 和 JS,也可以將程式碼移到外連的.css
和.js
檔案一樣;Component 同樣可以選擇將 HTML 和 CSS 直接寫在 ts 檔案中,或連到外部檔案。
(P.S. 如果硬要的話,「.spec」的測試程式碼似乎也可以直接寫在「.ts」裡......但自己測試自己總覺得哪裡都不太對。)
Component 內容構成
理解了 Component 檔案架構後,這裡就來打開 ts 檔案來稍作說明。
第一行import { Component} from '@angular/core';
是告訴 Angular 說我要從 angular/core 中載入 Component 這個功能,讓我這個 ts 檔案作為一個 Component 來使用。
再來這段是敘述構成 Component 的內容
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
selector
是指定app-root
為這個元件的 HTML 標籤名稱,templateUrl
是這個元件的 HTML 應該要使用哪個檔案,如果要直接寫在 ts 檔案裡,則改成template
即可;同理使用styleUrls
可以置入外連的 CSS 檔案,使用styles
則可以直接撰寫 CSS。
最後面的這段
export class AppComponent {
title = 'my-app';
}
則是匯出 (export) 一個叫做 AppComponent 的類別 (class)。
呃、有import、export 又出現了 class......這是該先去把 JS 的 ES6 撿回來看嗎?
關於這點的好消息是,Angular 使用這幾項關鍵字的方法基本上非常固定,import 基本上都是在需要匯入某些功能時使用,而 export、class 基本上也只在匯出 Component 時會用到而已。
下一次,就來更詳細討論如何在 ts 檔案內寫程式碼,與使用各種 Angular 內建功能的方法吧!
.
.
.
.
.
不會考但可以知道一下的課外補充:
小貼士:差一代差很多,Angular 系列的代溝
Angular 第一代一般稱 AngularJS,和 Angular2 以後的版本不相容。除了初代使用 JavaScript 而 2 以後使用 TypeScript 之外,光是程式的基本架構就完全不同,因此 Angular 一般指 2 代以後的版本,第一代的 Angular 則會特地區別成 AngularJS 討論。
小貼士:設計模式(design pattern)
設計模式(design pattern)是指在軟體設計中針對不同狀況進行設計所推演出來的模式,有了設計模式後,就可以避免掉程式設計中反覆出現的某些問題。比方說功能元件之間耦合性太高(彼此關聯性強,修改一項就會影響到另一項),或者相同程式碼不斷重複等等,但只要遵守訂定出來的設計模式,即可避免或者大幅度改善這些問題。
參考文件:
【Angular】
【設計模式】