链接vs编译vs控制器
在创build指令时,可以将代码放入编译器,链接函数或控制器中。
在文档中,他们解释说:
- 编译和链接function用于angular度循环的不同阶段
- 控制器在指令之间共享
不过,对于我来说还不清楚,哪种代码应该到哪里去。
例如:我可以在编译过程中创build函数,并将它们连接到作用域中,或者只将函数附加到控制器的作用域中?
控制器如何在指令之间共享控制器,如果每个指令都可以拥有自己的控制器? 控制器是真的共享还是只是范围属性?
编译:
这是Angular实际编译你的指令的阶段。 这个编译函数只对给定指令的每个引用调用一次。 例如,假设你正在使用ng-repeat指令。 ng-repeat将不得不查找它所连接的元素,提取它所连接的html片段并创build一个模板函数。
如果您已经使用了HandleBars,下划线模板或等价物,就像编译它们的模板来提取模板函数一样。 对于这个模板函数,你传递数据,并且该函数的返回值是正确位置的数据。
编译阶段是Angular中的那一步,它返回模板函数。 这个angular度模板函数被称为链接函数。
链接阶段:
链接阶段是将数据($ scope)附加到链接函数的地方,它应该返回链接的html。 由于该指令还指定了这个html到达的地方或者它的变化,这已经很不错了。 这是你想更改链接的HTML,即已经附加了数据的HTML的function。 在angular度上,如果你在链接函数中编写代码,它通常是后链接函数(默认情况下)。 在链接函数将数据链接到模板之后,这是一种callback。
控制器:
控制器是您放置一些指令特定逻辑的地方。 这个逻辑也可以进入链接function,但是你必须把这个逻辑放在范围内才能使它“共享”。 这个问题是你会用你的指令来破坏范围,这不是真正意义上的东西。 那么,如果两个指令要互相交stream/合作,还有什么select呢? 当然,你可以把所有的逻辑放到一个服务中,然后使这两个指令依赖于那个服务,但是这只是引入了一个更多的依赖。 另一种方法是为这个范围提供一个Controller(通常是隔离范围?),然后当这个指令“需要”另一个指令时,这个控制器被注入到另一个指令中。 例如,查看angularjs.org第一页的选项卡和窗格。
我还想补充一下Google团队的O'Reily AngularJS的书:
控制器 – 创build一个控制器,发布一个用于通过指令进行通信的API。 “ 指令通信指令”就是一个很好的例子
链接 – 以编程方式修改生成的DOM元素实例,添加事件监听器并设置数据绑定。
编译 – 以编程方式修改指令副本中的functionDOM模板,就像在ng-repeat中使用一样。 您的编译函数也可以返回链接函数来修改生成的元素实例。
directive
允许您以声明方式扩展HTML词汇表以构buildWeb组件。 ng-app
属性是一个指令, ng-controller
也是所有ng-controller
ng- prefixed attributes
。 指令可以是attributes
, tags
甚至class
names
, comments
。
指令如何诞生( compilation
和instantiation
)
编译:我们将使用compile
函数来manipulate
DOM,然后返回一个link
函数(这将处理我们的链接)。 这也是放置任何需要与这个指令的所有instances
共享的方法的地方。
链接:我们将使用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
函数返回post
链接函数。 在前链接函数中,我们有实例模板,也是controller
的作用域,但是模板没有被绑定到范围,仍然没有被转移的内容。
Post
链接function是后链接是执行的最后一个function。 现在,转换已完成, the template is linked to a scope
, view will update with data bound values after the next digest cycle
。 link
选项只是设置post-link
function的快捷方式。
控制器:指令控制器可以被传递到另一个指令链接/编译阶段。 它可以被注入到其他直接指令中,作为指导间通信的一种手段。
您必须指定所需的指令名称 – 它应该绑定到相同的元素或其父级。 该名称可以加上前缀:
? – 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 } } });
另外,使用控制器与链接函数(因为它们都可以访问范围,元素和attrs)是一个很好的理由,因为您可以将任何可用的服务或依赖项传递给控制器(以任何顺序),而你不能用链接function来做到这一点。 注意不同的签名:
controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...
与
link: function(scope, element, attrs) {... //no services allowed
这是了解指导阶段的好例子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>
- 编译 :在我们需要修改指令模板时使用,比如添加新的expression式,在这个指令中附加另一个指令
- 控制器 :当我们需要共享/重用$范围数据时使用
- 链接 :这是一个函数,当我们需要附加事件处理程序或操作DOM时使用。