可能有点语无伦次。。。。。因为第一次写这么长的博文~~~
最近跳入了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 这个博文内容比较杂,有时间分开一下 这样不好找,内容大概有
- 子路由
- 路由传参三种方式
- 路由守卫
第一个超简单路由应用
说明:点击主页显示的是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
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>
这篇博文到这里就完了,内容大概就这么多,也不是很全面,可以去中文社区看看,还有对应的例子可以练手,一边敲一边回忆,发现自己忘光了,然后又查文档看视频,总算是写完了,过一遍果然是有效果的哈哈哈哈哈~~~~~ 脑袋有点糊,如果哪里不正确还希望能指正,