AngularJS最佳实践 - 风格指南

时间:2014-03-25 10:20:56

标签: javascript angularjs code-organization prototypal-inheritance

我正在尝试使用google-styleguide网站上定义的一些角度最佳做法:https://google-styleguide.googlecode.com/svn/trunk/angularjs-google-style.html

但目前我正在努力解决一些问题。在我使用此样式指南之前,我有$scope变量可用于对变量执行$watch

app.controller('myController',['$scope', function($scope) {
    $scope.$watch('myVariable', function(val) {
       alert("I'm changed");
    });
}]);

现在用我的新方法我不知道如何处理这个问题?我还应该注射$scope吗?因为当我不使用$scope时,我不必注入$watch

function myController($scope) {
   var vm = this;

   vm.myVariable = "aVariable";
   vm.$watch('vm.myVariable', function(val) {
      // error because $watch is undefined
   });

   //$scope.$watch - works
}

app.controller('myController',['$scope', myController]);

风格指南还建议使用原型。但是,如果我必须注入服务怎么办?在原型中使用服务的最佳方法是什么?

function myController(MyService) {
   var vm = this;

   vm.myService = MyService;
}

myController.prototype.callService = function() {
   var vm = this;

   vm.myService.doSomething();
}

这是对的吗?或者我错过了什么,是否有一个地方可以找到关于这种角度编程风格的更多信息?

在我看来,感觉更像是自然的javascript,我想用这种方式来组织我的AngularJS应用程序。

提前致谢

更新

对于'服务'问题,我想到的事情如下:

function MyBaseController(AService, BService, CService) {
   this.aService = AService;
   this.bService = BService;
   this.cService = CService;
}

function myController() {
   var vm = this;
   MyBaseController.apply(vm, arguments);
}

myController.prototype.doSomething() {
   var vm = this;
   this.aService.somethingElse();
}

但这感觉不合适..

2 个答案:

答案 0 :(得分:7)

即使你使用“控制器为”语法,注入$ scope来访问诸如$ watch之类的东西也是完全有效的。例如:

JS

var MyController = function($scope) {
    $scope.$watch('ctrl.someVar' function() {
        ...
    });

    this.someVar = 123;
}

MyController.$inject = ['$scope'];

HTML

<div ng-controller="MyController as ctrl">
    ....
</div>

您将服务注入控制器的第一个示例很好。对于继承示例,我会做这样的事情。

var BaseController = function(AService, BService) {
    this.aService = AService;
    this.bService = BService;
}

BaseController.prototype.doSomethingWithAAndB = function() {
    ...
}

var MyController = function(AService, BService, CService) {
    BaseController.call(this, AService, BService);

    this.cService = CService;
}

MyController.$inject = ['AService', 'BService', 'CService'];

//Note: you'll need to add a polyfill for Object.create if you want to support ES3.
MyController.prototype = Object.create(BaseController.prototype);

如果您发现在子控制器中指定所有参数太麻烦,您可以随时注入$injector并将其传递给基本控制器。

答案 1 :(得分:1)

@rob回答是正确的。完全有正当理由仍希望$scope注入您的控制器,$watch $on $emit $broadcast等等。当然,在某些情况下,您可以使用指令或服务来逃避此要求,但并不总是值得花时间或复杂性。

我已经给出了controller as语法,但发现在我的大多数用例中,我仍然依赖于控制器中的$scope。我不喜欢这个,所以我最终得到了以下约定:

var MyController = function($scope) {
  $scope.vm = {};
  var vm = $scope.vm;

  vm.propA = 1;
  vm.propB = 2;
  vm.funcA = function(){};

  $scope.$watch('vm.propA' function() {
  });
}

所以它采用了“旧学校”的方法,但有了新的学校感觉。视图中的所有内容都会挂起vm