angular的uiRouter服務學習(2)


本篇接着上一篇 angular的uiRouter服務學習(1) 繼續講解uiRouter的用法

本篇主要講解uiRouter的嵌套狀態&嵌套視圖

 

嵌套狀態的方法:

狀態和狀態之間可以互相嵌套,狀態的嵌套共有以下幾種方式:

1.使用'.state()'進行嵌套. 比如 .state('contact',{}).state('contact.list',{})

2.使用 ui-router.stateHelper 來創建狀態嵌套樹. 這種方式需要另外引入依賴,所以很少被使用.也就不具體詳解了

3.定義狀態的'parent'屬性,屬性值是一個字符串,就是父狀態的名字.比如 {parent:'contacts'}

4.定義狀態的'parent'屬性,屬性值是一個對象,對象就是父狀態對象.比如 {parent:contacts}

 

使用.state()來創建嵌套狀態:

可以對$stateProvider使用.state()來指定狀態的嵌套繼承,比如下面的例子:contacts.list就是contacts的一個子狀態:

html:

<div>
  <a href="contacts">查看視圖</a>
  <a href="contacts/list">查看嵌套視圖</a>
  <ui-view>點擊鏈接后內容會被加載在這里</ui-view>
</div>

js

var nest = angular.module('nest',['ui.router']);
nest.config(function($stateProvider){
    $stateProvider.state('contacts',{
        url:'/contacts',
        templateUrl:'contacts.html'
    }).state('contacts.list',{
        url:'/list',
        templateUrl:'contacts.list.html'
    })
});

contacts.html

<h4>聯系人列表:</h4>
<ui-view></ui-view>

contacts.list.html

<p>我是contacts.list的內容</p>

*需要注意的是,子狀態的url是以父狀態的url為baseUrl的.所以這里子狀態的url應該是'/contacts/list'

 

定義狀態的'parent'屬性,屬性值是一個字符串: 

可以通過狀態的parent屬性來指定它的父狀態.

js:

nest.config(function($stateProvider){
    $stateProvider.state('contacts',{
        url:'/contacts',
        templateUrl:'contacts.html'
    }).state('list',{
        url:'/list',
        templateUrl:'contacts.list.html',
        parent:'contacts'
    })
});

這種方式和上一中方式的區別在於,子狀態不需要使用 '父狀態.子狀態' 這種格式.但是需要指定子狀態的parent屬性為'父狀態名'

 

基於對象的狀態實現嵌套狀態: 

如果你不喜歡上面說到的兩種方式,那么還可以使用基於對象的狀態: 為狀態添加一個name屬性,然后給子狀態設置parent屬性為父狀態對象.

需要注意的是,使用這種方式,子狀態的name屬性命名規則必須和.state()方法一樣,按照'父狀態.子狀態'的格式來命名

var contacts = {
    name:'parent',    //特意不取名叫'contacts'
    url:'/contacts',
    templateUrl:'contacts.html'
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts
};
nest.config(function($locationProvider,$stateProvider){
    $stateProvider.state(contacts).state(list);
});

 

狀態的注冊順序: 

狀態的注冊順序無關緊要,你也可以先注冊子狀態再注冊父狀態.它會被放在隊列里直到父狀態被注冊的時候才被注冊.

 

父狀態必須存在:  

如果你只注冊了一個子狀態,比如contacts.list, 你就必須定義一個叫做contacts的父狀態,(定義先后順序無所謂,但一定要定義),否則的話,將不會有狀態被注冊.contacts.list這個狀態會被放在隊列中,直到contacts狀態被定義. 如果你不定義父狀態,也不會有任何的報錯.所以需要注意,為了讓子狀態生效,必須定義父狀態.

 

狀態取名規則: 

沒有任何兩個狀態可以擁有相同的名字. 當使用.state()來創建嵌套狀態的時候,父狀態沒有被指定,而是通過推斷得到的. 當不使用.state()來創建嵌套狀態的時候,parent屬性必須被定義,但即使是兩個擁有不同父狀態的子狀態,你依然不能給它們取相同的名字.

 

狀態和視圖的嵌套: 

當應用處於一個特定的狀態時(也就是某個狀態被激活時),這個狀態的所有祖先狀態也都被激活了. 比如上面的所有例子: 當 'contacts.list' 狀態被激活,'contacts' 狀態也被隱式的激活了,因為它是 'contacts.list'的父狀態.

子狀態會把它的視圖模板加載到父狀態的模板的 ui-view 元素中去.

比如上面的這些例子,只要<a href="contacts/list">查看嵌套視圖</a>被點擊,contacts.list狀態被激活,contacts狀態也會被隱式的激活.

 

子狀態從父狀態繼承了什么?

子狀態從父狀態繼承了以下兩項: 

  • 父狀態中通過resolve定義的依賴
  • 父狀態自定義的data屬性

     其余的,比如控制器,模板,url,等都不會被繼承...

resolve繼承的栗子:

核心代碼:

var contacts = {
    name:'parent',
    url:'/contacts',
    templateUrl:'contacts.html',
    resolve:{
        resA:function(){
            return {value:'A'}
        }
    },
    controller:function($scope,resA){
        $scope.a = resA.value
    }
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts,
    resolve:{
        resB:function(resA){
            return {value:resA.value+'B'}
        }
    },
    controller:function($scope,resB){
        $scope.b = resB.value
    }
};
nest.config(function($locationProvider,$stateProvider){
    $locationProvider.html5Mode({enabled:true}).hashPrefix('!');
    $stateProvider.state(contacts).state(list);
});

contacts.html:

{{a}}    //A

contacts.list.html:

{{a}}    //A
{{b}}    //AB

可以看到,contacts.list子狀態繼承了contacts父狀態里resolve的依賴'resA'

需要注意: 如果你想在子狀態實例化之前解析完父狀態的resolve項里的某個promise依賴,那么,這個promise依賴必須被注入到子狀態里去.

data繼承的栗子:

核心代碼:

var contacts = {
    name:'parent',
    url:'/contacts',
    templateUrl:'contacts.html',
    data:{
        dataA:'a',
        dataB:'b'
    },
    controller:function($scope,$state){
        $scope.a = $state.current.data.dataA;
    }
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts,
    controller:function($scope,$state){
        $scope.a = $state.current.data.dataA;
        $scope.b = $state.current.data.dataB;
    }
};
nest.config(function($locationProvider,$stateProvider){
    $locationProvider.html5Mode({enabled:true}).hashPrefix('!');
    $stateProvider.state(contacts).state(list);
});

contacts.html:

{{a}}    //a

contacts.list.html:

{{a}}    //a
{{b}}    //b

可以看到,父狀態的data屬性都被子狀態繼承了

 

狀態的繼承是基於視圖的繼承的

注意,scope作用域的繼承和狀態的繼承無關,它只和視圖之間的嵌套關系有關.

很有可能有這種情況: 子狀態的視圖不僅用於被填充到父狀態的視圖中,也可能被填充到很多其他地方.在這種情況下.只有被填充到父狀態的子狀態的視圖,才能繼承父狀態的scope,這種繼承只是angular本身的scope繼承機制,和狀態繼承機制是無關的.所以被填充到其他地方的視圖是不能訪問到父狀態的scope的. 

 

抽象狀態

一個抽象狀態它擁有自己的子狀態,但是它不能激活自己. 它只能當子狀態被激活的時候,隱式的被激活.

如果要讓一個狀態成為抽象狀態,需要給它設置abstract屬性為true

下面是幾種抽象狀態常用的場合:

  • 給子狀態們的url提供一個基礎url.
  • 插入帶有ui-view(s)的視圖模板,顯示子狀態們通用的內容,而ui-view部分供各個子狀態不同的視圖模板來填充.
    • 可以給視圖添加一個控制器
    • 另外,這樣也可以把$scope對象繼承給子狀態.但是注意,就如同上一點所說的,這是通過angular的scope的視圖繼承機制實現的,不是狀態繼承    
  • 通過data屬性,給子狀態們提供數據.
  • 通過resolve屬性,給子狀態們提供依賴.
  • 通過觸發onEnter和onExit回調,來處理一些事情.
  • 以上幾種情況的混合.

注意: 抽象狀態也需要帶有<ui-view>元素來讓子狀態視圖填充,所以,如果你創建抽象狀態是為了給子狀態提供基礎url,提供resolve依賴,data數據,或者調用onEnter和onExit回調,那么你需要在template屬性中設置視圖模板為:''<ui-view/>". 

下面簡單舉幾個栗子:

栗子1:給子狀態們的url提供一個基礎url.

html:

<div>
  <a href="contacts">查看視圖</a>
  <a href="contacts/list">查看嵌套視圖1</a>
  <a href="contacts/detail">查看嵌套視圖2</a>
  <ui-view>點擊鏈接后內容會被加載在這里</ui-view>
</div>

js:

var contacts = {
    abstract:true,
    name:'parent',
    url:'/contacts',
    template:'<ui-view/>'
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts
};
var detail = {
    name:'parent.detail',
    url:'/detail',
    templateUrl:'contacts.detail.html',
    parent:contacts
};
nest.config(function($locationProvider,$stateProvider){
    $locationProvider.html5Mode({enabled:true}).hashPrefix('!');
    $stateProvider.state(contacts).state(list).state(detail);
});

contacts.list.html:

<p>我是contacts.detail</p>

contacts.detail.html:

<p>我是contacts.detail</p>

當url變為'contacts/list'和'contacts/detail'的時候,會激活相應的狀態

------------------------------------------------------------------------------------------------------------------------------------------

栗子2: 父狀態插入帶有ui-view(s)的視圖模板,顯示子狀態們通用的內容,而ui-view部分供各個子狀態不同的視圖模板來填充.

html同上.

js:

var contacts = {
    abstract:true,
    name:'parent',
    url:'/contacts',
    templateUrl:'contacts.html'
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts
};
var detail = {
    name:'parent.detail',
    url:'/detail',
    templateUrl:'contacts.detail.html',
    parent:contacts
};
nest.config(function($locationProvider,$stateProvider){
    $locationProvider.html5Mode({enabled:true}).hashPrefix('!');
    $stateProvider.state(contacts).state(list).state(detail);
});

contacts.html:

<h4>聯系人列表:</h4>
<ui-view></ui-view>

無論切換哪個子狀態,contacts.html中的<h4>聯系人列表:</h4>部分都是通用的.

------------------------------------------------------------------------------------------------------------------------------------------

栗子3: 混合使用

html:

<div>
  <a href="contacts">查看視圖</a>
  <a href="contacts/list">查看嵌套視圖1</a>
  <ui-view>點擊鏈接后內容會被加載在這里</ui-view>
</div>

js:

var contacts = {
    abstract:true,
    name:'parent',
    url:'/contacts',
    templateUrl:'contacts.html',
    controller:function($scope){
        $scope.contacts = [{id:0,name:'code_bunny'},{id:1,name:'white_bunny'},{id:2,name:'black_bunny'}]
    }
};
var list = {
    name:'parent.child',
    url:'/list',
    templateUrl:'contacts.list.html',
    parent:contacts
};
var detail = {
    name:'parent.detail',
    url:'/detail/:id',
    templateUrl:'contacts.detail.html',
    parent:contacts,
    controller:function($scope,$stateParams){
        $scope.id = $stateParams.id
    }
};
nest.config(function($locationProvider,$stateProvider){
    $locationProvider.html5Mode({enabled:true}).hashPrefix('!');
    $stateProvider.state(contacts).state(list).state(detail);
});

contacts.html:

<h4>聯系人列表:</h4>
<ui-view></ui-view>

contacts.list.html:

<ul>
  <li ng-repeat="contact in contacts">
    <a href="contacts/detail/{{contact.id}}">{{contact.name}}</a>
  </li>
</ul>

contacts.detail.html:

<p>{{contacts[id]['name']}}</p>

 

完整代碼: https://github.com/OOP-Code-Bunny/angular/tree/master/uiRouter

參考網站: https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM