angularjs的directive的屬性含義詳解


 在介紹directive之前,我想先講講MVC這個框架的相關知識。這樣可以更好的理解angular。

什么是MVC?mvc是一種設計模式,它把應用划分為三個部分,數據(模型),展現層(視圖),控制交互層(控制器),一個時間的發生時這樣的過程:

1.用戶和應用產生交互

2.控制器的事件處理器被觸發

3.控制器從模型中請求數據,並將其交給視圖

4.視圖將數據呈現給用戶。

模型

模型用來存放應用的所有數據對象,模型不必知曉視圖和控制器的細節,模型只需包含數據及直接和這些數據相關的邏輯。任何事件處理代碼、視圖模板,以及那些和模型無關的邏輯都應當隔離在模型之外。將模型和視圖的代碼混在一起,是違反MVC架構原則的。模型是最應該從你的應用中解耦出來的部分。

當控制器從服務端抓取數據或者創建新的記錄時,它就將數據包裝成模型實例,也就是說,我們的數據是面向對象的,任何定義在這個數據模型上的函數或者邏輯都可以直接被調用。

因此,不要這樣做:  

var user = users["foo"];
destroyUser(user);

  上面的代碼沒有命名空間的概念,並且不是面向對象的。如果在應用中定義了另一個destoryUser()函數的話,兩個函數就會產生沖突。我們應當確保全局變量和函數的個數盡可能少.而要這樣做。

var user = User.find("foo");
user.destroy();

  上面的代碼中,destory()函數是存放在命名空間User的實例中的。這種代碼更加清晰,而且非常容易做繼承,類似destory()的這種函數就不用在每個模型中都定義一遍了。

視圖

視圖層是呈現給用戶的,用戶與之產生交互,在JavaScript 應用中,視圖大都是由HTML、CSS和JavaScript模板組成的。除了模板中簡單的條件語句之外,視圖不應當包含任何其他邏輯。

這並不是說MVC不允許包含視覺呈現相關的邏輯,只要這部分邏輯沒有定義在視圖之內即可。我們將視覺呈現邏輯歸類為“視圖助手”(helper):和視圖有關的獨立的小型工具函數。

反例——formatDate()函數直接插入視圖:

// template.html
<div>
    <script>
        function formatDate(date) {
            /* ... */
        };
    </script>

    ${ formatDate(this.date) }
</div>

  應該這樣做——所有視覺呈現邏輯都包含在helper變量中,這是一個命名空間,可以防止沖突並保持代碼清晰、可擴展:

  

// helper.js
var helper = {};
helper.formatDate = function(){ /* ... */ };

// template.html
<div>
    ${ helper.formatDate(this.date) }
</div>

  控制器

控制器是模型和視圖之間的紐帶,控制器從視圖獲得時間和輸入,對它們驚醒處理(很可能包含模型),並相應的跟新視圖。當頁面加載工作時,控制器會給視圖添加事件監聽,比如監聽表單提交或者按鈕點擊。然后,當用戶和應用產生交互時,控制器中的事件觸發器就開始工作了。

下面用jQuery實現一個例子:

var Controller = {};

// 使用匿名函數來封裝一個作用域
(Controller.users = function($){

    var nameClick = function(){
        /* ... */
    };

    // 在頁面加載時綁定事件監聽
    $(function(){
        $("#view .name").click(nameClick);
    });
})(jQuery);

  上面的代碼創建了users控制器,這個控制器是放在Controller變量下的命名空間。然后用了一個匿名函數封裝了一個作用域,以避免對全局作用域造成污染。當頁面加載時,程序給視圖元素綁定了點擊事件的監聽。

上面就是mvc的簡單介紹。下面繼續directive的屬性講解。

基本上每個directive都會經過$compile編譯,然后通過link函數來拓展相應的DOM元素。下面介紹常用的directive定義的對象:

priority

當有多個directive定義在同一個DOM元素上時,有必要指定directive的應用順序。priority對象通常用數字表示,數字越大的,相應的指定便優先編譯,相反該directive對應的link函數便越靠后執行。priority的值默認為是0.

 scope(講到這個,值得提一提$scope對象,還有在controller中使用$scope和this(當在html中使用controller as時可以使用)的區別,感興趣的話自行搜索)

它的值有三種;true,false(默認),object(對象)。

什么是angular中的scope?

scope(http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope)是一個指向model的object。也是表達式的的執行上下文(請自行了解執行上下文的概念)。angular中提供了一些常用API:$watch API(http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$watch),用於監測model的變化,$apply API(http://code.angularjs.org/1.0.2/docs/api/ng.$rootScope.Scope#$apply),用於監測angular 定義的對象內外的所有model的變化。

在angular中,子作用域一般是通過原型繼承機制繼承其父作用域的屬性和方法,但是有一個例外:在directive中,使用scope:{...},這種方式創建的作用域是一個獨立的(isolate)作用域,它也有父作用域,但父作用域不在其原型鏈上,不會對父作用域原型繼承,這種方式定義作用域通常用於構造可復用的directive組件,因為這樣定義的scope,不會直接訪問或者時候修改父作用域的屬性,不會產生意外的副作用。

如果我們在子作用域中訪問一個父作用域中定義的屬性,那么程序會首先在子作用域中尋找該屬性,沒找到在從原型鏈上的父作用域中尋找,在沒找到,再往上一級原型鏈找。在angular中,作用域原型鏈的頂端是$rootScope。

在單獨的directive中,scope的概念還是比較清晰的。

當scope取值為false時,此時directive沒有獨立的scope對象,link函數中引用的scope對象為來自於當前節點的默認controller。

當scope取值為true是時,directive擁有獨立的scope對象,此scope是由父scope繼承而來,可以訪問父scope中的所有屬性,此時通過javasript原型繼承。值得注意的是:當給此scope繼承而來的屬性名稱賦值時,子scope會相應建立一個本地屬性,此時改變的是本scope的變量屬性,父scope中的屬性是不會改變的。

當scope取值為{propertyName:"=@propertyValue},此時directive擁有一個隔離的scope對象,其實就是一個全新的scope對象,和上面取值的區別就是不能通過原型繼承訪問父scope中的屬性,但是可以通過$parent屬性去訪問父scope中對象屬性的。

下面講講當scope取值為{...}時,申明scope對象的引用修飾符的用法:(http://stackoverflow.com/questions/14050195/angularjs-what-is-the-difference-between-and-in-directive-scope)

1.=或者=attr  隔離作用域的屬性與父作用域的屬性進行雙向綁定,任何一方修改都會影響對方,此時指令中的屬性取值為controller中對應的$scope上屬性的值,這是最常用的方式;

2.@或者@attr  此時指令中的屬性取值為html中的字面量或者直接量。這樣是建立一個local scope property到DOM的property的綁定,因為值總是string類型,故這個值總是返回一個字符串,並且字符串的值永遠是從父作用域繼承而來的(即只能讀取父作用域中屬性值,不能修改,屬於單向綁定)。如果沒有通過@attr指定屬性名稱,那么本地名稱將於DOM的屬性一致。例如<widget my-attr=”hello {{name}}”>,widget的scope定義為:{localName:’@myAttr’}。那么,widget scope property的localName會映射出”hello {{name}}"轉換后的真實值。name屬性值改變后,widget scope的localName屬性也會相應地改變(僅僅單向,與上面的”=”不同)。name屬性是在父scope讀取的(不是組件scope).

 3. & or &attr “Isolate”作用域把父作用域的屬性包裝成一個函數,從而以函數的方式讀寫父作用域的屬性,包裝方法是$parse();

 

 controller

這是嵌套directive之間交互的重要屬性對象。

 套用一個經典定義( what the O'Reily AngularJS book by the Google Team has to say):Controller - Create a controller which publishes an API for communicating across directives. A good example is Directive to Directive Communication。意即這個controller是用來存放一些可以在各個directive之間的共享的方法。當兩個或更多的directive之間需要通信時(即directive A需要用到directive B中的方法M),這時方法M就可以在directive B中的controller對象中來定義這個方法。此時方法M便類似一些公共的API(可以供其他的directive使用。)詳情請參考:http://www.cnblogs.com/xing901022/p/4290411.html

 這個controller可以注入以下本地變量:

$scope (當前元素作用域),$element(當前元素),$attrs(當前元素的屬性對象),$transclude(后面介紹這個變量,感興趣的自己去谷歌)。

require

 這個對象表示需要另外一個directive B(directive之間的通信)並且將會注入directive B所在的controller到linking function中,它的值一般是'xxxController'或者'^xxxController',表示這個directive需要使用directive B的controller屬性中的API。

restrict

限制directive在html中作用的方式:

'E' element name,表示以元素的形式在html中作用,例如<my-directive></my-directive>

'A' attribute ,表示以屬性的方式作用在html中,例如 <div my-directive='exp'></div>

'C' class ,表示以class的形式在html中作用,例如<div class='my-directive : exp ;'></div>

'M' 以注釋的方式在html中作用,例如<!-- directive: my-directive exp -->

當然,以上也可以組合使用,表示邏輯and。例如 restrict : 'EA',\

template 

模板代替directive的元素的內容(默認),也可以完全代替元素本身(當replace值為true時有效),也可以用來封裝directive的元素的內容(當transclude的值為true時有效)。

取值:

  • A string. For example <div red-on-hover>{{delete_str}}</div>.
  • A function which takes two arguments tElement and tAttrs (described in the compile function api below) and returns a string value.

templateUrl

模板加載地址,異步加載。

replace

取值為true時,模板將會取代directive的元素;取值為false,模板將會取代directive的元素的內容。

transclude

一般情況下取值有三種true,'element',{...},通常用到前兩種。

當取值為true時, transclude the content (i.e. the child nodes) of the directive's element.舉個例子:

比如說你有一個申明transclude :true的directive叫做my-transclude-true,如下:

<div>
  <my-transclude-true>
    <span>{{ something }}</span>
    {{ otherThing }}
  </my-transclude-true>
</div>

  當它被編譯之后,就會變成如下:

<div>
  <my-transclude-true>
    <!-- transcluded -->
  </my-transclude-true>
</div>

 my-transclude-true這個directive的內容content(子節點),即'<span>{{something..',將在這個directive中 可用。

再比如說你有一個申明transclude :'element'的directive叫做my-transclude-element,如下:

<div>
  <my-transclude-element>
    <span>{{ something }}</span>
    {{ otherThing }}
  </my-transclude-element>
</div>

  被編譯之后,就會變成如下:

<div>
   <!-- transcluded -->
</div>

  這里,它的整個元素包括它的子節點都將在這個directive中可用。當transclude這個屬性被申明為'element'時,directive中的template屬性將會失去作用。

最后一個重要的屬性:link

這個屬性只有在compile這個屬性未定義時才能使用。

一般的語法糖:link : function (scope,iAttrs,iElement,controller){...}

link function的作用:Programmatically modify resulting DOM element instances, add event listeners, and set up data binding.以編程方式修改生成的DOM元素實例,添加事件監聽器,設置數據綁定。這是整個directive邏輯放的最多的地方。

下面說說這個函數的參數含義:

scope  directive用來注冊監聽事件registering watches的作用域;

iElement  調用這個directive的實例的元素,比如:angular.module('app',[]).directive('myDirective',function(...){template :'<div data='data'><ul></ul></div>',replace:true});這個directive的元素就是'<div><ul></ul></div>',只有在postlink函數中處理元素的子節點'<ul></ul>'才是安全的,因為子節點已經被link了。(https://docs.angularjs.org/api/ng/service/$compile #link)

iAttrs 調用這個directive的實例的元素的屬性,如上為[data],是一個屬性列表集合。

controller:這個diective所需要的controller實例,通常在require這個屬性后面已經寫明。

以上大概就是平時開發過程中常用到的幾個屬性。

后面要續寫的內容預知:

1.嵌套directive之間的通訊(即directive之間的交互);

2.directive與controller之間的數據傳遞和通信;

3.controller與controller之間的數據傳遞和通信。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM