Angular路由2

URL参数

基本参数

通常,url动态部分被称为参数,有几个选项用于指定参数。基本参数如下:

1
2
3
4
5
6
7
8
9
10
$stateProvider
    .state('contacts.detail', {
        // 这里设置了url参数
        url: "/contacts/:contactId",
        templateUrl: 'contacts.detail.html',
        controller: function ($stateParams) {
            // If we got here from a url of /contacts/42
            expect($stateParams).toBe({contactId: 42});
        }
    })

或者,你也可以使用花括号的方式来指定参数:

1
2
// 与前面的设置方法等效
url: "/contacts/{contactId}"

示例:

  • '/hello/' - 只匹配'/hello/'路径,没有对斜杠进行特殊处理,这种模式将匹配整个路径,而不仅仅是一个前缀。
  • '/user/:id' - 匹配'/user/bob''/user/1234!!!',甚至还匹配'/user/',但是不匹配'/user''/user/bob/details'。第二个路径段将被捕获作为参数"id"
  • '/user/{id}' - 与前面的示例相同,但使用花括号语法。

含正则表达式的参数

使用花括号的方式可以设置一个正则表达式规则的参数:

1
2
// 只会匹配 contactId 为1到8位的数字
url: "/contacts/{contactId:[0-9]{1,8}}"

示例:

  • '/user/{id:[^/]*}' - 与'/user/{id}'相同
  • '/user/{id:[0-9a-fA-F]{1,8}}' - 与前面的示例相似,但只匹配1到8为的数字和字符
  • '/files/{path:.*}' - 匹配任何以'/files/'开始的URL路径,并且捕获剩余路径到参数'path'中。
  • '/files/*path' - 与前面相同,捕获所有特殊的语法。

警告:不要把捕获圆括号写进正则表达式,ui-router 的 UrlMatcher 将为整个正则表达式添加捕获。

Query Parameters

可以通过?来指定参数作为查询参数

1
2
url: "/contacts?myParam"
// 匹配 "/contacts?myParam=value"

如果你需要不止一个查询参数,请用&分隔:

1
2
url: "/contacts?myParam1&myParam2"
// 匹配 "/contacts?myParam1=value1&myParam2=wowcool"

绝对路由(^)

如果你使用绝对 url 匹配的方式,那么你需要给你的url字符串加上特殊符号"^"

1
2
3
4
5
6
7
8
9
$stateProvider
  .state('contacts', {
     url: '/contacts',
     ...
  })
  .state('contacts.list', {
     url: '^/list',
     ...
  });

路由将成为:

  • 'contacts'状态将匹配"/contacts"
  • 'contacts.list'状态将匹配"/list"。子状态的url没有附在父状态的url之后的,因为使用了^

$stateParams 服务

之前看到的$stateParams服务是一个对象,包含 url 中每个参数的键/值。$stateParams可以为控制器或者服务提供 url 的各个部分。
注意:$stateParams服务必须与一个控制器相关,并且$stateParams中的“键/值”也必须事先在那个控制器的url属性中有定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 如果状态中 url 属性是:
url: '/users/:id/details/{type}/{repeat:[0-9]+}?from&to'

// 当浏览
'/users/123/details//0'

// $stateParams 对象将是
{ id:'123', type:'', repeat:'0' }

// 当浏览
'/users/123/details/default/0?from=there&to=here'

// $stateParams 对象将是
{ id:'123', type:'default', repeat:'0', from:'there', to:'here' }

使用$stateParams的两个陷阱

  • 只有当状态被激活并且状态的所有依赖项都被注入时,$stateParams对象才存在。这代表你不能再状态的resolve函数中使用$stateParams对象,可以使用$state.current.params来代替。
1
2
3
4
5
6
7
8
9
10
$stateProvider.state('contacts.detail', {  
   resolve: { 
      someResolve: function($state){ 
         //*** 不能在这里使用 $stateParams , the service is not ready ***//
         //*** 使用 $state.current.params 来代替 ***//
         return $state.current.params.contactId + "!" 
      }; 
   },
   // ...
})
  • 在状态控制器中,$stateParams对象只包含那些在状态中定义的参数,因此你不能访问在其他状态或者祖先状态中定义的参数。
1
2
3
4
5
6
7
8
9
10
11
12
$stateProvider.state('contacts.detail', {
   url: '/contacts/:contactId',   
   controller: function($stateParams){
      $stateParams.contactId  //*** Exists! ***//
   }
}).state('contacts.detail.subitem', {
   url: '/item/:itemId', 
   controller: function($stateParams){
      $stateParams.contactId //*** 注意! DOESN'T EXIST!! ***//
      $stateParams.itemId //*** Exists! ***//  
   }
})
$state 对象提供自定义数据
$stateProvider
  .state(‘blog.index', {
    templateUrl: ’templates/blog_index.html',
    data: {
        current_page: 1,
        page_size: 20
    } 
})

上面 data 对象就是自定义数据,

里面定义了2页面的当前页和显示内容条数


在视图对应的 controller 中我们就可以通过下面的方法来获取自定义数据.

console.log($state.current.data.current_page);  // 1
console.log($state.current.data.page_size);  // 20

自定义数据也可以被附加到状态控制对象state configObject.该数据和预载入数据resolve属性相似,但是该数据不会被注入到控制器中,promise也不会被预载入,它的用途是从父状态传递数据到子状态。

onEnter,onExit 回调函数

当应用进入或者离开当前状态的视图时会调用这两个函数。这两个函数可以访问预载入的数据。这两个回调函数使开发者可以根据状态改变来采取某些动作,例如在用户要离开时可以弹出对话框‘你确定吗?’以及防止意外操作等。



state事件 

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){ ... })

$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){ ... })

$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ ... })

$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){ ... })


view事件 

View被加载但是DOM树构建之前时: 

$scope.$on('$viewContentLoading', function(event, viewConfig){ ... }); 

View被加载而且DOM树构建完成时: 

$scope.$on('$viewContentLoaded', function(event){ ... }); 


页面跳转
<a href="#/blog/1234”>博客详情</a> 
<a ui-sref=“blog.detail({blogID:blogID})”>博客详情</a>
$state.go(‘blog.detail', {blogID:blogID});


when()

该函数需要两个参数:1.当前的路径,2.需要重定向到的路径(或者是需要在路径被访问是运行的函数)。设置重定向前需要为$urlRouterProvider设置when函数来接受一个字符串。例如,当希望重定向一个空的路由到/inbox:

.config(function($urlRouterProvider) {
  $urlRouterProvider.when('', '/inbox');});

如果传递的是函数,在路径被匹配时该函数会被执行,处理器返回如下3个值中的一个: - falsy,该回应告诉$urlRouter没有匹配到当前url规则,应该尝试匹配新的路径,这样能保证用户访问了正常的路径。 - 字符串,$urlRouter将该字符串当做重定向的路径。 - TRUE 或者 undefined,该回应告诉$urlRouter,url已被处理

otherwise()

和ngRoute的otherwise()函数相似,在用户提交的路径没有被定义的时候它将重定向到指定的页面。这是个创建’默认‘路径的好方法。 otherwise()只接受一个参数,要么函数要么字符串,字符串必须为合法的url路由地址,函数则会在没有任何路径被匹配的时候被运行。

.config(function($urlRouterProvider) {
  $urlRouterProvider.otherwise('/');
  // or  $urlRouterProvider.otherwise(
    function($injector, $location) {
      $location.path('/');
    });});
rule()

如果想越过任何URL的匹配或者在其他路由前做路由修改,则可以使用rule()函数。在使用它的时候必须返回一个合法的代表路径的字符串。

app.config(function($urlRouterProvider){
  $urlRouterProvider.rule(
    function($injector, $location) {
      return '/index';
    });})
最后貼两行代码

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="bootstrap.min.css">
        <script src="jquery.min.js"></script>
        <script src="angular.js"></script>
        <script src="angular-ui-router.js"></script>
        <script src="bootstrap.min.js"></script>
        <script type="text/javascript">
            var app = angular.module('myapp', ['ui.router']);
            app.config(['$stateProvider', function($stateProvider) {
                $stateProvider.state('index', {
                    url: '/index',
                    views : {
                        'main1' : {
                            template: 'hello world1'
                        },
                        'main2' : {
                            template: 'hello world2'
                        }
                    }
                });
            }]);
        </script>
    </head>
    <body ng-app="myapp">
        <a href="#" ui-sref="index">click</a>
        <div ui-view="main1"></div>
        <div ui-view="main2"></div>
    </body>
</html>


<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="bootstrap.min.css">
        <script src="jquery.min.js"></script>
        <script src="angular.js"></script>
        <script src="angular-ui-router.js"></script>
        <script src="bootstrap.min.js"></script>
        <script type="text/javascript">
            var app = angular.module('myapp', ['ui.router']);
            app.config(['$stateProvider', function($stateProvider) {
                $stateProvider
                .state('index', {
                    url: '/index',
                    template: 'parent<div ui-view="main1"></div>{{content}}<div ui-view="main2"></div>parent',
                    controller: ['$scope', 'parent', function($scope, parent) {
                        console.log(parent)
                        console.log('after 5s..');
                        $scope.content = 'hello world';
                    }],
                    resolve: {
                        parent : ['$q', '$timeout', function ($q, $timeout) {
                            var defer = $q.defer();
                            $timeout(function () {
                                defer.resolve('return value');
                            }, 2000);
                            console.log('before 5s..')
                            console.log(defer.promise)
                            return defer.promise;
                        }]
                    }
                })
                .state('index.about', {
                    url : '/about', // final path is /index/about, use ^ can be just /about
                    views : {
                        'main1' : { //'main1@'
                            template: 'main1',
                            // resolve:{}
                            controller : ['parent', 'child', function(parent, child) {
                                //调用自身的解决项,以及父路由的解决项
                                console.log(child, parent);
                            }]
                        },
                        'main2' : { //'main2@'
                            template: 'main2'
                        }
                    },
                    resolve: {
                        child: ['parent', function (parent) {   // 调用父路由的解决项
                            return parent + ' and child';
                        }]
                    },
                });
            }]);
        </script>
    </head>
    <body ng-app="myapp">
        <a href="#" ui-sref="index.about">click</a>
        <div ui-view></div>
        <div ui-view="main1"></div><!-- main1@ -->
        <div ui-view="main2"></div><!-- main1@ -->
    </body>
</html>


关于ui-view如何匹配模板

$stateProvider
    .state('contacts.detail', {
        url: '/{contactId:[0-9]{1,4}}',
        views: {
            '' : {
                templateUrl: 'app/contacts/contacts.detail.html',
            },
            'hint@': {
                template: 'This is contacts.detail populating the "hint" ui-view'
            },
            'menuTip': {
                templateProvider: ['$stateParams', function($stateParams) {
                    return '<hr><small class="muted">Contact ID: ' + $stateParams.contactId + '</small>';
                }]
            }
        }
    });

首先注意这是一个嵌套模板,父state是contacts,它肯定也有template, 而且一定包含<ui-view>


看views下的三个key(也就是视图名):‘’,‘hint@’, ‘menuTip’

menuTip比较好理解,就是ui-view="menuTip"所在的页面使用下面对应的模板,那么这个页面在哪,默认是在当前state的父亲state的页面,这里contacts.detail的父亲是contacts,所以模板放在contacts的template中的ui-view="menuTip",而contacts的template是放在主页面index.html中的ui-view中的,换句话说这个主页面又算是contacts的父亲.

menuTip的解释也正说明一般子路由的模板是填充父路由中的ui-view.

对于'hint@', 和上面的menuTip比较其实多了一个@,那意思就不一样的了。上面menuTip等同于menuTip@contacts,这边的话因为自己加了@,就变成了hint@' ', ‘ ’表示最顶层的state,也就是index.html中的ui-view。所以最终hint@对应的模板填充到了index.html中的ui-view中,而不是contacts的ui-view中.

对于'',没有@,那么父state是contacts,最后变成' '@contacts,也就是说填充到父state的ui-view="" 中.


这个概念比较绕,不懂还是要多看几遍.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值