5

假设我得到了以下 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更适合?在什么情况下通过作用域继承直接操作模型会更好?

4

2 回答 2

7

如果您使用原型继承,则需要小心,因为在父控制器和子控制器中使用相同的变量名时很容易出错。这可以通过确保 $scope 变量在某处始终“有一个点”来避免,但需要纪律以确保您始终这样做。您还可以使用该结构访问在 RootCtrl 中设置的 NavCtrl 中的变量$scope.$parent.$parent,但这很脆弱,并且本质上将您的控制器与 DOM 结构联系在一起,这是导致问题的根源。

$emit/$on 如果您在事件名称中打错字,则可能会出现静默失败的问题,并且在发生错误时很难跟踪正在发生的事情。最好有节制地使用它们。http://eburley.github.io/2013/01/31/angularjs-watch-pub-sub-best-practices.html说只使用它们“当您需要让多个订阅者知道一个事件并且这些订阅者需要做的不仅仅是向他们的观点传播信息。”

在控制器之间共享数据模型的常规 Angular 方法是创建一个服务,然后将其注入到两个控制器中。这也符合 OOP 的“优先组合胜于继承”原则。

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关于 Angular 最佳实践的视频很有趣,它在 28 分钟左右讨论了在控制器和服务中放置的内容,以及更多关于事件($emit/$on)的内容。他的结论(意译)是事件有些问题,最好仅用于两件事确实不需要相互了解并且必须保持非常分开的情况,或者如果事件并不总是必要的,有时可以忽略。

我想说的基本规则是:

  • 使用服务在两个控制器之间共享数据,它比继承稍微复杂一些,但没什么难的。

  • 使用事件以复杂的方式在多个不同的订阅者之间共享。

  • 控制器中的 $scope 应该是“只写”(直接取自上面 Misko 的最佳实践视频的规则)。“NavCtrl 需要操作恰好存在于 RootCtrl 范围内的模型”的范围继承也将涉及读取父范围,因此我认为最好避免。

于 2013-08-12T04:42:09.190 回答
1

如果 RootCtrl 中的模型是一个对象,而 NavCtrl 只需要修改模型对象的几个属性,那么使用范围继承是最简单的。如果您想采用这种方法,请确保您知道原型是如何工作的。

正如 mikel 的回答中提到的那样,使用服务在控制器之间共享数据是可行的,但是对于简单的情况,它的设置非常过分,特别是当您可以使用范围继承时。而且,该服务将存在于您的应用程序的整个生命周期中,这可能不是您想要或需要的。

恕我直言, $emit/$on 在您的情况下效果很好。设置不太繁重,范围很好地解耦,对模型的所有修改都集中在 RootCtrl 中,我认为这对维护很有好处。如果您担心在键入事件名称时可能犯的错误,您可以使用 为事件名称创建常量module.constant(),然后使用这些常量而不是一直将事件名称作为字符串键入。

于 2013-08-12T06:10:51.080 回答