Angular JS:当我们已经有了带范围的指令控制器时,指令的链接功能有什么需求?


199

我需要对范围和模板执行一些操作。看来我可以在link函数或controller函数中执行此操作(因为两者都可以访问作用域)。

什么时候需要使用link功能而不是控制器?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

另外,我知道那link是非角度的世界。所以,我可以使用$watch$digest$apply

link当我们已经有了控制器时,该功能的意义是什么?


9
什么是你的意思“ 另外,据我所知,链接是无棱角的世界。所以,我可以使用$watch$digest$apply ”?
musicly_ut

2
在内部,link我们看不到任何棱角魔术。即没有2路绑定,等等。只是我们有可用的angular的api。
Yugal Jindle 2013年

Answers:


299

在与和函数进行最初的斗争并阅读了很多有关它们的内容之后,我认为现在我有了答案。linkcontroller

首先让理解

简而言之,角度指令如何工作:

  • 我们从模板开始(作为字符串或加载到字符串)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • 现在,将templateString其包装为角形元素

    var el = angular.element(templateString);

  • 使用el,现在我们用$compile进行编译,以获取链接功能。

    var l = $compile(el)

    这是发生了什么事

    • $compile 遍历整个模板并收集它可以识别的所有指令。
    • 所发现的所有指令均以递归方式编译link收集其功能。
    • 然后,所有link函数都包装在一个新link函数中,并以返回l
  • 最后,我们scope为此l(链接)函数提供函数,该函数进一步使用this scope及其对应的元素执行包装的链接函数。

    l(scope)

  • 这会将template作为新节点添加到,DOM并进行调用controller,这会将其监视添加到与DOM中的模板共享的范围

在此处输入图片说明

比较compile vs linkcontroller

  • 每个指令只能编译一次,链接功能将保留以供重复使用。因此,如果某个指令的所有实例都适用,则应在指令的compile功能内执行。

  • 现在,在编译之后,我们有了link模板附加到DOM时执行的功能。因此,因此我们执行特定于指令每个实例的所有操作。例如:附加事件基于范围更改模板等。

  • 最后,当指令在上运行时(附加后),该控制器应处于活动状态和反应状态DOM。因此:

    (1)设置带有链接的视图[ V ](即模板)后。$scope是我们的[ M ],$controller也是我们在MVC中的 [ C ]

    (2)通过设置手表利用$ scope2向绑定。

    (3)$scope期望在控制器中添加监视,因为这是在运行时监视模板。

    (4)最后,controller还用于能够在相关指令之间进行通信。(myTabs例如https://docs.angularjs.org/guide/directive中的示例)

    (5)的确,我们也可以在link函数中完成所有这些操作,但它只涉及关注点分离

因此,最后我们可以完美地满足以下所有要求:

在此处输入图片说明


5
我还发现本文对理解这里的执行顺序很有用:AngularJS指令中的编译和链接函数的
精髓

4
很好的解释。要提及的是,控制器在链接功能之前被调用。
jsbisht 2015年

38
控制器在链接之前执行
Royi Namir 2015年

10
令我惊讶的是,Stack Overflow要求编辑至少6个字符,因此不允许我纠正此答案中let的拼写。
user1886323

79

为什么需要控制器

之间的差异linkcontroller当你想在你的DOM巢指令和从父指令嵌套那些暴露的API函数的用武之地。

文档

最佳实践:要向其他指令公开API时,请使用控制器。否则使用链接。

假设您要有两个指令my-formmy-text-input并且希望my-text-input指令仅出现在内部,my-form而没有其他地方。

在这种情况下,您会在定义指令时my-text-input说它需要parent使用require参数从DOM元素中获取控制器,如下所示:require: '^myForm'。现在,来自父元素的控制器将作为第四个参数injected进入link函数,其后是$scope, element, attributes。您可以在该控制器上调用函数并与父指令进行通信。

此外,如果未找到这样的控制器,则会引发错误。

为什么要使用链接

link如果正在定义该函数,则实际上不需要使用该函数,controller因为$scope可以在上使用controller。此外,在定义link和时controller,确实需要注意两者的调用顺序(controller之前已执行)。

但是,与Angular方式保持一致,大多数DOM操纵和2向绑定使用$watchers通常是在link函数中完成的,而用于子项和$scope操纵的API 则是在中完成的controller。这不是一成不变的规则,但是这样做会使代码更具模块化,并有助于分离关注点(控制器将维护directive状态,link函数将维护DOM+外部绑定)。


那很棒。现在,您能帮助我解决问题的第二部分吗?
Yugal Jindle 2013年

我的意思是,因为我们已有控制器,可以用来与其他指令进行通信。那么,有什么需要link
Yugal Jindle 2013年

1
您的答案以某种方式无法回答实际的问题。
Yugal Jindle 2013年

1
定义a时会发生任何问题controller吗?为什么我要发明一个全新的功能,只是避免定义控制器?
Yugal Jindle

1
似乎@scalaGirl s的链接不再起作用
Minato

17

controller功能/对象表示一个抽象模型-视图-控制器(MVC)。尽管没有什么新的关于MVC的文章可以写,但是它仍然是angular的最重要的优势:将关注点分成更小的部分。就是这样,仅此而已,因此,如果您需要对Model来自View的更改做出反应,则Controller是合适的来完成这项工作。

关于link功能的故事是不同的,它与MVC来自不同的角度。一旦我们想跨越controller/model/view (模板)的边界,这真的很重要。

让我们从传递给link函数的参数开始:

function link(scope, element, attrs) {
  • scope是Angular作用域对象。
  • element是此伪指令匹配的jqLit​​e包装的元素。
  • attrs是具有规范化属性名称及其对应值的对象。

要把link上下文放到上下文中,我们应该提到所有指令都通过了初始化过程:CompileLinkBrad Green和Shyam Seshadri的《 Angular JS》摘录:

编译阶段(链接的姐妹,让我们在这里提到它以获得清晰的图片):

在此阶段,Angular遍历DOM以标识模板中所有已注册的指令。然后,对于每个指令,它根据指令的规则(模板,替换,转写等)转换DOM,并调用编译函数(如果存在)。结果是一个编译的模板函数,

链接阶段

为了使视图动态化,Angular然后为每个指令运行一个链接函数。链接功能通常在DOM或模型上创建侦听器。这些侦听器始终保持视图和模型同步。

link可以在这里找到如何使用的一个很好的示例:创建自定义指令。请参见示例:创建处理DOM的指令,该指令将“日期时间”插入页面,并且每秒刷新一次。

上面的丰富资源中仅一小段,显示了DOM的实际操作。$ timeout服务有钩子函数,并且在其析构函数调用中将其清除以避免内存泄漏

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...

3
您似乎已经比较了compilerlink。他们的问题是为什么link我们何时拥有controller
Yugal Jindle 2013年

我已经扩展了答案,甚至可以更详细地描述控制器。现在,controllervs 的概念link应该更加清晰……
RadimKöhler2013年

1
我可以寻求解决的理由。但这似乎有点模糊。如果来自角度小组的人本身可以为它发言,并预测他们看到它的方向,那就太好linkcontroller
Yugal Jindle

1
那是我想了解的唯一部分(何时还不够?)。另外,我获得了angular in的所有好处,controller并且link相对难看。因此,棱角分明的团队必须有充分的理由,而不仅仅是一个选择。
Yugal Jindle

1
问题:控制器不足时?回答:当您需要非Angular的经验,例如使用JQuery插件或使用文档(docs.angularjs.org/api/ng/function/angular.element:)中提到的JQlite功能时,则需要链接
Hasteq
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.