在學習自定義指令,分享一篇文章。
angular建立自定義指令使用directive()例如:css
var app = angular.module('myapp',[]);
app.directive('helloWorld',function(){app
return { restrict: 'AE', //推薦使用A replace: true, //template會覆蓋掉自定義標籤 template: '<h3>Hello World!</h3>' //自定義標籤要顯示的內容 }
});
建立出來的便籤推薦使用<div hello-world></div>函數
第一個參數是指令的名稱學習
第二個參數是一個返回指令定義對象的函數。若是你的指令對額外的對象/服務(services)例如 $rootScope, $http 或者 $compile 有依賴,它們也能夠在其中被注入。rest
link函數和做用域code
link函數是負責操做DOM元素,例如:對象
app.directive('helloWorld',function(){繼承
return { restrict: 'AE', replace: true, template: '<p></p>', link: function(scope,elem,attr){ elem.bind('click',function(){ elem.css('background-color','white'); scope.$apply(function(){ scope.color = "white"; }); }); elem.bind('mouseover',function(){ elem.css('cursor','pointer'); }); } }
});
注意到link函數被用在了指令中。它接收三個參數:seo
scope – 它表明指令被使用的做用域。在上面的例子中它等同於符控制器的做用域。
elem – 它表明綁定指令的元素的jQlite(jQuery的一個本身)包裹元素。若是你在AngularJS被包含以前就包括了jQuery,那麼它將變成jQuery包裹元素。因爲該元素已經被jQuery/jQlite包裹,咱們沒有必要將它包含在$()中來進行DOM操做。
attars – 它表明綁定指令的元素上的屬性。例如,若是你在HTML元素上有一些指令形式爲:<hello-world some-attribute></hello-world>,你能夠在link函數內用attrs.someAttribute來引用這些屬性。
link函數主要是用來對DOM元素綁定事件監聽器,監視模型屬性變化,並更新DOM。在前面的指令代碼中,咱們綁定了兩個監聽器,click和mouseover。click處理函數重置了隊列
的背景顏色,而mouseover處理函數則將遊標改變爲pointer。模板中擁有表達式{{color}},它將隨着父做用域中的模型color的變化而變化,從而改變了Hello World的背景色。
Compile函數
Compile函數主要用來在link函數運行以前進行一些DOM轉化。它接收下面幾個參數:
tElement – 指令綁定的元素
attrs – 元素上聲明的屬性
這裏要注意compile不可以訪問scope,並且必須返回一個link函數。可是,若是沒有compile函數以依然能夠配置link函數。compile函數能夠被寫成下面的樣子:
app.directive('test',function(){
return { compile: function(tElem,attrs){ //在這裏原則性的作一些DOM轉換 return function(scope,elem,attrs){ //這裏編寫link函數 } } }
});
何時使用compile?
大多數時候,你僅僅只須要編寫link函數。這是由於大部分指令都只關心與註冊事件監聽器,監視器,更新DOM等等,它們在link函數中便可完成。像是ng-repeat這樣的指令,須要屢次克隆並重復DOM元素,就須要在link函數運行以前使用compile函數。你可能會問威懾呢麼要將兩個函數分別使用。爲何咱們不能只編寫一個函數?爲了回答這個問題咱們須要理解Angular是如何編譯指令的!
指令是如何被編譯的
當應用在啓動時,Angular開始使用$compile服務解析DOM。這項服務會在標記中尋找指令而後將它們各自匹配到註冊的適齡。一旦全部的指令都已經被識別完成,Angular就開始執行它們的compile函數。正如前面所提到的,compile函數返回一個link函數,該函數會被添加到稍後執行的link函數隊列中。這叫作編譯階段(compile phase)。注意到即便同一個指令有幾個實例存在,compile函數也只會運行一次。
在編譯階段以後就到了連接階段(link phase),這時link函數就一個接一個的執行。在這個階段中模板被生成,指令被運用到正確的做用域,DOM元素上開始有了事件監聽器。不像是compile函數,lin函數會對每一個指令的實例都執行一次。
改變指令的做用域
默認狀況下指令應該訪問父做用域。可是咱們並不像對全部狀況一律而論。若是咱們對指令暴露了父控制器的scope,那麼指令就能夠自由的修改scope屬性。在一些狀況下你的指令可能想要添加一些只有內部可使用的屬性和函數。若是咱們都在父做用域中完成,可能會污染了父做用域。所以,咱們有兩種選擇:
一個子做用域 – 這個做用域會原型繼承父做用域。
一個隔離的做用域 – 一個全新的、不繼承、獨立存在的做用域。
做用域能夠由指令定義對象中的scope屬性定義。下面的例子展現了這一點:
app.directive('helloWorld',function(){
return { scope: true, //使用一個繼承父做用域的自做用域 restrict: 'AE', replace: true, template: '<h3>Hello World!</h3>' }
});
上面的代碼要求Angular爲指令提供一個可以原型繼承父做用域的子組用於。另外一種情形,一個隔離做用域,代碼以下所示:
app.directive('helloWorld',function(){
return { scope: {}, //使用一個全新的隔離做用域 restrict: 'AE', replace: true, template: '<h3>Hello World!</h3>' }
});
上面的指令使用一個不繼承父做用域的全新隔離做用域。當你想要建立一個可重用的組件時隔離做用域是一個很好的選擇。經過隔離做用域咱們確保指令是自包含的兵能夠輕鬆地插入到任何HTML app中。這種作法防止了父做用域被污染,因爲它不可訪問父做用域。在咱們修改後的helloWorld指令中若是你將scope設置爲{},那麼代碼就不會再正常運行。它將建立一個隔離的做用域而後表達式{{color}}將沒法引用隔離做用域中的屬性所以值變爲undefined。
隔離做用域並不意味着你一點都不能獲取到父做用域中的屬性。有一些技巧可使你訪問父做用域中的屬性同時監聽這些屬性的變化。咱們將在下一篇文章中提到這種高級技巧。
原文地址:http://www.xgllseo.com/?p=3511