AngularJS 詳解Directive(指令)機制

來源:互聯網
上載者:User


AngularJS  5個執行個體詳解Directive(指令)機制

 

大漠窮秋  http://damoqiongqiu.iteye.com/blog/1917971

 

  1.一點小說明

 

指令的作用:實現語義化標籤

 

我們常用的HTML標籤是這樣的:

 

<div>    <span>一點點內容</span></div>

 

而使用AngularJS的directive(指令)機制,我們可以實現這樣的東西:

 

<tabpanel>    <panel>子面板1</panel>    <panel>子面板2</panel></tabpanel>

 

很多人可能看出,這和JSP或者Struts等等架構裡面的taglib很像啊。

 

呃,說實話,實際上就是這樣的,只不過這裡是使用JavaScript來實現的。正因為如此,所以很多taglib做不到的功能,使用它就都可以做到,比如訪問N層scope裡面的對象之類的事情(參見後面第5個例子)。

  2.執行個體1:從最簡單的開始

    【注意: directive的命名--1. 都為字元,不能有底線; 2.如果使用駝峰命名方法,則在使用時,要使用-隔開駝峰詞;如trHello,則HTML中使用tr-Hello】 

<html ng-app='app'>    <body>        <hello></hello>    </body>    <script src="../angular-1.0.3/angular.min.js"></script>    <script src="HelloDirect.js"></script></html>

 

對於以上代碼裡面的<hello>標籤,瀏覽器顯然是不認識的,它唯一能做的事情就是無視這個標籤。那麼,為了讓瀏覽器能夠認識這個標籤,我們需要使用Angular來定義一個hello指令(本質上說就是自己來把<hello>這種玩意兒替換成瀏覽器能識別的那些標準HTML標籤)。

 

來看這段溫馨的JS代碼:

 

var appModule = angular.module('app', []);appModule.directive('hello', function() {    return {        restrict: 'E',        template: '<div>Hi there</div>',        replace: true    };});

 

以上代碼大概看兩眼就可以了,不要太在意細節。

 

然後我們就可以在瀏覽器裡面看到這樣的內容:

 



 

 

實際產生的標籤結構是這樣的:

 



 

 

可以看到,<hello>這個東東已經被<div>Hi there</div>這個標籤替換掉了,這也是以上JS代碼裡面replace:true這行配置的作用,代碼裡面的template配置 項當然就是我們要的div標籤啦,至於restrict:'E'這個配置項的含義,請看下錶:

 



 

 

ok,看完上面的表格,對於restrict這個屬性相信你已經秒懂了,那麼我們來玩兒點花樣吧。如果我們需要替換的HTML標籤很長,顯然不能用 拼接字串的方式來寫,這時候我們可以用templateUrl來替代template,從而可以把模板寫到一個獨立的HTML檔案中。

  3.執行個體2:transclude(變換)

 

先看例子,JS代碼:

 

var appModule = angular.module('app', []);    appModule.directive('hello', function() {    return {        restrict: 'E',        template: '<div>Hi there <span ng-transclude></span></div>',        transclude: true    };});

 

HTML代碼:

 

<html ng-app='app'>    <head>        <meta http-equiv="content-type" content="text/html; charset=utf-8" />    </head>    <body>        <hello>            <br/>            <span>原始的內容,</span><br/>            <span>還會在這裡。</span>        </hello>        <hello>        </hello>    </body>    <script src="../angular-1.0.3/angular.min.js"></script>    <script src="Transclude.js"></script></html>

 

運行效果如下:

 



 

 

產生的HTML標籤結構如下:

 



 

 

和第一個例子對比,這個例子的JS和HTML代碼都略有不同,JS代碼裡面多了一個transclude: true,HTML代碼裡面在<hello>內部出現了子標籤。

 

按照我們在第一個例子中的說法,指令的作用是把我們自訂的語義化標籤替換成瀏覽器能夠認識的HTML標籤。那好,如果我們自訂的標籤內部出現了子標籤,應該如何去處理呢。很顯然,transclude就是用來處理這種情況的。

 

對於當前這個例子,transclude的作用可以簡化地理解成:把<hello>標籤替換成我們所編寫的HTML模板,但是<hello>標籤內部的內容保持不變

 

很顯然,由於我們沒有加replace:true選項,所以<hello>標籤還在,沒有被替換掉。同時,通過這個例子你還還會發現一 個暗藏的屬性,那就是瀏覽器實際上非常智能,雖然它並不認識<hello>這個標籤,但是頁面沒有出錯,它只是默默地把這個標籤忽略掉了。怎 麼樣。是不是碉堡了。

 

你可以自己在上面的JS代碼裡面加上replace:true,然後再看產生的HTML結構。

  4.執行個體3:關於compile和link

 

JS代碼:

 

var appModule = angular.module('app', []);appModule.directive('hello', function() {    return {        restrict: 'E',        template: '<span>Hi there</span>',        replace: true    };});appModule.controller('MyController',function($scope) {    $scope.things = [1,2,3,4,5,6];});

 

HTML代碼:

 

<html ng-app='app'>    <body ng-controller='MyController'>        <div ng-repeat='thing in things'>            {{thing}}.<hello></hello>        </div>    </body>    <script src="../angular-1.0.3/angular.min.js"></script>    <script src="CompileAndLink.js"></script></html>

 

呃,這個例子是用來解釋一點點理論的,所以單純看效果可能看不出個鳥。

 

如前所述,指令的本質其實是一個替換過程。好,既然如此,Angular到底是如何進行替換的呢。嗯嗯,這個過程分2個階段,也就是本區段標頭所說的compile(編譯)和link(串連)了。

 

簡而言之,compile階段進列標籤解析和變換,link階段進行資料繫結等操作。這裡面更加細節的處理過程請參見《AngularJS》這本書中的解析,這裡就不贅述了(呃,實際上是因為解釋起來很長很麻煩,叔懶得在這兒說了)。

 

那麼,知道這件事情有什麼用途呢。

 

比方說,你有一些事件需要綁定到某個元素上,那麼你需要提供一個link函數,做法請看下一個例子。

  5.執行個體4:一個複雜一點的例子Expander

 

這是《AngularJS》這本書裡面提供的一個例子,但是書裡面沒有給出完整的可運行代碼,所以這裡給出來,大家參考一下。

 

JS代碼:

 

var expanderModule=angular.module('expanderModule', [])expanderModule.directive('expander', function() {    return {        restrict : 'EA',        replace : true,        transclude : true,        scope : {            title : '=expanderTitle'        },        template : '<div>'                 + '<div class="title" ng-click="toggle()">{{title}}</div>'                 + '<div class="body" ng-show="showMe" ng-transclude></div>'                 + '</div>',        link : function(scope, element, attrs) {            scope.showMe = false;            scope.toggle = function toggle() {                scope.showMe = !scope.showMe;            }        }    }});expanderModule.controller('SomeController',function($scope) {    $scope.title = '點擊展開';    $scope.text = '這裡是內部的內容。';});

 

HTML代碼:

 

<html ng-app='expanderModule'>    <head>        <meta http-equiv="content-type" content="text/html; charset=utf-8" />        <script src="../angular-1.0.3/angular.min.js"></script>        <link rel="stylesheet" type="text/css" href="ExpanderSimple.css"/>    </head>    <body>        <div ng-controller='SomeController'>            <expander class='expander' expander-title='title'>                {{text}}            </expander>        </div>    </body>    <script src="ExpanderSimple.js"></script></html>

 

CSS代碼:

 

.expander {    border: 1px solid black;    width: 250px;}.expander>.title {    background-color: black;    color: white;    padding: .1em .3em;    cursor: pointer;}.expander>.body {    padding: .1em .3em;}

 

運行效果如下:

 



 

 

注意一下JS代碼裡面的這一段:

 

link : function(scope, element, attrs) {    scope.showMe = false;    scope.toggle = function toggle() {        scope.showMe = !scope.showMe;    }}

 

自己跑一跑例子,研究一番,不多解釋。

  6.執行個體5:一個綜合的例子

 

JS代碼:

 

var expModule=angular.module('expanderModule',[])expModule.directive('accordion', function() {    return {        restrict : 'EA',        replace : true,        transclude : true,        template : '<div ng-transclude></div>',        controller : function() {            var expanders = [];            this.gotOpened = function(selectedExpander) {                angular.forEach(expanders, function(expander) {                    if (selectedExpander != expander) {                        expander.showMe = false;                    }                });            }            this.addExpander = function(expander) {                expanders.push(expander);            }        }    }});expModule.directive('expander', function() {    return {        restrict : 'EA',        replace : true,        transclude : true,        require : '^?accordion',        scope : {            title : '=expanderTitle'        },        template : '<div>'                   + '<div class="title" ng-click="toggle()">{{title}}</div>'                   + '<div class="body" ng-show="showMe" ng-transclude></div>'                   + '</div>',        link : function(scope, el
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.