码迷,mamicode.com
首页 > 其他好文 > 详细

ui-router学习笔记

时间:2015-11-13 06:13:41      阅读:314      评论:0      收藏:0      [点我收藏+]

标签:

State Manager.

$stateProvider 和angular的router功能相似,但它只关心状态(state)的变化

一个最简单的state形式如下所示:

<!-- in index.html -->
<body ng-controller="MainCtrl">
  <section ui-view></section>
</body>
// in app-states.js (or whatever you want to name it)
$stateProvider.state(‘contacts‘, {
  template: ‘<h1>My Contacts</h1>‘
})

temlate 如何插入

如果state 被激活了,该 state 的template 就会被自动地插入到它的parent template的 ui-view 中。如果该state处于top-level(即没有父级的state).则它的parent template 就是 index.html

激活一个state

有三种激活state的方式

  • 1. 调用 $state.go(), 还有一个类似的方法 $state.transitionTo,官方文档说是low level 的方法,大部分情况都用 go(),所以...

    $state.go(to, [, toParams], [, options])

    $state.go() 提供一个转换到 new state 的方便快捷的方式,它会在内部调用 $state.transitionTo 方法,并且自动设置options 参数为

    { location: true, inherit: true, relative: $state.$current, notify: true }
    

    to

    $state.go()可以传入一个state name 或者 一个相对路径作为第一个参数, 如果一个路径以 ^ 或者 . 开头,则改路径是相对的,否则是绝对的。

    几个例子:

    • $state.go(‘contact.detail‘) 会转换到 ‘contact.detail‘ state
    • $state.go(‘^‘) 转换到 parent state.
    • $state.go(‘^.sibling‘) 转换到 sibling state.
    • $state.go(‘.child.grandchild‘) 转换到 grandchild state.

    toParams

    toParams 以一个对象直接量的形式填充到 $stateParams

    如果参数为指定将会从当前已经定义的参数中继承, sibilings state 可以共享继承自parent state的参数,child state 可以继承当前state的参数

    options

    各种配置参数

  • 2.  点击包含ui-sref指令的链接
    用法:
    ui-sref=‘stateName‘   --- 转换到一个state,无附加参数
    ui-sref=‘stateName({param: value, param: value})‘; --- 转换到一个state,并且传递参数 

  • 3.  链接跳转到 state 对应的 url
    提一下url传递参数的方法,
    url: ‘/contacts/:contactId‘ ----- 当访问 /contact/42时, $stateParams 为 {contactId: 42}
    url: ‘/contacts/{contactId}‘ ----- 和上面一样
    例子:
    ‘ /hello/ ‘ -- 只匹配 url 为 /hello/ 
    ‘ /user/:id ‘ -- 匹配 url 为 ‘/user/bob‘ 或者 ‘/user/1234‘, 也能匹配 ‘/user/‘. 但是不匹配 ‘/user‘ , ‘user/bob/detail‘
    ‘ /user/{id} ‘ -- 与前面一个相同
    ‘ /user/{id: int} ‘  -- 参数正则匹配, : 后面可以写一个正则,但是不能使用分组 

resolve

resolve属性是一个可选的对象,应当被作为依赖注入到controller中,当 $stateChangeSuccess 事件触发时,resolve会在controller实例化之前被解析。

resolve是一对键值对,其中

  • key - {string}:a name of a dependency to be injected into the controller.
  • factory - {string | function}:
    如果是字符串,则该字符串为service的别名
    如果是函数,则该函数被注入,其返回值被当作依赖。如果返回值是一个promise, 它会在controller实例化之前被解析,并将返回值注入到controller中
    例子:
    $stateProvider.state(‘myState‘, {
          resolve:{
    
             // 直接返回一个值,由于不是promise,会被立即解析
             simpleObj:  function(){
                return {value: ‘simple!‘};
             },
    
             // 返回要给promise
             // 这是一种典型的用法
             // 你需要在function中注入你用到的所有服务,比如这里的 $http服务
             promiseObj:  function($http){
                // $http returns a promise for the url data
                return $http({method: ‘GET‘, url: ‘/someUrl‘});
             },
      
             // 另外一种常见用法,如果你需要对返回值进行操作,可以使用链式的 .then() 方法
             promiseObj2:  function($http){
                return $http({method: ‘GET‘, url: ‘/someUrl‘})
                   .then (function (data) {
                       return doSomeStuffFirst(data);
                   });
             },        
    
             // 直接使用已经定义的service的名称,
             // 这里会在当前的module中寻找名为 translations 的service,并将其返回
             // 注意: 这里的service也可以返回一个promise,然后像上面那样操作
             translations: "translations",
    
             // 直接将 service 注入到 resolve 函数的例子
             // service 返回一个promise
             // 小建议: 注入 $stateParams 来访问 url 参数
             translations2: function(translations, $stateParams){
                 // 我们假定 getLang 是一个service 的方法,使用$http服务从url为 "/:lang/home" 来获取数据
                 return translations.getLang($stateParams.lang);
             },
    
             // 返回自定义promise的例子
             greeting: function($q, $timeout){
                 var deferred = $q.defer();
                 $timeout(function() {
                     deferred.resolve(‘Hello!‘);
                 }, 1000);
                 return deferred.promise;
             }
          },
          // controller 会等上面所有的item完全解析之后才进行实例化。
          // 在下面的例子中,所有的promise对象在controller实例化之前都已经全部初始化并且注入到controller中等待被使用
          controller: function($scope, simpleObj, promiseObj, promiseObj2, translations, translations2, greeting){
              $scope.simple = simpleObj.value;
    
              // You can be sure that promiseObj is ready to use!
              $scope.items = promiseObj.data.items;
              $scope.items = promiseObj2.items;
    
              $scope.title = translations.getLang("english").title;
              $scope.title = translations2.title;
    
              $scope.greeting = greeting;
          }
       }) 

嵌套state

几种嵌套state的方法

1. 使用 . 号,例如 .state(‘ contacts.list ‘, {})

2. 使用 ui-router.stateHelper 从一个state树创建state

3. 使用 parent 属性和string类型的 parent state. 例如, parent: ‘contacts‘

4. 使用 parent 属性和object类型的 parent state. 例如, parent: contacts (这里 contacts 是一个stateObject)

Child State 从 Parent State继承了啥

  • 解析后的resolve依赖(原文是 resolved dependencies via resolve, 我翻译的什么玩意儿啊)
  • 自定义的data属性

abstract states 的 child state 会继承它的url prefix。除此之外没有其他的继承

Inherited Resolved Dependencies(0.2.0新增)

child state 会从它的祖先state(s)继承 resolved dependencies, 并且可以覆盖他们。你可以在 child states 的 resolve function 中注入 resolved dependencies。

直接看例子吧,翻译成中文说不明白

$stateProvider.state(‘parent‘, {
      resolve:{
         resA:  function(){
            return {‘value‘: ‘A‘};
         }
      },
      controller: function($scope, resA){
          $scope.resA = resA.value;
      }
   })
   .state(‘parent.child‘, {
      resolve:{
         // 这里的 resA 继承自parent state, 可以将其注入到 resolve function,和 controller 中
         resB: function(resA){
            return {‘value‘: resA.value + ‘B‘};
         }
      },
      controller: function($scope, resA, resB){
          $scope.resA2 = resA.value;
          $scope.resB = resB.value;
      }

注意:resolve 的key必须被注入到 child states 中,如果你想在 children state 实例化之前解析 promise 的话

 

抽象state (Abstract States)

抽象state 可以拥有child state,但是不能使其自身得到激活. 一个抽象state就是不能被转换到的状态,当它的任何一个后代state被激活时它会被隐式的激活。

你可能会用到抽象state的一些场景

1,在所有 child state的url之前插入一个url prefix

2,通过它自身的 ui-view(s) 插入一个 template,用来装载 child states

  • 指定一个可选的controller 给template,controller与template必须匹配(匹配啥呢?)
  • 另外,children states 可以继承$scope对象,但是要明确一点,$scope是通过 view 的嵌套来继承的,而不是state,state的嵌套与$scope的继承没有任何关系

3,提供 resolved dependencies 给 child states 使用

4,提供 自定义data给child states 或者 事件监听器使用

5,执行 onEnter 或 onExit 函数

记住:抽象state 仍然需要它自己的 template 来装载它的孩子们。所以,如果你正在使用抽象state做上面的事情,你需要额外的设置 template: ‘<ui-view/>‘;

 

抽象state使用示例:

为后代插入url prefix 的例子

$stateProvider
    .state(‘contacts‘, {
        abstract: true,
        url: ‘/contacts‘,

        // Note: abstract still needs a ui-view for its children to populate.
        // You can simply add it inline here.
        template: ‘<ui-view/>‘
    })
    .state(‘contacts.list‘, {
        // url will become ‘/contacts/list‘
        url: ‘/list‘
        //...more
    })
    .state(‘contacts.detail‘, {
        // url will become ‘/contacts/detail‘
        url: ‘/detail‘,
        //...more
    })

插入template 来装载后代的例子

$stateProvider
    .state(‘contacts‘, {
        abstract: true,
        templateUrl: ‘contacts.html‘
    })
    .state(‘contacts.list‘, {
        // contacts.list.html的html片段会被插入到 contacts.html中
        templateUrl: ‘contacts.list.html‘
    })
    .state(‘contacts.detail‘, {
        // 同样contacts.detail.html的html片段也会被插入到 contacts.html中
        templateUrl: ‘contacts.detail.html‘
    })
<!-- contacts.html -->
<h1>Contacts Page</h1>
<div ui-view></div>

综合应用

$stateProvider
    .state(‘contacts‘, {
        abstract: true,
        url: ‘/contacts‘,
        templateUrl: ‘contacts.html‘,
        controller: function($scope){
            $scope.contacts = [{ id:0, name: "Alice" }, { id:1, name: "Bob" }];
        }           
    })
    .state(‘contacts.list‘, {
        url: ‘/list‘,
        templateUrl: ‘contacts.list.html‘
    })
    .state(‘contacts.detail‘, {
        url: ‘/:id‘,  // url 会变为 ‘/contacts/:id‘
        templateUrl: ‘contacts.detail.html‘,
     // 继承了contacts state 的$scope controller: function($scope, $stateParams){ $scope.person = $scope.contacts[$stateParams.id]; } })
<!-- contacts.html -->
<h1>Contacts Page</h1>
<div ui-view></div>
<!-- contacts.list.html -->
<ul>
    <li ng-repeat="person in contacts">
        <a ng-href="#/contacts/{{person.id}}">{{person.name}}</a>
    </li>
</ul>
<!-- contacts.detail.html -->
<h2>{{ person.name }}</h2>

 多个命名的views

当你需要设置多个views时,要用到state的views属性,states是要给对象

views 会覆盖 state 的template 属性

当你设置了 views 对象时,state 的 templateUrl, template, templateProvider属性会被忽略,在这种情况下,你需要一个parent view 来安置这些 views, 你可以定义一个包含一个template的抽象state,一个在该抽象state template 内部的child state来容纳这个 views 对象。

views 对象中的key 名应该与 ui-view中的名称匹配

<!-- index.html -->
<body>
  <div ui-view="filters"></div>
  <div ui-view="tabledata"></div>
  <div ui-view="graph"></div>
</body>
$stateProvider
  .state(‘report‘, {
    views: {
      ‘filters‘: { ... templates and/or controllers ... },
      ‘tabledata‘: {},
      ‘graph‘: {},
    }
  })

每个在views中的view可以单独设置它自己的template,controller和resolve

$stateProvider
  .state(‘report‘,{
    views: {
      ‘filters‘: {
        templateUrl: ‘report-filters.html‘,
        controller: function($scope){ ... controller stuff just for filters view ... }
      },
      ‘tabledata‘: {
        templateUrl: ‘report-table.html‘,
        controller: function($scope){ ... controller stuff just for tabledata view ... }
      },
      ‘graph‘: {
        templateUrl: ‘report-graph.html‘,
        controller: function($scope){ ... controller stuff just for graph view ... }
      }
    }
  })

view names 相对vs绝对

每个view会遵从 viewname@statename 的机制在后台分配一个绝对名称,这里 viewname 是写在view 指令中那个,statename 是 view指令所在的 那个state 的绝对名称。

你可以根绝绝对命名语法写自己的view names

上面要给例子可以用绝对命名改写成以下形式:

.state(‘report‘,{
    views: {
      ‘filters@‘: { },
      ‘tabledata@‘: { },
      ‘graph@‘: { }
    }
  })

这里  view names 全部采用绝对命名, 分别指向位于未命名state的 template 中的三个 views ( "filters" , "tabledata", "graph").由于root state未命名,所以这里@后面什么也没有。未命名的 template 就是 index.html

绝对命名法可以让我们做很多强大的view 定位,看栗子

<!-- index.html (root unnamed template) -->
<body ng-app>
<div ui-view></div> <!-- contacts.html plugs in here -->
<div ui-view="status"></div>
</body>


<!-- contacts.html -->
<h1>My Contacts</h1>
<div ui-view></div>
<div ui-view="detail"></div>


<!-- contacts.detail.html -->
<h1>Contacts Details</h1>
<div ui-view="info"></div>
$stateProvider
  .state(‘contacts‘, {
    // 这个template会被插入到为命名的ui-view中,因为他是top level 的     
    //state,它的父级state 的template就是index.html
    templateUrl: ‘contacts.html‘   
  })
  .state(‘contacts.detail‘, {
    views: {
        ////////////////////////////////////
        // Relative Targeting             //
        // Targets parent state ui-view‘s //
        ////////////////////////////////////

        // 相对地命中父级state-contacts中的 detail view 
        // <div ui-view=‘detail‘/> within contacts.html
        "detail" : { },            

        // 相对地命中父级state-contacts中的未命名view
        // <div ui-view/> within contacts.html
        "" : { }, 

        ///////////////////////////////////////////////////////
        // 绝对 Targeting using ‘@‘                      //
        //命中当前state或者其祖先state的任何view //
        ///////////////////////////////////////////////////////

        //绝对命中当前state, ‘contacts.detail‘.
        // <div ui-view=‘info‘/> within contacts.detail.html
        "info@contacts.detail" : { }

        // 绝对命中 ‘contacts‘ state 中的detail view
        // <div ui-view=‘detail‘/> within contacts.html
        "detail@contacts" : { }

        // 绝对命中父级state-- ‘contacts‘ 中的未命名view.
        // <div ui-view/> within contacts.html
        "@contacts" : { }

        //绝对命中未命名根state中的status view.
        // <div ui-view=‘status‘/> within index.html
        "status@" : { }

        // 绝对命中未命名根state中的未命名view
        // <div ui-view/> within index.html
        "@" : { } 
  });

搞得很烦,到此为止!!

 

ui-router学习笔记

标签:

原文地址:http://www.cnblogs.com/walle2/p/4960733.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!