此博客不再维护,博客已迁移至 https://github.com/purplebamboo/blog/issues
文章目录
  1. 1. 什么是directive?
  2. 2. 系统自带的一些directive的介绍
    1. 2.0.1. ng-app
    2. 2.0.2. ng-model
    3. 2.0.3. ng-controller
    4. 2.0.4. ng-click,ng-blur,ng-mousedown等
    5. 2.0.5. ng-show
  • 3. 自己编写directive
    1. 3.1. 修改当前的dom节点
    2. 3.2. 模板类的directive
      1. 3.2.1. 1. restrict
      2. 3.2.2. 2.scope
      3. 3.2.3. 3.transclude
      4. 3.2.4. 4.require与controller
    3. 3.3. 总结

    这篇文章用来介绍angular里面directives的使用,大部分是参考的官方的教程。由于本人也是学习之中,难免有错误的地方。欢迎指正。

    什么是directive?

    官方是这么说的:directive是dom节点上的一种标签。angular的解析引擎匹配到这个标签后,会给当前的dom节点增加行为,或者改变dom节点和子节点。
    说白了就是用来在当前节点上干点特别的事的。

    系统自带的一些directive的介绍

    其实之前我们已经用过很多directive了。下面对一些主要的做一些介绍。

    ng-app

    这个算是最常用的directive了,这个directive的作用就是启动当前应用,让angular从它指向的节点开始一层层的遍历。然后做一系列的编译操作。后面可以跟上模块名。

    ng-model

    这个标签的作用是,修改当前control上的$scope对象的属性值。这个标签经常使用在input,select, textarea 这些dom节点上。比如 ngmodel="v" 就会将当前的dom节点(input,select, textarea)的值跟$scope的v属性值绑定,这样你重新输入一个值后,$scope的v属性也会自动变化。

    ng-controller

    这个标签很简单,就是用来指定当前dom使用哪个control函数的。这样当前dom下可以直接访问到control函数的$scope所有属性还有方法。

    ng-click,ng-blur,ng-mousedown等

    这些标签都是用来监听事件的。后面可以跟相应的事件处理函数。

    ng-show

    这类标签其实之前有介绍过,主要用来处理dom的显示和隐藏的。ng-show=”v”的机制是这样的。当$scope.v的值为非true的值时就会给当前的dom节点增加一个class => ng-hide 并且这个class被angular设成了。.ng-hide {display: none !important;},也就是说只有$scope.v为true类型的值时,这个dom才会显示出来。

    自己编写directive

    自己编写directive可以实现很多功能,主要通过当前模块的directive方法实现。大概有如下这些类型:

    下面一一介绍。

    修改当前的dom节点

    这类directive主要用来修改当前的dom的一些属性,或者显示隐藏这类的。

    下面看个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    <!doctype html>
    <html >
      <head>
        <meta charset="utf-8">
        <script src="angular.js"></script>
        <script type="text/javascript">
        var Dm = angular.module('testDirective',[]);
     
        Dm.controller('DmCtrl', function($scope) {
            
            $scope.money="123"
    
        });
    
        Dm.directive('moneyWrap', function() {
     
          function link(scope, element, attrs) {
            element.text(scope[attrs.cuName]+"¥")
          }
       
          return {
            link: link
          };
        });
        </script>
      </head>
      <body ng-app="testDirective">
        <div class="wrap" ng-controller="DmCtrl">
          <h2>用来测试directive的例子</h2>
          <span money-wrap cu-name="money"></span>
        </div>
      </body>
    </html>
    

    非常简单的例子,用于打印当前的金钱,末尾加个¥。

    首先directive方法用来在当前模块里生成一个标签。返回一个对象:

    1
    2
    3
    
    return {
            link: link
    };
    

    对象里面指定了link函数。这个link函数就是用来操作dom的主。

    我们看下link函数的参数:

    1. scope
      这个就是当前control的$scope对象,没啥好说的。
    2. element
      这个是当前dom节点经过“jquery”处理过后的对象。用过jquery的都知道这个概念。当然这边的jquery是angular自己实现的阉割版的jquery。方法少了许多,不过按angular的话说,够用了。
    3. attrs
      这个对象包含,当前的dom节点上的各种属性标签的值。不过要注意的是这边会将xxx-bbb这种形式的改写成xxxBbb的这种驼峰形式。

    看看我们的link函数吧:

    1
    2
    3
    
    function link(scope, element, attrs) {
        element.text(scope[attrs.cuName]+"¥")
    }
    

    简简单单的一句话就涵盖了三个参数哈。
    意思很简单,就是先通过attrs.cuName获取到属性名称money,之后拿到model的值,再通过text(jquery的方法)操作dom的值。
    这样一个简单的directive就实现了。

    directive也可以简写,直接返回一个link函数。
    这样上面的就可以简写为:

    1
    2
    3
    4
    5
    
    Dm.directive('moneyWrap', function() {
          return function (scope, element, attrs) {
            element.text(scope[attrs.cuName]+"¥")
          }
     });
    

    模板类的directive

    前面提到的都是通过link函数来操作当前dom本身的。directive还支持一种模板类的扩展形式。

    下面先看个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    <!doctype html>
    <html >
      <head>
        <meta charset="utf-8">
        <script src="angular.js"></script>
        <script type="text/javascript">
        var Dm = angular.module('testDirective',[]);
     
        Dm.controller('DmCtrl', function($scope) {      
            $scope.me = {
              money:"123"
            }
        });
    
        Dm.directive('moneyWrap', function() {
          return {
            template: '你值: {{me.money}}'
          };
        });
        </script>
      </head>
      <body ng-app="testDirective">
        <div class="wrap" ng-controller="DmCtrl">
          <h2>用来测试directive的例子</h2>
          <span money-wrap></span>
          
        </div>
      </body>
    </html>
    

    通过template属性。可以设置模板。

    不过这样只能设置字符串,显然不是最好的方式。我们可以用
    templateUrl: 'my.html'来加载script模板,或者其他文件。

    所以我们可以这么变:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    <!doctype html>
    <html >
      <head>
        <meta charset="utf-8">
        <script src="angular.js"></script>
        <script type="text/javascript">
        var Dm = angular.module('testDirective',[]);
     
        Dm.controller('DmCtrl', function($scope) {      
            $scope.me = {
              money:"123"
            }
        });
    
        Dm.directive('moneyWrap', function() {
          return {
            templateUrl: 'my.html'
          };
        });
        </script>
         <!-- my.html -->
      <script type="text/ng-template" id="my.html">
        你值: {{me.money}}</script>
      </head>
      <body ng-app="testDirective">
        <div class="wrap" ng-controller="DmCtrl">
          <h2>用来测试directive的例子</h2>
          <span money-wrap></span>
          
        </div>
      </body>
    </html>
    

    不过记得angular做了限制,这个必须在服务器里才能跑。不然angular会报跨域的错误。你可以用个nodejs,或者php开个服务测试。

    我们能做的其实有很多。下面介绍些高级的用法。

    我们知道directive会返回一个对象,这个对象其实支持很多配置值。下面介绍这些比较高端的类容:

    1. restrict

    restrict用来指定directive的形式,支持“A”,”E”,”AE”三种。A就是attribute,E是element。默认是A也就是我们的用法;
    <span money-wrap></span>。如果我们改成“E”就要这么用:<money-wrap></money-wrap>。“EA”就是两种都可以用,很简单吧。

    2.scope

    这个属性,有人一看直接就是一个子标签的scope对象吧。用来定义自己的scope属性。这话是不对的,这边的scope有个专门的名字,叫isolate scope。如果你没有定义这个scope的话,那么你的子模板,也就是使用templateUrl引用的html里面使用的scope会是外面的control的。但是你一旦定义了scope,那么对不起,外面的那个scope就不能用了,那种原型链式的属性访问也不存在了。
    下面看个官方的例子学习下:

    html如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    <div ng-app="docsIsolationExample">
      <div ng-controller="Ctrl">
        <my-customer info="naomi"></my-customer>
      </div>
      <!-- my-customer-plus-vojta.html -->
      <script type="text/ng-template" id="my-customer-plus-vojta.html">
        Name: {{customerInfo.name}} Address: {{customerInfo.address}}
        <hr>
        Name: {{vojta.name}} Address: {{vojta.address}}
      </script>
    </div>
    

    js如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    angular.module('docsIsolationExample', [])
      .controller('Ctrl', function($scope) {
        $scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
    
        $scope.vojta = { name: 'Vojta', address: '3456 Somewhere Else' };
      })
      .directive('myCustomer', function() {
        return {
          restrict: 'E',
          scope: {
            customerInfo: '=info'
          },
          templateUrl: 'my-customer-plus-vojta.html'
        };
      });
    

    还是很好理解的吧,只要注意这边这个

    1
    2
    3
    
    scope: {
            customerInfo: '=info'
    },
    

    这个意思是设置一个isolate scope这个isolate scope里面有个customerInfo属性,而这个属性的值等于info。info是哪里来的呢?你看下html里面的第三行;

    1
    
    <my-customer info="naomi"></my-customer>
    

    看见没有,引用directive的时候,有个属性info设置为了外面control的scope里面的naomi。这样angular就会把外面的Ctrl的$scope.naomi对象赋值到isolate scope的customerInfo属性上。注意这边是克隆了一份,所以你修改isolate scope里面的值是不会影响到外面的。

    isolate scope里面的属性名如果与directive上面的属性一样,可以只简写为=。也就是说可以这么写scope:scope: {info: '='}

    这边不止支持=,还支持@,&符号。@符号是用来赋值string类型的值的。而&符号可以用来执行表达式和方法。比如你定义

    1
    
    <my-customer info="naomi"  t="1111{{naomi.name}}" x="1+1"></my-customer>
    

    那你就得这么调用:

    1
    2
    3
    4
    5
    
    scope: {
            customerInfo: '=info',
            t: '@',
            x:'&'
     },
    

    这样t的值为‘1111Naomi’。x为‘2’。

    3.transclude

    transclude属性用来实现这样的事情,就是directive包含的类容会使用外面的scope对象,而不使用内部的。看下面这个例子:
    html:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    <div ng-app="docsTransclusionDirective">
      <div ng-controller="Ctrl">
        <my-dialog>Check out the contents, {{name}}!</my-dialog>
      </div>
      <!-- my-dialog.html -->
      <script type="text/ng-template" id="my-dialog.html">
        <div class="alert" ng-transclude>
        </div>
      </script>
    </div>
    

    js:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    angular.module('docsTransclusionDirective', [])
      .controller('Ctrl', function($scope) {
        $scope.name = 'Tobias';
      })
      .directive('myDialog', function() {
        return {
          restrict: 'E',
          scope:{},
          transclude: true,
          templateUrl: 'my-dialog.html'
        };
      });
    

    这边结果为Check out the contents, Tobias!

    由于定义了isolate scope,所以不能访问外面的control的scope,很麻烦。
    但是这边 使用了transclude: true。里面的类容<my-dialog>Check out the contents, {{name}}!</my-dialog>是可以使用外面的scope对象的。解析完成后。在my-dialog.html里面我们通过系统自带的ng-transclude标签将那边的内容直接全部引入过来。这个主要使用在dialog这样的场景里。

    4.require与controller

    这两个属性用于两个directive的之间的相互作用。

    直接看下面的例子吧:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    angular.module('docsTabsExample', [])
      .directive('myTabs', function() {
        return {
          restrict: 'E',
          scope: {},
          controller: function($scope) {
            this.addPane = function(pane) {
             
            };
          }
        };
      })
      .directive('myPane', function() {
        return {
          require: '^myTabs',
          restrict: 'E',
          scope: {},
          link: function(scope, element, attrs, tabsCtrl) {
            tabsCtrl.addPane(scope);
          }
        };
      });
    

    使用并不复杂。
    上面的myTabs定义了controller,这个其实就相当于在当前的directive节点上增加了 ng-controller标签一样。就是定义了一个control处理函数。
    下面的myPane通过require: ‘^myTabs’可以向上查找。^的意思是向父标签寻找。这边是找寻myTabs。找到myTabs后,当前directive的link函数就可以拿到require进来的directive里面定义的controller。这边就是tabsCtrl。通过它就可以调用myTabs里面的一系列方法。

    总结

    可以看到directives非常灵活,可以处理很多事情,但是不能烂用。实际上这边的模板各种引用,后面会介绍使用路由来实现这种模板的各种相互关系。这是后面的内容了。

    文章目录
    1. 1. 什么是directive?
    2. 2. 系统自带的一些directive的介绍
      1. 2.0.1. ng-app
      2. 2.0.2. ng-model
      3. 2.0.3. ng-controller
      4. 2.0.4. ng-click,ng-blur,ng-mousedown等
      5. 2.0.5. ng-show
  • 3. 自己编写directive
    1. 3.1. 修改当前的dom节点
    2. 3.2. 模板类的directive
      1. 3.2.1. 1. restrict
      2. 3.2.2. 2.scope
      3. 3.2.3. 3.transclude
      4. 3.2.4. 4.require与controller
    3. 3.3. 总结