angular4、angular4.0从入门到实战 打造股票管理网站 1.子路由 2. 路由传参三种方式 3. 路由守卫

可能有点语无伦次。。。。。因为第一次写这么长的博文~~~

最近跳入了angular4的坑,之前看的angular权威教程是angularJS1.的版本,之后的angular2和angular4改动非常大,可以说是两个框架了(雷锋和雷峰塔),google公司只对angularJS1.维护两年,所以果断弃了angularJS,现在大多是angular2和angular4应用居多 锤子科技官网http://www.smartisan.com/#/shop就是用angular4写的,现在学到了路由,跟着视频过了一遍,然后又自己写一遍代码加深记忆,视频是慕课网出的angular4.0从入门到实战 打造股票管理网站 有需要的小伙伴可以留言 路由这一章课程有三个小例子,spa (single page application)单页面应用,路由真的炒鸡有用啊感觉, 才接触angular我想记录下来因为忘的炒鸡快啊衰,环境搭建的时候有各种错误 搞得心累 要装node,angularCli npm 环境搭建这里有问题也可以留言因为我真的碰到好多问题!!!! 我用的是webstorm2017.2 这个博文内容比较杂,有时间分开一下 这样不好找,内容大概有

  1. 子路由
  2. 路由传参三种方式
  3. 路由守卫

这是最终的目录截图

第一个超简单路由应用

说明:点击主页显示的是home组件的内容,商品详情是product组件的内容,
我会放截图还有需要注意的地方
先说一下流程(环境搭建就不说了,网上有很多教程博文)
1.创建项目 ng new myrouter –routing
/———后面的–routing必须加上,才会生成路由配置文件,我下面那个图里可以看到app-routing-modules.ts———/
2.npm install jquery –save (两个横线!)
npm install bootstrap –save
npm install @types/jquery –save-dev
npm install @types/bootstrap –save-dev
(后面这两个也要装上,因为angular是typescript写的,而这两个库
javascript~~大概是因为这个)
3.接下来就是添加你要用的组件了
ng g component home
ng g component product
ng g component code404
4.准备工作都做好了,现在开始码代码~
app.component.html
这是app.component.html里的内容,<router-outlet>标签必须有,这相当于插座,让待显示的组件的内容知道放到哪里,
home.component.html

  <div class="home">
  <p>
    这里是主页组件
  </p>

</div>

product.component.html

<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <p>
    商品ID是
  </p>
  <p>
    商品ID是
  </p>

</div>

组件里的内容可以自由构思,接下来就是路由配置
在app-routing.modules.ts里配置,只需要修改Routes里内容即可,

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';

const routes: Routes = [
    {path: 'home', component: HomeComponent},
    {path: 'product', component: ProductComponent},
    {path: '', redirectTo: '/home', pathMatch: 'full'},
    {path: '**', component: Code404Component}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
{path: '', redirectTo: '/home', pathMatch: 'full'},

这个意思就是一进入页面就跳转显示指定的home组件的内容,这个可以自己指定,path不能以斜杠(/)开头。 路由器会为解析和构建最终的URL,这样当我们在应用的多个视图之间导航时,可以任意使用相对路径和绝对路径。路由的定义顺序是刻意如此设计的。路由器使用先匹配者优先的策略来匹配路由,所以,具体路由应该放在通用路由的前面。在上面的配置中,带静态路径的路由被放在了前面,后面是空路径路由,因此它会作为默认路由。而通配符路由被放在最后面,这是因为它能匹配上每一个URL,因此应该只有在前面找不到其它能匹配的路由时才匹配它。

 {path: 'product', component: ProductComponent},
    {path: '**', component: Code404Component}

这两行代码,第一行是常规指定路径的方法,一般在输入ProductComponent时会自动在文件前面添加import{…},alt+enter就可以添加 我下载的webstorm没有自己配置,如果设置快捷键了就按自己的,,第二行path路径是通配符,意思就是如果用户输入的路径不存在就会显示指定的组件Code404Component

import {HomeComponent} from './home/home.component';
import {ProductComponent} from './product/product.component';
import {Code404Component} from './code404/code404.component';

子路由、和三种给路由传递参数的方法

要求:在商品信息组件设置点击“显示商品描述”,
首先添加一个 product-desc组件,编辑对应的html文件,想让这个组件在product组件下显示,所以正题来了。。。。
1. product.html

<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <a [routerLink]="['./desc',2]">点击查看商品详情</a>
</div>

<router-outlet></router-outlet>

标签必须写,routerLink是一个数组,后面的数字是传入的参数,子路由是./
2.配置路由,如果要传入参数记得格式path:’desc/:id’ id是自定义的
{path: 'product', component: ProductComponent, children: [
{path: 'desc/:id', component: ProductDescComponent}
]},

3.到这一步已经实现了子路由,对于传进去的参数可以获取到
因为是给子路由传递的参数,所以在product-desc.component.html

<p>这里是商品描述</p>
<p> 商品ID是{{productId}}</p>

product-desc.component.ts

import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';

@Component({
  selector: 'app-product-desc',
  templateUrl: './product-desc.component.html',
  styleUrls: ['./product-desc.component.css']
})
export class ProductDescComponent implements OnInit {

  public  productId: number;
  constructor(private routerInfo: ActivatedRoute) { }

  ngOnInit() {
    this.productId = this.routerInfo.snapshot.params['id'];
  }
}

这样就可以在路由到product-desc时页面上就会显示productId
传递参数的方法有三种,一种是上面提到的在路径中传递,还有一种是在查询参数中传递 代码如下
product.component.html

 <a [routerLink]= "['./desc']" [queryParams] = "{id:1}"> 点击查看商品详情</a>

配置路径这里:

 {path: 'product', component: ProductComponent, children: [
      {path: 'desc', component: ProductDescComponent}
    ]},

product-desc.component.html

 ngOnInit() {
    this.productId = this.routerInfo.snapshot.queryParams['id'];
  }

第三种方式:在路由配置中添加静态数据传递参数
路由配置:
{path: 'product', component: ProductComponent, children: [
{path: 'desc', component: ProductDescComponent, data: [{'id': 1}]}
]},

获取 :data[0][‘id’]表示获取路由参数中第一个对象的id属性

this.productId = this.routerInfo.snapshot.data[0]['id'];

product.component.html

  <a [routerLink]= "['./desc']"> 点击查看商品详情</a>

路由守卫

这一章剩下的内容就是路由守卫,
看一下angular4中文社区对路由守卫的描述

上面的例子,用户都能在任何时候导航到任何地方。 但有时候这样是不对的。

  • 该用户可能无权导航到目标组件。
  • 可能用户得先登录(认证)。
  • 在显示目标组件前,我们可能得先获取某些数据。
  • 在离开组件前,我们可能要先保存修改。
  • 我们可能要询问用户:你是否要放弃本次更改,而不用保存它们?

我们可以往路由配置中添加守卫,来处理这些场景。守卫返回一个值,以控制路由器的行为:

如果它返回true,导航过程会继续
如果它返回false,导航过程会终止,且用户会留在原地。

守卫还可以告诉路由器导航到别处,这样也取消当前的导航。
守卫可以用同步的方式返回一个布尔值。但在很多情况下,守卫无法用同步的方式给出答案。 守卫可能会向用户问一个问题、把更改保存到服务器,或者获取新数据,而这些都是异步操作。

因此,路由的守卫可以返回一个Observable或Promise,并且路由器会等待这个可观察对象被解析为true或false。

路由器支持多种守卫:

  • 用CanActivate来处理导航到某路由的情况。
  • 用CanActivateChild处理导航到子路由的情况
  • 用CanDeactivate来处理从当前路由离开的情况。
  • 用Resolve在路由激活之前获取路由数据。
  • 用CanLoad来处理异步导航到某特性模块的情况。

在分层路由的每个级别上,我们都可以设置多个守卫。 路由器会先按照从最深的子路由由下往上检查的顺序来检查CanDeactivate()和CanActivateChild()守卫。 然后它会按照从上到下的顺序检查CanActivate()和CanActivateChild()守卫。 如果特性模块是异步加载的,在加载它之前还会检查CanLoad()守卫。 如果任何一个守卫返回false,其它尚未完成的守卫会被取消,这样整个导航就被取消了。

这一章介绍三个路由守卫

1.canactivate:要求认证
应用程序通常会根据访问者来决定是否授予某个特性区的访问权。 我们可以只对已认证过的用户或具有特定角色的用户授予访问权,还可以阻止或限制用户访问权,直到用户账户激活为止。
CanActivate守卫是一个管理这些导航类业务规则的工具。
CanActivate:[] 接收一个数组,可以指定多个路由守卫,当视图进入此路由时,所有守卫会被依次调用,如果有一个守卫返回false,则路由请求会被拒绝掉,看一下步骤
a.创建一个directive文件夹名为guard
b.在此文件夹下建一个typescript文件,命名为login.guard.ts
c.编写login.guard.ts

import {CanActivate} from '@angular/router';

export class LoginGuard implements  CanActivate {
  canActivate() {
    let loggedIn : boolean = Math.random() < 0.5;
    if (!loggedIn) {
      console.log( ' 用户未登录' );
    }
    return  loggedIn;
  }
}

d.配置路由,可以添加多个守卫

 {path: 'home', component: HomeComponent, canActivate: [LoginGuard]},

e.路由配置文件里要添加providers
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [LoginGuard]
})

我测试了一下,对一个组件添加多个守卫,给上一个home组件按照同样的步骤添加一个test.ts ,让这个守卫返回false,果然home这个组件就没法加载出来
test.ts

import {CanActivate} from '@angular/router';

export class TestGuard implements  CanActivate {
    canActivate () {
      return false;
    }
}

2.来说下CanDeactivate 处理未保存的更改
在现实世界中,我们得先把用户的改动积累起来。 我们可能不得不进行跨字段的校验,可能要找服务器进行校验,可能得把这些改动保存成一种待定状态,直到用户或者把这些改动作为一组进行确认或撤销所有改动。

当用户要导航到外面时,该怎么处理这些既没有审核通过又没有保存过的改动呢? 我们不能马上离开,不在乎丢失这些改动的风险,那显然是一种糟糕的用户体验。

我们应该暂停,并让用户决定该怎么做。如果用户选择了取消,我们就留下来,并允许更多改动。如果用户选择了确认,那就进行保存。

在保存成功之前,我们还可以继续推迟导航。如果我们让用户立即移到下一个界面,而保存却失败了(可能因为数据不符合有效性规则),我们就会丢失该错误的上下文环境。

在等待服务器的答复时,我们没法阻塞它 —— 这在浏览器中是不可能的。 我们只能用异步的方式在等待服务器答复之前先停止导航。

我们需要CanDeactivate守卫。
步骤与canactivate一样,这里就不再赘述了直接上代码
1.unsave.guard.ts

import {CanDeactivate} from '@angular/router';
import {HomeComponent} from "../home/home.component";

export class UnsaveGuard implements CanDeactivate <HomeComponent> {
  canDeactivate (component: HomeComponent) {
         return window.confirm('你还没有保存,确定离开吗?');
  }

2.路径配置

    {path: 'home', component: HomeComponent, canActivate: [LoginGuard, TestGuard], canDeactivate: [UnsaveGuard]},


@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [LoginGuard, TestGuard, UnsaveGuard],
})

当离开home时浏览器会弹出消息框 如果确认就会路由到其他组件,如果取消就会留在当前
3.resolve守卫
预先获取组件数据,导航前预先加载路由信息
1.在guard文件夹里添加文件product.resolve.ts

import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router';
import {Injectable} from '@angular/core';
import {Product} from '../product/product.component';
@Injectable ()
export class  ProductResolve implements  Resolve <Product> {
  constructor(private  router: Router) {
  }
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    const productId: number = route.params['id'];
    if (productId == 1) {
      return new Product(2);
    }else {
      this.router.navigate(['/home']);
      return undefined;
    }
  }
}

2.product.component.ts里实例化
export class Product {
constructor(public productIds: number) {
}
}

3.路径配置
{path: 'product/:id', component: ProductComponent, children: [
{path: 'desc', data: [{id: 1}], component: ProductDescComponent}
], resolve: [ProductResolve]},

4.providers里注入

providers: [LoginGuard, TestGuard, UnsaveGuard, ProductResolve],

5.product.component.html

<div class="product">
  <p>
    这里是商品信息组件
  </p>
  <a [routerLink]= "['./desc']"> 点击查看商品详情</a>
  {{productIds}}
</div>

<router-outlet></router-outlet>




这篇博文到这里就完了,内容大概就这么多,也不是很全面,可以去中文社区看看,还有对应的例子可以练手,一边敲一边回忆,发现自己忘光了,然后又查文档看视频,总算是写完了,过一遍果然是有效果的哈哈哈哈哈~~~~~ 脑袋有点糊,如果哪里不正确还希望能指正,



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值