AngularJS中控制器(controller)和指令(directive)有什么区别?

9

我是AngularJS的初学者。我正在努力理解AngularJS中控制器和指令之间的确切区别。


3
这个问题已经在这里有答案:https://dev59.com/IGMl5IYBdhLWcg3wBzDy - Nilesh Mahajan
它可能已经在那个帖子中有了答案。但是在阅读后,我发现Kalles的回答更好、更具描述性,并且他还提供了一个非常简单和清晰的示例来突出差异+所问的问题是一个实际的问题“X和Y之间的区别是什么?”,而不是像“AngularJS-指令与控制器”这样的标题。 - greensin
3个回答

15

这里涉及的内容有些多,无法完全解释每个细节,因此我会尝试简要说明每个部分以及给出一个例子。

控制器

使用控制器来处理视图的逻辑,并分配你想要在视图中显示的数据。例如,如果你的应用程序中有一个名为 "所有用户" 的页面,你想要显示一个用户列表,你可以在控制器中定义一个用户数组并将其附加到 $scope 对象上。

var myApp = angular.module('myApp',[]);

myApp.controller('allUsersController', ['$scope', function($scope) {
  $scope.users = [
    { name: "User 1", id: 1},
    { name: "User 2", id: 2},
    { name: "User 3", id: 3}
  ];
}]);

将用户数组附加到作用域中,可以从视图中访问此数据。因此,现在您可以使用ng-repeat在视图中输出用户列表:

<ul>
 <li ng-repeat="user in users">{{user.name}}</li>
<ul>

指令

指令主要用于两件事:

  1. 创建可重复使用的组件
  2. 操作DOM

指令一开始使用起来有些棘手,但它们非常强大。下面这段话来自文档说明了它们之所以如此强大:

指令是 DOM 元素上的标记(例如属性、元素名称、注释或 CSS 类),告诉 AngularJS 的 HTML 编译器 ($compile) 将特定行为附加到该 DOM 元素(例如通过事件侦听器),甚至可以转换 DOM 元素及其子级。

从中需要理解的关键点是指令允许你将某些逻辑/行为附加到特定的元素上,而控制器通常只能将逻辑附加到页面/视图上。

假设在前一个示例中,我们想要添加一些在用户列表中可以执行的操作,例如喜欢和不喜欢按钮。我们可以像这样创建喜欢和不喜欢按钮:

JS

var myApp = angular.module('myApp',[]);

myApp.controller('allUsersController', ['$scope', function($scope) {
  $scope.users = [
    { name: "User 1", id: 1, like: 0},
    { name: "User 2", id: 2, like: 0},
    { name: "User 3", id: 3, like: 0}
  ];

  $scope.like = function(user){
    user.like++;
  }

  $scope.dislike = function(user){
    user.like--;
  }
}]);

HTML

<ul>
 <li ng-repeat="user in users"> 
   {{user.name}}
   <button ng-click="like(user)">LIKE</button>
   <button ng-click="dislike(user)">DISLIKE</button> 
 </li>
<ul>

比较简单,我们在控制器中添加了喜欢/不喜欢的方法来增加/减少用户的点赞数量。这段代码可以正常工作,但是如果我想在另一个视图中创建另一个用户列表怎么办?假设你有三个包含用户列表的不同视图:“所有用户”,“我的朋友”和“推荐用户”,所有三个视图都包含相同的操作(喜欢或不喜欢),但显示的用户在每个视图中都不同。我们希望使用我们在 allUsersController 中定义的相同的喜欢/不喜欢方法,但我们在不同的视图上,所以无法访问它们,因此您必须将相同的代码复制到其他视图的控制器中。在我们的示例中可能看起来不是很重要,但随着应用程序变得越来越大和复杂,这变得非常繁琐且难以维护。

这就是指令发挥作用的地方,您可以在指令中定义每个用户项背后的逻辑,而不是在控制器中分配它:

app.directive('userItem', function() {
return {
    template: '<div>{{userData.name}} <button ng-click="like()">Like</button> <button ng-click="dislike()">Dislike</button>',
    scope: {
      userData: "="
    },
    link: function(scope, element, attrs) {
      scope.like = function(){
       scope.userData.like++;
      }

      scope.dislike = function(){
       scope.userData.like--;
      }
    }
}
});

在你的HTML代码中:

<div class="user_list>
   <user-item ng-repeat="user in users" user-data="user"></user-item>
</div>
通过使用user-item指令,您现在可以在应用程序的任何位置创建用户列表,而无需重新定义每个用户相关逻辑。您会注意到这也使我们的html代码更加清晰,并且避免了大量重复的代码。该指令将您的html和js封装成一个可重用组件。
编辑: 关于如何将用户数据传递给指令,这与指令中的隔离作用域有关,您可以在这里阅读更多信息。基本思想是它将指令的范围与父范围(我们例子中的allUsersController)隔离开来,这样可以避免两个作用域之间的冲突并促进重用性。但同时,有些数据我们希望控制器与指令共享,因此我们“挖了一个洞”通过隔离作用域允许某些东西进入,这里是指令作用域中定义的userData
您可以访问指令文档并向下滚动以了解更多示例。

如果控制器名称为"user",则标签名称应为<user>吗? - kalles
<user-item ng-repeat="user in users" user-data="user"></user-item> 我们从哪里获取“users”数据? - kalles
抱歉,那是个笔误,指令名称应该是"userItem"而不仅仅是"user"。至于指令的工作原理细节,我会在我的答案中更新一个简要的解释,但像我说的,指令和控制器有很多内容需要解释,无法在一个答案中完全解释清楚。我的回答更侧重于理解用户案例,而不是解释控制器和指令的所有技术细节或语法。 - Ahmed Wagdi

0

控制器是一个js函数,如果您在html中使用ng-controller='MyController',它将被执行。

它可以根据您的url自动调用angular-route。

指令是可以应用代码的自定义HTML元素。指令可以包含html模板,也可以包含要执行的链接函数,也可以同时包含两者。

指令的示例:ng-repeatng-modelng-include


-1

控制器通常用于包含和维护视图的逻辑,通过 $scope 与视图绑定。

指令是您可能会重复使用的内容,并且可以直接通过指令名称在视图中调用,您可以将其作为属性传递。

例如:ng-if、ng-repeat 都是指令。

您可以为代码或逻辑编写自定义指令,该代码或逻辑在您的代码中重复使用。

一个很好的阅读材料,用于使用和实现指令是: http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/

干杯!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接