zoukankan      html  css  js  c++  java
  • AngularJS中ui-router全攻略

    首先是angular-ui-router的基本用法。

    ■ 如何引用依赖angular-ui-router

    angular.module('app',["ui.router"])
        .config(function($stateProvider){
            $stateProvider.state(stateName, stateCofig);
        })

    ■ $stateProvider.state(stateName, stateConfig)

    stateName是string类型
    stateConfig是object类型

    //statConfig可以为空对象
    $stateProvider.state("home",{});

    //state可以有子父级
    $stateProvider.state("home",{});
    $stateProvider.state("home.child",{})

    //state可以是链式的
    $stateProvider.state("home",{}).state("about",{}).state("photos",{});

    stateConfig包含的字段:template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, data

    ■ $urlRouteProvider

    $urlRouteProvider.when(whenPath, toPath)
    $urlRouterProvider.otherwise(path)
    $urlRouteProvider.rule(handler)

    ■ $state.go

    $state.go(to, [,toParams],[,options])
    形参to是string类型,必须,使用"^"或"."表示相对路径;
    形参toParams可空,类型是对象;
    形参options可空,类型是对象,字段包括:location为bool类型默认true,inherit为bool类型默认true, relative为对象默认$state.$current,notify为bool类型默认为true, reload为bool类型默认为false

    $state.go('photos.detail')
    $state.go('^')到上一级,比如从photo.detail到photo
    $state.go('^.list')到相邻state,比如从photo.detail到photo.list
    $state.go('^.detail.comment')到孙子级state,比如从photo.detail到photo.detial.comment

    ■ ui-sref

    ui-sref='stateName'
    ui-sref='stateName({param:value, param:value})'

    ■ ui-view

    ==没有名称的ui-view

    <div ui-view></div>
    
    $stateProvider.state("home",{
        template: "<h1>hi</h1>"
    })

    或者这样配置:

    $stateProvider.state("home"{
        views: {
            "": {
                template: "<h1>hi</h1>"
            }
        }
    })

    ==有名称的ui-view

    <div ui-view="main"></div>
    
    $stateProvider.state("home",{
        views: {
            "main" : {
                template: "<h1>hi</h1>"
            }
        }
    })

    ==多个ui-view

    <div ui-view></div>
    <div ui-view="data"></div>
    
    $stateProvider.state("home",{
        views: {
            "":{template: "<h1>hi</h1>"},
            "data": {template: "<div>data</div>"}
        }
    })


    ■ 项目文件结构

    node_modules/
    partials/
    .....about.html
    .....home.html
    .....photos.html
    app.js
    index.html

    ■ 创建state和view

    app.js

    var photoGallery = angular.module('photoGallery',["ui.router"]);
    
    photoGallery.config(function($stateProvider, $urlRouterProvider){
        $urlRouterProvider.otherwise('/home');
    
        $stateProvider
            .state('home',{
                url: '/home',
                templateUrl: 'partials/home.html'
            })
            .state('photos',{
                url: '/photos',
                templateUrl: 'partials/photos.html'
            })
            .state('about',{
                url: '/about',
                templateUrl: 'partials/about.html'
            })
    })

    index.html

    <!DOCTYPE html>
    <html lang="en" ng-app="photoGallery">
    <head>
      <meta charset="UTF-8">
      <title></title>
      <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"/>
    </head>
    <body>
    
      <h1>Welcome</h1>
      <div ui-view></div>
    
    <script src="node_modules/jquery/dist/jquery.js"></script>
    
    <script src="node_modules/angular/angular.js"></script>
    <script src="node_modules/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="node_modules/angular-animate/angular-animate.js"></script>
    
    <script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
    <script src="node_modules/angular-bootstrap/ui-bootstrap-tpls.js"></script>
    
    <script src="app.js"></script>
    </body>
    </html>

    ■ state之间的跳转

    index.html

    <nav class="navbar navbar-inverse">
    <div class="container-fluid">
      <div class="navbar-header">
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a ui-sref="home" class="navbar-brand">Home</a>
      </div>
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
          <li>
            <a ui-sref="photos">Photos</a>
          </li>
          <li>
            <a ui-sref="about">About</a>
          </li>
        </ul>
      </div>
    </div>
    </nav>
    
    <div ui-view></div>

    以上通过ui-sref属性完成state之间的跳转。

    ■ 多个view以及state嵌套

    有时候,一个页面上可能有多个ui-view,比如:

    <div ui-view="header"></div>
    <div ui-view="body"></div>

    假设,以上页面属于一个名称为parent的state中。

    我们知道在ui-router中,一个state大致是这样设置的:

    .state('content.photos',{
        url: 'photos',
        views:{
            "body@content":{templateUrl: 'partials/photos.html'}
        }
    })

    所有state下views下的所有键值对(类似 "body@content":{templateUrl: 'partials/photos.html'})都被放到一个键值集合中。而ui-view的工作原理就是根据自己的属性值,到这个键值集合中去找匹配的键,找到就把对应的页面显示出来。


    点击header对应的页面链接,可能会跳转到另外的子页面出现在<div ui-view="body"></div>这个位置。这时候页面出现了子父关系,而每个页面都属于某个state,这样state间就出现了子父关系。这些跳转的子页面,在路由设置中,可能被称为parent.son1, parent.son2...这就是state的嵌套。

    在现有的文件结构上增加content.html, header.html,文件结构变为:


    node_modules/
    partials/
    .....about.html
    .....home.html
    .....photos.html
    .....content.html
    .....header.html
    app.js
    index.html

    content.html 包含了多各ui-view, 一个ui-view和页头相关,保持不变;令一个ui-view和会根据页头上的点击呈现不同的内容


    <div ui-view="header"></div>
    <div ui-view="body"></div>


    header.html 把原先indext.html中nav部分放到这里来

    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <div class="navbar-header">
          <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a ui-sref="content.home" class="navbar-brand">Home</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li>
              <a ui-sref="content.photos">Photos</a>
            </li>
            <li>
              <a ui-sref="content.about">About</a>
            </li>
          </ul>
        </div>
      </div>
    </nav>

    index.html 这时变成了这样

    <div ui-view></div>

    app.js 路由现在这样设置

    var photoGallery = angular.module('photoGallery',["ui.router"]);
    
    photoGallery.config(function($stateProvider, $urlRouterProvider){
        $urlRouterProvider.otherwise('home');
    
        $stateProvider
            .state('content',{
                url: '/',
                views:{
                    "":{templateUrl: 'partials/content.html'},
                    "header@content":{templateUrl: 'partials/header.html'},
                }
            })
            .state('content.home',{
                url: 'home',
                views:{
                    "body@content":{templateUrl: 'partials/home.html'}
                }
            })
            .state('content.photos',{
                url: 'photos',
                views:{
                    "body@content":{templateUrl: 'partials/photos.html'}
                }
            })
            .state('content.about',{
                url:'about',
                views:{
                    "body@content":{templateUrl: 'partials/about.html'}
                }
            })
    })

    这时候,页面是这样呈现出来的:

    → 来到home这个路由

    .state('content.home',{
        url: 'home',
        views:{
            "body@content":{templateUrl: 'partials/home.html'}
        }
    })

    以上,告诉我们partials/home.html将会被加载到与"body@content"匹配的ui-view中。暂时对应的ui-view还没有出现,于是等待。

    → 路由看到index.html上的<div ui-view></div>

    .state('content',{
        url: '/',
        views:{
            "":{templateUrl: 'partials/content.html'},
            "header@content":{templateUrl: 'partials/header.html'},
        }
    })

    于是,就找到了content这个state下views下的 "":{templateUrl: 'partials/content.html'}这个键值对,把partials/content.html显示出来。

    → 分别加载partials/content.html页面上的各个部分

    看到<div ui-view="header"></div>,就加载如下:

    "header@content":{templateUrl: 'partials/header.html'},


    看到<div ui-view="body"></div>,先加载 "body@content":{templateUrl: 'partials/home.html'}


    → 点击header上的链接

    点击<a ui-sref="content.photos">Photos</a>,来到:

    .state('content.photos',{
        url: 'photos',
        views:{
            "body@content":{templateUrl: 'partials/photos.html'}
        }
    })

    把partials/photos.html显示到<div ui-view="body"></div>中去。


    点击<div ui-view="body"></div>,来到:

    .state('content.about',{
        url:'about',
        views:{
            "body@content":{templateUrl: 'partials/about.html'}
        }
    })

    把partials/about.html显示到<div ui-view="body"></div>中去。


    ■ state多级嵌套

    以上,在路由设置中,state名称有content, content.photos有了这样的一层嵌套。接下来,要实现state的多级嵌套。

    在photos.html页面准备加载一个子页面,叫做photos-list.html;
    与photo-list.html页面相邻的还有一个页面,叫做photo-detail.html;
    在photo-detail.html页面上加载一个子页面,叫做photos-detail-comment.html;

    这样,页面有了嵌套关系,state也相应的会有嵌套关系。

    现在,文件结构变成:

    node_modules/
    partials/
    .....about.html
    .....home.html
    .....photos.html
    .....content.html
    .....header.html
    .....photos-list.html
    .....photo-detail.html
    .....photos-detail-comment.html
    app.js
    index.html

    photos.html 加一个容纳子页面的ui-view

    photos
    <div ui-view></div>

    如何到达这个子页面呢?修改header中的相关部分如下:

    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <div class="navbar-header">
          <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a ui-sref="content.home" class="navbar-brand">Home</a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li>
              <a ui-sref="content.photos.list">Photos</a>
            </li>
            <li>
              <a ui-sref="content.about">About</a>
            </li>
          </ul>
        </div>
      </div>

    以上,通过<a ui-sref="content.photos.list">Photos</a>来到photos.html的子页面photos-list.html.

    photos-list.html 通过2种途径到相邻页photo-detail.html

    <h1>photos-list</h1>
    <ul>
      <li><a ui-sref="^.detail">我通过相对路径到相邻的state</a></li>
      <li><a ui-sref="content.photos.detail">我通过绝对路径到相邻的state</a></li>
    </ul>

    photo-detail.html 又提供了来到其子页面photos-detail-comment.html的ui-view

    <h1>photo-details</h1>
    <a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
    <div ui-view></div>

    photos-detail-comment.html 则很简单:
    <h1>photos-detail-comment</h1>

    app.js state多级嵌套的设置为

    var photoGallery = angular.module('photoGallery',["ui.router"]);
    
    photoGallery.config(function($stateProvider, $urlRouterProvider){
        $urlRouterProvider.otherwise('home');
    
        $stateProvider
            .state('content',{
                url: '/',
                views:{
                    "":{templateUrl: 'partials/content.html'},
                    "header@content":{templateUrl: 'partials/header.html'},
                }
            })
            .state('content.home',{
                url: 'home',
                views:{
                    "body@content":{templateUrl: 'partials/home.html'}
                }
            })
            .state('content.photos',{
                url: 'photos',
                views:{
                    "body@content":{templateUrl: 'partials/photos.html'}
                }
            })
            .state('content.photos.list',{
                url: '/list',
                templateUrl: 'partials/photos-list.html'
            })
            .state('content.photos.detail',{
                url: '/detail',
                templateUrl: 'partials/photos-detail.html'
            })
            .state('content.photos.detail.comment',{
                url: '/comment',
                templateUrl: 'partials/photos-detail-comment.html'
            })
            .state('content.about',{
                url:'about',
                views:{
                    "body@content":{templateUrl: 'partials/about.html'}
                }
            })
    })

    ■ 抽象state

    如果一个state,没有通过链接找到它,那就可以把这个state设置为abstract:true,我们把以上的content和content.photos这2个state设置为抽象。

    .state('content',{
        url: '/',
        abstract: true,
        views:{
            "":{templateUrl: 'partials/content.html'},
            "header@content":{templateUrl: 'partials/header.html'},
        }
    })
    ...
    
    
    .state('content.photos',{
        url: 'photos',
        abstract: true,
        views:{
            "body@content":{templateUrl: 'partials/photos.html'}
        }
    })

    那么,当一个state设置为抽象,如果通过ui-sref或路由导航到该state会出现什么结果呢?

    --会导航到默认路由上

    $urlRouterProvider.otherwise('home');

    .state('content.home',{
        url: 'home',
        views:{
            "body@content":{templateUrl: 'partials/home.html'}
        }
    })

    最终把partials/home.html显示出来。

    ■ 使用控制器

    在实际项目中,数据大多从controller中来。

    首先在路由中设置state所用到的控制器以及控制器别名。

    var photoGallery = angular.module('photoGallery',["ui.router"]);
    
    photoGallery.config(function($stateProvider, $urlRouterProvider){
        $urlRouterProvider.otherwise('home');
    
        $stateProvider
            .state('content',{
                url: '/',
                abstract: true,
                views:{
                    "":{templateUrl: 'partials/content.html'},
                    "header@content":{templateUrl: 'partials/header.html'},
                }
            })
            .state('content.home',{
                url: 'home',
                views:{
                    "body@content":{
                        templateUrl: 'partials/home.html',
                        controller: 'HomeController',
                        controllerAs: 'ctrHome'
                    }
                }
            })
            .state('content.photos',{
                url: 'photos',
                abstract: true,
                views:{
                    "body@content":{
                        templateUrl: 'partials/photos.html',
                        controller: 'PhotoController',
                        controllerAs: 'ctrPhoto'
                    }
                }
            })
            .state('content.photos.list',{
                url: '/list',
                templateUrl: 'partials/photos-list.html',
                controller: "PhotoListController",
                controllerAs: 'ctrPhotoList'
            })
            .state('content.photos.detail',{
                url: '/detail',
                templateUrl: 'partials/photos-detail.html',
                controller: 'PhotoDetailController',
                controllerAs: 'ctrPhotoDetail'
            })
            .state('content.photos.detail.comment',{
                url: '/comment',
                templateUrl: 'partials/photos-detail-comment.html'
            })
            .state('content.about',{
                url:'about',
                views:{
                    "body@content":{templateUrl: 'partials/about.html'}
                }
            })
    })

    添加controller.js,该文件用来定义所用到的controller.现在的文件结构为:


    asserts/
    .....css/
    .....images/
    ..........image1.jpg
    ..........image2.jpg
    ..........image3.jpg
    ..........image4.jpg
    node_modules/
    partials/
    .....about.html
    .....home.html
    .....photos.html
    .....content.html
    .....header.html
    .....photos-list.html
    .....photo-detail.html
    .....photos-detail-comment.html
    app.js
    index.html

    controllers.js

    photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
        this.message = 'Welcome to the Photo Gallery';
    }]);
    
    //别名:ctrPhoto
    photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
        this.photos = [
            { id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.jpg', comments:[
                {name: 'user1', comment: 'Nice'},
                { name:'User2', comment:'Very good'}
            ]},
            { id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.jpg', comments:[
                { name: 'user2', comment: 'Nice'},
                { name:'User1', comment:'Very good'}
            ]},
            { id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.jpg', comments:[
                {name: 'user1', comment: 'Nice'}
            ]},
            { id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.jpg', comments:[
                {name: 'user1', comment: 'Nice'},
                { name:'User2', comment:'Very good'},
                { name:'User3', comment:'So so'}
            ]}
        ];
    
        //给子state下controller中的photos赋值
        this.pullData = function(){
            $scope.$$childTail.ctrPhotoList.photos = this.photos;
        }
    }]);
    
    //别名:ctrPhotoList
    photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
        this.reading = false;
        this.photos = new Array();
    
        this.init = function(){
            this.reading = true;
            setTimeout(function(){
                $scope.$apply(function(){
                    $scope.ctrPhotoList.getData();
                });
            }, 1500);
        }
    
        this.getData = function(){
    
            //调用父state中controller中的方法
            $scope.$parent.ctrPhoto.pullData();
    
            /*this.photos = $scope.$parent.ctrPhoto.photos;*/
            this.reading = false;
    
        }
    }]);
    
    
    //别名:ctrPhotoDetail
    photoGallery.controller('PhotoDetailController',['$scope', '$state', function($scope,$state){
    
    }]);

    以上,通过$scope.$$childTail.ctrPhotoList在父state中的controller中拿到子state中的controller;通过$scope.$parent.ctrPhoto在子state中的controller中拿到父state中的controller。

    photos-list.html

    <h1>photos-list</h1>
    <div ng-init="ctrPhotoList.init()">
      <div style="margin:auto;  40px;" ng-if="ctrPhotoList.reading">
        <i class="fa fa-spinner fa-5x fa-pulse"></i>
      </div>
    
      <div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
        <div class="media">
          <div class="media-left" style="15%;">
            <a ui-sref="content.photos.detail">
              <img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="">
            </a>
          </div>
          <div class="media-body">
            <h4 class="media-heading">{{photo.title}}</h4>
            {{photo.description}}
          </div>
        </div>
      </div>
    </div>


    ■ state间如何传路由参数

    在content.photos.detail这个state设置接收一个路由参数。

    .state('content.photos.detail',{
        url: '/detail/:id',
        templateUrl: 'partials/photos-detail.html',
        controller: 'PhotoDetailController',
        controllerAs: 'ctrPhotoDetail'
    })

    photos-list.html 送出一个路由参数

    <h1>photos-list</h1>
    <div ng-init="ctrPhotoList.init()">
      <div style="margin:auto;  40px;" ng-if="ctrPhotoList.reading">
        <i class="fa fa-spinner fa-5x fa-pulse"></i>
      </div>
    
      <div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
        <div class="media">
          <div class="media-left" style="15%;">
            <a ui-sref="content.photos.detail({id:photo.id})">
              <img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="">
            </a>
          </div>
          <div class="media-body">
            <h4 class="media-heading">{{photo.title}}</h4>
            {{photo.description}}
          </div>
        </div>
      </div>
    </div>

    以上,通过<a ui-sref="content.photos.detail({id:photo.id})">把路由参数送出。



    controller.js PhotoDetailController控制器通过$stateParams获取路由参数

    ...
    //别名:ctrPhotoDetail
    photosGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
        function($scope, $state, $stateParams){
    
            var id = null;
            this.photo = null;
            this.init = function(){
                id = parseInt($stateParams.id);
                this.photo = $scope.ctrPhoto.photos[id];
            }
    
        }
    ]);

    photos-detail.html 从以上的PhotoDetailController中获取数据。

    <h1>photo-details</h1>
    <a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
    <a ui-sref="content.photos.list" style="margin-left: 15px;">
      <i class="fa fa-arrow-circle-left fa-2x"></i>
    </a>
    
    <div ng-init="ctrPhotoDetail.init()">
      <img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
           style="margin:auto;  60%;">
      <div class="well well-sm" style="margin:auto;  60%; margin-top: 15px;">
        <h4>{{ctrPhotoDetail.photo.title}}</h4>
        <p>{{ctrPhotoDetail.photo.description}}</p>
      </div>
    
      <div style="margin:auto;  80%; margin-bottom: 15px;">
        <button style="margin-top: 10px; 100%;"
                class="btn btn-default" ui-sref=".comment">Comments</button>
      </div>
    </div>
    
    
    <div ui-view></div>

    ■ state间如何传字符串参数

    在路由中这样设置:

    .state('content.photos.detail.comment',{
        url:'/comment?skip&limit',
        templateUrl: 'partials/photos-detail-comment.html',
        controller: 'PhotoCommentController',
        controllerAs: 'ctrPhotoComment'
    })

    controllers.js 中修改如下

    photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
        this.message = 'Welcome to the Photo Gallery';
    }]);
    
    //别名:ctrPhoto
    photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
        this.photos = [
            { id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.JPG', comments:[
                { name:'User1', comment: 'Nice', imageName: 'man.png'},
                { name:'User2', comment:'Very good', imageName: 'man.png'},
                { name:'User3', comment:'Nice', imageName: 'woman.png'},
                { name:'User4', comment:'Very good', imageName: 'woman.png'},
                { name:'User5', comment:'Very good', imageName: 'man.png'},
                { name:'User6', comment:'Nice', imageName: 'woman.png'},
                { name:'User7', comment:'So so', imageName: 'man.png'}
            ]},
            { id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.JPG', comments:[
                { name:'User1', comment: 'Nice', imageName: 'man.png'},
                { name:'User2', comment:'Very good', imageName: 'man.png'},
                { name:'User3', comment:'Nice', imageName: 'woman.png'},
                { name:'User4', comment:'Very good', imageName: 'woman.png'}
            ]},
            { id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.JPG', comments:[
                { name:'User1', comment: 'Nice', imageName: 'man.png'},
                { name:'User2', comment:'Very good', imageName: 'man.png'},
                { name:'User3', comment:'Nice', imageName: 'woman.png'},
                { name:'User4', comment:'Very good', imageName: 'woman.png'},
                { name:'User5', comment:'Very good', imageName: 'man.png'},
                { name:'User6', comment:'Nice', imageName: 'woman.png'},
                { name:'User7', comment:'So so', imageName: 'man.png'}
            ]},
            { id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.JPG', comments:[
                { name:'User6', comment:'Nice', imageName: 'woman.png'},
                { name:'User7', comment:'So so', imageName: 'man.png'}
            ]}
        ];
    
        //给子state下controller中的photos赋值
        this.pullData = function(){
            $scope.$$childTail.ctrPhotoList.photos = this.photos;
        }
    }]);
    
    //别名:ctrPhotoList
    photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
        this.reading = false;
        this.photos = new Array();
    
        this.init = function(){
            this.reading = true;
            setTimeout(function(){
                $scope.$apply(function(){
                    $scope.ctrPhotoList.getData();
                });
            }, 1500);
        }
    
        this.getData = function(){
    
            //调用父state中controller中的方法
            $scope.$parent.ctrPhoto.pullData();
    
            /*this.photos = $scope.$parent.ctrPhoto.photos;*/
            this.reading = false;
    
        }
    }]);
    
    
    //别名:ctrPhotoDetail
    photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
        function($scope, $state, $stateParams){
    
            var id = null;
            this.photo = null;
            this.init = function(){
                id = parseInt($stateParams.id);
                this.photo = $scope.ctrPhoto.photos[id];
            }
    
        }
    ]);
    
    
    photoGallery.controller('PhotoCommentController', ['$scope', '$state', '$stateParams',
        function($scope, $state, $stateParams){
            var id, skip, limit = null;
            this.comments = new Array();
    
            this.init = function(){
                id = parseInt($stateParams.id);
                var photo = $scope.ctrPhoto.photos[id];
    
    
                if($stateParams.skip){
                    skip = parseInt($stateParams.skip);
                }else{
                    skip = 0;
                }
    
                if($stateParams.limit){
                    limit = parseInt($stateParams.limit);
                }else{
                    limit = photo.comments.length;
                }
    
                this.comments = photo.comments.slice(skip, limit);
    
            }
        }
    ]);

    也就是,$stateParams不仅可以接收路由参数,还可以接收查询字符串参数。



    photo-detail.html 需要把查询字符串参数传递出去

    <h1>photo-details</h1>
    <a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
    <a ui-sref="content.photos.list" style="margin-left: 15px;">
      <i class="fa fa-arrow-circle-left fa-2x"></i>
    </a>
    
    <div ng-init="ctrPhotoDetail.init()">
      <img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
           style="margin:auto;  60%;">
      <div class="well well-sm" style="margin:auto;  60%; margin-top: 15px;">
        <h4>{{ctrPhotoDetail.photo.title}}</h4>
        <p>{{ctrPhotoDetail.photo.description}}</p>
      </div>
    
      <div style="margin:auto;  80%; margin-bottom: 15px;">
        <button style="margin-top: 10px; 100%;"
                class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
      </div>
    </div>
    
    
    <div ui-view></div>

    以上,通过ui-sref=".comment({skip:0, limit:2})把查询字符串传递出去。

    photos-detail-comment.html

    <h1>photos-detail-comment</h1>
    
    <div ng-init="ctrPhotoComment.init()" style="margin-top:15px;">
      <div ng-repeat="comment in ctrPhotoComment.comments" class="well well-sm" style="margin: auto;  60%;">
        <div class="media">
          <div class="media-left media-middle">
            <a href="">
              <img class="img-circle" style="60px;" src="../assets/images/{{comment.imageName}}" alt="">
            </a>
          </div>
          <div class="media-body">
            <h4 class="media-heading">{{comment.name}}</h4>
            {{comment.comment}}
          </div>
        </div>
      </div>
    </div>

    ■ state间如何传递对象

    通过data属性,把一个对象赋值给它。

    .state('content',{
        url: '/',
        abstract: true,
        data:{
            user: "user",
            password: "1234"
        },
        views:{
            "":{templateUrl: 'partials/content.html'},
            "header@content":{templateUrl: 'partials/header.html'},
        }
    })

    给header.html加上一个对应的控制器,并提供注销方法。

    $stateProvider
        .state('content',{
            url: '/',
            abstract: true,
            data:{
                user: "user",
                password: "1234"
            },
            views:{
                "":{templateUrl: 'partials/content.html'},
                "header@content":{
                    templateUrl: 'partials/header.html',
                    controller: function($scope, $rootScope, $state){
                        $scope.logoff = function(){
                            $rootScope.user = null;
                        }
                    }
                }
            }
        })

    添加一个有关登录页的state

    .state('content.login',{
        url:'login',
        data:{
            loginError: 'User or password incorrect.'
        },
        views:{
            "body@content" :{
                templateUrl: 'partials/login.html',
                controller: function($scope, $rootScope, $state){
                    $scope.login = function(user, password, valid){
                        if(!valid){
                            return;
                        }
    
                        if($state.current.data.user === user && $state.current.data.password === password){
                            $rootScope.user = {
                                name: $state.current.data.user
                            }
    
                            // Or Inherited
    
                            /*$rootScope.user = {
                                name: $state.$current.parent.data.user
                            };*/
    
                            $state.go('content.home');                            
                        }else{
                            $scope.message = $state.current.data.loginError;
                        }
    
                    }
                }
            }
        }
    
    })

    添加login.html文件,现在的文件结构为:

    asserts/
    .....css/
    .....images/
    ..........image1.jpg
    ..........image2.jpg
    ..........image3.jpg
    ..........image4.jpg
    node_modules/
    partials/
    .....about.html
    .....home.html
    .....photos.html
    .....content.html
    .....header.html
    .....photos-list.html
    .....photo-detail.html
    .....photos-detail-comment.html
    .....login.html
    app.js
    index.html

    login.html

    <form name="form" ng-submit="login(user, password, form.$valid)">
        <div class="panel panel-primary" style="360px; margin: auto;">
            <div class="panel-heading">
                <h3 class="panel-title">Indentification</h3>
            </div>
            <div class="panel-body">
                <input name="user" type="text" class="form-control" ng-model="user" placeholder="User ..." required>
                <span ng-show="form.user.$error.required && form.user.$dirty" class="label label-danger">Enter the user</span>
                <hr>
                <input name="password" type="password" class="form-control" ng-model="password" placeholder="Password ..." required>
                <span ng-show="form.password.$error.required && form.password.$dirty" class="label label-danger">Enter the password</span>            
            </div>
            <div class="panel-footer">
                <button class="btn btn-default" type="submit">Login</button>
                <button class="btn btn-default" type="reset">Reset</button>
                <span class="label label-danger">{{message}}</span>            
            </div>    
        </div>
    </form>

    header.html 修改如下

    <nav class="navbar navbar-inverse">
          <div class="container-fluid">
            <div class="navbar-header">
              <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">            
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" ui-sref="content.home">Home</a>
            </div>
    
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
              <ul class="nav navbar-nav">
                    <li>
                        <a ui-sref="content.photos.list">Photos</a>    
                    </li>
                    <li>
                        <a ui-sref="content.about">About</a>    
                    </li> 
              </ul>
                <ul class="nav navbar-nav navbar-right">                
                    <li ng-if="user.name" class="dropdown">
                        <a class="dropdown-toggle" role="button" aria-expanded="false" href="#" data-toggle="dropdown">{{user.name}} <span class="caret"></span></a>
                        <ul class="dropdown-menu" role="menu">
                            <li><a ui-sref="content.home" ng-click="logoff()">Sing out</a></li>                        
                        </ul>                    
                    </li>                                
                    <li ng-if="!user.name">
                        <a ui-sref="content.login">Sing In</a>
                    </li>                    
                </ul>    
            </div>
          </div>
        </nav>

    ■ onEnter和onExit事件

    .state('content.photos.detail',{
        url: '/detail/:id',
        templateUrl: 'partials/photos-detail.html',
        controller: 'PhotoDetailController',
        controllerAs: 'ctrPhotoDetail',
        resolve:{
            viewing: function($stateParams){
                return{
                    photoId: $stateParams.id
                }
            }
        },
        onEnter: function(viewing){
    
            var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
            if(!photo){
                photo = {
                    views: 1,
                    viewing: 1
                }
            }else{
                photo.views = photo.views + 1;
                photo.viewing = photo.viewing + 1;
            }
    
            sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
    
        },
        onExit: function(viewing){
            var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
            photo.viewing = photo.viewing - 1;
            sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
        }
    })

    在PhotoDetailController中:

    photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
        function($scope, $state, $stateParams){
    
            var id = null;
            this.photo = null;
            this.viewObj = null;
            this.init = function(){
                id = parseInt($stateParams.id);
                this.photo = $scope.ctrPhoto.photos[id];
                this.viewObj = JSON.parse(sessionStorage.getItem($stateParams.id));
            }
    
        }
    ]);

    photos-detail.html

    <h1>photo-details</h1>
    <a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
    <a ui-sref="content.photos.list" style="margin-left: 15px;">
      <i class="fa fa-arrow-circle-left fa-2x"></i>
    </a>
    
    <div ng-init="ctrPhotoDetail.init()">
      <img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
           style="margin:auto;  60%;">
      <div class="well well-sm" style="margin:auto;  60%; margin-top: 15px;">
        <div class="well well-sm pull-right" style=" 100px;">
          <i>Views <span class="badge">{{ctrPhotoDetail.viewObj.views}}</span></i>
        </div>
        <div class="well well-sm pull-right" style=" 110px;">
          <i>Viewing <span class="badge">{{ctrPhotoDetail.viewObj.viewing}}</span></i>
        </div>
    
        <h4>{{ctrPhotoDetail.photo.title}}</h4>
        <p>{{ctrPhotoDetail.photo.description}}</p>
      </div>
    
      <div style="margin:auto;  80%; margin-bottom: 15px;">
        <button style="margin-top: 10px; 100%;"
                class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
      </div>
    </div>
    
    
    <div ui-view></div>

    ■ StateChangeStart事件



    controller.js 增加如下

    photoGallery.controller('RootController', ['$scope', '$state', '$rootScope',
        function($scope, $state, $rootScope){
            $rootScope.$on('$stateChangeStart',
                function(event, toState, toParams, fromState, fromParams){
                    if(toState.data.required && !$rootScope.user){
                        event.preventDefault();
                        $state.go('content.login');
                    }
                });
    
        }
    ]);

    修改content这个state:

    .state('content',{
        url:'/',
        abstract: true,
        data:{
            user: "user",
            password: "1234"
        },
        views:{
            "":{
                templateUrl: 'partials/content.html',
                controller: 'RootController'
            },
            "header@content":{
                templateUrl: 'partials/header.html',
                controller: function($scope, $rootScope, $state){
                    $scope.logoff = function(){
                        $rootScope.user = null;
                    }
                }
            }
        }
    
    })

    content.photos.detail这个state

        .state('content.photos.detail',{
            url:'/detail/:id',
            templateUrl: 'partials/photos-detail.html',
            controller: 'PhotoDetailController',
            controllerAs: 'ctrPhotoDetail',
            data:{
                required: true
            },
            resolve:{
                viewing: function($stateParams){
                    return{
                        photoId: $stateParams.id
                    }
                }
            },
            onEnter: function(viewing){
                
                var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
                if(!photo){
                    photo = {
                        views: 1,
                        viewing: 1
                    }
                }else{
                    photo.views = photo.views + 1;
                    photo.viewing = photo.viewing + 1;
                }
                
                sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
                
            },
            onExit: function(viewing){
                var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
                photo.viewing = photo.viewing - 1;
                sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
            }
        })

       
    以上,添加了        
    data:{
        required: true
    }    


    同理,content.photos.detail.comment这个state

    .state('content.photos.detail.comment',{
            url:'/comment?skip&limit',
            templateUrl: 'partials/photos-detail-comment.html',
            controller: 'PhotoCommentController',
            controllerAs: 'ctrPhotoComment',
            data:{
                required: true
            }
        })


    ■ StateNotFound事件

    photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
                function($scope, $state, $rootScope){
                    
                    $rootScope.$on('$stateChangeStart', 
                    function(event, toState, toParams, fromState, fromParams){
                        
                        if(toState.data.required && !$rootScope.user){
                            event.preventDefault();
                            $state.go('content.login');
                            return;
                        }    
                        
                    });
                    
                    $rootScope.$on('$stateNotFound', 
                    function(event, unfoundState, fromState, fromParams){
                        event.preventDefault();
                        $state.go('content.notfound');
                    });
                }
    ]);

    添加一个state:

        .state('content.notfound',{
            url:'notfound',
            views: {
                "body@content": {templateUrl: 'partials/page-not-found.html'}    
            }        
        })


    page-not-found.html

    <div class="well well-sm" style="margin: 20px;">
        <i class="fa fa-frown-o fa-4x pull-left"></i><h3>404 - Sorry! Not found your page.</h3>
    </div>

    ■ StateChangeSuccess事件

    photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
                function($scope, $state, $rootScope){
                    
                    $rootScope.accessLog = new Array();
                    
                    $rootScope.$on('$stateChangeStart', 
                    function(event, toState, toParams, fromState, fromParams){
                        
                        if(toState.data.required && !$rootScope.user){
                            event.preventDefault();
                            $state.go('content.login');
                            return;
                        }    
                        
                    });
                    
                    $rootScope.$on('$stateNotFound', 
                    function(event, unfoundState, fromState, fromParams){
                        event.preventDefault();
                        $state.go('content.notfound');
                    });
                    
                    $rootScope.$on('$stateChangeSuccess', 
                    function(event, toState, toParams, fromState, fromParams){
                        $rootScope.accessLog.push({
                            user: $rootScope.user,
                            from: fromState.name,
                            to: toState.name,
                            date: new Date()
                        });
                    });
                    
                }
    ]);

    添加一个state

        .state('content.log',{
            url:'log',
            data:{
                required: true
            },
            views: {
                "body@content": {templateUrl: 'partials/log.html'}    
            }        
        })

    log.html

    <h1><i class="fa fa-file-text-o"></i> Access Log</h1>
    <div style="margin:auto;  380px;">
        <div class="well well-sm" ng-repeat="log in accessLog track by $index">
            <i class="fa fa-pencil fa-2x pull-left"></i>
            {{log.user ? log.user.name: 'anonymous'}} in {{log.date | date: 'longDate'}} at {{log.date | date: 'shortTime'}}
            <p>From: {{log.from}} => to: {{log.to}}</p>
        </div>
    </div>


    ■ StateChangeError事件

    photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
                function($scope, $state, $rootScope){
                    
                    $rootScope.accessLog = new Array();
                    
                    $rootScope.$on('$stateChangeStart', 
                    function(event, toState, toParams, fromState, fromParams){
                        
                        if(toState.data.required && !$rootScope.user){
                            event.preventDefault();
                            $state.go('content.login');
                            return;
                        }    
                        
                    });
                    
                    $rootScope.$on('$stateNotFound', 
                    function(event, unfoundState, fromState, fromParams){
                        event.preventDefault();
                        $state.go('content.notfound');
                    });
                    
                    $rootScope.$on('$stateChangeSuccess', 
                    function(event, toState, toParams, fromState, fromParams){
                         $rootScope.accessLog.push({
                             user: $rootScope.user,
                             from: fromState.name,
                             to: toState.name,
                             date: new Date()
                         });
                    });
                    
                    $rootScope.$on('$stateChangeError', 
                    function(event, toState, toParams, fromState, fromParams, error){
                        event.preventDefault();
                        $state.go('content.error', {error: error});
                    });
                    
                }
    ]);

    添加2个state:

        .state('content.profile', {
            url:'profile',
            data:{
                required: true
            },
            resolve:{
                showError: function(){
                    throw 'Error in code.';
                }
            },
            views:{
                "body@content": {template: '<div>Error</div>'}
            }    
        })
        
     .state('content.error',{
            url:'error/:error',
            views:{
                "body@content":{
                    templateUrl: 'partials/error.html',
                    controller: function($scope, $stateParams){
                        $scope.error = {
                            message: $stateParams.error
                        }
                    }
                }
            }
        })   

    error.html

    <div class="well well-sm" style="margin: 20px;">
        <i class="fa fa-exclamation-circle fa-2x"> Sorry! But this message was displayed: {{error.message}}</i>
    </div>
  • 相关阅读:
    MVC vs SVC
    迪米特原则与接口隔离原则
    依赖倒置原理:依赖、稳定的抽象层
    【调侃】IOC前世今生
    Visual SVN Server启动失败0x8007042a错误
    syntax error, unexpected '['
    navicat将多个表导出为一个sql文件
    我的flashfxp左右界面怎么变成这样了?
    什么是国际顶级域名?
    什么是A记录/CNAME记录/MX记录/TXT记录
  • 原文地址:https://www.cnblogs.com/darrenji/p/5167999.html
Copyright © 2011-2022 走看看