使用 ui 路由器的范围和控制器实例化
scope and controller instantiation with ui router
我对何时实例化控制器感到困惑。此外,控制器如何在嵌套状态时被实例化。我可能对作用域如何附加到视图和控制器感到困惑,也就是说,如果每个视图都有自己的控制器和作用域,或者它们是否共享相同的作用域。
有人可以解释一下控制器何时被实例化吗?在嵌套路由下,所有视图是否共享一个控制器和作用域?当我切换状态并返回到另一个控制器实例化的状态时会发生什么?
以下是我的路线(配置文件):
.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) ->
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppController'
})
.state('app.pincode', {
url: '/pincode',
views: {
menuContent: {
templateUrl: 'templates/pincode-yield.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.create', {
url: '/create',
views: {
pincode: {
templateUrl: 'templates/pincode-create.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.pincodeLogin', {
url: '/login',
views: {
pincode: {
templateUrl: 'templates/pincode-login.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.settings', {
url: '/settings',
views: {
pincode: {
templateUrl: 'templates/settings.html',
controller: 'PincodeController'
}
}
})
每当您访问特定状态时,控制器都会被实例化。例如,当第一次访问 app.pincode.pincodeLogin
时,构建了一个 AppController
和两个 PincodeControllers
,假设您使用了正确的模板,每个视图都有自己的视图。切换到 'app.pincode.settings'
会破坏最里面的控制器并用一个新控制器替换它,尽管不会触及层次结构中较高的两个控制器。范围遵循标准 AngularJS' 继承模式,它们不是孤立的。
您可能希望删除子状态中的控制器(并处理父控制器中的业务逻辑)或为每个状态设置不同的控制器 - 不同模板和视图的相同控制器通常是糟糕的设计。
为了得到更详细的答案,我们can/should观察源代码并检查文档。让我尝试解释所有三个问题(并引用代码和文档)。
1. When do controllers get instantiated?
这里我们可以观察到ui-view
指令的代码:
[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]
控制器与视图相关。那些 views
,在 .state()
内部定义为 views
object:
.state('...', {
// The view definition
views : {
'' : {
template: ...
controller: ...
resolve: ..
}
},
resolve: ...
}
因此,只要 view(ui-view
)填充了状态视图内部定义的设置,它几乎可以作为 标准,但增强指令。
1) 找到模板,
2) Resolves 已解决
...
x) 控制器实例化...
视图目标(ui-view
指令)可以使用名称,并且可以由层次结构中的不同状态填充。
这可能意味着,一个视图中可能有一个内容 (例如 title),由 [=111= 定义]parent 以及替换为 child
// parent
.state('parent', {
views : {
'' : {...} // the main parent view, with ui-view="title"
'title@parent' : { ...} // here we go and fill parent's ui-view="title"
},
...
}
// child
.state('parent.child', {
views : {
'title' : { ...} // here we change the parent's target ui-view="title"
},
...
}
上面的状态定义将(每当我们在这两个状态之间转换时)做:
$state.go('parent')
- 'title@parent' : { ...}
中定义的视图(模板、控制器...)将被注入目标 ui-view="title"
并按上述方式实例化
$state.go('parent.child')
- 几乎相同,只是视图取自 child state/view 定义 'title' : { ...}
。这将替换 ui-view="title"
的内容,并将按上述方式实例化
每次我们从parent到child和从child到parent.
2. Under nested routes do all the views share one controller and scope?
一个简单的答案是NO,有no共同分享。
事实上,每个控制器 都有它自己的作用域,它是从parent 视图作用域创建的。首先是文档:
What Do Child States Inherit From Parent States?
...
Scope Inheritance by View Hierarchy Only
Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).
It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.
所以,每当我们的 controller
(嗯 view with template, controller...) 注入 parent 的目标 ui-view="..."
它获得继承范围:
newScope = scope.$new();
简而言之就是说JS objects (例如scope.Model = {}
)可以被共享child 和 parent.
$scope.Model.id = 1; // will refer to the same id in both parent & child
但是,基本的Javascript类型不是通过引用传递的,因此它们的值不会在作用域之间自动同步:
// set in parent
$scope.id = 1;
// in child after inherted still === 1
$scope.id = 2; // now 2 for a child, different value in parent - still === 1
值得在这里阅读更多关于原型继承的内容:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
3. What happens when I switch states and go back to a state - does another controller get instantiated?
视情况而定。
如果把parent子视图(记得上面的ui-view="title"
)换成child视图,那就是re-created (从 child 过渡到 parent) - 这样的控制器将是 re-initialized(上面讨论过)。
但是当我们说到 main parent view (usually unnamed), 表示 parent (例如下面带有控制器的未命名视图 'ParentMainCtrl')
.state('parent', {
views : {
'' : { // // the main parent view
controller: 'ParentMainCtrl',
}
'title@parent'
'tooltip@parent'
},
那么我们可以确定这样的控制器不是re-instantiated。它在其所有 children 的生命周期内存活,加上 parent 的一个 (未选择 child 状态)。
为了re-load这个view/controller,我们必须使用一个选项reload
$state.go(to, params, options)
...
options Options object. The options are:
- ...
- reload -
{boolean=false}
,如果 true 将强制转换,即使状态或参数没有改变,又名重新加载相同的状态。它与 reloadOnSearch 不同,因为当一切都相同(包括搜索参数)时您想要强制重新加载时会使用它。
希望对您有所帮助。如需更多信息,请查看这些资源:
- Nested States & Nested Views
- Multiple Named Views
- API Reference
- State.js of the sample application - 我会说最好的记录代码片段 ever
控制器在第一次加载相应的视图时被实例化。
例如,如果您有 3 个选项卡与 3 个控制器关联 - 那么与默认视图关联的控制器首先实例化。接下来,当您加载其他视图时,关联的控制器也会被实例化。
但有趣的是,一旦在 DOM 中加载视图 - 默认情况下会对其进行缓存。当视图离开时,它的元素留在 DOM 中,并且它的范围与 $watch 循环断开连接。当导航到一个已经被缓存的视图时,它的范围会被重新连接,并且留在 DOM 中的现有元素成为活动视图。
我对何时实例化控制器感到困惑。此外,控制器如何在嵌套状态时被实例化。我可能对作用域如何附加到视图和控制器感到困惑,也就是说,如果每个视图都有自己的控制器和作用域,或者它们是否共享相同的作用域。
有人可以解释一下控制器何时被实例化吗?在嵌套路由下,所有视图是否共享一个控制器和作用域?当我切换状态并返回到另一个控制器实例化的状态时会发生什么?
以下是我的路线(配置文件):
.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) ->
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppController'
})
.state('app.pincode', {
url: '/pincode',
views: {
menuContent: {
templateUrl: 'templates/pincode-yield.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.create', {
url: '/create',
views: {
pincode: {
templateUrl: 'templates/pincode-create.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.pincodeLogin', {
url: '/login',
views: {
pincode: {
templateUrl: 'templates/pincode-login.html',
controller: 'PincodeController'
}
}
})
.state('app.pincode.settings', {
url: '/settings',
views: {
pincode: {
templateUrl: 'templates/settings.html',
controller: 'PincodeController'
}
}
})
每当您访问特定状态时,控制器都会被实例化。例如,当第一次访问 app.pincode.pincodeLogin
时,构建了一个 AppController
和两个 PincodeControllers
,假设您使用了正确的模板,每个视图都有自己的视图。切换到 'app.pincode.settings'
会破坏最里面的控制器并用一个新控制器替换它,尽管不会触及层次结构中较高的两个控制器。范围遵循标准 AngularJS' 继承模式,它们不是孤立的。
您可能希望删除子状态中的控制器(并处理父控制器中的业务逻辑)或为每个状态设置不同的控制器 - 不同模板和视图的相同控制器通常是糟糕的设计。
为了得到更详细的答案,我们can/should观察源代码并检查文档。让我尝试解释所有三个问题(并引用代码和文档)。
1. When do controllers get instantiated?
这里我们可以观察到ui-view
指令的代码:
[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]
控制器与视图相关。那些 views
,在 .state()
内部定义为 views
object:
.state('...', {
// The view definition
views : {
'' : {
template: ...
controller: ...
resolve: ..
}
},
resolve: ...
}
因此,只要 view(ui-view
)填充了状态视图内部定义的设置,它几乎可以作为 标准,但增强指令。
1) 找到模板,
2) Resolves 已解决
...
x) 控制器实例化...
视图目标(ui-view
指令)可以使用名称,并且可以由层次结构中的不同状态填充。
这可能意味着,一个视图中可能有一个内容 (例如 title),由 [=111= 定义]parent 以及替换为 child
// parent
.state('parent', {
views : {
'' : {...} // the main parent view, with ui-view="title"
'title@parent' : { ...} // here we go and fill parent's ui-view="title"
},
...
}
// child
.state('parent.child', {
views : {
'title' : { ...} // here we change the parent's target ui-view="title"
},
...
}
上面的状态定义将(每当我们在这两个状态之间转换时)做:
$state.go('parent')
-'title@parent' : { ...}
中定义的视图(模板、控制器...)将被注入目标ui-view="title"
并按上述方式实例化$state.go('parent.child')
- 几乎相同,只是视图取自 child state/view 定义'title' : { ...}
。这将替换ui-view="title"
的内容,并将按上述方式实例化
每次我们从parent到child和从child到parent.
2. Under nested routes do all the views share one controller and scope?
一个简单的答案是NO,有no共同分享。
事实上,每个控制器 都有它自己的作用域,它是从parent 视图作用域创建的。首先是文档:
What Do Child States Inherit From Parent States?
...
Scope Inheritance by View Hierarchy Only
Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).
It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.
所以,每当我们的 controller
(嗯 view with template, controller...) 注入 parent 的目标 ui-view="..."
它获得继承范围:
newScope = scope.$new();
简而言之就是说JS objects (例如scope.Model = {}
)可以被共享child 和 parent.
$scope.Model.id = 1; // will refer to the same id in both parent & child
但是,基本的Javascript类型不是通过引用传递的,因此它们的值不会在作用域之间自动同步:
// set in parent
$scope.id = 1;
// in child after inherted still === 1
$scope.id = 2; // now 2 for a child, different value in parent - still === 1
值得在这里阅读更多关于原型继承的内容:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
3. What happens when I switch states and go back to a state - does another controller get instantiated?
视情况而定。
如果把parent子视图(记得上面的ui-view="title"
)换成child视图,那就是re-created (从 child 过渡到 parent) - 这样的控制器将是 re-initialized(上面讨论过)。
但是当我们说到 main parent view (usually unnamed), 表示 parent (例如下面带有控制器的未命名视图 'ParentMainCtrl')
.state('parent', {
views : {
'' : { // // the main parent view
controller: 'ParentMainCtrl',
}
'title@parent'
'tooltip@parent'
},
那么我们可以确定这样的控制器不是re-instantiated。它在其所有 children 的生命周期内存活,加上 parent 的一个 (未选择 child 状态)。
为了re-load这个view/controller,我们必须使用一个选项reload
$state.go(to, params, options)
... options Options object. The options are:
- ...
- reload -
{boolean=false}
,如果 true 将强制转换,即使状态或参数没有改变,又名重新加载相同的状态。它与 reloadOnSearch 不同,因为当一切都相同(包括搜索参数)时您想要强制重新加载时会使用它。
希望对您有所帮助。如需更多信息,请查看这些资源:
- Nested States & Nested Views
- Multiple Named Views
- API Reference
- State.js of the sample application - 我会说最好的记录代码片段 ever
控制器在第一次加载相应的视图时被实例化。
例如,如果您有 3 个选项卡与 3 个控制器关联 - 那么与默认视图关联的控制器首先实例化。接下来,当您加载其他视图时,关联的控制器也会被实例化。
但有趣的是,一旦在 DOM 中加载视图 - 默认情况下会对其进行缓存。当视图离开时,它的元素留在 DOM 中,并且它的范围与 $watch 循环断开连接。当导航到一个已经被缓存的视图时,它的范围会被重新连接,并且留在 DOM 中的现有元素成为活动视图。