链接 vs 编译 vs 控制器
Posted
技术标签:
【中文标题】链接 vs 编译 vs 控制器【英文标题】:Link vs compile vs controller 【发布时间】:2013-03-18 13:58:59 【问题描述】:当您创建指令时,您可以将代码放入编译器、链接函数或控制器中。
在文档中,他们解释说:
编译和链接函数用于angular的不同阶段 循环 控制器在指令之间共享但是,对我来说,不清楚哪种代码应该放在哪里。
例如:我可以在 compile 中创建函数并将它们附加到链接中的作用域,还是只将函数附加到控制器中的作用域?
如果每个指令都可以有自己的控制器,那么指令之间如何共享控制器?控制器真的是共享的还是只是范围属性?
【问题讨论】:
另见***.com/questions/12546945/… 或许更全面的指令函数概述:Angular directives - when to use compile, controller, pre-link and post-link. 我写了一篇带有指令生命周期图(创建阶段)的帖子。也许它可以帮助某人:filimanjaro.com/2014/… Difference between the 'controller', 'link' and 'compile' functions when defining a directive的可能重复 【参考方案1】: compile:当我们需要修改指令模板时使用,例如添加新表达式,在该指令中附加另一个指令 控制器:当我们需要共享/重用 $scope 数据时使用 link:它是我们需要附加事件处理程序或操作 DOM 时使用的函数。【讨论】:
【参考方案2】:我还想补充一下 Google 团队的 O'Reily AngularJS 书中所说的:
Controller - 创建一个控制器,该控制器发布用于跨指令通信的 API。一个很好的例子是Directive to Directive Communication
链接 - 以编程方式修改生成的 DOM 元素实例、添加事件侦听器并设置数据绑定。
编译 - 以编程方式跨指令副本修改 DOM 模板的功能,就像在 ng-repeat 中使用时一样。您的编译函数还可以返回链接函数来修改生成的元素实例。
【讨论】:
您的 thinkster.io 链接不付费就无法观看。不是我的链接,但也许这更合适:toddmotto.com/directive-to-directive-communication-with-require【参考方案3】:directive
允许您以声明方式扩展 html 词汇表以构建 Web 组件。 ng-app
属性是一个指令,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
函数返回 pre
和 post
链接函数。在预链接函数中,我们有实例模板和来自controller
的范围,但是模板没有绑定到范围并且仍然没有嵌入的内容。
Post
链接函数是 post 链接是最后执行的函数。现在transclusion
已完成,the template is linked to a scope
和view 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
);
【讨论】:
你提到你展示了如何让 parentDirectiveCtrl 进入孩子的控制器......这个例子孩子没有控制器,而是链接功能......我没有坚持这个目前的问题,所以它可能不是那么重要,而是一个奇怪的问题。【参考方案4】:这是理解指令阶段的一个很好的示例 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 指令注入到依赖指令的控制器中吗?
您的代码示例:未捕获的错误:[$injector:modulerr] 无法实例化模块 myapp 由于:错误:[$injector:unpr] 未知的提供程序:slngStylePrelinkProvider【参考方案5】:
编译:
这是 Angular 实际编译指令的阶段。对于给定指令的每个引用,此编译函数仅调用一次。例如,假设您正在使用 ng-repeat 指令。 ng-repeat 必须查找它附加到的元素,提取它附加到的 html 片段并创建一个模板函数。
如果您使用过 HandleBars、下划线模板或类似的模板,就像编译它们的模板以提取模板函数一样。向此模板函数传递数据,该函数的返回值是包含正确位置数据的 html。
编译阶段是 Angular 中返回模板函数的那一步。这个 Angular 中的模板函数称为链接函数。
链接阶段:
链接阶段是将数据 ( $scope ) 附加到链接函数的地方,它应该返回链接的 html。由于该指令还指定了此 html 的去向或更改的内容,因此它已经很好了。这是您要更改链接的 html 的函数,即已经附加了数据的 html。如果您在链接函数中编写代码,则它通常是链接后函数(默认情况下)。这是一种在链接函数将数据与模板链接后调用的回调。
控制器:
控制器是您放置某些指令特定逻辑的地方。该逻辑也可以进入链接功能,但是您必须将该逻辑放在范围内以使其“可共享”。这样做的问题是你会用你的指令破坏范围,这并不是真正的预期。 那么,如果两个指令想要相互交谈/相互合作,还有什么选择呢?当然,您可以将所有这些逻辑放入服务中,然后使这两个指令都依赖于该服务,但这只会带来更多的依赖。另一种方法是为此范围提供一个控制器(通常是隔离范围?),然后当该指令“需要”另一个指令时,将此控制器注入另一个指令。有关示例,请参见 angularjs.org 第一页上的选项卡和窗格。
【讨论】:
澄清一下:compile 编译整个页面使用的模板。链接器与每个实例相关联。正确的?然后控制器在实例之间工作。 @CMCDragonkai 每个指令controller
函数在编译之后 执行,但之前 pre-link
在本地DOM 树分支中执行。同样controller
和pre-link
函数以自上而下 的方式遍历本地DOM 分支。之后post-link
以自下而上的方式执行。
如果你不理解它只是一团糟。它这样做是有原因的。
这是正确的技术答案,但是,我仍然有疑问何时应该使用链接功能。
我们应该到处使用controller
而不是link
吗?这样以后如果需要共享方法或要引入一些逻辑,我就不需要更改代码?一直使用controller
而不是链接有什么陷阱吗?【参考方案6】:
另外,使用控制器与链接函数的一个很好的理由(因为它们都可以访问范围、元素和属性)是因为您可以将任何可用的服务或依赖项传递给控制器(并且以任何顺序),而您不能使用链接功能做到这一点。注意不同的签名:
controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) ...
对比
link: function(scope, element, attrs) ... //no services allowed
【讨论】:
当您对答案投反对票时,请发表评论以解释您的观点。谢谢 我不是反对者,但这并不完全正确,因为您仍然可以将任何所需的依赖项注入指令本身,例如:module.directive('myDirective', function($window) etc...
。然后可以从链接函数内部访问它。
这似乎完全不正确,因为您可以将服务注入链接功能
@JoshRibakoff 最终结果是一样的,你可以访问链接功能中的服务。它是否在函数的参数中声明并不重要。在这方面,迈克·张伯伦是正确的
@cwyatt1 我在纠正用语,plnkr 没有显示注入到 link() 函数中,因为这不是 Angular 的功能。你可能认为我是迂腐的,但 metamatts 的评论已经概述了 plunkr 所做的与注入控制器所做的许多重要区别。 OP正在询问有什么区别,并且有区别。以上是关于链接 vs 编译 vs 控制器的主要内容,如果未能解决你的问题,请参考以下文章
我用VS2010 编译的控制台应用 输出中文也是乱码。。请问您是怎么解决的?