【发布时间】:2016-09-15 09:18:15
【问题描述】:
controller中传入的$scope和directive中传入的$scope有什么区别和关系?
你将如何设置这些?
【问题讨论】:
-
@BuhBuh 这些是 wiki 答案,您决定为可能需要这些信息的人创建一个问题并回答它
标签: angularjs inheritance angularjs-directive scope angular-controller
controller中传入的$scope和directive中传入的$scope有什么区别和关系?
你将如何设置这些?
【问题讨论】:
标签: angularjs inheritance angularjs-directive scope angular-controller
这里简单解释一下controller中传入的$scope和directive中传入的$scope的区别和关系是:
正如您在下面的基本 Angular 设置中看到的那样,$scope 被传递给 Angular Controller 和 Angular Directive。但是有什么区别,这些$scopes 如何相互关联和交互?
基本角度设置
Angular 应用:
angular.module('app', []);
角度控制器:
angular.module('app').controller('mainCtrl', function($scope) {
$scope.user = {
name: 'Luke Skywalker',
address: {
street: 'PO Box 123',
city: 'Secret Rebel Base',
planet: 'Yavin 4'
},
friends: [
'Han',
'Leia',
'Chewbacca'
]
}
});
角度指令:
angular.module('app').directive('userInfoCard', function() {
return {
templateUrl: "userInfoCard.html",
restrict: "E",
controller: function($scope) {
$scope.knightMe = function(user) {
user.rank = "knight";
}
}
}
});
有 3 种方法可以设置 directive scope 和包含 controller scope 之间的关系:
默认是directive 与包含controller 的范围共享。此图说明了这种关系。
指令范围 - 共享
您可以看到以紫色显示的父 $scope,我们可以看到在父 Controller 上创建的 User object。具有共享 $scope 的指令完全位于父 controller's $scope 中,并且它可以访问父 controller $scope 上的每个对象。
如果指令必须修改或添加项目到 $scope,它将属于 parent controller's $scope 而不是 directive。如果您必须在controller 和directive 中添加一行以注销$scope (console.log($scope);,您可以轻松看到这一点。您会注意到两个 ChildScopes 的 $id 是相同的。
Shared Scope 是在directives 中处理$scope 的最简单方法。
指令继承范围
下图说明directive继承$scope:
图表 1
我们再次在控制器 $scope 中创建了一个用户对象,但指令设置为继承了 $scope。
当我们在directive $scope 中创建新项目时,它将变为内部数据,并且对父$scope 不可见。换句话说,该项目将存在于directive $scope 而不是父$scope。
见下图 2:
图表 2
您想要这样做的原因有多种,最常见的是将数据封装在directive 中。
要创建带有继承 $scope 的指令,请在指令中添加 scope property,并将其设置为 true(将其设置为 false 将共享 $scope - 这是在任何情况下都是默认的)。
请参阅下面的directive 代码:
角度指令:
angular.module('app').directive('userInfoCard', function() {
return {
templateUrl: "userInfoCard.html",
restrict: "E",
scope: true,
controller: function($scope) {
$scope.knightMe = function(user) {
user.rank = "knight";
}
}
}
});
当您通过控制台注销时,您会像以前一样注意到 2 个 ChildScope 对象。但是这次 $id 对于每个 $scope 对象是不同的。
需要注意的一点:directive ChildScope 对象有一个名为 $parent 的属性。这与 controller ChildScope 对象具有相同的 $id。所以包含controller $scope 已被设置为directive $scope 的$parent。您还会注意到 user 对象在 parent $scope 中可见。这是真正的 JavaScript 继承。
注意:您会注意到指令 ChildScope 对象有一个 原型 (_proto_)。当您查看原型时,您可以看到这也是指令的同一范围对象,从而实现了真正的继承。
阅读:
https://developer.mozilla.org/en/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
http://javascript.info/tutorial/inheritance
这里的主要区别不是子作用域在父作用域上可以看到什么,而是当子作用域创建新数据时会发生什么。此数据在子作用域内部,对父作用域不可见。
隔离作用域
下图说明了这种情况:
再一次,我们有一个父 controller $scope 包含一个 user 对象。与继承 $scope 一样,在directive $scope 中创建的数据对于@987654387 将是内部 和不可见 @$scope。
但是我们遇到了directive $scope 无法看到controller $scope 上的数据的问题。我们经常希望看到controller $scope 的某些数据元素。
要解决此问题,您可以逐个对象在隔离的$scope 和父$scope 之间创建特殊绑定。这样隔离的$scope 无法看到父$scope 上的所有内容,但它可以看到您设置为可见的特定项目。
为此,您将 scope 属性上的 true 更改为 object {}。
如果您必须将此记录到控制台,您会再次看到每个 ChildScope 对象都有自己唯一的 $id。您还会注意到子作用域 (directive) 仍然有一个作为父作用域 (controller) 的 $parent 对象,但是这次没有链接到 的父作用域>原型。
要使controller 的user 对象在directive 的范围内可见,您可以在“user”的指令范围对象中添加一个属性,并将其值设置为“=”,告诉作用域期望一个对象以“user”的值传递给它。
下面的代码演示了这一点:
angular.module('app').directive('userInfoCard', function() {
return {
templateUrl: "userInfoCard.html",
restrict: "E",
scope: {
user: '='
},
controller: function($scope) {
$scope.collapsed = ($scope.initialCollapsed === 'true');
$scope.knightMe = function(user) {
user.rank = "knight";
}
$scope.collapse = function() {
$scope.collapsed = !$scope.collapsed;
}
}
}
});
这就是在directive范围和包含controller范围之间建立关系的3种方法。
特别感谢乔·埃姆斯。 https://github.com/joeeames
【讨论】: