Fork me on GitHub

angular之directive详解一

前言

      工作中使用angular1.x已经有很长一段时间了,但是有些angular上重要的难点,自己觉得是时候详细总结一下,一是对自己的总结,二是看自己那些还不熟悉。angular1.x中一大难点部分就是自定义指令,接下来我尽可能详细的对angular中的directive做总结。

下面内容都是自己一点点写上去的,如果有什么问题,请及时指正,若要转载请备注作者,谢谢配合。


如何定义一个自定义指令

1
2
3
4
5
6
7
8
angular.module('app', [])
// 参数1: 指令名字(驼峰命名法) {String}
// 参数2: 指令的回调函数 {Function}, 这个函数一般返回的是一个对象, 也可以返回一个函数
.directive('myDirective', function(){
return {
// 这里书写参数配置项
}
})

directive中第二个参数中返回对象的配置项

大致有如下参数项:

restrict

  • 作用:在DOM视图中的应用形式
  • 取值: EACM,不是必填项
  • js

    1
    2
    3
    4
    5
    6
    angular.module('app', [])
    .directive('myDirective', function(){
    return {
    restrict: 'EACM'
    }
    })
  • html

    1
    2
    3
    4
    5
    6
    7
    8
    <!-- E:(元素) -->
    <my-directive></my-directive>
    <!-- A:(属性 默认值) -->
    <div my-directive></div>
    <!-- C:(类名) -->
    <div class="my-directive"></div>
    <!-- M:(注释) -->
    <--directive:my-directive expression-->
  • demo
    http://zjrzpp.gitee.io/directivecase/#!/restrict

priority

terminal

  • 作用:告诉angularJS是否停止运行当前元素上比本指令优先级更低的指令,但与当前指令优先级同级的指令或者更高的指令还是会被执行的
  • 取值:Boolean值
  • js

    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
    angular.module('app', [])
    .directive('myDirective1', function(){
    return {
    restrict: 'A',
    priority: 1,
    link: function(scope) {
    console.log('myDirective11111')
    }
    }
    })
    .directive('myDirective2', function(){
    return {
    restrict: 'A',
    priority:2,
    terminal: true,
    link: function(scope, el) {
    console.log('myDirective222222')
    }
    }
    })
    .directive('myDirective3', function(){
    return {
    restrict: 'A',
    priority:5,
    link: function(scope, el) {
    console.log('myDirective33333')
    }
    }
    })
  • html

    1
    2
    3
    <div my-directive1 my-directive2 my-directive3>
    angularJS!!!
    </div>
  • result

    • 1.当terminal = true时,控制台会打印
      1
      2
      myDirective222222
      myDirective33333

    也就是说优先级比它低的没有执行,阻止了

    • 2.当terminal = false时,控制台会打印
      1
      2
      3
      myDirective11111
      myDirective222222
      myDirective33333

    也就是说执行顺序是由低到高myDirective1 -> myDirective2 -> myDirective3

  • demo
    http://zjrzpp.gitee.io/directivecase/#!/terminal

    template

  • 作用:展示在页面上的模板字符串
  • 取值:String或者 Funtion
  • 注意: template返回的模板中,DOM结构中必须存在一个根节点
  • js

    1
    2
    3
    4
    5
    6
    7
    angular.module('app', [])
    .directive('myDirective1', function(){
    return {
    restrict: 'EA',
    template: '<p style="color:red;">hello</p>'
    }
    })
  • demo
    http://zjrzpp.gitee.io/directivecase/#!/template

templateUrl

  • 作用:通过url地址把模板展示在页面上
  • 取值:String(文件路径)或者Funtion
  • js

    • 下面模板地址是在本地写的模板,一般项目中的模板都是存在后台,异步获取,这就意味着会编译或者链接,所以会用到angular中的缓存模板$templateCache
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <script type="text/javascript">
      angular.module('app', [])
      .directive('myDirective1', function(){
      return {
      restrict: 'EA',
      templateUrl: 'template.html'
      }
      })
      </script>
      <script type="text/ng-template" id="template.html">
      <p>This is the content of the template</p>
      </script>
  • demo
    http://zjrzpp.gitee.io/directivecase/#!/templateUrl

    replace

  • 作用:false: 模板的内容将会被插入到视图中应用指令元素的内部; true: 则表示替代,即插入到视图中时,应用指令的html元素将被删除,取而代之的是html模板。
  • 取值:Boolean
  • js

    • replace: true

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <script type="text/javascript">
      angular.module('app', [])
      .directive('myDirective1', function(){
      return {
      restrict: 'EA',
      replace: true,
      templateUrl: 'template.html',

      }
      })
      </script>
      <script type="text/ng-template" id="template.html">
      <p>This is the content of the template</p>
      </script>

      result: replace1

    • replace: false
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <script type="text/javascript">
      angular.module('app', [])
      .directive('myDirective1', function(){
      return {
      restrict: 'EA',
      replace: false,
      templateUrl: 'template.html',

      }
      })
      </script>
      <script type="text/ng-template" id="template.html">
      <p>This is the content of the template</p>
      </script>

    result: replace2

  • demo
    http://zjrzpp.gitee.io/directivecase/#!/replace

scope

  • 作用:

    • Boolean:默认是false,即该指令并不会创建新的作用域,改指令内部或外部的作用域是一样的; true: 会继承父作用域并创建一个新的作用域对象

      • true

        • js

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          <script type="text/javascript">
          angular.module('app', [])
          .controller('mainCtrl', ['$scope', function($scope){
          $scope.mainData = '我是main里内容'

          }])
          .directive('myDirective1', function(){
          return {
          restrict: 'EA',
          scope: true,
          templateUrl: 'submain.html',
          controller: function($scope) {
          $scope.submain = '我是指令自己的内容'

          }
          }
          })
          </script>
          <script type="text/ng-template" id="submain.html">
          <p>我能拿到父级的数据:{{mainData}}</p>
          <p>我自己的数据: {{submain}}</p>
          </script>
        • html

          1
          2
          3
          4
          5
          6
          <div ng-controller="mainCtrl">
          父级自己的内容:{{mainData}}
          <my-directive1></my-directive1>
          </br>
          我是父级我可以访问指令里面的内容吗:{{submain}}
          </div>
        • result
          true

        • demo
          http://zjrzpp.gitee.io/directivecase/#!/scope1
      • false

        • js

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          <script type="text/javascript">
          angular.module('app', [])
          .controller('mainCtrl', ['$scope', function($scope){
          $scope.mainData = '我是main里内容'

          }])
          .directive('myDirective1', function(){
          return {
          restrict: 'EA',
          scope: false,
          templateUrl: 'submain.html',
          controller: function($scope) {
          $scope.submain = '我是指令自己的内容'

          }
          }
          })
          </script>
          <script type="text/ng-template" id="submain.html">
          <p>我能拿到父级的数据:{{mainData}}</p>
          <p>我自己的数据: {{submain}}</p>
          </script>
        • html

          1
          2
          3
          4
          5
          6
          <div ng-controller="mainCtrl">
          父级自己的内容:{{mainData}}
          <my-directive1></my-directive1>
          </br>
          我是父级我可以访问指令里面的内容吗:{{submain}}
          </div>
        • result
          false

    • Object:隔离作用域,也就是隔离模板与外界作用域,但是也是可以访问外面的值,取值如下:

      • @ 本地作用域属性
      • = 双向绑定
      • & 父级作用域绑定
  • 第一种使用方式

    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
    <script type="text/javascript">
    angular.module('app', [])
    .controller('mainCtrl', ['$scope', function($scope){
    $scope.mainData = 'parent'
    $scope.mainModel = 'aa'
    $scope.getMsg = function() {
    console.log('方法执行了')
    }

    }])
    .directive('myDirective1', function(){
    return {
    restrict: 'EA',
    scope: {
    myChild: '@', // 储存与myChild相关联的字符串
    myModel: '=', // 将myModel指定对象或者变量绑定
    myFun: '&' // 将外部方法传递给这个方法
    },
    templateUrl: 'submain.html',
    controller: function($scope) {

    }
    }
    })
    </script>
    <script type="text/ng-template" id="submain.html">
    <p>通过隔离作用域拿到父级变量值:{{myChild}}</p>
    <input type="text" ng-model="myModel">
    <button class="btn" type="button" ng-click="myFun()">提交</button>
    </script>
    1
    2
    3
    4
    5
    <div ng-controller="mainCtrl" class="main">
    <input type="text" ng-model="mainModel">
    <hr>
    <my-directive1 my-child="{{mainData}}" my-model="mainModel" my-fun="getMsg()"></my-directive1>
    </div>

result: obejct
注意:定义传参时采用的是驼峰命名法

  • 第二种采用别名方式
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
34
<script type="text/javascript">
angular.module('app', [])
.controller('mainCtrl', ['$scope', function($scope){
$scope.mainData = 'parent'
$scope.mainModel = 'aa'
$scope.getMsg = function() {
console.log('方法执行了')
}

}])
.directive('myDirective1', function(){
return {
restrict: 'EA',
scope: {
// myChild: '@', // 储存与myChild相关联的字符串
// myModel: '=', // 将myModel指定对象或者变量绑定
// myFun: '&' // 将外部方法传递给这个方法
a: '@myChild',
b: '=myModel',
c: '&myFun'
},
templateUrl: 'submain.html',
controller: function($scope) {


}
}
})
</script>
<script type="text/ng-template" id="submain.html">
<p>通过隔离作用域拿到父级变量值:{{a}}</p>
<input type="text" ng-model="b">
<button class="btn" type="button" ng-click="c()">提交</button>
</script>
1
2
3
4
5
<div ng-controller="mainCtrl" class="main">
<input type="text" ng-model="mainModel">
<hr>
<my-directive1 my-child="{{mainData}}" my-model="mainModel" my-fun="getMsg()"></my-directive1>
</div>

transclude

  • 作用:你要不要把你指令内部的元素(不是指令的模板)嵌入到你的模板中去,
  • 取值:Boolean值,默认是false; true或者Object: 它会将整个DOM嵌入到指令内部定义的模板中,包括DOM中的其他指令,经常和ng-transclude配合使用。
  • transclude: true

    • js

      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
      <script type="text/javascript">
      angular.module('app', [])
      .controller('demoCtrl', ['$scope', function($scope){
      $scope.datas = ['apple', 'orange', 'banana'];

      }])
      .directive('sidebox', function(){
      return {
      restrict: 'EA',
      scope: {
      title: '@',
      },
      transclude: true,
      templateUrl: 'template.html',

      }
      })
      </script>
      <script type="text/ng-template" id="template.html">
      <div class="sidebox">
      <div class="content">
      <h2 class="header">{{title}}</h2>
      <span class="content" ng-transclude></span>
      </div>
      </div>
      </script>
    • html

      1
      2
      3
      4
      5
      <div title="fruit" sidebox>
      <ul>
      <li ng-repeat="item in datas">{{item}}</li>
      </ul>
      </div>
    • 图解
      transclude:true

    • demo
      http://zjrzpp.gitee.io/directivecase/#!/transclude1
  • transclude: Object
    • js
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
34
35
36
37
38
39
40
<script type="text/javascript">
angular.module('app', [])
.controller('demoCtrl', ['$scope', function($scope){
}])
.directive('mainBox', function(){
return {
restrict: 'EA',
scope: {
title: '@',
},
transclude: {
// content 之后是作为ng-transclude的值
// contentDirective:其他嵌入指令的名字
'content': 'contentDirective',
// ?代表这个嵌入点不一定有对应的指令存在
'menu': '?menuDirective'
},
templateUrl: 'template.html',
}
})
.directive('contentDirective', function() {
return {
restrict : 'EA',
template: '<div>我是内容指令的内容</div>'
}
})
.directive('menuDirective', function() {
return {
restrict : 'EA',
template: '<div>我是菜单指令的内容</div>'
}
})
</script>
<script type="text/ng-template" id="template.html">
<div class="main">
<h1>{{title}}</h1>
<div ng-transclude="content"></div>
<div ng-transclude="menu"></div>
</div>
</script>
-------------本文结束感谢您的阅读-------------