通過使用模板,我們可以把model和controller中的資料組裝起來呈現給瀏覽器,還可以通過資料繫結,實時更新檢視,讓我們的頁面變成動態的。ng的模板真是讓我愛不釋手。學習ng道路還很漫長,從模板開始入手是個不錯方式,因為這部分內容相對簡單好理解,而且是檢視層的東西,大家都喜歡可以立馬看得見的東西嘛。本篇我將蒐羅模板中的常用指令一一測試,瞭解其使用方法,有點像背單詞的感覺,會比較枯燥。不過對於初學,這樣的枯燥是必須要經歷的,開始~
一、模板中可使用的東西及表示式
模板中可以使用的東西包括以下四種:
- 指令(directive)。ng提供的或者自定義的標籤和屬性,用來增強HTML表現力。
- 標記(markup)。即雙大括號{{}},可將資料單向繫結到HTML中。
- 過濾器(filter)。用來格式化輸出資料。
- 表單控制。用來增強表單的驗證功能。
其中,指令無疑是使用量最大的,ng內建了很多指令用來控制模板,如ng-repeat,ng-class,也有很多指令來幫你完成業務邏輯,如ng-controller,ng-model。過濾器通常是伴隨標記來使用的,將你model中的資料格式化為需要的格式。表單的控制功能主要涉及到資料驗證以及表單控制元件的增強。
在這裡有必要說明一下表示式的概念,畢竟我們模板中大部分使用的都是變數。ng中的表示式與javascript表示式類似但是不可以劃等號,它是ng自己定義的一套模式。表示式可以作為指令的值,如ng-modle=”people.name”、ng-click=”showMe()”,看起來是如此像字串,故而也叫字串表示式。也可以在標記中使用表示式,如{{1+2}},或者與過濾器一起使用{{1+2 | currency}}。在框架內部,字串不會簡單的使用eval()來執行,而是有一個專門的$parse服務來處理。在ng表示式中不可以使用迴圈語句、判斷語句,事實上在模板中使用複雜的表示式也是一個不推薦的做法,這樣檢視與邏輯就混雜在一起了。
二、樣式相關的指令
既然模板就是普通的HTML,那我首要關心的就是樣式的控制,元素的定位、字型、背景色等等如何可以靈活控制。下面來看看常用的樣式控制指令。
1. ng-class
ng-class用來給元素繫結類名,其表示式的返回值可以是以下三種:
1) 類名字串,可以用空格分割多個類名,如’redtext boldtext’;
2) 類名陣列,陣列中的每一項都會層疊起來生效;
3) 一個名值對應的map,其鍵值為類名,值為boolean型別,當值為true時,該類會被加在元素上。
下面來看一個使用map的例子:
如果你想拼接一個類名出來,可以使用插值表示式,如:
<div class=”{{style}}text”>字型樣式測試</div>
然後在controller中指定style的值:
$scope.style = ‘red’;
注意我用了class而不是ng-class,這是不可以對換的,官方的文件也未做說明,姑且認為這是ng的語法規則吧。
與ng-class相近的,ng還提供了ng-class-odd、ng-class-even兩個指令,用來配合ng-repeat分別在奇數列和偶數列使用對應的類。這個用來在表格中實現隔行換色再方便不過了。
2. ng-style
ng-style用來繫結元素的css樣式,其表示式的返回值為一個js物件,鍵為css樣式名,值為該樣式對應的合法取值。用法比較簡單:
<div ng-style="{color:'red'}">ng-style測試</div> <div ng-style="style">ng-style測試</div> $scope.style = {color:'red'};
3. ng-show,ng-hide
對於比較常用的元素顯隱控制,ng也做了封裝,ng-show和ng-hide的值為boolean型別的表示式,當值為true時,對應的show或hide生效。框架會用display:block和display:none來控制元素的顯隱。
三、表單控制元件功能相關的
對於常用的表單控制元件功能,ng也做了封裝,方便靈活控制。
ng-checked控制radio和checkbox的選中狀態
ng-selected控制下拉框的選中狀態
ng-disabled控制失效狀態
ng-multiple控制多選
ng-readonly控制只讀狀態
以上指令的取值均為boolean型別,當值為true時相關狀態生效,道理比較簡單就不多做解釋。注意: 上面的這些只是單向繫結,即只是從資料到模板,不能反作用於資料。要雙向繫結,還是要使用 ng-model
。
四、事件繫結相關
事件繫結是javascrpt中比較重要的一部分內容,ng對此也做了詳細的封裝,正如我們之前使用過的ng-click一樣,其他事件的指令如下:
ng-change
ng-dblclick
ng-mousedown
ng-mouseenter
ng-mouseleave
ng-mousemove
ng-mouseover
ng-mouseup
ng-submit
事件繫結指令的取值為函式,並且需要加上括號,例如:
<select ng-change=”change($event)”></select>
然後在controller中定義如下:
$scope.change = function($event){ alert($event.target); //…………………… }
在模板中可以用變數$event將事件物件傳遞到controller中。
對於ng的這種設計,一些人有所質疑,檢視與事件繫結混在一起到底好不好?我們不是要講究檢視與邏輯分離嗎?如此一來,把事件的繫結又變回了內聯的,豈不是歷史的倒退。我也一樣對此表示不解,因為不寫onclick已經很多年。。。但既然已經存在了,我們不妨往合理的方向上想一想,或許ng的設計者壓根就不想讓模板成為單純的檢視層,本來就是想增強HTML,讓它有一點業務能力。這麼想的話似乎也能想通,好吧,先欺騙一下自己吧~
五、特殊的ng-src和ng-href
在說明這兩個指令的特殊之前,需要先了解一下ng的啟動及執行過程,如下圖:
1) 瀏覽器載入靜態HTML檔案並解析為DOM;
2) 瀏覽器載入angular.js檔案;
3) angular監聽DOMContentLoaded
事件,監聽到時開始啟動;
4) angular尋找ng-app指令,確定作用範圍;
5) 找到app中定義的Module使用$injector服務進行依賴注入;
6) 根據$injector服務建立$compile服務用於編譯;
7) $compile服務編譯DOM中的指令、過濾器等;
8) 使用ng-init指令,將作用域中的變數進行替換;
9) 最後生成了我們在最終檢視。
可以看到,ng框架是在DOMcontent載入完畢後才開始發揮作用。假如我們模板中有一張圖片如下:
<img src=”{{imgUrl}}” />
那麼在頁面開始載入到ng編譯完成之前,頁面上會一直顯示一張錯誤的圖片,因為路徑{{imgUrl}}還未被替換,就像這樣:
為了避免這種情況,我們使用ng-src指令,這樣在路徑被正確得到之前就不會顯示找不到圖片。同理,<a>標籤的href屬性也需要換成ng-href,這樣頁面上就不會先出現一個地址錯誤的連結。
順著這個思路再多想一點,我們在模板中使用{{}}顯示資料時,在ng編譯完成之前頁面上豈不是會顯示出大括號及裡面的表示式?確實是這樣。為了避免這個,ng中有一個與{{}}等同的指令:ng-bind,同樣用於單向繫結,在頁面剛載入的時候就不會顯示出對使用者無用的資料了。儘管這樣你可能不但沒舒心反而更糾結了,{{}}那麼好用易理解,還不能用了不成?好訊息是我們依然可以使用。因為我編寫的是單頁面應用,頁面只會在載入index.html的時候出這個問題,只需在index.html中的模板中換成ng-bind就行。其他的模板是我們動態載入的,就可以放心使用{{}}了。
六、總結一下
枯燥的內容終於寫完!~在寫這篇文章之前我就在糾結,寫這樣的內容是不是有點多餘,因為這些東西在angular官網(http://docs.angularjs.org/api/)一看就明白,而且線上示例也寫的很棒。本著不急於求成的原則我還是決定先把這些東西都試一試吧,所以就有詳有略的介紹了以上內容,必要的時候也可以當一個備忘。
學英語有兩種方法,一種是先做題,遇到不會的單詞再查,另一種是先拿著單詞本背。儘管專家好像更推薦前者,但如果你現在一竅不通,還是老老實實先背單詞吧~