关于angularjs:链接vs编译与控制器

Link vs compile vs controller

创建指令时,可以将代码放入编译器、链接函数或控制器中。

在文件中,他们解释说:

  • 编译和链接函数用于角度的不同阶段周期
  • 控制器在指令之间共享

然而,对我来说,还不清楚哪种代码应该放在哪里。

例如:我可以在编译中创建函数,并将它们附加到链接中的作用域,还是只将函数附加到控制器中的作用域?

如果每个指令都可以有自己的控制器,那么如何在指令之间共享控制器?控制器是真正共享的还是仅仅是作用域属性?


编译:

这是角度实际编译指令的阶段。对于给定指令的每个引用,只调用一次此编译函数。例如,假设您正在使用ng repeat指令。ng repeat必须查找它附加到的元素,提取它附加到的HTML片段,并创建一个模板函数。

如果您使用了手柄、下划线模板或等效模板,则类似于编译模板以提取模板函数。对于这个模板函数,您传递数据,该函数的返回值是HTML,其中的数据位于正确的位置。

编译阶段是返回模板函数的角度步骤。这个角度模板函数叫做链接函数。

链接阶段:

链接阶段是将数据($scope)附加到链接函数的阶段,它应该返回链接的HTML。由于该指令还指定了该HTML的去向或更改内容,所以它已经很好了。此函数用于更改链接的HTML,即已附加数据的HTML。如果在链接函数中编写代码,则通常是后链接函数(默认情况下)。它是一种回调,在链接函数将数据与模板链接后调用。

控制器:

控制器是一个放置在特定于指令的逻辑中的地方。这个逻辑也可以进入链接函数,但随后您必须将这个逻辑放到作用域中,使其"可共享"。问题是,你会用你的指令破坏作用域,而这些东西并不是你所期望的。那么,如果两个指令想要相互交谈/相互合作,那么还有什么选择呢?当然,您可以将所有的逻辑放到一个服务中,然后使这两个指令都依赖于该服务,但这只会带来更多的依赖。另一种选择是为此作用域提供控制器(通常是隔离作用域?)然后,当该指令"需要"另一个指令时,该控制器被注入到另一个指令中。例如,请参见angularjs.org首页的选项卡和窗格。


我还想补充一下谷歌团队的O'Reily AngularJS书中所说的:

Controller - Create a controller which publishes an API for communicating across directives. A good example is Directive to Directive Communication

Link - Programmatically modify resulting DOM element instances, add event listeners, and set up data binding.

Compile - Programmatically modify the DOM template for features across copies of a directive, as when used in ng-repeat. Your compile function can also return link functions to modify the resulting element instances.


directive允许您以声明性方式扩展HTML词汇表,以构建Web组件。ng-app属性是一个指令,ng-controller和所有ng- prefixed attributes属性也是一个指令。指令可以是attributestags甚至是classnamescomments

指令是如何产生的(compilationinstantiation)

编译:在呈现之前,我们将把compile函数同时用于manipulateDOM,并返回link函数(这将为我们处理链接)。这也是放置需要与本指令的所有instances共享的任何方法的地方。

链接:我们将使用link函数在一个特定的dom元素(从模板克隆的)上注册所有侦听器,并设置到页面的绑定。

如果在compile()函数中设置,它们将只设置一次(这通常是您想要的)。如果在link()函数中设置,则每次HTML元素绑定到
对象中的数据时都会设置这些元素。

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
    <simple>
        Inner content
    </simple>


app.directive("simple", function(){
   return {
     restrict:"EA",
     transclude:true,
     template:"{{label}}",        
     compile: function(element, attributes){  
     return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});

compile函数返回prepost链接函数。在pre-link函数中,我们有实例模板和controller中的作用域,但是模板没有绑定到作用域,也没有转包内容。

postlink函数是最后一个要执行的函数。现在,transclusion完成了,the template is linked to a scopeview will update with data bound values after the next digest cycle完成了。link选项只是设置post-link功能的快捷方式。

控制器:可以将指令控制器传递到另一个指令链接/编译阶段。它可以作为一种用于指令间通信的手段注入其他方向。

您必须指定需要的指令的名称——它应该绑定到同一个元素或其父元素。名称的前缀可以是:

1
2
? – Will not raise any error if a mentioned directive does not exist.
^ – Will look for the directive on parent elements, if not available on the same element.

使用方括号[‘directive1′, ‘directive2′, ‘directive3′]要求多指令控制器。

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
var app = angular.module('app', []);

app.controller('MainCtrl', function($scope, $element) {
});

app.directive('parentDirective', function() {
  return {
    restrict: 'E',
    template: '<child-directive></child-directive>',
    controller: function($scope, $element){
      this.variable ="Hi Vinothbabu"
    }
  }
});

app.directive('childDirective', function() {
  return {
    restrict:  'E',
    template: 'I am child',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});


另外,使用控制器与链接函数(因为它们都可以访问范围、元素和属性)的一个很好的理由是,您可以将任何可用的服务或依赖项传递到控制器中(并且以任何顺序),而不能使用链接函数。注意不同的签名:

1
controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...

VS

1
link: function(scope, element, attrs) {... //no services allowed


这是了解指令阶段的一个很好的示例http://codepen.io/anon/pen/oxmdbq?编辑= 101

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
var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher's first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

HTML

1
2
3
4
5
6
<body ng-app="myapp">
   
       
       
   
</body>


  • 编译:当需要修改指令模板时使用,如添加新表达式,在此指令内附加另一个指令
  • 控制器:在需要共享/重用$scope数据时使用
  • 链接:它是一个函数,在需要附加事件处理程序或操作DOM时使用。