【问题标题】:scope and controller instantiation with ui router使用 ui 路由器的范围和控制器实例化
【发布时间】:2015-03-17 18:30:24
【问题描述】:

我对控制器何时被实例化感到困惑。此外,嵌套状态时如何实例化控制器。我可能对范围如何附加到视图和控制器感到困惑,也就是说,如果每个视图都有自己的控制器和范围,或者它们是否共享相同的范围。

有人可以解释一下控制器何时被实例化吗?在嵌套路由下,所有视图是否共享一个控制器和范围?当我切换状态并返回某个状态时会发生什么情况,是否会实例化另一个控制器?

以下是我的路线(配置文件):

.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'
      }
    }
  })

【问题讨论】:

    标签: angularjs angularjs-scope angular-ui-router angularjs-routing


    【解决方案1】:

    要获得更详细的答案,我们可以/应该观察源代码并查看文档。让我尝试解释所有三个问题(并引用代码和文档)。

    1.控制器什么时候被实例化?

    这里我们可以观察ui-view指令的代码:

    [$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]

    控制器与视图相关。那些views,在.state() 内部定义为views 对象:

    .state('...', {
      // The view definition
      views : {
        '' : {
          template: ...
          controller: ...
          resolve: ..
        }
      },
      resolve: ...
    }
    

    因此,每当 viewui-view)填充状态视图内部定义的设置时,它几乎就像一个标准但增强的指令

    1) 找到模板,
    2) 解决了
    ...
    x) 控制器被实例化...

    视图目标(ui-view 指令)可以使用名称,并且可以由层次结构中的不同状态填充。

    这可能意味着,一个视图中可能有一个内容(例如title,由parent定义并被替换孩子

    // 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') - 几乎相同,只是视图将取自子状态/视图定义'title' : { ...}。这将替换ui-view="title" 的内容,并将按上述方式实例化

    每次我们从父母到孩子从孩子到父母时都会发生这种情况。

    2。在嵌套路由下,所有视图是否共享一个控制器和范围?

    一个简单的答案是NO,没有no共同分享。

    事实上,每个控制器都有自己的作用域,它是从父视图作用域创建的。首先是文档:

    What Do Child States Inherit From Parent States?

    ...

    Scope Inheritance by View Hierarchy Only

    请记住,如果您的状态视图是嵌套的,则范围属性只会沿状态链继承。范围属性的继承与您的状态的嵌套无关,而与您的视图(模板)的嵌套有关。

    您完全有可能拥有嵌套状态,其模板在您的站点内的各种非嵌套位置填充 ui-views。在这种情况下,您不能期望在子状态视图中访问父状态视图的范围变量。

    所以,每当我们的controller (以及带有模板、控制器的视图...) 注入到父目标ui-view="..." 时,它都会获得继承范围:

    newScope = scope.$new();
    

    简而言之,这意味着 JS 对象 (例如scope.Model = {} 可以在子级和父级之间共享。

    $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.当我切换状态并返回一个状态时会发生什么 - 是否会实例化另一个控制器?

    这取决于。

    如果父子视图(记得上面的ui-view="title"被子视图替换,然后重新创建(从子视图过渡到父视图) -这样的控制器将被重新初始化(上面讨论过)。

    但是当我们谈到主父视图 (通常是未命名的),它代表父视图 (例如未命名的使用控制器“ParentMainCtrl”查看下方)

    .state('parent', {
      views : {
        '' : {  //  // the main parent view
          controller: 'ParentMainCtrl',
        }
        'title@parent'
        'tooltip@parent'
      },
    

    然后我们可以确定这样的控制器没有被重新实例化。它存在于其所有孩子的生命周期中,加上父母的一个(未选择子状态)

    要重新加载此视图/控制器,我们必须使用选项reload

    $state.go(to, params, options)

    ... 选项选项对象。选项有:

    • ...
    • reload - {boolean=false},如果为 true,即使状态或参数没有改变,也会强制转换,也就是重新加载相同的状态。它与 reloadOnSearch 不同,因为当您想要在一切都相同(包括搜索参数)时强制重新加载时,您会使用它。

    希望能有所帮助。如需更多信息,请查看以下资源:

    【讨论】:

      【解决方案2】:

      每当您访问特定状态时,控制器都会被实例化。例如,在第一次访问app.pincode.pincodeLogin 时,会构造一个AppController 和两个PincodeControllers,假设您的模板正确,每个都有自己的视图。切换到'app.pincode.settings' 会破坏最里面的控制器并用新的控制器替换它,尽管层次结构中较高的两个控制器不会被触及。范围遵循标准 AngularJS 的继承模式,它们不是孤立的。

      您可能希望删除子状态中的控制器(并在父控制器中处理业务逻辑)或为每个状态使用不同的控制器 - 不同模板和视图的相同控制器通常是设计不良的标志.

      【讨论】:

      • 创建的两个 PincodeController,一个用于 pincode,另一个用于 pincode.pincodeLogin?此外,如果我修改我的代码以删除存根阶段上的控制器。那会创建 1 个密码控制器和一个应用程序控制器吗?另外,当导航子状态时……新的密码控制器会被实例化吗?
      • 1.是的,2. 是的,3. 是的,代替之前的子状态控制器
      • 所以我做了这些改变。我在 pincode 父控制器中添加了 abstract: true 并删除了子状态中的控制器。我还在控制器顶部添加了一条警告语句,以查看控制器何时被实例化。我注意到警报语句仅在应用程序加载时开始触发一次。我希望每次切换状态时都会发出警报。我的期望是正确的还是我搞砸了?
      • 最后一件事,您提到控制器在您第一次访问该状态时被实例化。当您重新访问状态时会发生什么,是否会再次实例化新的控制器?
      • 再次是的 :) 但仅适用于实际更改的部分。如果它是根状态的控制器,它是所有其他状态的父级,它将只被实例化一次。将 ui-router 想象成这个懒惰的家伙,只会做必要的工作来满足您的要求,并且没有缓存或记忆。
      【解决方案3】:

      当第一次加载相应的视图时,控制器会被实例化。

      例如,如果您有 3 个选项卡与 3 个控制器关联 - 那么与默认视图关联的控制器将首先实例化。接下来,当您加载其他视图时,关联的控制器也会被实例化。

      但有趣的是,一旦视图被加载到 DOM 中 - 默认情况下它会被缓存。当一个视图被导航离开时,它的元素留在 DOM 中,并且它的范围与 $watch 循环断开连接。当导航到一个已经缓存的视图时,它的范围会被重新连接,并且留在 DOM 中的现有元素成为活动视图。

      【讨论】:

      • 我可以知道我们应该如何使用不同的控制器来获得不同的视图。说点击 tab-2 我只想加载 tab2Controller。
      • @John 你能详细说明这个问题吗?顺便说一句 - 您使用的是哪个版本的 Ionic?
      • 请参考此链接 [stackoverflow.com/questions/27768033/…,最后他在所有嵌套视图中使用名为 editController 的同一控制器,但我想使用不同的控制器说 editDetailsControlleredit.detailseditInfoController 用于编辑信息。我可以知道我们怎样才能做到这一点吗??
      • @John :尽管我并不清楚这种控制器隔离的目的。然而,这里有一个工作示例 [plnkr.co/edit/35j5b1Tfl5RTPtBApHCs?p=preview] 展示了 2 个不同的控制器如何用于嵌套视图。请查阅。主要思想是将父范围注入到子控制器中——这样通过范围链——你可以访问父模型。
      • 请参考这个 [stackoverflow.com/questions/42087649/…,几分钟前我发布了这个问题。希望它可以帮助你,帮助我:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-24
      • 2016-04-10
      • 2015-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多