ui-router使用

作者: liuchungui | 来源:发表于2018-04-07 19:37 被阅读0次

去年的时候,在公司做过一个ui-router的分享,今天将它整理成文字,发出来。后面,也会陆陆续续将以前的技术分享发出来。

开篇之前,需要提前说明的是,此分享使用的Angular是1.x版本的。

在Angular中,ngRoute是Angular自带的路由模块,它是基于url来驱动视图
ui-router是AngularUI独立的路由模块,它是基于状态来驱动视图。相比于ngRoute,ui-router具有更强大的功能,主要体现在视图的嵌套方面。

安装

使用npm安装

npm install --save angular-ui-router

简单使用

在模板中定义添加<ui-view></ui-view>标签,添加ui-sref跳转链接,然后在js中配置好路由(注册状态)。

index.html的代码如下:

<!DOCTYPE html><html><head>    <meta charset="utf-8"/>    <script src="../node_modules/angular/angular.min.js"></script>    <script src="../node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>    <script src="helloWorld.js"></script>    <style>        .active {            color: red;            font-weight: bold;        }    </style></head><body ng-app="myApp"><a ui-sref="hello" ui-sref-active="active">Hello</a><a ui-sref="home" ui-sref-active="active">Home</a><ui-view></ui-view></body></html>

helloWord.js中的代码如下:

//让app依赖ui.router
var myApp = angular.module('myApp', ['ui.router']);

myApp.config(function ($stateProvider, $urlRouterProvider) {    var helloState = {        name: 'hello',        url: '/hello',        template: '<h3>{{title}}</h3>',        controller: function ($scope) {            $scope.title = "Hello world";        }    };    var aboutState = {        name: 'about',        url: '/about',        templateUrl: 'about.html'    };    $stateProvider.state(helloState);    $stateProvider.state(aboutState);});

上面,helloWord.js中注册路由时,使用nameurltemplate等状态属性。那么,ui-router中有哪些状态属性呢?

  • name: 状态的名字,例如hello
  • url: 在浏览器里面的url部分,例如当hello状态激活时,浏览器里面将会变成/hello
  • template: 模板,状态的视图
  • templateUrl: 模板的url
  • controller:控制器,它可以管理模板中的内容

在上面的index.html代码中,我们使用ui-viewui-srefui-sref-active三个指令,这也是我们经常使用指令,它们代表意思是:

  • ui-view: 某个状态激活时,会被加载到这个标签内部
  • ui-sref:相当于href,是一个链接,点击会激活相应的状态
  • ui-sref-active:当对应状态激活时,这个指令会给所在元素添加class
注册状态另外一种写

除了上面helloWorld.js中的写法外,还有另外一种,这也是我常用的写法:

myApp.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {    $stateProvider    //对应前面的helloState        .state("hello", {            url: '/hello',            template: '<h3>{{title}}</h3>',            controller: function ($scope) {                $scope.title = "Hello world";            }        })        //对应前面的aboutState        .state("about", {            url: '/about',            templateUrl: 'about.html'        });}]);

路由嵌套

路由嵌套包括了状态嵌套和视图嵌套,状态嵌套就是在注册状态时,建立状态树(父子状态关系);视图嵌套,就是在父状态的模板中需要有一个ui-view标签,它用来加载子状态的模板内容。

状态嵌套和视图嵌套是一起使用的,共同构成路由嵌套。如果没有建立状态的父子关系,跳转会报错;如果没有视图的嵌套关系,跳转时url变化,但是页面的内容不会变化,因为子状态的模板视图不知道加载到哪里。

嵌套实现的四种方式

  • 使用.来进行嵌套,例如.state('home.list', {})
  • 使用ui-router.stateHelper去构建嵌套,是第三方实现的,请参考ui-router.stateHelper
  • 使用parent属性,来指定父状态的名称,例如:parent: 'home'
  • 使用parent属性,来指定父状态对象,例如:parent: home
"."嵌套

我最常使用的嵌套方式是使用"."来嵌套,示例如下:

$stateProvider    .state("home", {        url: '/home',        templateUrl: 'home.html'    })    .state("home.list", {        url: '/list',        templateUrl: 'list.html',        controller: function ($scope) {            $scope.dataArray = ['first cell', 'second cell', 'third cell']        }    })

注意: 上面的home.list对应路径是#/home/list,它是home状态的url与子状态home.list的url一起拼接起来的。

使用parent来嵌套

这个,我比较少使用,示例如下:

$stateProvider    .state("home", {        url: '/home',        templateUrl: 'home.html'    })    .state("detail", {        url: '/detail',        parent: 'home',        template: '<p>这是详情部分</p>'    })

路由嵌套注意的地方

  • 状态注册可以是任何顺序,子状态在父状态之前注册也没可以
  • 父状态必须存在
  • 当子状态激活时,它的父状态也是激活状态,例如home.list激活时,home也会激活
  • 嵌套状态和视图时,子状态只会加载自己的模板到父状态的ui-view中。如果父状态模板中不存在ui-view时,激活子状态,url会发生变化,但是视图不会发生变化,因为没有加载子状态模板的ui-view。

路由嵌套时URL组成

有两种方式组成URL:拼接路径绝对路径

第一种:拼接路径(默认)

当前状态是父状态的url与当前状态的url拼接起来的,例如:

$stateProvider    .state("home", {        url: '/home',        templateUrl: 'home.html'    })    .state("home.list", {        url: '/list',        templateUrl: 'list.html',        controller: function ($scope) {            $scope.dataArray = ['first cell', 'second cell', 'third cell']        }    })
第二种: 绝对路径(^)

使用^符号匹配绝对路径,例如:

$stateProvider    .state('contacts', {        url: '/contacts',        ...}).state('contacts.list', {    url: '^/list',    ...});
  • contacts 状态匹配 /contacts
  • contacts.list 状态匹配 /list

路由跳转

当我们使用路由时,还需要知道路由如何跳转的,而在ui-router中,跳转路由有下面几种方式:

第一种,通过$stage.go()来跳转

//跳转到home状态
$sate.go('home');

第二种,通过设置一个含有ui-sref指令的链接

<a ui-sref="home" ui-sref-active=“active”>Home</a>

这种方式,点击Home就会跳转到home状态

第三种,通过url直接导航到对应页面

<a href="#/home" ui-sref-active="active">Hello</a>

或者

window.location = '#/home';

注意: 这里是使用angular 1.5.8,如果是angular1.6以上的,有!符号,如window.location = '#!/home'。

跳转并刷新

除了简单跳转之外,有时,我们想跳转到某个状态下,并且刷新页面。这时,我们可以使用ui-srefui-sref-opts一起来实现,如下:

<div ui-sref="home.list" ui-sref-opts="{reload: true}" ui-sref-active="active">List</div>

当然,我们也可以在js中,使用$stage.go()来实现,如下:

$state.go("home.list",{}, {reload: true}); 

相对跳转

实现相对跳转很简单,使用.开头就行了。

在html中使用ui-sref方式时,示例如下:

<div ui-sref=".list" ui-sref-opts="{reload: true}" 
ui-sref-active=“active">List</div>

在js中,使用$stage.go()也可以实现,示例如下:

$state.go(".list"); 

Resolve

Resolve是一个可选的依赖,当设置它时,它内部的属性就会被注入到控制器中。它的用途是,为状态控制器提供定制化的数据。

示例如下:

.state("detail", {    url: '/detail',    parent: 'home',    template: '<div><p>这是详情部分</p></div>',    resolve: {        //resolve是一个        config: function () {            return {                name: 'homeConfig',                content: 'Hell'            }        },        greeting: function($q, $timeout){            var deferred = $q.defer();            $timeout(function() {                deferred.resolve('Hello!');            }, 2000);            return deferred.promise;        },        page: function ($http) {            return $http.get('http://localhost');        }    },    controller: function ($scope, config, greeting, page) {        console.log(config);        console.log(greeting);        console.log(page);    }})

注意:当Resolve中存在promise时,它会等待每个promise relove之后才实例化控制器,然后触发$stateChangeSuccess事件。还有,Resolve中的数据,在子状态也可以获取。

参数

路由传递参数有两种,一种将参数嵌入到url当中;另外一种,没有嵌入到url当中。

参数嵌入方式

第一种:参数嵌入在URL中

嵌入在URL中的参数也分成两种,一种是嵌入在URL路径中;另外一种是放在query部分(也就是?后面)

嵌入在URL路径中时

示例如下:

.state("about.detail", {    url: '/detail/:name',    template: '<p>这是about的详情页面, 关于{{name}}</p>',    controller: function ($scope, $stateParams) {        $scope.name = $stateParams.name;    }})

上面代码也可以使用括号,效果完全一样,如下:

.state("about.detail", {    url: ‘/detail/{name}’,    template: '<p>这是about的详情页面, 关于{{name}}</p>',    controller: function ($scope, $stateParams) {        $scope.name = $stateParams.name;    }})

注意:放在URL路径里面时,还可以使用正则,例如: url:'/detail/*'

参数放在query部分

在?后面指定参数,例如:url: "/contacts?myParam",它将匹配: "/contacts?myParam=value"
多个参数时,用'&'连接:url: "/contacts?myParam1&myParam2",它将匹配: "contacts?myParams1=value1&myParam2=value2"

第二种:参数不嵌入URL中

注册路由时,设置状态属性params

.state("home.test", {    url: '/test',    params: {        name: null    },    template: '<p>这是测试页面</p>',    controller: function ($scope, $stateParams) {        console.log($stateParams);    }})

传递参数

<div ui-sref="about.detail({name: 'default about’})”>Detail</div>

或者使用$state.go()的方式:

$state.go('about.detail', {name: 'default about'});

获取参数

.state("about.detail", {    url: '/detail/:name',    template: '<p>这是about的详情页面, 关于{{name}}</p>',    controller: function ($scope, $stateParams) {        $scope.name = $stateParams.name;    }});

$urlRouterProvider使用

$urlRouterProvider可以用来做重定向处理无效状态定制化url

我们经常使用的功能是重定向和处理无效请求,它分别通过when()otherwise()来实现,而定制化url,则是通过rule()方法实现。

重定向

重定向使用的是when(),它可以传递字符串:

例如,我们项目中,当跳转到project状态时,会默认重定向到"所有项目",如下:

$urlRouterProvider.when("/project", "/project/list/所有");

它也可以传递参数:

例如,我们项目中,曾经就有重定向的情况:

$urlRouterProvider.when('/project/detail/:id/evaluate', ['$match', '$stateParams', function ($match, $stateParams) {    return '/project/detail/' + $urlRouterProvider.$stateParams.id + '/evaluate/analyst'}]);

无效状态处理

无效状态处理,使用的是otherwise(),它传递一个url或函数参数。

例如,在我们的一个项目中,跳转到无效的路由时,它默认会跳转到个人信息页面(”/account”)

$urlRouterProvider.otherwise("/account");

url定制化

url定制化,使用的是rule(),它需要传递一个函数来处理url。

例如,将所有url都转换成小写:

app.config(function ($urlRouterProvider) {    $urlRouterProvider.rule(function ($injector, $location) {        var path = $location.path(), normalized = path.toLowerCase();        if (path != normalized) {            $location.replace().path(normalized);        }    });})

onEnter和onExit

状态还有两个可选的属性,那就是onEnter和onExit回调函数,当状态激活时,它会回调onEnter中的方法(在controller初始化之前);当状态从激活变成非激活时,它会回调onExit方法。

示例:

onEnter: function () {    console.log('进入home页面');},onExit: function () {    console.log('退出home页面')}

注意:这个回调函数,可以访问所有Resolved中的依赖,也就是说它也会等待所有Resolved中的promise处理完之后才执行。

状态变化事件

注意:状态变化事件在1.0之后被放弃了,被 transition hooks代替了。

  • $stateChangeStart 状态变化开始
  • $stateNotFound 未被发现
  • $stateChangeSuccess 状态改变成功
  • $stateChangeError 状态改变失败

使用,如下:

$rootScope.$on("$stateChangeSuccess", function () {   console.log('状态改变成功');});

使用transition hooks代替时,如下:

myApp.run(function($rootScope) {    $rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams) {        console.log("$stateChangeStart " + fromState.name + JSON.stringify(fromParams) + " -> " + toState.name + JSON.stringify(toParams));    });    $rootScope.$on('$stateChangeSuccess', function() {        console.log("$stateChangeSuccess " + fromState.name + JSON.stringify(fromParams) + " -> " + toState.name + JSON.stringify(toParams));    });    $rootScope.$on('$stateChangeError', function() {        console.log("$stateChangeError " + fromState.name + JSON.stringify(fromParams) + " -> " + toState.name + JSON.stringify(toParams));    });});

视图加载事件

  • $viewContentLoading 当视图开始加载时触发一次,在DOM渲染之前
  • $viewContentLoaded 当视图加载完触发一次,在DOM渲染之后

示例如下:

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

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

多个命名视图

一个模板中,还可以放多个命名的视图,如下:

<!-- index.html -->
<body>
  <div ui-view="filters"></div>
  <div ui-view="tabledata"></div>
  <div ui-view="graph"></div>
</body>

多个视图可以显示各自的模板:

$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 ... }
      }
    }
  })

相关文章

  • AngularJS 子路由与多视图

    ui-router 的使用 多视图 路由嵌套 home_tpl.html

  • ui-router使用

    去年的时候,在公司做过一个ui-router的分享,今天将它整理成文字,发出来。后面,也会陆陆续续将以前的技术分享...

  • AngularJs 嵌套路由(ui-router)

    AngularJs 嵌套路由(ui-router) //1.声明Angularjs 模块,把ui-router 传...

  • 如何使用ui-router?

    如何使用ui-router? 一.背景介绍 angular路由 路由(route),几乎所有的MVC(VM)框架都...

  • 深究AngularJS——ui-router详解

    https://github.com/angular-ui/ui-router 我们都知道,如果使用原生路由的话,...

  • ionic ui-router

    ionic ui-router

  • 如何使用ui-router?

    如何使用ui-router? 目录 1.背景介绍 2.知识剖析 3.常见问题 4.解决方案 5.编码实战 6.扩展...

  • 如何使用ui-router?

    大家好,我是IT修真院武汉分院第10期学员余佳贝,一枚正直善良的web程序员。 今天给大家分享一下,修真院官网js...

  • 如何使用ui-router?

    1.背景介绍 UI-Router它是一个让开发者能够根据URL状态或者说是'机器状态'来组织和控制界面UI的渲染,...

  • 如何使用ui-router

    【JS-6】 如何使用ui-router? 小课堂【武汉分院第137期】 分享人:徐恒 目录 1.背景介绍 2.知...

网友评论

    本文标题:ui-router使用

    本文链接:https://www.haomeiwen.com/subject/suayhftx.html