首页 文章

链接vs编译与控制器

提问于
浏览
516

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

在文档中,他们解释说:

  • 编译和链接功能用于角度循环的不同阶段

  • 控制器在指令之间共享

但是,对我而言,目前尚不清楚哪种代码应该去哪里 .

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

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

6 回答

  • 461

    Compile :

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

    如果您使用过HandleBars,下划线模板或等效模板,就像编译模板以提取模板函数一样 . 对于此模板函数,您传递数据,该函数的返回值是html,数据位于正确的位置 .

    编译阶段是Angular中返回模板函数的步骤 . 角度中的此模板函数称为链接函数 .

    Linking phase :

    链接阶段是将数据($ scope)附加到链接函数的位置,它应该返回链接的html . 由于该指令还指定了这个html的去向或更改的内容,因此它已经很好了 . 这是您要对链接的html进行更改的功能,即已经附加数据的html . 在角度中如果你在链接函数中编写代码,它通常是post-link函数(默认情况下) . 它是一种在链接函数将数据与模板链接后调用的回调 .

    Controller :

    控制器是您放置某些指令特定逻辑的地方 . 这个逻辑也可以进入链接函数,但是你必须将该逻辑放在范围内以使其“可共享” . 问题在于,您将使用指令来破坏范围,而这些东西实际上并不是预期的 . 那么,如果两个指令希望彼此交谈/相互合作,那么又有什么选择呢?当然,您可以将所有逻辑放入服务中,然后使这两个指令依赖于该服务,但这只会带来一个依赖性 . 另一种方法是为这个范围提供一个控制器(通常是隔离范围?),然后当该指令“需要”另一个指令时,该控制器被注入另一个指令 . 有关示例,请参见angularjs.org第一页上的选项卡和窗格 .

  • 9

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

    Controller - 创建一个控制器,该控制器发布用于跨指令进行通信的API . 一个很好的例子是Directive to Directive Communication Link - 以编程方式修改生成的DOM元素实例,添加事件监听器和设置数据绑定 . 编译 - 以编程方式修改指令副本中的功能的DOM模板,如在ng-repeat中使用时 . 您的编译函数也可以返回链接函数来修改结果元素实例 .

  • 10

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

    指令如何诞生( compilationinstantiation

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

    link: 我们将使用 link 函数注册特定DOM元素上的所有侦听器(从模板克隆)并设置我们对页面的绑定 .

    如果在 compile() 函数中设置,它们只会被设置一次(这通常是你想要的) . 如果在 link() 函数中设置,则每次HTML时都会设置它们element绑定到 `` 对象中的数据 .

    <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 link函数是post link是最后执行的函数 . 现在 transclusion 已完成, the template is linked to a scopeview will update with data bound values after the next digest cycle . link 选项只是设置 post-link 函数的快捷方式 .

    controller: 指令控制器可以传递给另一个指令链接/编译阶段 . 它可以作为在指令间通信中使用的手段注入其他指南 .

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

    ? – 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
        }
      }
    });
    
  • 48

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

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

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

    这是了解指令阶段的好例子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>
    
  • 2
    • compile :当我们需要修改指令模板时使用,比如添加新表达式,在此指令中附加另一个指令

    • controller :当我们需要共享/重用$ scope数据时使用

    • link :它是一个在我们需要附加事件处理程序或操作DOM时使用的函数 .

相关问题