创建指令时,可以将代码放入编译器,链接函数或控制器中。
在文档中,他们解释说:
- 编译和链接功能用于角度循环的不同阶段
- 指令之间共享控制器
但是,对我来说,不清楚哪种代码应该放在哪里。
例如:我可以在编译中创建函数并将它们附加到链接的作用域中,还是仅将函数附加到控制器的作用域中?
如果每个指令可以有自己的控制器,则如何在指令之间共享控制器?控制器是真正共享的还是仅仅是作用域属性?
创建指令时,可以将代码放入编译器,链接函数或控制器中。
在文档中,他们解释说:
但是,对我来说,不清楚哪种代码应该放在哪里。
例如:我可以在编译中创建函数并将它们附加到链接的作用域中,还是仅将函数附加到控制器的作用域中?
如果每个指令可以有自己的控制器,则如何在指令之间共享控制器?控制器是真正共享的还是仅仅是作用域属性?
Answers:
编译:
这是Angular实际编译指令的阶段。对于给定指令的每个引用,仅一次调用此编译函数。例如,假设您正在使用ng-repeat指令。ng-repeat将必须查找其附加到的元素,提取其附加到的html片段,并创建一个模板函数。
如果您使用过HandleBars,下划线模板或等效模板,则就像编译其模板以提取出模板函数一样。向此模板函数传递数据,该函数的返回值是html,数据放在正确的位置。
编译阶段是Angular中返回模板功能的那一步。这种以角度表示的模板函数称为链接函数。
链接阶段:
链接阶段是将数据($ scope)附加到链接函数的阶段,它应该返回链接的html。由于该指令还指定了该html的位置或更改的位置,因此可以很好地使用它。这是您要更改链接的html的功能,即已附加数据的html。如果您在链接功能中编写代码,则为角度形式,通常是后链接功能(默认情况下)。这是一种在链接功能将数据与模板链接之后被调用的回调。
控制器:
控制器是放置特定指令逻辑的地方。该逻辑也可以进入链接功能,但是您必须将该逻辑放在作用域上才能使其“可共享”。这样做的问题是,您随后将使用指令内容破坏范围,这实际上并不是预期的。那么,如果两个指令要互相交谈/彼此合作,该怎么办?当然,您可以将所有逻辑放入服务中,然后使这两个指令都依赖于该服务,但这只会带来一个依赖性。另一种方法是为此范围提供一个Controller(通常是隔离范围?),然后当该控制器“需要”另一个指令时,将该控制器注入另一个指令。
controller
功能执行后编译,但之前 pre-link
在当地的DOM树的分支。并且controller
,pre-link
以自上而下的方式遍历本地DOM分支并执行功能。之后,post-link
以自下而上的方式执行。
controller
而不是link
到处使用吗?这样,如果该方法需要共享或需要引入一些逻辑,那么以后就不需要更改代码了。一直使用controller
链接而不是链接有什么陷阱吗?
我还想补充一下Google团队写的O'Reily AngularJS书中所说的话:
控制器-创建一个控制器,该控制器发布用于跨指令通信的API。一个很好的例子是指令通信指令
链接-以编程方式修改生成的DOM元素实例,添加事件侦听器并设置数据绑定。
编译-像在ng-repeat中使用时一样,以编程方式修改跨指令副本的功能的DOM模板。您的编译函数还可以返回链接函数,以修改生成的元素实例。
A directive
允许您以声明的方式扩展HTML词汇表以构建Web组件。该ng-app
属性是一个指令,ng-controller
所有也是ng- prefixed attributes
。指令可以attributes
,tags
甚至class
names
,comments
。
指令的诞生方式(compilation
和instantiation
)
编译:我们将在DOM呈现之前将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
函数返回pre
和post
链接函数。在pre link函数中,我们具有实例模板以及的作用域controller
,但是该模板未绑定到作用域,并且仍然没有包含的内容。
Post
链接功能是发布链接是最后执行的功能。现在,transclusion
完成了the template is linked to a scope
,并且view 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
}
}
});
另外,使用控制器vs.链接功能的一个很好的理由(因为它们都可以访问作用域,元素和属性)是因为您可以将任何可用的服务或依赖项(按任何顺序)传递给控制器,而您无法使用链接功能做到这一点。请注意不同的签名:
controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...
与
link: function(scope, element, attrs) {... //no services allowed
module.directive('myDirective', function($window) { etc...
。然后可以从链接功能内部进行访问。
这是了解指令阶段的好示例 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>
link
,compile
以及controller
?
require
d指令注入到从属指令的控制器中吗?