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

在文件中,他们解释说:

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

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

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

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


当前回答

这是理解指令阶段的一个很好的示例 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>

其他回答

这是理解指令阶段的一个很好的示例 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>

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

控制器——创建一个控制器,它发布一个API用于跨指令通信。指令对指令通信就是一个很好的例子 Link -以编程方式修改生成的DOM元素实例,添加事件侦听器,并设置数据绑定。 Compile -通过编程方式修改DOM模板,以获得跨指令副本的特性,就像在ng-repeat中使用的那样。编译函数还可以返回链接函数来修改生成的元素实例。

另外,使用控制器函数和链接函数(因为它们都可以访问作用域、元素和attrs)的一个很好的理由是,您可以将任何可用的服务或依赖项传递到控制器中(并且以任何顺序),而使用链接函数则不能这样做。注意不同的特征:

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

vs.

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

指令允许您以声明式的方式扩展HTML词汇表,以构建web组件。ng-app属性是一个指令,ng-controller和所有ng前缀的属性也是一个指令。指令可以是属性、标签,甚至是类名、注释。

指令如何生成(编译和实例化)

Compile:我们将使用Compile函数在DOM呈现之前操作它,并返回一个链接函数(该函数将为我们处理链接)。这也是放置任何需要与该指令的所有实例共享的方法的地方。

link:我们将使用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){

     }
   };
});

编译函数返回前后链接函数。在pre - 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
    }
  }
});

编译:

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

如果你使用了HandleBars,下划线模板或类似的东西,这就像编译他们的模板来提取模板函数。向这个模板函数传递数据,该函数的返回值是数据在正确位置的html。

编译阶段是Angular中返回模板函数的步骤。这个模板函数在angular中被称为链接函数。

连接阶段:

The linking phase is where you attach the data ( $scope ) to the linking function and it should return you the linked html. Since the directive also specifies where this html goes or what it changes, it is already good to go. This is the function where you want to make changes to the linked html, i.e the html that already has the data attached to it. In angular if you write code in the linking function its generally the post-link function (by default). It is kind of a callback that gets called after the linking function has linked the data with the template.

控制器:

The controller is a place where you put in some directive specific logic. This logic can go into the linking function as well, but then you would have to put that logic on the scope to make it "shareable". The problem with that is that you would then be corrupting the scope with your directives stuff which is not really something that is expected. So what is the alternative if two Directives want to talk to each other / co-operate with each other? Ofcourse you could put all that logic into a service and then make both these directives depend on that service but that just brings in one more dependency. The alternative is to provide a Controller for this scope ( usually isolate scope ? ) and then this controller is injected into another directive when that directive "requires" the other one. See tabs and panes on the first page of angularjs.org for an example.