bell 已發佈 2019-11-21

Angular 超入門學前幼幼班(二)

上一篇在最後已經建立了一個新專案,這邊就來稍微深入了解一下 Angular 專案究竟長什麼樣。

開啟專案資料夾後,根目錄長相如下:
images

其中「e2e」資料夾是與測試有關檔案,「node_modules」裡面則是 npm 下載回來並安裝好的套件包們,而其他檔案則是基本設定、測試框架、說明文件等等沒事不太會去碰的東西。

所以以上都讓它們繼續安靜躺在那裡,然後展開「src」資料夾看到如下畫面:
images

好的,這層的檔案基本上也都不太需要管它。

等等!?這層不是有個很重要的網頁首頁「index.html」嗎?還有「style.css」也在這裡耶?

但是啊,人家 Angular 是分工詳細的大企業,像「index.html」這種頂層角色都嘛只偶爾在董事會議出席,平常很少有機會看到,而像是「test.ts」這種管理測試程式碼的企業顧問,很可能你從進公司到畢業都不曾見過咧。

而這也是 Angular 實現軟體工程中設計模式(design pattern)其中一部份概念,也就是盡量拆解並讓工作單元能獨立運作的實際體現。

透過這樣詳細的分工方式,可以讓我們從茫茫程式海中解脫。想像一下如果是像電商網站那樣版面複雜的網頁,要從 5000 行程式碼中找出其中一行的<li>,添加個 id 之後,打開另一個有 10000 行程式碼的 JS 檔案開始撰寫,這樣反覆下去還沒寫完一個專案應該就想摔鍵盤了。

那麼 Angular 究竟是怎麼分工的呢?首先來看看「index.html」長什麼樣子吧。
images

你切換畫面看了一下瀏覽器......嗯是個正常的網頁沒錯,但這個「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」資料夾。
images

這個資料夾裡會看到有許多檔名相似的東西,首先打開「app.component.ts」這個檔案,然後在這裡找到了剛才見過的「app-root」。
images

除此之外,同樣被@Component({})包起來的,還有./app.component.html./app.component.css,而左邊的目錄中,在跟「app.component.ts」同層的資料夾裡也能找到這兩個檔案,顯然它們彼此是有關聯的。

這裡就先來看看熟悉的html檔案,打開「/app.component.html」後,終於出現看起來好像認得的東西了。

首先跳過預設範本中開頭那一大串<style>,往下拉到標示 Toolbar 開始的地方。
images

現在再試著回頭對照瀏覽器開啟的範例網站...還好還好,果然是這個檔案沒有開錯。

接著再往下拉一段,一直看到<span>{{ title }} app is running!</span>這行程式碼:
images

嗯...但網頁上的文字顯示的是「my-app app is running!」耶?
images

這時不要緊張,冷靜地回到「app.component.ts」檔案,找到下面這段程式碼:

export class AppComponent {
  title = 'my-app';
}

喔...好像有點頭緒了,總之這東西就跟 JS 一樣,可以寫一些變數然後在 HTML 裡顯示對吧?

沒錯,這裡來試著將變數title更改成title = 'My First Angular App',存檔後讓網頁重載之後,網頁上的文字果然跟著改變了。
images

目前為止能夠理解,「.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】

  1. Angular-台灣
  2. Angular 深入淺出三十天
  3. 也来说是 AngularJS、 Angular 2、Angular 4 的区别(簡)

【設計模式】

  1. 設計模式 (電腦) - 維基百科
  2. 初探設計模式
  3. 物件導向程式設計基本原則 - SOLID

關於筆者

暱稱:bell

介紹:剛入行的萌新工程師一枚,正在努力聽懂各種外星語......

文章列表 文章列表