写在前面

控制器和指令都有作用域

  1. angular.module('myApp', [])
  2. .controller('demo', function () {})
  3. .directive('demo1', function () {})
  4. .directive('demo2', function () {})

上面这样写是可以的,但是我们通常只会在一个module上挂载一个directive/component,因为指令也会创建一个新的作用域,方便复用以及代码管理。

  1. angular
  2. .module('directive', [])
  3. .directive('directive', directive);

作用域里有什么

  • 作用域提供了 ($watch) 方法监听数据模型的变化
  • 作用域提供了 ($apply) 方法把不是由Angular触发的数据模型的改变引入Angular的控制范围内(如控制器,服务,及Angular事件处理器等)
  • 以及scope上的数据

    简单的指令

    1. <body ng-controller="MainCtrl as vm">
    2. <echo></echo>
    3. </body>
    1. angular.module('myApp', [])
    2. .controller('MainCtrl', function () {
    3. })
    4. .directive('echo',function(){
    5. return{
    6. restrict:'E',
    7. replace:true,
    8. template:'<div>你好,我是听风是风。</div>'
    9. }
    10. });

    一个完整的directive是这样的:

    1. angular.module('myApp', [])
    2. .directive('directiveName', function () {
    3. return {
    4. restrict: String,
    5. priority: Number,
    6. terminal: Boolean,
    7. template: ' String or Template Function',
    8. templateUrl: String,
    9. replace: 'Boolean or String',
    10. scope: 'Boolean or Object',
    11. transclude: Boolean,
    12. controller: function (scope, element, attrs, transclude, otherInjectables) {},
    13. controllerAs: String,
    14. require: String,
    15. link: function (scope, iElement, iAttrs) {},
    16. compile: function (tElement, tAttrs, transclude) {
    17. return {
    18. pre: function (scope, iElement, iAttrs, controller) {},
    19. post: function (scope, iElement, iAttrs, controller) {}
    20. };
    21. //或 return function postLink() {}
    22. }
    23. };
    24. });

    属性详解

  • restrict表示指令在DOM中能以哪种形式被声明,是一个可选值,可选值范围有E(元素)A(属性)C(类名)M(注释)四个值,如果不使用此属性则默认值为EA。

  • priority值为数字,表示指令的优先级,若一个DOM上存在多个指令时,优先级高的指令先执行,注意此属性只在指令作为DOM属性时起作用。
  • terminal值为布尔值,用于决定优先级低于自己的指令是否还执行
  • template的值是一段HTML文本或一个函数,template函数接受两个参数,tElement和tAttrs,这里我们分别输出两个属性,可以看到tElement表示正在使用此指令的DOM元素,而tAttrs包含了使用此指令DOM元素上的所有属性。
  • templateUrl 模板路径。template 只支持一个跟元素。
  • replace值为布尔值,用于决定指令模板是否替换声明指令的DOM元素,默认为false。
  • require属性就是用来引用其它指令的controller,require的值可以是一个字符串或者一个数组,字符串就是其它指令名字,而数组就是包含多个指令名的数组,require 的几种前缀

    require

    如果没有前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器(或具有指定名字的指令)就抛出一个错误。

如果添加了^前缀,指令会在自身以及父级指令链中查找require参数所指定的指令的控制器,如果没找到报错。

同样是在当前指令中找,如果没找到会将null传给link函数的第四个参数。与不加前缀的区别是提供null从而不报错。

?与^的组合,从当前找,如果没找到去上层找,如果没找到就提供null。

^^ Angular 1.5.6版本之后新增,表示跳过自身直接从父级开始找,找不到报错。

scope

scope:flase 时,表示指令不创建额外的作用域,默认继承使用父级作用域,所以指令中能正常使用和修改父级中所有变量和方法。共用了一份数据,不管我们修改父或者子指令,这份数据都将同步改变并影响彼此,这就是继承不隔离。

scope:true 时表示指令创建自己的作用域,但仍然会继承父作用域,说直白点就是,指令自己有的用自己的,没有的找父级拿,同一份数据父级能影响指令,但指令却无法反向影响父级,这就是继承但隔离。

scope:{} 时,表示指令创建一个隔离作用域,此时指令作用域不再继承父作用域,两边的数据不再互通。

controller

我们常常在控制器操作数据通过scope作为桥梁以达到更新视图变化的目的,很明显指令拥有自己的scope,当然拥有自己的controller控制器也不是什么奇怪的事情。

controller的值可以是一个函数,或者一个字符串,如果是字符串指令会在应用中查找与字符串同名的构造函数作为自己的控制器函数。

controllerAs用于设置控制器的别名,我们都知道angularjs在1.2版本之后,对于数据绑定提供了额外一种方式,第一种是绑定在scope上,第二种是使用controller as vm类似的写法,绑定在this上。

controller的形参一共有$scope,$element,$attrs,$transclude四个
$scope:指令当前的作用域,所有在scope上绑定的属性方法,在指令中都可以随意使用.
$element:使用指令的当前元素.
$attr:使用指令当前元素上的属性.
$transclude:链接函数,用于克隆和操作DOM元素.

component

component就是阉割版的directive,用法上还是大同小异,directive怎么玩到了component还是一样,但从创建组件角度来说,component确实更简单更方便。

component父传子传递过来的数据不是绑定在scope上,而是组件的控制器上,可设置controllerAs。不过 directive有一个bindToController属性,作用就是将传递过来的值绑定在控制器上,我们修改代码,为directive添加此bindToController:true。

directive中require的值是一个字符串或者一个数组(注入多个时),并且注入的指令/组件控制器将成为link函数的第四个参数,注意是link函数不是controller。而component的require值一直是个对象,且挂载到 this 上。

component的controller中操作传递过来的数据component得使用钩子函数中才能获取到.