搞定angular1.x——复杂指令

本文深入探讨AngularJS指令的创建和使用方法,包括不同类型的指令、模板的使用方式、作用域的管理等内容,并提供了丰富的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

名称

描述

compile

指定一个编译函数

controller

为指令创建一个控制器函数

link

为指令指定链接函数

replace

指定模板内容是否替换指令所应用到的元素

require

声明对某个控制器的依赖

restrict

指定指令如何使用ACEM

scope

为指令创建一个新的作用域或者一个隔离的作用域

template

指定一个将被插入到HTML文档的模板

templateUrl

指定一个将被插入到HTML文档的外部模板

transclude

指定指令是否被用于包含任意内容

 

  1. .directive('unorderedList', function () {
  2.     return {
  3.         link: function (scope, element, attrs) {
  4.             var data = scope[attrs['unorderedList'] || attrs['listSource'] ];
  5.             var propertyName = attrs['listProperty'] || "price || currency";
  6.             if(angular.isArray(data)){
  7.                 var listElem = angular.element("<ul>");
  8.                 if(element[0].nodeName == "#comment"){
  9.                     element.parent().append(listElem);
  10.                 }else{
  11.                     element.append(listElem);
  12.                 }
  13.                 for(var i=0, len=data.length; i<len; i++){
  14.                     var itemElem = angular.element('<li>').text(scope.$eval(propertyName, data[i]));
  15.                     listElem.append(itemElem);
  16.                 }
  17.             }
  18.         },
  19.         restrict:'EACM'
  20.     };
  21. });

如何使用指令

当作元素使用(E)

  1. <unordered-list list-source="products" list-property="price | currency" />

        当unordered-list当作元素使用,需要添加另外的属性代替unordered-list属性的作用。

  1. var data = scope[attrs['unorderedList'] || attrs['listSource'] ];

当作属性使用(A)

  1. <div unordered-list="products" list-property="price | currency"></div>

当作类的属性值使用(C)

  1. <div class="unordered-list: products" list-property="price | currency"></div>

当作注释使用(M)

  1. <!-- directive: unordered-list products  -->

使用模板指令

  1. .directive('unorderedList', function () {
  2.     return {
  3.         link: function (scope, element, attrs) {
  4.             scope.data = scope[attrs['unorderedList']];
  5.         },
  6.         restrict: 'A',
  7.         template:"<ul><li ng-repeat='item in data'>{{item.price | currency}}</li></ul>"
  8.     };
  9. });

使用函数作为模板

        template属性除了使用字符串,也可以指定一个函数来生成模板化的内容。该函数传入两个函数(指令所应用到的元素以及属性集合)并返回将被插入到文档中的HTML代码片段。

  1. <script type="text/javascript" id="listTemplate">
  2.     <ul>
  3.         <li ng-repeat="item in data">{{item.price | currency}}</li>
  4.     </ul>
  5. </script>
  6. <script>
  7. var myApp = angular.module('myApp', [])
  8.  
  9.     .controller('myCtrl', ["$scope", function ($scope) {
  10.         $scope.products = [
  11.             { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
  12.             { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
  13.             { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
  14.         ];
  15.     }])
  16.         .directive('unorderedList', function () {
  17.             return {
  18.                 link: function (scope, element, attrs) {
  19.                     scope.data = scope[attrs['unorderedList']];
  20.                 },
  21.                 restrict: 'A',
  22.                 template:function () {
  23.                     return angular.element(
  24.                             document.querySelector("#listTemplate")
  25.                     ).html();
  26.                 }
  27.             };
  28.         });
  29. </script>

使用外部模板

itemTemplate.html

  1. <p>This is the form the template file</p>
  2. <ul>
  3.     <li ng-repeat="item in data">{{item.price | currency}}</li>
  4. </ul>
  1. .directive('unorderedList', function () {
  2.     return {
  3.         link: function (scope, element, attrs) {
  4.             scope.data = scope[attrs['unorderedList']];
  5.         },
  6.         restrict: 'A',
  7.         templateUrl:"itemTemplate.html"
  8.     };
  9. });

通过函数选择一个外部模版

tableTemplate.html

  1. <table>
  2.     <thead>
  3.         <tr>
  4.             <th>Name</th>
  5.             <th>Price</th>
  6.         </tr>
  7.     </thead>
  8.     <tbody>
  9.         <tr ng-repeat="item in data">
  10.             <td>{{item.name}}</td>
  11.             <td>{{item.price | currency}}</td>
  12.         </tr>
  13.     </tbody>
  14. </table>
  1. <div unordered-list="products" template="table" class="table table-striped">
  2.     This is where the list will go
  3. </div>
  1. .directive('unorderedList', function () {
  2.     return {
  3.         link: function (scope, element, attrs) {
  4.             scope.data = scope[attrs['unorderedList']];
  5.         },
  6.         restrict: 'A',
  7.         templateUrl: function (elem, attrs) {
  8.             return attrs['template'] == "table" ? "tableTemplate.html" : "itemTemplate.html";
  9.         }
  10.     };
  11. });

        table-striped样式并没有起作用,设置replace属性为true后的效果是模版内容将替换掉指令所应用到的div元素。

管理指令的作用域

为每个指令实例创建自己的作用域

        设置scope属性为true将允许我们在同一个控制器里复用这个指令,可以避免指令共享数据值。

  1. <div class="panel panel-default">
  2.    <div  class="panel-body" scope-demo></div>
  3.     <div  class="panel-body" scope-demo></div>
  4. </div>
  1. var myApp = angular.module('myApp', [])
  2. .controller('myCtrl', ["$scope", function ($scope) {
  3.     $scope.data = {name:"Staven"};
  4.     $scope.city = "China"
  5. }])
  6. .directive('scopeDemo', function () {
  7.     return {
  8.        template: function () {
  9.            return angular.element(document.querySelector("#scopeTemplate")).html();
  10.        },
  11.         scope:true
  12.     };
  13. });

        data.name这个属性是在一个对象上定义的,意味着这个值将会在指令的哥哥实例之间所共享,而且所有相应的视图会同步更新。

        city是直接在控制器的作用于上被直接赋值的,意味着这个值只在此指令的作用域上有效。

创建隔离的作用域

        对于在一个对象上定义的属性,可能会被其他人改变。解决方法就是创建一个隔离的作用域,就是Angularjs为指令的每个实例创建一个独立的作用域的地方,但是这个作用域并不继承自控制器的作用域。当scope定义属性被设置为一个对象时,可创建一个隔离的作用域。隔离的作用域的最基本类型是用一个没有属性的对象表示。

  1. .directive('scopeDemo', function () {
  2.     return {
  3.        template: function () {
  4.            return angular.element(document.querySelector("#scopeTemplate")).html();
  5.        },
  6.         scope:{}
  7.     };
  8. });

        当创建在不同情况下复用的指令时,隔离的作用域是一种重要的构件时。因为它防止了在控制器作用域和指令之间出现了意料外的交互。但是完全隔绝一个指令会使得难以输入和输出数据。

        隔绝的作用域允许使用应用于指令旁边的元素上的属性将数据值绑定到控制器作用域上。

单向绑定@:

        向以@为前缀的作用域对象上增添一个属性,以在一个隔离的作用力创建一个单向绑定。

  1. <body ng-app="myApp" ng-controller="myCtrl">
  2.     <div class="panel panel-default">
  3.        <div class="panel-body">
  4.            Direct Binding:<input ng-model="data.name" />
  5.        </div>
  6.         <div class="panel-body" scope-demo nameprop="{{data.name}}"></div>
  7.     </div>
  8. </body>
  9. <script type="text/ng-template" id="scopeTemplate">
  10.     <div class="panel-body">
  11.         <p>Data Value:{{local}}</p>
  12.     </div>
  13. </script>
  14. <script>
  15. var myApp = angular.module('myApp', [])
  16. .controller('myCtrl', ["$scope", function ($scope) {
  17.     $scope.data = {name:"staven"};
  18. }])
  19. .directive('scopeDemo', function () {
  20.     return {
  21.        template: function () {
  22.            return angular.element(document.querySelector("#scopeTemplate")).html();
  23.        },
  24.         scope:{
  25.            local:"@nameprop"
  26.         }
  27.     };
  28. });
  29. </script> 

        local属性的值以@为前缀,制定了属性local的值应该从一个来自名为nameprop的特性的单向绑定来获得。

        使用一个隔离的作用域使得指令不会继承控制器作用域中的数据。

双向绑定=:

        向以=为前缀的作用域对象上增添一个属性,以在一个隔离的作用域里创建一个双向绑定。

        在隔离作用于上的单向绑定总是被计算作字符串值,如果想访问一个数组,就必须使用双向绑定。

  1. <div class="panel panel-default">
  2.    <div class="panel-body">
  3.        Direct Binding:<input ng-model="data.name" />
  4.    </div>
  5.     <div class="panel-body" scope-demo nameprop="data.name"></div>
  6. </div>
  1. <script type="text/ng-template" id="scopeTemplate">
  2.     <div class="panel-body">
  3.         <p>Data Value:<input ng-model="local" /></p>
  4.     </div>
  5. </script>
  6. <script>
  7.     scope:{
  8.        local:"=nameprop"
  9.     }
  10. </script>

        使用单向绑定时,提供了一个被"{{"和"}}"字符所包围的绑定表达式,但是angularjs需要知道在双向绑定中哪个属性需要被更新,所以不需要被"{{"和"}}"包围。

计算表达式&:

        向以&为前缀的作用域对象上增添一个属性,在父作用域的上下文计算一个表达式。

  1. <body ng-app="myApp" ng-controller="myCtrl">
  2. <div class="panel panel-default">
  3.    <div class="panel-body">
  4.        Direct Binding:<input ng-model="data.name" />
  5.    </div>
  6.     <div class="panel-body" scope-demo city="getCity(data.name)" nameprop="data.name"></div>
  7. </div>
  8. </body>
  9. <script type="text/ng-template" id="scopeTemplate">
  10.     <div class="panel-body">
  11.         <p>Name:{{local}}, City:{{cityFn()}}</p>
  12.     </div>
  13. </script>
  14. <script>
  15. var myApp = angular.module('myApp', [])
  16. .controller('myCtrl', ["$scope", function ($scope) {
  17.     $scope.data = {name:"staven",defaultCity:"hefei"};
  18.     $scope.getCity = function (name) {
  19.         console.log(1);
  20.         return name == 'staven' ? $scope.data.defaultCity : "Unknown";
  21.     }
  22. }])
  23. .directive('scopeDemo', function () {
  24.     return {
  25.        template: function () {
  26.            return angular.element(document.querySelector("#scopeTemplate")).html();
  27.        },
  28. scope:{
  29.     local:"=nameprop",
  30.     cityFn:"&city"
  31. }
  32.     };
  33. });
  34. </script>

        调用cityFn()时,使用了圆括号,要计算被这个特性所指定的表达式,这是必需的,即使当表达式本身就是一个函数调用时。

使用隔离作用域的数据来计算一个表达式

        可以将来自代计算的隔离作用域的数据为控制器作用域表达式的一部分。

  1. <div class="panel-body" scope-demo city="getCity(nameVal)" nameprop="data.name"></div>
  1. <script type="text/ng-template" id="scopeTemplate">
  2.     <div class="panel-body">
  3.         <p>Name:{{local}}, City:{{cityFn({nameVal: local})}}</p>
  4.     </div>
  5. </script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值