534

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

在文档中,他们解释说:

  • compile 和 link 函数用于角循环的不同阶段
  • 控制器在指令之间共享

但是,对我来说,不清楚哪种代码应该放在哪里。

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

如果每个指令都可以有自己的控制器,那么控制器如何在指令之间共享?控制器真的是共享的还是只是范围属性?

4

6 回答 6

474

编译:

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

如果您使用过 HandleBars、下划线模板或类似的模板,就像编译它们的模板以提取模板函数一样。向此模板函数传递数据,该函数的返回值是包含正确位置数据的 html。

编译阶段是 Angular 中返回模板函数的那一步。这个 Angular 中的模板函数称为链接函数。

链接阶段:

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

控制器 :

控制器是您放置一些指令特定逻辑的地方。该逻辑也可以进入链接功能,但是您必须将该逻辑放在范围内以使其“可共享”。这样做的问题是,你会用你的指令破坏范围,这并不是真正的预期。那么,如果两个指令想要相互交谈/相互合作,还有什么选择呢?当然,您可以将所有这些逻辑放入服务中,然后使这两个指令都依赖于该服务,但这只会带来更多的依赖。另一种方法是为此范围提供一个控制器(通常是隔离范围?),然后当该指令“需要”另一个指令时,将此控制器注入到另一个指令中。

于 2013-03-28T11:58:06.113 回答
100

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

控制器 - 创建一个控制器,该控制器发布用于跨指令通信的 API。一个很好的例子是Directive to Directive Communication

链接 - 以编程方式修改生成的 DOM 元素实例、添加事件侦听器并设置数据绑定。

编译 - 以编程方式修改 DOM 模板以跨指令副本的功能,就像在 ng-repeat 中使用时一样。您的编译函数还可以返回链接函数来修改生成的元素实例。

于 2014-06-04T19:59:44.587 回答
53

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

指令是如何产生的(compilationinstantiation

编译:我们将在渲染之前将compile函数用于DOM 并返回一个函数(它将为我们处理链接)。这也是放置需要与所有该指令共享的任何方法的地方。manipulatelinkinstances

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

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

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

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

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

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

     }
   };
});

Compile函数返回prepost链接函数。在预链接函数中,我们有实例模板以及来自 的范围controller,但是模板没有绑定到范围并且仍然没有嵌入的内容。

Post链接功能是发布链接是最后执行的功能。现在transclusion已完成,the template is linked to a scopeview will update with data bound values after the next digest cycle。该link选项只是设置post-link功能的快捷方式。

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

您必须指定所需指令的名称——它应该绑定到相同的元素或其父元素。该名称可以带有前缀:

? – 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′]需要多个指令控制器。

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: '<h1>I am child</h1>',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});
于 2015-09-29T14:07:00.370 回答
14

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

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

对比

link: function(scope, element, attrs) {... //no services allowed
于 2013-11-07T15:47:07.190 回答
10

这是理解指令阶段的一个很好的示例 http://codepen.io/anon/pen/oXMdBQ?editors=101

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

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>
于 2015-07-18T15:28:54.297 回答
8
  • compile:当我们需要修改指令模板时使用,例如添加新表达式,在该指令中附加另一个指令
  • 控制器:当我们需要共享/重用 $scope 数据时使用
  • link:它是我们需要附加事件处理程序或操作 DOM 时使用的函数。
于 2017-06-22T14:50:35.140 回答