AngularJS中的指令

来源:http://www.cnblogs.com/ww-ervin-72/archive/2016/03/19/5296788.html
-Advertisement-
Play Games

說到AngularJS,我們首先想到的大概也就是雙向數據綁定和指令系統了,這兩者也是AngularJS中最為吸引人的地方。雙向數據綁定呢,感覺沒什麼好說的,那麼今天我們就來簡單的討論下AngularJS這個框架的指令系統,本人也是初學,查閱了一些資料,要是有一些說的不好的地方,各位看官一笑而過便是,


說到AngularJS,我們首先想到的大概也就是雙向數據綁定和指令系統了,這兩者也是AngularJS中最為吸引人的地方。雙向數據綁定呢,感覺沒什麼好說的,那麼今天我們就來簡單的討論下AngularJS這個框架的指令系統,本人也是初學,查閱了一些資料,要是有一些說的不好的地方,各位看官一笑而過便是,廢話不多說下麵開始。

指令作為AngularJS中最為重要的部分,所以這個框架本身也是自帶了比較多的的指令,但是在開發中,這些指令通常不能滿足我們的需要,所以我們也是需要自定義一些指令的。那麼一個AngularJS指令在HTML代碼中可以有四種表現形式:

1、作為一個新的HTML元素來使用。

<hello></hello>或者<hello/>

2、作為一個元素的屬性來使用

<div hello></div>

3、作為一個元素的類來使用

<div class="hello"></div>

4、作為註釋來使用

<!--directive: hello -->

註意這裡有一個陷阱,就是在“directive: hello”這個的後面要有一個空格,不然的話是沒有效果的,同時推薦註釋的方法的還是少用,如果非要追求高大上,那就隨性吧。既然指令有以上四種表現形式,那麼具體他是怎麼來定義的呢?

.directive('hello',function(){
      return {
        restrict:'AECM',
        template:'<button>click me</button>'
      }
    })

上面就是定義一個指令最簡單的代碼了,沒有之一。在上面的代碼中,directive()這個方法定義了一個新的指令,該方法有兩個參數,第一個'hello'就是規定指令的名字為hello,第二個參數是返回指令對象的函數。那麼在上面的代碼中,該函數主要使用了兩個屬性來定義這個hello指令:

1、restrict[string]這個屬性,主要是用來規定指令在HTML代碼中可以使用什麼表現形式。A代表屬性、E代表元素、C代表類、M代表註釋。實際情況中我們一般使用AE這兩種方式。

2、template[string or function]這個屬性,規定了指令被Angular編譯和鏈接(link)後生成的HTML標記,這個屬性可以簡單到只有一個HTML文本在裡面,也可以特別複雜,當該屬性的值為function的時候,那麼該方法返回的就是代表模板的字元串,同時也可以在裡面使用{{}}這個表達式。

template: function () {
          return '<button>click me</button>';
 }

但是在一般情況下,template這個屬性都會被templateUrl取代掉,用它來指向一個外部的文件地址,所以我們通常把模板放在外部的一個HTML文件中,然後使用templateUrl來指向他。

在定義指令的時候,除了以上兩個最基礎的屬性外,我們還會使用到其他的很多屬性,那麼下麵我們就來一一的說下:

1、priority[number]屬性,這個屬性是來規定自定義的指令的優先順序的,當一個DOM元素上面有一個以上的指令的時候,就需要去比較指令的優先順序了,優先順序高的指令先執行。這個優先順序就是用來在執行指令的compile函數前,先排序的,那麼關於compile這個函數,我們會在下麵仔細的說下。

2、terminal[boolean]屬性,該參數用來定義是否停止當前元素上比本指令優先順序低的指令,如果值為true,就是正常情況,按照優先順序高低的順序來執行,如果設置為false,就不會執行當前元素上比本指令優先順序低的指令。

3、replace[boolean]屬性,這個屬性用來規定生成的HTML內容是否會替換掉定義此指令的HTML元素。當我們把該屬性的值設為true的時候,打開控制台看看你會發現這個指令生成的元素會是這樣的:

當我們設置為false的時候會是這樣的:

4、link[function]屬性,在上面的例子中,我們自定義的指令其實沒有多大意義,這隻是一個最簡單的指令,有好多的屬性我們都沒有為他定義,所以沒有多大用途。比如這個link函數,它包括三個參數:scope、element、attrs。這個link函數主要是用來添加對DOM元素的事件監聽、監視模型屬性變化、以及更新DOM的。它裡面三個參數:

一:scope參數,在我們沒有為指令定義scope屬性的時候,那麼他代表的就是父controller的scope。

二:element參數,就是指令的jQLite(jQuery的子集)包裝DOM元素。如果你在引入AngularJS之前引入了jQuery,那麼這個元素就是jQuery元素,而不是jQLite元素。由於這個元素已經被jQuery/jQLite包裝了,所以我們就在進行DOM操作的時候就不需要再使用 $()來進行包裝。

三:attrs參數,它包含了該指令所在元素的屬性的標準化參數對象。

5、scope[boolean or object]屬性,該屬性是用來定義指令的scope的範圍,預設情況下是false,也就是說該指令繼承了父controller的scope,可以隨意的使用父controller的scope里的屬性,但是這樣的話就會污染到父scope里的屬性,這樣是不可取的。所以我們可以讓scope取以下兩個值:true和{}。

當為true的時候,表示讓Angular給指令創建一個繼承於父scope的scope。

var myapp=angular.module('myapp',[])
    .controller('myctrl',['$scope', function ($scope) {
      $scope.color='red';
    }])
    .directive('hello', function () {
      return{
        restrict:'AECM',
        replace:true,
        template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>',
        scope:true,
        link: function (scope,elements,attrs) {
          elements.bind('click', function () {
            elements.css('background-color','blue');
          })
        }
      }
    })

這裡我們為父scope定義了一個color的屬性,並賦值為red,在hello指令的scope屬性中,我們給了true,所以angular就為這個指令創建了一個繼承於父scope的scope,然後在template屬性中,我們用{{}}使用了從父scope中繼承過來的color屬性,所以按鈕會是紅色的。

當為{}的時候,表示創建一個隔離的scope,不會繼承父scope的屬性。但是在有的時候我們也要需要訪問父scope里的屬性或者方法,那麼我們應該怎麼辦呢。angular早就為我們想到了這一點,有以下的三個辦法可以讓我們記性上面的操作:

一:使用@實現單向綁定,如果我們只給scope的這個{}值的話,那麼上面代碼的按鈕的背景色將會是灰色的。,而如果我們需要使用父scope的color屬性的時候,我們可以這樣寫:

scope{
    color:'@color'
}
<hello color="{{color}}"></hello>

這裡有兩點需要註意:1、scope里的屬性color代表的是模板{{}}這個表達式裡面的color,兩者必須一致。2、scope里的屬性color的值,也就是@後面的color,表示的是下麵的HTML元素里的屬性color,所以這兩者也必須一致,當這裡的屬性名和模板里表達式{{}}裡面使用的名稱相同的話,就可以省略掉@後面的屬性名了,然後寫成下麵的形式。

scope{
    color:'@'
}

從指令中scope的值可以看出,指令模板中的表達式{{}}里的color的指向的是當前元素元素的color屬性,這個color屬性的值就是父scope的屬性color的值。父scope把他的color屬性值傳遞給了當前元素的color屬性,然後color屬性又把值傳遞給了模板中表達式里的color,這個過程是單向的。

二:使用=實現雙向綁定

    .directive('hello', function () {
      return{
        restrict:'AECM',
        replace:true,
        template:'<button style="background-color: {{color}}">click me</button>',
        scope:{
          color:'='
        },
        link: function (scope,elements,attrs) {
          elements.bind('click', function () {
            elements.css('background-color','blue');
            scope.$apply(function () {
              scope.color='pink';
            })
          })
        }
      }
    })
<hello color="color"></hello>
<input type="text" ng-model="color"/>

這裡我們給指令的scope中的color屬性和父scope中的color屬性進行了雙向綁定,並且給指令的link函數里,添加了一個單擊事件,點擊按鈕會讓按鈕的顏色發生變化,並且改變指令scope的color屬性的值,再給HTML頁面中加了一個input標簽,輸出或者輸入父scope的color屬性的值。這裡有兩個地方需要註意:1、當前元素的屬性名(這裡是color)必須和模板裡面表達式{{}}里的(這裡也是color)一致。2、當前元素的屬性名的值不用再加上{{}}這個表達式了,因為這裡父scope傳遞的是一個真實的scope數據模型,而不是簡單的字元串,所以這樣我們就可以傳遞簡單的字元串、數組、甚至複雜的對象給指令的scope。現在讓我們來看看點擊這個按鈕將會發生什麼。

這裡我們能看到,按鈕的顏色變成了粉色的,說明點擊讓指令的scope的color屬性發生了變化,從而導致按鈕的顏色發生了變化。但是這裡不僅僅是按鈕發生了變化,註意看,input表單里的值也變成了pink,這就說明父scope的color屬性也發生了變化。 另外,再讓我們來給input裡面輸入一個顏色,看看發生什麼變化。

,可以看出當我們在表單里輸入另外一種顏色的時候,按鈕的顏色也發生了變化,這就說明指令的scope的color屬性被改變了。綜上我們可以發現使用'='實現的是雙向綁定。

三:使用&調用父scope里的方法

var myapp=angular.module('myapp',[])
    .controller('myctrl',['$scope', function ($scope) {
      $scope.color='red';
      $scope.sayhello= function () {
        alert('hello');
      };
    }])
    .directive('hello', function () {
      return{
        restrict:'AECM',
        replace:true,
        template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>',
        scope:{
          color:'=',
          sayhello:'&'
        },
        link: function (scope,elements,attrs) {
          elements.bind('click', function () {
            elements.css('background-color','blue');
            scope.$apply(function () {
              scope.color='pink';
            })
          })
        }
      }
    })
<hello color="color" sayhello="sayhello()"></hello>
<input type="text" ng-model="color"/>

這裡我們也有兩個地方需要註意:1、我們不僅需要在模板中使用ng-click指令,綁定上要調用的父scope中的方法,而且要在給當前元素添加一個屬性,並且這個屬性指向要調用的父scope的方法。2、指令scope的屬性sayhello、當前元素的屬性sayhello、模板綁定的事件方法名sayhello這三者要一致。那麼這樣我們就可以點擊按鈕,彈出一個對話框了。

6、transclude[boolean]屬性,這個屬性用來讓我們規定指令是否可以包含任意內容

.directive('hello', function () {
      return{
        restrict:'AECM',
        replace:true,
        transclude:true,
        scope:{},
        template:'<div ng-transclude></div>',
      }
    })
<hello>
  hello
  <span>{{color}}</span>
</hello>

當他的值為true的時候,這是頁面上輸出的值。當為false的時候,頁面上將會是空白的。這裡有一個地方需要註意,就是<span>{{color}}</span>,這裡的color是父scope里的color。並不是指令里的scope的color屬性。

7、compile[function]參數,該方法有兩個參數element,attrs,第一個參數element指指令所在的元素,第二個attrs指元素上賦予的參數的標準化列表。這裡我們也有個地方需要註意:compile 函數不能訪問 scope,並且必須返回一個 link 函數。但是如果沒有設置 compile 函數,你可以正常地配置 link 函數,(有了compile,就不能用link,link函數由compile返回)。

.directive('hello', function () {
      return{
        restrict:'AECM',
        replace:true,
        translude:true,
        template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>',
        scope:{
          color:'=',
          sayhello:'&'
        },
        compile: function (element,attrs) {
          return function (scope,elements,attrs) {
            elements.bind('click', function () {
              elements.css('background-color','blue');
              scope.$apply(function () {
                scope.color='pink';
              })
            })
          };
        }
      }
    })

現在讓我們來點擊這個按鈕

我們發現,這裡點擊按鈕之後發生的事情和前面用link屬性的一樣,這其實是沒有多少差別的。

其實在大多數的情況下,我們只需要使用 link 函數。這是因為大部分的指令只需要考慮註冊事件監聽、監視模型、以及更新DOM等,這些都可以在 link 函數中完成。 但是對於像 ng-repeat 之類的指令,需要克隆和重覆 DOM 元素多次,在 link 函數執行之前由 compile 函數來完成。那麼為什麼我們需要兩個分開的函數來完成生成過程,為什麼不能只使用一個?要回答好這個問題,我們需要理解指令在Angular中是如何被編譯的!

8、指令是如何被編譯的

當我們的angular應用引導啟動的時候,angular將會使用$compile服務遍歷DOM元素,在所有的指令都被識別之後,將會調用指令的compile方法,返回一個link函數,然後將這個link函數添加到稍後執行的 link 函數列表中,這個過程被稱為編譯階段。像ng-repeat這樣的指令,需要被重覆克隆很多次,compile函數只在編譯階段被執行一次,並且複製這些模板,但是link 函數會針對每個被覆制的實例被執行。所以分開處理,讓我們在性能上有一定的提高(這句話有點不太理解,我是從別的地方copy過來的。原文在這裡http://blog.jobbole.com/62249/)。

9、controller[string or function]和require[string or string[]]參數,當我們想要允許其他的指令和你的指令發生交互時,我們就需要使用 controller 函數。當另一個指令想要交互時,它需要聲明它對你的指令 controller 實例的引用(require)。

.directive('hello', function () {
      return{
        scope:{},
        require:'^he',
        compile: function (element,attrs) {
          return function (scope,elements,attrs,cntIns) {
            cntIns.fn()
          };
        }
      }
    })
    .directive('he', function () {
      return {
        restrict:'AE',
        scope:{},
        controller: function ($scope, $compile, $http) {
          this.fn= function () {
            alert('hello');
          };
        }
      }
    })
<he>
  <hello color="color" sayhello="sayhello()"></hello>
</he>

當頁面載入完畢之後,會彈出一個對話框。

好了上面就是我這段時間學習angular,所瞭解到的指令的知識,就先寫到這裡了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大家好,我是小Alan,很高興大家能夠看到這篇小小的技術點文章,這還是從參加工作以來,小Alan寫的第一篇博文。喜歡能夠給一些朋友帶來方便。 說到eclipse編碼格式的設置其實一個非常非常小的事情,但是在eclipse的開發使用中卻又是一個無法忽視的問題,它甚至會影響到我們的工作以及和團隊成員之間
  • 學習head first python一書的資料,Android、gae環境程式,sl4a_r3.apk,GoogleAppEngine-1.5.2.msi,GoogleAppEngine-1.5.2.msi等
  • 通過分析如下代碼,大致瞭解Disruptor的原理 1. 第2行代碼 EventFactory<LongEvent> eventFactory = new LongEventFactory(); 數據工廠類構造單個數據,disruptor使用此工廠類預分配數據。 2. 第5行代碼 final Dis
  • 沒看過前幾篇的可以猛戳這裡: underscore.js源碼解析(一) underscore.js源碼解析(二) underscore.js源碼解析(三) 本文解析的underscore.js版本是1.8.3 _.pluck的作用就是獲取數據對象中的相應屬性,然後存在數組當中返回 _.where就是
  • 1、HTML DOM 定義了訪問和操作HTML文檔的標準方法。 2、HTML DOM 把 HTML 文檔呈現為帶有元素、屬性和文本的樹結構(節點樹)。 3、通過 JavaScript,您可以重構整個 HTML 文檔。您可以添加、移除、改變或重排頁面上的項目。要改變頁面的某個東西,JavaScript
  • compass和sass相當於,jquery和javascript,一個是封裝的css庫,另一個是javascript庫,它們都目的是一樣的,簡化開發。 一般來說,安裝SASS的話,會自動幫助你安裝compass。如果不確認是否有安裝compass,在cmd中輸入 顯示 'compass' 不是內部
  • 你知道嗎?JavaScript可以為任何HTML元素添加任意的自定義屬性,而且你可能無意中已經使用過自定義屬性了,那麼自定義屬性通常有哪些應用呢? 1、想用“匹配”、對應關係的時候就用索引值 2、同時控制多組元素 3、開關切換,多組元素開關的切換 就總結到這裡,下麵來看看幾個例子吧 JavaScri
  • 《javaScript高級程式設計》第四章 讀書筆記 4.1 基本類型 和 引用類型 的值 1. 基本類型值 包括:Undefined、Null、Boolean、Number 和 String。 引用類型值 指那些可能由多個值構成的對象。【註意:字元串不是引用類型的】 2. 基本類型 在記憶體中占據固
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...