日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

AngularJS进阶学习

發布時間:2025/4/9 javascript 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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, listener, [objectEquality]);
  • $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()方法進行手動引導:

  • angular.bootstrap(element, [modules], [config]);
  • bootstrap方法有三個參數:

    • element : 一個DOM元素,以這個元素為Angular應用的根,等同自動引導時ng-app所在 的元素。這個參數是必須的。比如:document、document.body等。
    • modules : 引導時需要載入的模塊數組。比如:[]、["ezstuff"]等。由于我們的HTML中引用 了ezstuff模塊中定義的ez-duang指令,所以,我們需要指定載入ezstuff模塊。
    • config :引導配置項,可選。我們先忽略。
    angular.element(document).ready(function(){var e = document.querySelector("#bootstrap");angular.element(e).on("click",function(){angular.bootstrap(document,["ezstuff"]); }) }) ; angular.module("ezstuff",[]) .directive("ezDuang",function(){return {restrict : "E",template : "<img src='http://ww4.sinaimg.cn/bmiddle/757eb2ffjw1eptcr4qobjg209205dthh.gif'>"}; });

    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里:

  • var injector = angular.injector(["ng","ezstuff"]);
  • angular.element(document).data("$injector",injector);
  • 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子樹進行編譯。

    編譯過程通常借助于指令,完成這幾種操作:

  • 對DOM對象進行變換。
  • 在DOM對象上掛接事件監聽。
  • 在DOM對象對應的scope對象上掛接數據監聽。
  • 手動引導需要如下:

    • 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元素的標簽和屬性名轉化成規范的駝峰式字符串:

  • 去除名稱前綴的x-和data-
  • 以: , - 或 _ 為分割符,將字符串切分成單詞,除第一個單詞外,其余單詞首字母大寫
  • 重新拼接各單詞
  • 例如,下面的寫法都等效地匹配ngBind指令:

  • <span ng-bind="name"></span> <br>
  • <span ng:bind="name"></span> <br>
  • <span ng_bind="name"></span> <br>
  • <span data-ng-bind="name"></span> <br>
  • <span x-ng-bind="name"></span> <br>
  • 4. 控制器

    在AngularJS中,實現數據綁定的核心是scope對象。沒有控制器/controller,我們沒有地方定義業務模型

    控制器讓我們有機會在scope上定義我們的業務邏輯,具體說,可以使用控制器:

  • 對scope對象進行初始化
  • 向scope對象添加方法
  • 4.1 在模板中聲明控制器

    在一個HTML元素上使用ng-controller指令,就可以引入一個控制器對象:

  • <div ng-controller="myController">...</div>
  • 4.2 控制器的實現

    控制器實際上就是一個JavaScript的類/構造函數:

  • //控制器類定義
  • var myControllerClass = function($scope){
  • //模型屬性定義
  • $scope.text = "...";
  • //模型方法定義
  • $scope.do = function(){...};
  • };
  • //在模塊中注冊控制器
  • angular.module('someModule',[])
  • .controller("myController",myControllerClass);
  • 4.3 控制器的一次性

    控制器構造函數僅在AngularJS對HTML文檔進行編譯時被執行一次。從這個角度看, 就更容易理解為何將控制器稱為對scope對象的增強:一旦控制器創建完畢,就意味著scope對 象上的業務模型構造完畢,此后就不再需要控制器了- scope對象接管了一切。

    4.4 控制器對scope的影響

    4.4.1 控制器總是會創建新的scope對象

    ng-controller指令總是創建一個新的scope對象:

    在圖中,我們看到:

  • ng-app指令引發$rootScope對象的創建。開始時,它是一個空對象。
  • body元素對應的scope對象還是$rootScope。ng-init指令將sb對象掛在了$rootScope上。
  • div元素通過ng-controller指令創建了一個新的scope對象,這個對象的原型是$rootScope。
  • 因為原型繼承的關系,在do函數中對sb的引用指向$rootScope.sb。
  • 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方法進行登記:

  • //定義構造函數
  • var myServiceProvider = function(){
  • this.$get = function(){
  • return ....
  • };
  • };
  • //在模塊中登記
  • angular.module("myModule",[])
  • .provider("myService",myServiceProvider);
  • ?

    5.2 可配置的服務

    有時我們希望服務在不同的場景下可以有不同的行為,這意味著服務可以進行配置。

    比如,我們希望小計算器可以根據不同的本地化區域,給計算結果追加貨幣符號前綴, 那么需要在這個服務創建之前,首先配置本地化區域的值,然后在具體的計算中, 根據這個值選擇合適的貨幣符號。

    AngularJS使用模塊的config()方法對服務進行配置,需要將實例化的服務提供者?(而不是服務實例)注入到配置函數中:

  • angular.module("myModule",[])
  • .config(["myServiceProvider",function(myServiceProvider){
  • //do some configuration.
  • }]);
  • 注意:服務提供者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方法要求提供一個對象工廠,調用該類工廠將返回服務實例。

  • var myServiceFactory = function(){
  • return ...
  • };
  • angular.module("myModule",[])
  • .factory("myService",myServiceFactory);
  • INSIDE:AngularJS會將factory方法封裝為provider,上面的示例 等同于:

  • var myServiceFactory = function(){
  • return ...
  • };
  • angular.module("myModule",[])
  • .provider("myService",function(){
  • this.$get = myServiceFactory;
  • });
  • 如下:

    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使用這個構造函數創建服務實例:

  • var myServiceClass = function(){
  • this.method1 = function(){...}
  • };
  • angular.module("myModule",[])
  • .service("myService",myServiceClass);
  • INSIDE:AngularJS會將service方法封裝為provider,上面的示例 等同于:

  • var myServiceClass = function(){
  • //class definition.
  • };
  • angular.module("myModule",[])
  • .provider("myService",function(){
  • this.$get = function(){
  • return new myServiceClass();
  • };
  • });
  • 如下:

    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方法提供了對這種情況的簡化封裝:

  • angular.module("myModule",[])
  • .value("myValueService","cx129800123");
  • INSIDE:AngularJS會將value方法封裝為provider,上面的示例 等同于:

  • angular.module("myModule",[])
  • .provider("myService",function(){
  • this.$get = function(){
  • return "cx129800123";
  • };
  • });
  • 5.3.4 constant方法

    有時我們需要在不同的組件之間共享一個常量,可以將這種情況視為一種服務: provider返回的總是常量的值。

    constant方法提供了對這種情況的簡化封裝:

  • angular.module("myModule",[])
  • .constant("myConstantService","Great Wall");
  • 和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 創建指令

    指令也是一種服務,只是這種服務的定義有幾個特殊要求:

  • 必須使用模塊的directive()方法注冊服務
  • 必須以對象工廠/factory()方法定義服務實現
  • 對象工廠必須返回一個指令定義對象
  • //定義指令的類工廠
  • var directiveFactory = function(injectables){
  • //指令定義對象
  • var directiveDefinationObject = {
  • ...
  • };
  • return directiveDefinationObject;
  • };
  • //在模塊上注冊指令
  • angular.module("someModule",[])
  • .directive("directiveName",directiveFactory);
  • 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樹、實現數據綁定。

  • scope:指令對應的scope對象。如果指令沒有定義自己的本地作用域,那么傳入的就是外部的 作用域對象。
  • iElement:指令所在DOM對象的jqLite封裝。如果使用了template屬性,那么iElement對應 變換后的DOM對象的jqLite封裝。
  • iAttrs:指令所在DOM對象的屬性集。這是一個Hash對象,每個鍵是駝峰規范化后的屬性名。
  • transclude?:?true|false|'element'

    允許指令包含其他HTML元素,這通常用于實現一個容器類型的Widget。

    有些指令需要能夠包含其他未知的元素。比如我們定義一個指令ez-dialog,用來 封裝對話框的樣式和行為,它應當允許在使用期(也就是在界面模板文件里)才指 定其內容:

  • <ez-dialog>
  • <p>對話框的內容在我們開發ez-dialog指令的時候是無法預計的。這部分內容需要
  • 被轉移到展開的DOM樹中適當的位置。</p>
  • </ez-dialog>
  • transclude屬性可以告訴編譯器,利用所在DOM元素的內容,替換template中包含 ng-transclude指令的元素的內容:

    從上圖中可以看到,使用transclude有兩個要點:

  • 需要首先聲明transclude屬性值為true,這將告訴編譯器,使用我們這個指令的 DOM元素,其內容需要被復制并插入到編譯后的DOM樹的某個點。
  • 需要在template屬性值中使用ng-transclude指明插入點。
  • 7. 過濾器

    7.1 在視圖模板中使用過濾器

    過濾器也是一種服務,負責對輸入的內容進行處理轉換,以便更好地向用戶顯示。

    過濾器可以在模板中的{{}}標記中使用:

  • {{ expression | filter:arg1:arg2}}
    • 預置的過濾器

    AngularJS的ng模塊實現了一些預置的過濾器,如:currency、number等等,可以直接 使用。例如下面的示例將對數字12使用currency過濾器,結果將是"$12.00":

  • {{12|currency}}
    • 帶參數的過濾器

    過濾器也可以有參數,例如下面的示例將數字格式化為"1,234.00":

  • {{1234|number:2}}
    • 過濾器流水線

    過濾器可以應用于另一個過濾器的輸出,就像流水線,語法如下:

  • {{expression|filter1|filter2|...}}
  • 7.2 在代碼中使用過濾器

    別忘了過濾器也是一種服務,所以你可以將它注入你的代碼中。

    和普通的服務不同,過濾器在注入器中注冊時,名稱被加了一個后綴:Filter。 例如,number過濾器的服務名稱是:numberFilter,而currency過濾器的服務名稱是: currencyFilter。

    通常我們的代碼被封裝在三個地方:控制器、服務、指令。這些地方都支持服務的直接 注入,例如:

  • angular.module('myModule',[])
  • .controller(function($scope,numberFilter){
  • //...
  • })
  • 有時你需要顯式的通過注入器調用過濾器,那么使用注入器的invoke()方法:

  • angular.injector(['ng'])
  • .invoke(function(numberFilter){
  • //...
  • })
  • 總之,記住過濾器是一種服務,除了名字需要追加Filter后綴,和其他服務的調用方法沒 什么區別。

    右邊的示例在控制器中注入了number和currency過濾器,實現對total的格式化。

    7.3 創建過濾器

    和指令類似,過濾器也是一種特殊的服務,與創建一個普通的服務相比較:

  • 必須使用模塊的filter()接口注冊服務
  • 必須提供對象工廠/factory方法
  • 對象工程必須返回一個過濾器函數,其第一個參數為輸入變量
  • //定義過濾器類工廠
  • var filterFactory = function(){
  • //定義過濾器函數
  • var filter = function(input,extra_args){
  • //process input and generate output
  • return output
  • }
  • };
  • //在模塊上注冊過濾器
  • angular.module("someModule",[])
  • .filter("filterName",filterFactory);
  • 右邊的示例定義了一個將字符串格式化為大寫的過濾器。

    7.4 為過濾器增加參數

    過濾器的行為可以通過額外的參數來調整。比如,我們希望改進上一節的示例,使其可以 支持僅大寫每個單詞的首字母。

    • 實現

    通過在過濾器類工廠返回的過濾器函數中傳入額外的參數,就可以實現這個功能。

  • var filter = function(input,argument1,argument2){...}
    • 使用

    在使用過濾器時,額外的參數通過前綴:引入,比如

  • {{expression|filter:argument1:argument2}}
  • 右邊的示例實現了支持參數的過濾器ezUC,試著去掉HTML模板中過濾器ezUC的參數, 看看顯示輸出的區別!

    轉載于:https://www.cnblogs.com/dorothychai/p/4686625.html

    總結

    以上是生活随笔為你收集整理的AngularJS进阶学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美人与按摩师xxxx | 久久久精品亚洲 | 日韩三级免费看 | 欧美黄色免费网站 | 在线毛片观看 | 亚洲综合免费观看高清完整版 | 极品videosvideo喷水 | 久久久久亚洲精品 | 久久精品二区 | 激情戏网站 | 日韩一级视频 | 99国产精品99 | 69av在线播放 | 国产精品久久99 | 在线色播| 国产又爽又黄视频 | 一区二区三区国产在线观看 | 在线色播| 亚av在线 | 国产亚洲自拍一区 | 欧美性视频一区二区 | 日韩黄色一级视频 | 99久久久久久久久久 | 国产精品亚洲二区 | 亚洲精品偷拍 | 国产毛片久久久久久 | 性色av浪潮av | 极品少妇在线观看 | www.精品久久| 97超碰人人网 | 91成人精品一区在线播放 | 亚洲熟妇无码爱v在线观看 九色福利 | 国产又爽又黄免费视频 | 熟妇女人妻丰满少妇中文字幕 | 波多野结衣1区2区3区 | 日本高清xxx | 日韩成人在线看 | 黄色资源网站 | 黄页视频在线免费观看 | 欧美春色| 熟妇熟女乱妇乱女网站 | 欧美一区二区视频 | 97视频一区 | 亚洲欧洲久久 | 亚洲国产私拍精品国模在线观看 | 西西人体44www大胆无码 | 欧美一区久久 | 日韩不卡免费视频 | 日本无翼乌邪恶大全彩h | 天天干夜操 | 怡红院成永久免费人全部视频 | 欧美做爰爽爽爽爽爽爽 | 男女午夜网站 | 日日摸天天添天天添破 | 国产精品久久久久毛片大屁完整版 | 精品人妻无码在线 | 在线观看免费成人 | 大奶在线播放 | 亚洲午夜视频在线观看 | 69xxxx日本 | 青娱乐国产盛宴 | 精品一区二区视频在线观看 | 亚洲成人一区二区三区 | 欧美不卡视频在线观看 | 一级片免费观看视频 | 欧美裸体精品 | 国产伦理吴梦梦伦理 | 成人高清视频在线观看 | 欧美人妻精品一区二区三区 | 久热这里只有精品在线 | 怎么可能高潮了就结束漫画 | 国产精品三区在线观看 | 国产久久精品 | 9999在线视频 | 国产视频久久久久久 | 久久女人网| 97人妻精品一区二区三区 | 91麻豆精品一区二区三区 | 国产伦精品一区二区三 | 三级成人在线 | 91大尺度 | av资源在线免费观看 | 97国产精品视频人人做人人爱 | 鲁啊鲁在线视频 | 国产真实乱人偷精品 | 韩国美女毛片 | 性欧美大战久久久久久久免费观看 | 黄色大片中文字幕 | 久久久久国产精品国产 | 亚洲 小说区 图片区 都市 | 两个人看的www视频免费完整版 | 男人深夜影院 | 欧美激情精品久久久久久变态 | 亚洲av成人无码网天堂 | 久久久久久久久久久av | 人妻无码一区二区三区免费 | 视频这里只有精品 | 欧美老熟 | 女人看黄色网 |