AngularJS - 为什么使用“Controller as vm”?

时间:2014-03-09 17:38:04

标签: angularjs

这个整个周末,我非常痛苦,不明白为什么父控制器的功能没有被子控制器识别。

我很快意识到将控制器作为vm是原因:

 <div data-ng-controller="ParentCtrl as vm">
   <div data-ng-controller="Child1 as vm"></div>
   <div data-ng-controller="Child2 as vm"></div>
 </div>

当然,现在看来很明显,child1和2都不会在ParentCtrl中看到函数,如果我使用的是先前的工作模式而没有vm,而是使用$ scope,那么一切都会很好。

所以我的问题是“使用”vm“方法对任何人都有什么好处,如果它优于不使用它,怎么能在ParentCtrl中调用函数调用而不发出?

谢谢

5 个答案:

答案 0 :(得分:24)

使用控制器作为语法的一个优点是,它允许您将控制器定义为一个简单的javascript构造函数,其属性和函数直接从实例化对象而不是$ scope中公开。

例如:

function MyController() {

    var ctl = this;

    ctl.message = 'You have not clicked anything yet.';

    ctl.onClick = function() {
        ctl.message = 'You clicked something.';
    };

    return ctl;
}

...

myModule.controller('MyController', MyController);

...

<div ng-controller="MyController as vm">
    <span>{{vm.message}}</span>
    <button ng-click="vm.onClick()">Click Me</button>
</div>

请注意,我们可以使用一个普通的旧javascript控制器,甚至没有绑定到angular。对于需要其他依赖项(如$ scope或其他服务)的场景,您仍然可以轻松地将它们传递给构造函数,但是这种模式可以直接在$ scope上减少混乱,并且还可以在直接设置变量时解决变量隐藏问题关于范围。

归根结底,它真的归结为偏好问题,但对我来说,我真的不想直接在范围内定义所有内容,并尽可能将我的控制器视为任何旧的javascript对象。

这是一篇关于控制器用法的优秀文章: http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/

答案 1 :(得分:15)

我曾经使用控制器作为vm语法,但最近我一直在远离它。我发现当我使用范围隔离使用嵌套指令构建复杂页面时,传统的$ scope方法更容易使用。

你的问题是我想知道的一段时间。我能看到的唯一真正值是,当您在页面中使用嵌套控制器时,您可以获得每个范围的语义引用,以便您的标记变得更容易阅读。所以,例如:

<div ng-controller="CustomersCtrl as customers">
    <div ng-controller="OrdersCtrl as orders">
         <p>Showing{{customers.model.length}} customers with a total of {{orders.model.length}} orders</p>
    </div>
</div>

除此之外,我并没有真正看到这个值,如果你喜欢像我一样使用指令嵌套,那么这个值很快就会无效。

答案 2 :(得分:8)

您在使用此示例时遇到的问题并非特别是由于使用控制器作为语法;相反,它是由于您的嵌套对象因命名而隐藏父对象。

当与其他编译为JavaScript的语言(如CoffeeScript或TypeScript)进行广泛协作时,作为选项的控制器非常有用。它还允许您创建更轻量级的控制器,由于不需要$ scope注入,因此可以与非角度组件互换。它只是一种替代语法,但如果您愿意,仍然可以使用$ scope。

这里真正的问题是为什么那些将控制器的示例写为语法的人决定使用“as vm”。从技术上讲,语法旨在提供MVVM样式的编码体验,因此使用“as vm”可能有意义,但这暴露了您所看到的问题。您的父控制器是一个名为vm的对象,您的子对象也被命名为vm,因此子对象隐藏父对象。相反,如果您以不同的方式命名对象,那么您的子对象在访问父对象时将没有任何问题,并且在代码中实际上非常清楚对象是您正在使用的属性来自哪个对象。

答案 3 :(得分:5)

我认为其中一个主要优点是它会自动确保您的绑定中最终会有.。因为Angular中的经验法则是,如果你的绑定中没有.,你可能会在脚下射击自己。

考虑你有这个:

<input ng-model="foo" />

这可能无法按预期工作。另一方面,如果您使用SomeController as vm语法,则会自动结束:

<input ng-model="vm.foo" />

这将使您免于数据绑定无法按预期工作的潜在问题。

原型继承在JavaScript中起作用的原因背后的原因在这里有非常详细的描述:What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

答案 4 :(得分:1)

据我所知,使用“controller as vm”语法的主要原因是angularjs中的控制器实际上充当模型(封装数据并提供行为),或者查看模型(将数据暴露给html)

在大多数情况下它运行良好,但我遇到的一个主要后果是很难从子控制器访问父控制器中的数据,并且可能的解决方案(Get parent controller in child controller which all use 'controller as vm' notation)是不优雅。