4.9

【angularjs】【学习心得】路由

    AngularJS自带有路由模块ngRoute,但是有经验的老师都推荐我们使用功能更完善更强大的ui-router来做路由。那到底什么是路由呢?我自己的理解是:路由可以看作一个总控制器,它会根据页面的不同状态来填充页面的内容,这就是路由的主要用处。前端路由能极大地减少对服务器资源的请求数量,因此在前端做路由显得尤为重要。

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

    由于路由是控制整个应用的显示状态的,所以我们要让路由模块第一时间接管整个应用。

    使用ui-router很简单,下载它的包,在index.html中引入js文件,然后在模块的依赖中引入即可。    

1
     var routerApp = angular.module('routerApp', ['ui.router']);

    ui-router的本质其实是向我们预留的部分填充模板,它会在页面中去寻找ui-view这条指令,然后根据当前页面状态把对应的模板填充到ui-view所在的区块中。

    比如一个典型的页面是nav+footer固定不变,中间主要部分作为内容显示区域时常发生变化。对应的页面结构就是    

1
2
3
4
5
     < body >
         < nav >This is nav</ nav >
         < div  ui-view></ div >
         < footer >This is footer</ footer >
     </ body >

    然后我们的路由根据页面的状态,选择不同的html模板填充到ui-view的这个div里面。

    在js中具体怎么使用ui-router呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
routerApp.config( function ($stateProvider,$urlRouterProvider) {
         $urlRouterProvider.otherwise( '/index' );
         $stateProvider
                .state( 'index' ,{
                        url           :  '/index' ,
                        templateUrl    :  'tpls/index.html'
                })
                .state( 'list' ,{
                        url           :  '/list' ,
                        templateUrl     :  'tpls/list.html'
                })
                .state( 'detail' ,{
                        url           :  '/detail' ,
                        templateUrl     :  'tpls/detail.html'
                });
});

    以上就是angular路由最基本的模板。但是要注意一个问题,state的第一个参数并不是匹配规则,而是叫状态名,也就是说这个参数事实上可以是任意的,它用来给当前状态增加一个名字,触发路由规则还是看url的内容。比如这样

1
2
3
4
     .state( 'home' ,{
         url         :  '/index' ,
         templateUrl :  'tpls/index.html'
     })

    我们必须要地址栏输入www.xx.com/index,才会加载对应的模板而不是输入home,它仅仅是一个名字而已。

    但是说,这个名字也是有它的作用的。看一个例子就明白了。

    index.html

1
2
3
     < nav >This is the nav</ nav >
     < div  ui-view></ div >
     < footer >This is the footer</ footer >

    list.html

1
2
3
4
     < div >
         < p >this is the list page</ p >
         < div  ui-view></ div >
     </ div >

    list-main.html

1
2
3
         < div >
                < p >This is list-main Page</ p >
         </ div >

 

    如果我们的路由这么写

1
2
3
4
5
6
7
8
                .state( 'aaa' ,{
                        url           :  '/list' ,
                        templateUrl :  'tpls/list.html'
                })
                .state( 'bbb' ,{
                        url           :  '/list/main' ,
                        templateUrl :  'tpls/list-main.html'
                })

   那当我们在浏览器中输入www.xx.com/list/main的时候,页面结果为

      5472d6ee0001fc2803350157.jpg                                                

    如果我们的路由这么写

1
2
3
4
5
6
7
8
                .state( 'aaa' ,{
                        url            :  '/list' ,
                        templateUrl :  'tpls/list.html'
                })
                .state( 'aaa.bbb' ,{
                        url            :  '/main' ,
                        templateUrl :  'tpls/list-main.html'
                })

    那当我么输入www.xx.com/list/main的时候,页面结果为

    5472d6fd0001ebcf03690177.jpg

    也就是说state的的第一个参数为页面定义了一个名字,这个页面的模板只能放到它的父级中的ui-view去。如果没有.这种写法,那么默认的父级是index.html,所以第一种写法bbb模板的父级是index.html,所以输入/list/main时会把对应模板加载到index.html中的ui-view里面。而第二种写法aaa.bbb,这意思是说bbb的父级是aaa,所以bbb的模板要放到aaa模板(也就是list.html)中的ui-view中。这时的url是在aaa页面的url后的url。

    当然还有页面的嵌套,这部分其实大漠老师在视频中已经讲得很清楚了。

    这是路由需要注意的一个作用域问题。

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

    当然路由还有很多其他问题,因为路由是angularjs中很重要的一部分,但基本的用法就是上面所讲的了,如果把所有静态页面都写好了,那么用以上的内容就已经能做出一个精美的web了。现在学习了路由的基本用法,其它问题的话我们碰到一个再解决一个吧。


 


2014-11-24 2115 浏览 7 回答

    今天还是来说一下angular中的路由模块。我们实际项目中,各个页面的切换是经常会与Auth相关的。比如我网站的后台,是需要登录过的用户才能进去,那么我们用angularJS做前端路由的时候应该怎么完成这个功能呢

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

    我们还是先设想一个最简单的场景吧。我们的应用有两个页面,登录页面后内容页面,要求是必须要验证登录成功后才能进入内容页面,下面我们一起来实现一下这个例子吧。当然我觉得我的方法可能会比较Low,但是学习阶段我们能先把功能做出来比什么都重要。

    首先用bootstrap来写一个简单的登录页面吧。具体bootstrap代码我就不说了,我们关注的是angular在这里面如何用起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
< div  class = "col-md-offset-3 col-md-4" >
     < form  class = "form"  role = "form"  name = "loginForm"  ng-submit = "loginCheck()" >
         < div  class = "form-group" >
             < label  class = "control-label" >用户名</ label >
             < input  type = "text"  class = "form-control"  required  placeholder = "请输入管理员账号"  ng-model = "admin.username" >
         </ div >
         < div  class = "form-group" >
             < label  class = "control-label" >密码</ label >
             < input  type = "password"  class = "form-control"  ng-model = "admin.pwd"  required  placeholder = "请输入密码" >
         </ div >
         < div  ng-show = "showError"  class = "alert alert-danger alert-dismissible"  role = "alert" >
               < button  ng-click = "showError=false"  type = "button"  class = "close"  data-dismiss = "alert" >< span  aria-hidden = "true" >&times;</ span >< span  class = "sr-only" >关闭</ span ></ button >
               用户名或密码错误!!你还有一次机会
         </ div >
 
         < input  type = "submit"  class = "btn btn-primary btn-lg"  value = "登录"  ng-disabled = "loginForm.$invalid" >
     </ form >      
</ div >

    效果如下

        54788faf000197b405000227.jpg

    当然我之前还有一些css的布局,粘代码过去可能会出错哦,至少得在最外层加一个div class="row"

    还可以看见,我给登录按钮加了个ng-disabled,当表单没有通过验证的时候是不能点登录的。

    然后我加了一个提示的tips,用到了ng-show,在controller里会有一个showError的属性来控制它的显示,当验证账号密码错误时showError为true。

    当我们验证出错的时候

        547892c90001675104860298.jpg

    

    接着我们来看一下路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var  myApp = angular.module( 'myApp' , [ 'ui.router' , 'myModule' ]);
myApp.run( function ($rootScope, $state, $stateParams){
     $rootScope.$state = $state;
     $rootScope.$stateParams = $stateParams;
     $rootScope.$state.isLogin =  false ;
});
myApp.config( function ($stateProvider, $urlRouterProvider) {
     $urlRouterProvider.otherwise( '/login' );
     $stateProvider
         .state( 'login' ,{
             url        :  '/login' ,
             templateUrl :  'tpls/login.html' ,
             controller  :  'LoginController'
         })
         .state( 'index' ,{
             url        :  '/index' ,
             templateUrl :  'tpls/index.html' ,
             controllerProvider :  function ($rootScope){
                 if ($rootScope.$state.isLogin ==  false ){
                     $rootScope.$state.go( 'login' );
                 }
                 return  function (){};
             }
         });
     }

    因为在整个页面中我们都会用到登录状态,所以我把登录状态绑定到rootscope中,isLogin刚开始是false表示未登录。

    接着看路由里面,login这个很简单,主要看index页面。

    关键的一步就是index的controller,在这里我选择用controllerProvider的方式来生成controller,可以看到我们最后实际上是返回的一个空的function,但是在返回空controller之前(index页面还没有解析),我可以做一些事情,那就是验证权限啦!

    如果$rootScope.$state.isLogin为false也就是还没有登录,那就直接跳转到登录页面。跳转用到了$state里面的go方法,go中的变量就是我们每个页面的状态名,也就是state的第一个参数。我是go('login'),它就跳转到state的第一个参数是login的那个页面去了,也就是登录页面。换句话说,如果我们登录提交后验证没有成功,当我们在地址栏输入/index的时候会跳到登录页面的哦。

    那么再来看看我们的验证模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
myModule
    .controller( 'LoginController' function ($scope,$rootScope,$http){
       $scope.showError =  false ;
       $scope.loginCheck =  function (){
         var  username = $scope.admin.username;
     var  pwd = $scope.admin.pwd;
     var  loginSuccess =  false ;
     http.get( '/acm-admin/data/user.json' )
      .success( function (response){
        for ( var  i=0; i<response.length; i++){
          if (response[i].username == username && response[i].pwd == pwd){
         $rootScope.$state.isLogin =  true ;
         loginSuccess =  true ;
         $rootScope.$state.go( 'index' );
          }
        }
        if (!loginSuccess){
         $scope.showError =  true ;
        }
     });
    }
   })

    

    初始化我们给showError一个值为false,不要显示错误提示框。然后来看看验证登录的这个方法。首先获取到用户输入的用户名和密码,设置登录成功的状态的false。然后通过$http.get,到指定的地方去取一个json文件,很显然这是个假数据,我们把预设的用户名和密码存放到这个json文件中。取出预设的用户名和密码之后就和用户输入的来进行对比,相信这都很简单,大家肯定能看明白。如果用户名和密码都对上了,那么就把登录状态设置为true,登录成功也设置为true。然后用$state的go方法跳转到Index页面。

    如果登录信息验证失败,那么就把showError赋为true,页面上就会显示提示信息咯。

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

    怎么样,很简单吧。当然还有其它实现这一功能的方法,而且我上述的方法很可能还有诸多安全隐患,而且模块的分工也是不明确的,淡然实际部署不推荐这么写了。我们可以优化改进的地方很多,比如验证的模块是不是应该独立出去呢,或者用户有没有什么办法能轻易绕过这个登录保护呢?这就留待小伙伴们自己探究了……继续学习angular去了,大家晚安!!

2014-11-28
回复  2
    今天来说一点angularjs中看起来很简单但是实践起来又有不少问题的ng-class吧

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

    不过还是先说一下和angular无关的一个js的小坑,不知道大家遇到过没有,就是json格式的文件。之前一直都在js中定义json数组,或者从php后台用json_encode编码后直接返回,从没有自己写过json格式的数据,今天就遇到点麻烦。

    在js中定义json数组这么写就好了:

1
     var  arr = [{a:1,b:2},{a:5,b:10}];

    但是在json文件中千万不能这么写

1
     [{a:1,b:2},{a:5,b:10}]

    必须给key加上引号才行哦。今天调试好久才发现这个问题,也算个教训吧……

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

    然后说ng-class这个东西,老师讲的时候一句带过,用的时候还是需要费些时间的。

    我总结了一下通过ng-class给元素动态地加class有4种做法,下面一个一个来说。

    先看一下官方的说明

    547747ed00019d2705000171.jpg

    不知道大家能不能看清,给个链接吧https://code.angularjs.org/1.3.0-beta.11/docs/api/ng/directive/ngClass

    大致翻译一下就是说ng-class指令有3中操作方式,通过ng-class等于的表达式计算出来的值的类型来决定是哪种

    方式1: 当它的值为一个字符串时,它就会把用空格分开的字符串加到class中

    方式2: 当值为一个数组时,它每个字符串元素都会被加到class中

    方式3: 当值为一个对象时(key=>value),把value为true的key加到class中


    首先是最不推荐的

1
2
3
4
5
6
7
     < div  ng-class = "{{myclass}}" ></ div >
     ....
     < script >
         function someController($scope){
             $scope.myclass = "xxx";
         }
     </ script >

    上面这种方法效果上来说没问题,但是完全没必要用ng-class,普通的也能实现这个效果。而且在controller中控制样式总感觉有点儿别扭……


    然后说另一种用法

1
     < div  ng-class = "{true :'red', false :'green'}[someVariable]" ></ div >

    这种用法就是说variable为true时,就给元素加上red这个class,如果variable为false就加上green这个class,这个在逻辑比较简单的时候还是蛮好用的。


    下一种适合需要添加多个类的时候,也就是ng-class的值为一个对象

1
2
3
4
5
6
     < p  ng-class = "{strike: deleted, bold: important, red: error}" >Map Syntax Example</ p >
     < input  type = "checkbox"  ng-model = "deleted" > deleted (apply "strike" class)
     < br >
     < input  type = "checkbox"  ng-model = "important" > important (apply "bold" class)
     < br >
     < input  type = "checkbox"  ng-model = "error" > error (apply "red" class)

    上面代码ng-class就是一个对象,我们把deleted,important,error进行双向数据绑定,当我们在checkbox勾选时,它们变为true,然后对应的key就被加到class中,效果图

    547749e500016b1f02880112.jpg

    

    还有一种就是数组类型的,数组都每个字符串元素都会被加到class中

1
2
3
4
5
6
     < p  ng-class = "[style1, style2, style3]" >Using Array Syntax</ p >
     < input  ng-model = "style1"  placeholder = "Type: bold, strike or red" >
     < br >
     < input  ng-model = "style2"  placeholder = "Type: bold, strike or red" >
     < br >
     < input  ng-model = "style3"  placeholder = "Type: bold, strike or red" >

    当我们在样式中定义好bold,strike,red;类的样式后,我们输入这些字符串就会出现效果

    54774a860001390801760135.jpg

    大概就是这几种用法,我推荐大家用对象来添加对象,那样最好控制逻辑也清楚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值