javascript
AngularJS进阶学习
參考:http://***/class/54f3ba65e564e50cfccbad4b
1. AJAX:Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)可以與服務器交換數據并更新部分網頁,而無需重新加載整個頁面。
2. JQuery:瀏覽器里原生的JavaScript有點像匯編語言,不同的瀏覽器就像不同的CPU架構,匯編語言各有千秋,這讓前端開發者很惱火。聰明人很快發現了這個痛點,于是,抹平瀏覽器差異的jQuery庫出現了。
3. AngularJS:jQuery看成庫的話,AngularJS則是一個框架,它以一種特殊的方式向jQuery表達了敬意:內置精簡版的jQuery - jqLite。如果某種原因你不愿意使用jqLite,也可以在AngularJS之前引入jQuery庫。 AngularJS自動地將jqLite升級成jQuery。
?
指令directive:類似ng-app,ez-clock這樣的非標準HTML標簽叫做指令(JavaScript文件)
模板:包含AngularJS標記的html文件被稱為模板
編譯:將指令解析成為瀏覽器可以理解的html元素和腳本的過程叫做編譯
視圖:通過編譯器解析處理模板文件,生成的結果就是視圖
一般過程:構造聲明式界面模板,來提出需求,繼而抽取并實現自定義指令。
1. 作用域/Scope
在HTML模板中,我們用了兩個內置指令:
- ng-app指令會在啟動引導時創建一個$rootScope對象。
- ng-init指令用來在作用域上初始化變量,這個指令將在$rootScope上建立sb對象。
1.1 層級的作用域
在默認情況下,一個DOM子元素不會創建新的作用域,也就是說,這個子元素所對應的 scope對象,其實就是它的最近一級的祖先對象對應的scope對象。
有些指令會導致創建新的作用域,比如ng-controller。如果在一個DOM對象上創建了新 的作用域,那么這個scope對象的原型是其最近一級的組件對象的scope對象。
1.2 監聽Scope數據的變化
編譯僅僅在啟動引導時執行一次,這意味著我們的link函數只會被調用一次,所以需要監聽數據變化來使得界面和數據一致。
$watch方法要求傳入三個參數:
- watchExpression - 要監聽的表達式,比如:"sb"
- listener - 變化發生時的回調函數,AngularJS將向這個函數傳入新值和舊值
- objectEquality - 如果監聽表達式的值是一個對象,應當將這個參數置為true。
以上便建立了從 數據到界面的單向綁定。
1.3 修改Scope上的數據
掛接監聽函數(示例中使用keyup事件), 在監聽函數中實現對sb變量的修改。
以上便建立了從 界面到數據的單向綁定。
angular.module("ezstuff",[]) .directive("ezNamecardEditor",function(){return {restrict : "E",template : "<ul class='nceditor'></ul>",replace : true,link : function(scope,element,attrs){//獲得變量名稱var model = attrs.data;//展開HTML模板,使用field屬性標記對應字段element.append("<li>name : <input type='text' field='name'></li>").append("<li>gender : <input type='text' field='gender'></li>").append("<li>age : <input type='text' field='age'></li>");//監聽DOM事件,變化時修改變量值element.find("input").on("keyup",function(ev){var field = ev.target.getAttribute("field");scope[model][field] = ev.target.value;//將對scope的修改進行傳播scope.$apply("");});}}; }) .directive("ezLogger",function(){return {restrict : "A",link : function(scope,element,attrs){var model = attrs.data;scope.$watch(model,function(nv){var cnt = JSON.stringify(nv,null," ");element.html("<pre>"+cnt+"</pre ");},true);}}; });1.4 數據變化的傳播
數據綁定有兩個方向:
- 數據 → 界面:我們使用scope對象的$watch()方法監聽數據的變化,來更新界面。
- 界面 → 數據:我們在界面的DOM對象上監聽變化事件,來更新數據,并通過$apply()方法傳播變化。
- $watch()
每個scope對象都維護了一個私有的監聽隊列,每次當我們在scope上執行一次$watch方法,就相當于 向這個監聽隊列里塞入一個監聽函數。
- $apply()
為了捕捉對數據的修改,AngularJS要求開發者使用scope對象的$apply方法對數據進行修改, $apply方法內部會自動地調用監聽隊列里的監聽函數
//方法1:直接修改sb對象. 不會自動觸發監聽函數 scope.sb.name = 'Tonny';//方法2:使用scope的$apply方法,在數據修改后會自動觸發監聽函數 scope.$apply("sb.name = 'Tonny'");//方法3:直接修改sb對象,然后調用$apply方法來傳播變化。 scope.sb.name = 'Tonny'; scope.$apply("");
2. 依賴注入:注入器
在依賴注入的模式下,所有的組件必須通過容器才能相互訪問,這導致了在AngularJS中, 你必須通過一個中介才能獲得某個組件的實例對象:
var injector = angular.injector(['ng']); injector.invoke(function($http){//do sth. with $http });這個中介,就是依賴注入模式中的容器,在AngularJS中,被稱為:注入器
AngularJS的組件之間不可以互相直接調用,一個組件必須通過注入器才 可以調用另一個組件。這些組件有一個統稱 - 供給者/provider。
配方其實就是:名稱+類構造函數。AngularJS啟動時,這些provider首先使用其配方在注入器內注冊。比如,http請求服務組件封裝在$httpProvider類內,它通過"$http"這個名字在注入器內注冊。其他組件,比如一個用戶的控制器,如果需要使用http功能,使用"$http"這個名字 向注入器請求,就可以獲得一個http服務實例了。
2.1 注冊服務組件
從injector的角度看,組件就是一個功能提供者,因此被稱為供給者/Provider。 在AngularJS中,provider以JavaScript類(構造函數)的形式封裝。
Provider類要求提供一個$get函數(類工廠),injector通過調用該函數, 就可以獲得服務組件的實例。
名稱和類函數的組合信息,被稱為配方。injector中維護一個集中的配方庫, 用來按需創建不同的組件。這個配方庫,其實就是一個Hash對象,key就是服務名稱,value 就是類定義。
2.2 調用組件服務:獲得注入器對象,而后通過注入器調用API
獲取注入器的方法有兩個:
- 創建一個新的注入器
可以使用angular.injector()創建一個新的注入器:
angular.injector(modules, [strictDi]);- 獲取已經創建的注入器
如果AngularJS框架已經啟動,那么可以使用DOM對象的injector()方法獲 得已經創建的注入器:
var element = angular.element(dom_element); var injector = element.injector();注入器有兩個方法可供進行API調用:invoke()和get()。
- invoke()
使用注入器的invoke()方法,可以直接調用一個用戶自定義的函數體,并通過函數參數 注入所依賴的服務對象,這是AngularJS推薦和慣例的用法:
angular.element(document).ready(function(){angular.injector(["ng","ezstuff"]).invoke(function(ezHello){//將ezHello實例對象轉成字符串顯示出來var e = document.querySelector("#logger");angular.element(e).text(ezHello);}); });- get()
也可以使用注入器的get()方法,獲得指定名稱的服務實例:
angular.element(document).ready(function(){//直接通過注入器獲取ezHello實例對象var myHello = angular.injector(["ng","ezstuff"]).get("ezHello");//將ezHello實例對象轉成字符串顯示出來var e = document.querySelector("#logger");angular.element(e).text(myHello); });2.3 注入的方式和原理
有兩種方法告知注入器需要注入的服務對象:參數名注入和依賴數組注入。
- 參數名注入
AngularJS在執行invoke()函數時,將待注入函數定義轉化為字符串,通過 正則表達式檢查其參數表,從而發現并注入所所依賴的服務對象:
//myfunc通過參數表聲明這個函數依賴于"$http"服務 var myfunc = function($http){ //do sth. with $http injector.invoke(myfunc); //myfunc的定義將被轉化為字符串進行參數名檢查example:
//在ezstuff模塊上登記一個服務ezHello angular.module("ezstuff",[]) .provider("ezHello",function(){//$get方法是一個類工廠,返回服務的實例this.$get = function(){return "hello,world!";}; });angular.element(document).ready(function(){var myfunc = function(ezHello){//將ezHello實例對象轉成字符串顯示出來var e = document.querySelector("#logger");angular.element(e).text(ezHello);};angular.injector(["ng","ezstuff"]).invoke(myfunc); });這樣有一個問題,就是當我們對JavaScript代碼進行壓縮處理時,$http可能會被 變更成其他名稱,這將導致注入失敗。
- 依賴數組注入
AngularJS采用依賴項數組的方法解決代碼壓縮混淆產生的問題。這時傳入invoke()的 是一個數組,數組的最后一項是實際要執行的函數,其他項則指明需要向該函數注入 的服務名稱。注入器將按照數組中的順序,依次向函數注入依賴對象。
采用這種方法,待注入函數的參數表的名稱就無關緊要了:
//myfunc依賴于"$http"和"$compile"服務 var myfunc = ["$http","$compile",function(p1,p2){//do sth. with p1($http),p2($compile) injector.invoke(myfunc);example:
//在ezstuff模塊上登記一個服務ezHello angular.module("ezstuff",[]) .provider("ezHello",function(){//$get方法是一個類工廠,返回服務的實例this.$get = function(){return "hello,world!";}; });angular.element(document).ready(function(){var myfunc = ["ezHello",function(hhh){//將ezHello實例對象轉成字符串顯示出來var e = document.querySelector("#logger");angular.element(e).text(hhh);}];angular.injector(["ng","ezstuff"]).invoke(myfunc); });3. 啟動引導
當你在HTML文件中引入angular.min.js時,AngularJS只是建立了一個全局的?angular對象,這個對象有一些方法可供開發者調用,但應用的框架還沒有建立。
在這個階段,AngularJS還只是一個庫,和jQuery類似,你可以使用angular.element() 操作DOM,也可以使用angular.injector()創建注入器... 但是,你定義的指令,你 創建的控制器,你封裝的服務,你開發的模板...所有這些組件,還靜靜地躺在那里, 沒有被整合在一起。
我們說,框架還沒有運轉起來,現在還是庫階段。
只有通過啟動引導,AngularJS框架才開始將那些組件拼接在一起,應用才真正 開始運轉。
3.1 自動引導啟動框架
就像你看到的那樣,如果HTML模板中有某個標簽有ng-app屬性,那么當DOM樹建立成功后, AngularJS就會自動進入引導過程,啟動整個框架:
?
3.2 手工引導啟動框架
在大多數情況下,我們都使用ng-app指令來進行自動引導啟動,但是如果一個HTML文件中 有多個ng-app,AngularJS只會自動引導啟動它找到的第一個ng-app應用,這是需要手工引導 的一個應用場景。
我們可以利用angular.bootstrap()方法進行手動引導:
bootstrap方法有三個參數:
- element : 一個DOM元素,以這個元素為Angular應用的根,等同自動引導時ng-app所在 的元素。這個參數是必須的。比如:document、document.body等。
- modules : 引導時需要載入的模塊數組。比如:[]、["ezstuff"]等。由于我們的HTML中引用 了ezstuff模塊中定義的ez-duang指令,所以,我們需要指定載入ezstuff模塊。
- config :引導配置項,可選。我們先忽略。
3.3 引導的一般過程
3.3.1 引導第1步:創建注入器
引導過程使AngularJS從庫轉變成了一個框架。AngularJS深入骨髓地使用著依賴注入,那么,在引導過程 之初,首先需要創建一個注入器就毫不奇怪了。注入器是通向AngularJS所有功能的入口,而AngularJS的功能實現,是通過模塊的方式組織的。所以, 在創建注入器的時候,需要告訴AngularJS載入哪些模塊(ng模塊是內置載入的,不需要顯式指定)。
在自動啟動引導的場景下,可以給ng-app賦值以指定一個需要載入的模塊,比如:
- ng-app = "ezstuff"
在手動啟動引導的場景下,通過bootstrap方法的第二個參數指定需要載入的模塊,比如:
- angular.bootstrap(document,["ezstuff"]);
INSIDE:無論自動啟動還是手工啟動,最終都是調用angular對象上的injector()方法創建了一個 注入器,然后把這個注入器存入了根對象的data里:
3.3.2 引導第2步:創建根作用域
scope對象是AngularJS實現數據綁定的重要服務,所以,在引導啟動建立了注入器之后, AngularJS馬上在應用的根節點上創建一個根作用域:$rootScope對象。
如果是自動引導啟動,那么ng-app所在的DOM節點對應著根作用域。如果是手工引導啟動, 那么在bootstrap方法中指定的第一個參數就對應著根作用域。
無論哪一種情況,一旦$rootScope對象創建成功,AngularJS就將這個對象存儲到根節點 的data中:
- var rootScope = injector.get("$rootScope");
angular.element(document).data("$rootScope",rootScope);
我們可以使用如下的方法查看這個對象:
- angular.element(approot).data("$rootScope");
3.3.3 引導第3步:編譯DOM子樹
引導過程的最后一步,是以ng-app所在DOM節點為根節點,對這棵DOM子樹進行編譯。
編譯過程通常借助于指令,完成這幾種操作:
手動引導需要如下:
- var compile = injector.get("$compile")
compile(document)(rootScope);
3.4 編譯器/$compile
編譯器$compile是一個AngularJS的內置服務,它負責遍歷DOM樹來查找匹配指令, 并調用指令的實現代碼進行處理。
HTML編譯包括3個步驟:
- 匹配指令
$compile遍歷DOM樹,如果發現有元素匹配了某個指令,那么這個指令將被加入 該DOM元素的指令列表中。一個DOM元素可能匹配多個指令。
- 執行指令的編譯函數
當一個DOM元素的所有指令都找齊后,編譯器根據指令的優先級/priority指令進行排序。 每個指令的compile函數被依次執行。每個compile執行的結果產生一個link函數,這些 link函數合并成一個復合link函數。
- 執行生成的鏈接函數
$compile通過執行指令的link函數,將模板和scope鏈接起來。結果就是一個DOM視圖和scope對象模型 之間的動態數據綁定。
3.5 指令/directive
指令可以放置在元素名、屬性、CSS類名稱及備注中。指令的實現本質上就是一個類工廠,它返回一個指令定義對象,編譯器根據這個指令定義對象進行操作。
指令的規范化
AngularJS在進行匹配檢測之前,首先對HTML元素的標簽和屬性名轉化成規范的駝峰式字符串:
例如,下面的寫法都等效地匹配ngBind指令:
4. 控制器
在AngularJS中,實現數據綁定的核心是scope對象。沒有控制器/controller,我們沒有地方定義業務模型。
控制器讓我們有機會在scope上定義我們的業務邏輯,具體說,可以使用控制器:
4.1 在模板中聲明控制器
在一個HTML元素上使用ng-controller指令,就可以引入一個控制器對象:
4.2 控制器的實現
控制器實際上就是一個JavaScript的類/構造函數:
4.3 控制器的一次性
控制器構造函數僅在AngularJS對HTML文檔進行編譯時被執行一次。從這個角度看, 就更容易理解為何將控制器稱為對scope對象的增強:一旦控制器創建完畢,就意味著scope對 象上的業務模型構造完畢,此后就不再需要控制器了- scope對象接管了一切。
4.4 控制器對scope的影響
4.4.1 控制器總是會創建新的scope對象
ng-controller指令總是創建一個新的scope對象:
在圖中,我們看到:
4.4.2 初始化$scope對象
通常在應用啟動時,需要初始化scope對象上的數據模型。我們之前曾使用ng-init指令進行初始化, 而使用控制器則是更為規范的做法。
右邊的示例定義了一個ezController,利用這個控制器,我們對業務模型進行了初始化賦值:
請注意,控制器僅僅負責在編譯時在scope對象上建立視圖對象vm,視圖對象和模板的綁定則是由 scope負責管理的。
4.4.2 向cope對象添加方法
業務模型是動態的,在數據之外,我們需要給業務模型添加動作。
在之前建立的業務模型上,我們增加一個隨機挑選的方法:shuffle,這個方法負責 從一個小型的名人庫中隨機的選擇一個名人來更新模型的sb屬性:
通過在button上使用ng-click指令,我們將模型的shuffle方法綁定到了鼠標點擊 事件上。試著用鼠標點擊【shuffle】按鈕,我們的模型將從庫里隨機的選出一個 名人,顯示在視圖里。
控制器的設計出發點是封裝單個視圖的業務邏輯,因此,不要進行以下操作:
- DOM操作
應當將DOM操作使用指令/directive進行封裝。
- 變換輸出形式
應當使用過濾器/filter對輸出顯示進行轉化。
- 跨控制器共享代碼
對于需要復用的基礎代碼,應當使用服務/service進行封裝
5. 封裝服務
5.1 創建服務組件
在AngularJS中創建一個服務組件很簡單,只需要定義一個具有$get方法的構造函數, 然后使用模塊的provider方法進行登記:
?
5.2 可配置的服務
有時我們希望服務在不同的場景下可以有不同的行為,這意味著服務可以進行配置。
比如,我們希望小計算器可以根據不同的本地化區域,給計算結果追加貨幣符號前綴, 那么需要在這個服務創建之前,首先配置本地化區域的值,然后在具體的計算中, 根據這個值選擇合適的貨幣符號。
AngularJS使用模塊的config()方法對服務進行配置,需要將實例化的服務提供者?(而不是服務實例)注入到配置函數中:
注意:服務提供者provider對象在注入器中的登記名稱是:服務名+Provider。 例如: $http的服務提供者實例名稱是"$httpProvider"。
function doCalc(){var injector = angular.injector(["ezstuff"]),mycalculator = injector.get("ezCalculator"),ret = mycalculator.add(3,4);document.querySelector("#result").innerText = ret; }angular.module("ezstuff",[]).provider("ezCalculator",function(){var currency = "$";this.setLocal = function(l){var repo = {"CN":"¥","US":"$","JP":"¥","EN":"€"};if(repo[l]) currency = repo[l];};this.$get = function(){return {add : function(a,b){return currency + (a+b);},subtract : function(a,b){return currency + (a-b);},multiply : function(a,b){return currency + (a*b);},divide: function(a,b){return currency + (a/b);} }};}).config(function(ezCalculatorProvider){ezCalculatorProvider.setLocal("CN");});5.3 服務定義語法糖
使用模塊的provider方法定義服務組件,在有些場景下顯得有些笨重。AngularJS友好 地提供了一些簡化的定義方法,這些方法通常只是對provider方法的封裝, 分別適用于不同的應用場景:
- factory
使用一個對象工廠函數定義服務,調用該工廠函數將返回服務實例。
- service
使用一個類構造函數定義服務,通過new操作符將創建服務實例。
- value
使用一個值定義服務,這個值就是服務實例。
- constant
使用一個常量定義服務,這個常量就是服務實例。
5.3.1 factory方法
factory方法要求提供一個對象工廠,調用該類工廠將返回服務實例。INSIDE:AngularJS會將factory方法封裝為provider,上面的示例 等同于:
如下:
angular.module("ezstuff",[]).factory("ezCalculator",function(){return {add : function(a,b){return a+b;},subtract : function(a,b){return a-b;},multiply : function(a,b){return a*b;},divide: function(a,b){return a/b;} }})5.3.2 service方法
service方法要求提供一個構造函數,AngularJS使用這個構造函數創建服務實例:INSIDE:AngularJS會將service方法封裝為provider,上面的示例 等同于:
如下:
var ezCalculatorClass = function(){this.add = function(a,b){return a+b;};this.subtract = function(a,b){return a-b;};this.multiply = function(a,b){return a*b;};this.divide = function(a,b){return a/b;}; };angular.module("ezstuff",[]) .service("ezCalculator",ezCalculatorClass);5.3.3 value方法
有時我們需要在不同的組件之間共享一個變量,可以將這種情況視為一種服務: provider返回的總是變量的值。
value方法提供了對這種情況的簡化封裝:
INSIDE:AngularJS會將value方法封裝為provider,上面的示例 等同于:
5.3.4 constant方法
有時我們需要在不同的組件之間共享一個常量,可以將這種情況視為一種服務: provider返回的總是常量的值。
constant方法提供了對這種情況的簡化封裝:
和value方法不同,AngularJS并沒有將constant方法封裝成一個provider,而僅僅 是在內部登記這個值。這使得常量在AngularJS的啟動配置階段就可以使用(創建任何 服務之前):你可以將常量注入到模塊的config()方法中。
如下,將constant換成value則不能運行:
angular.module("ezstuff",[]).constant("ezCurrency","CN").provider("ezCalculator",function(){var currency = "$";this.setLocal = function(l){var repo = {"CN":"¥","US":"$","JP":"¥","EN":"€"};if(repo[l]) currency = repo[l];};this.$get = function(){return {add : function(a,b){return currency + (a+b);},subtract : function(a,b){return currency + (a-b);},multiply : function(a,b){return currency + (a*b);},divide: function(a,b){return currency + (a/b);} }};}).config(function(ezCurrency,ezCalculatorProvider){ezCalculatorProvider.setLocal(ezCurrency);});6. 封裝指令
6.1 創建指令
指令也是一種服務,只是這種服務的定義有幾個特殊要求:
INSIDE:指令在注入器中的登記名稱是:指令名+Directive。 例如,ng-app指令的服務名稱是:"ngAppDirective"。
6.2 指令定義對象
每個指令定義的工廠函數,需要返回一個指令定義對象。指令定義對象就是 一個具有約定屬性的JavaScript對象,編譯器/$compile在編譯時就根據這 個定義對象對指令進行展開。
指令定義對象的常用屬性如下:
- template?:?string
使用template指定的HTML標記替換指令內容(如果replace = true,那么用HTML片段替換指令本身。如果transclue屬性為true,則為包裹指令的內容。)
- restrict?:?string
用來限定指令在HTML模板中出現的位置。restict屬性可以是EACM這四個字母的任意組合,用來限定指令的應用場景。 如果不指定這個屬性,默認情況下,指令將僅允許被用作元素名和屬性名:
- E - 指令可以作為HTML元素使用
- A - 指令可以作為HTML屬性使用
- C - 指令可以作為CSS類使用
- M - 指令可以在HTML注釋中使用
- replace?:?true|false
使用這個屬性指明template的替換方式。作圖為false,有圖為true
<body><div ng-controller="ezCtrl"><ez-customer></ez-customer></div> </body>當然,因為replace為true時,要求模板有 一個根節點,所以定義如下:
.directive("ezCustomer", function() {return {restrict:"E",replace:true,template: Name: {{customer.name}} Address: {{customer.address}}}; });- scope?:?true|false|{...}
scope屬性為指令創建私有的作用域,這在創建可復用的Widget時非常有用。通過設置scope屬性,指令的每個實例都將獲得一個隔離的本地作用域:
scope上有兩種約定符號:@表示DOM值變則Scope值變,=表示DOM值和Scope值雙向影響。如下圖的理解:
angular.module("ezstuff",[]) .controller("ezCtrl", ["$scope", function($scope) {$scope.Emmy = {name: "Emmy",address: "1600 Amphitheatre"};$scope.Edison = {name: "Edison",address: "2500 Amphitheatre"}; }]) .directive("ezCustomer", function() {return {restrict:"E",replace:true,scope:{name:"@name",address: "=address"},template: "<div>Name: <input field='name' value={{name}}></input> Address: <input field='address' value={{address}}></input></div>",link : function(scope,element,attrs){element.find("input").on("keyup",function(ev){var field = ev.target.getAttribute("field");scope[field] = ev.target.value;//將對scope的修改進行傳播scope.$apply("");});}}; }).directive("ezLogger",function(){return {restrict : "A",link : function(scope,element,attrs){var model = attrs.data;scope.$watch(model,function(nv){var cnt = JSON.stringify(nv,null," ");element.html("<pre>"+cnt+"</pre ");},true);}}; }); <html ng-app="ezstuff"> <head><script src="angular.min.js"></script> </head> <body><div ng-controller="ezCtrl"><ez-customer name="{{Emmy.name}}" address="Emmy.address"></ez-customer><ez-customer name="{{Edison.name}}" address="Edison.address"></ez-customer><div ez-logger data="Emmy"></div><div ez-logger data="Edison"></div></div> </body> </html>- link?:?function(..){...}
link屬性是一個函數,用來在指令中操作DOM樹、實現數據綁定。
允許指令包含其他HTML元素,這通常用于實現一個容器類型的Widget。
有些指令需要能夠包含其他未知的元素。比如我們定義一個指令ez-dialog,用來 封裝對話框的樣式和行為,它應當允許在使用期(也就是在界面模板文件里)才指 定其內容:
transclude屬性可以告訴編譯器,利用所在DOM元素的內容,替換template中包含 ng-transclude指令的元素的內容:
從上圖中可以看到,使用transclude有兩個要點:
7. 過濾器
7.1 在視圖模板中使用過濾器
過濾器也是一種服務,負責對輸入的內容進行處理轉換,以便更好地向用戶顯示。
過濾器可以在模板中的{{}}標記中使用:
- 預置的過濾器
AngularJS的ng模塊實現了一些預置的過濾器,如:currency、number等等,可以直接 使用。例如下面的示例將對數字12使用currency過濾器,結果將是"$12.00":
- 帶參數的過濾器
過濾器也可以有參數,例如下面的示例將數字格式化為"1,234.00":
- 過濾器流水線
過濾器可以應用于另一個過濾器的輸出,就像流水線,語法如下:
7.2 在代碼中使用過濾器
別忘了過濾器也是一種服務,所以你可以將它注入你的代碼中。
和普通的服務不同,過濾器在注入器中注冊時,名稱被加了一個后綴:Filter。 例如,number過濾器的服務名稱是:numberFilter,而currency過濾器的服務名稱是: currencyFilter。
通常我們的代碼被封裝在三個地方:控制器、服務、指令。這些地方都支持服務的直接 注入,例如:
有時你需要顯式的通過注入器調用過濾器,那么使用注入器的invoke()方法:
總之,記住過濾器是一種服務,除了名字需要追加Filter后綴,和其他服務的調用方法沒 什么區別。
右邊的示例在控制器中注入了number和currency過濾器,實現對total的格式化。
7.3 創建過濾器
和指令類似,過濾器也是一種特殊的服務,與創建一個普通的服務相比較:
右邊的示例定義了一個將字符串格式化為大寫的過濾器。
7.4 為過濾器增加參數
過濾器的行為可以通過額外的參數來調整。比如,我們希望改進上一節的示例,使其可以 支持僅大寫每個單詞的首字母。
- 實現
通過在過濾器類工廠返回的過濾器函數中傳入額外的參數,就可以實現這個功能。
- 使用
在使用過濾器時,額外的參數通過前綴:引入,比如
右邊的示例實現了支持參數的過濾器ezUC,試著去掉HTML模板中過濾器ezUC的參數, 看看顯示輸出的區別!
轉載于:https://www.cnblogs.com/dorothychai/p/4686625.html
總結
以上是生活随笔為你收集整理的AngularJS进阶学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CF 546E(最大流
- 下一篇: (iOS)Storyboard/xib小