说我得到以下HTML结构:
<body ng-app="demo" ng-controller="RootCtrl">
<header>
<!-- Header Material -->
</header>
<main ng-controller="MainCtrl">
<!-- Main Content -->
<nav ng-controller="NavCtrl">
<!-- Navbar -->
</nav>
</main>
<body>
现在,假设NavCtrl
需要操纵恰好存在于RootCtrl
范围内的模型 - 在哪种情况下$emit/$on
更适合?在哪种条件下通过范围继承直接操作模型会更好?
答案 0 :(得分:7)
如果您正在使用原型继承,则需要小心,因为在父控制器和子控制器中使用相同的变量名时很容易出错。这可以通过确保$ scope变量在某处始终“有一个点”来避免,但需要遵守规则以确保始终执行此操作。您还可以使用$scope.$parent.$parent
结构访问RootCtrl中的NavCtrl集中的变量,但这很脆弱,并且实际上将您的控制器与DOM结构联系起来,这是一个解决问题的方法。
$ emit / $ on会导致可能无声地失败的问题,并且可能使得在发生错误时很难发现正在发生的事情。谨慎使用它们会更好。 http://eburley.github.io/2013/01/31/angularjs-watch-pub-sub-best-practices.html仅表示使用它们“当您需要让多个订阅者知道某个事件时,这些订阅者需要做的不仅仅是向他们的视图辐射信息。”
跨控制器共享数据模型的正常Angular方法是创建服务,然后将其注入到两个控制器中。这也符合OOP的“prefer composition over inheritance”原则。
app.service('dayService', function () {
var day = 'Monday';
return {
getDay: function() {
return day;
},
setDay: function(thisDay) {
day = thisDay;
}
};
})
function NavCtrl($scope, dayService) {
$scope.day = dayService.getDay();
}
function RootCtrl($scope, dayService) {
dayService.setDay('Sunday');
}
HTML:
<nav ng-controller="NavCtrl">
Today is {{day}}
</nav>
你可能也会发现Misko的video on Angular best practices很有意思,它会谈到在28分钟左右的控制器和服务中放置什么,以及更多关于事件($ emit / $ on)的信息。他的结论(释义)是事件有些问题,最好只用于两件事情实际上不需要彼此了解并且必须保持非常独立的情况,或者如果事件并非总是必要的话有时会被忽略。
我会说基本规则是:
使用服务在两个控制器之间共享数据,它比继承稍微复杂,但没什么太困难。
使用事件以复杂方式在多个不同订阅者之间共享。
控制器中的$ scope应该是“只写”(直接来自上面的Misko最佳实践视频的规则)。范围继承“NavCtrl需要操作碰巧存在于RootCtrl范围内的模型”也会涉及读取父范围,所以我认为最好避免。
答案 1 :(得分:1)
如果RootCtrl中的模型是一个对象,而NavCtrl只需要修改模型对象的一些属性,那么使用范围继承将是最简单的。如果您想采用这种方法,请确保您知道原型是如何工作的。
使用服务在控制器之间共享数据工作,如mikel的回答所述,但对于简单的情况,它的设置非常过分,特别是当你可以使用范围继承时。而且,该服务将存在于您的应用的整个生命周期中,这可能不是您想要或需要的。
恕我直言,$ emit / $ on在您的情况下效果相当不错。安装不是太重,范围很好地解耦,所有对模型的修改都集中在RootCtrl中,这对我认为的维护很有帮助。如果您担心在输入事件名称时可能会犯的错误,可以使用module.constant()
为事件名创建常量,然后使用这些常量而不是一直键入事件名作为字符串。