知向前端
angular配置全局路由跳转不添加到历史记录之曲线救国
2019-10-13 Jon
在开发angular项目中遇到一个需求是路由跳转不记录在浏览器历史中,即使用浏览器回退时不会退到进入当前页面的前一个页面,而是退到前前一个页面。



这个其实很简单,在angular也给出了相应的解决方案即

1.如果跳转发生在html中即使用routerLink时加上replaceUrl="true"即可

<button routerLink="/order" replaceUrl="true">to order</button>

2.如果跳转发生在ts中即

this.router.navigate(['/order'], { replaceUrl: true });

参数中添加replaceUrl字段使其为true即可

这样就实现了某个路由跳转不记录在浏览器历史中



需求升级为所有路由跳转都不记录在浏览器历史中

产生需求原因:

在ios10以上系统中的微信中访问页面时(所有前端页面,也包括angular)涉及到连接跳转就会出现底部导航区(前进和返回按钮),这大大影响了页面的美观。为了在ios不出现此底部导航区,目前微信并没有给出像样的解决烦恼,这就要用程序欺骗的方式隐蔽掉这个问题,即让所有跳转都不记录到历史中,这样就对系统隐瞒了程序中的所有跳转,自然就不会出现这个烦人的导航区了。



angular解决方案

有了上述replaceUrl:true的知识自然就想到在所有跳转的页面都加上 replaceUrl

这当然可行,但是如果跳转过多,工作量和维护成本将很大,加上后期判断是否是ios,是安卓则不需要加,这无疑是一场灾难。

这就不得不想到要用一个全局的配置去解决这个问题,但是操蛋的是在angular文档中并没有发现全局配置方案。

然鹅,只能使用曲线救国方案来使这一切看起来更加优雅。



先放方案再做解释

angular 路由守卫+逻辑代码


app-routing.module.ts






hash-type-guard.service.ts





我们知道路由守卫可以对路由跳转进行拦截

这就给我们提供了良好的解决入口,写个路由守卫拦截所有的跳转路由,在使用我们自己的逻辑进行跳转

这样就实现了每一次跳转都不会记录到浏览器历史中。



为何不使用 canActivateChild?

如果我没有懒加载模块,使用canActivateChild会更加简洁

但是canActivateChild的子模块中有使用懒加载模块就会执行两次路由守卫的canActivateChild方法


这个不知道是不是angular 中的bug还是有意为之,但是这无疑是混乱的,所以我放弃了canActivateChild






2019.10.25 更

针对懒加载模块 canActivateChild 会执行两次路由守卫的 canActivateChild方法 的解释

这个canActivateChild方法中有2个参数,根据第一个参数对象中的url数组可以得到跳转目标路由

执行第一次时这个url数组是有一个值得

执行第二次的时候这个url数组是空值

所以根据这个url的长度判断可以忽略第二次的进入

这样就可以做到使用 canActivateChild 去监听懒加载模块路由也不会存在问题了

以下给出例子app-routing.module.ts


import { NgModule } from '@angular/core';
import { Router, Routes, RouterModule, PreloadAllModules, NavigationStart } from '@angular/router';
import { HomeComponent } from './layout/home/home.component';
import { DashboardComponent } from './routes/dashboard/dashboard.component';
import { ProductComponent, ChildComponent } from './routes/product/product.component';
// CanDeactivate
import { UnsaveGuard } from './guard/unsave-guard.service';
import { ProductResolve } from './guard/product-resolve.service';
// CanActivate
import { HashTypeGuard } from './guard/hash-type-guard.service';
const routes: Routes = [
{
path: '',
component: HomeComponent,
// canActivate: [HashTypeGuard],
canActivateChild: [ HashTypeGuard ],
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{
path: 'task',
loadChildren: () => import('./routes/task/task.module').then(m => m.TaskModule),
// canActivate: [HashTypeGuard],
},
{ path: 'inherit',
loadChildren: () => import('./routes/inherit/inherit.module').then(m => m.InheritModule),
// canActivate: [HashTypeGuard],
},
{ path: 'cesiums',
loadChildren: () => import('./routes/cesiums/cesium.module').then(m => m.CesiumModule)
// ,canActivate: [HashTypeGuard],
},
{ path: 'webrtc',
loadChildren: () => import('./routes/webrtc/webrtc.module').then(m => m.WebrtcModule)
// ,canActivate: [HashTypeGuard],
},
{ path: 'dashboard', component: DashboardComponent,
// canActivate: [HashTypeGuard],
},
{
path: 'a',
pathMatch: 'prefix',
children: [
// { path:'**', pathMatch: 'prefix',redirectTo: 'dashboard'}
{ path:'**', component: ChildComponent},
]
},
{
path: 'product/:id',
component: ProductComponent,
resolve: {
product: ProductResolve
}
},
{
path: 'order',
loadChildren: () => import('./routes/order/order.module').then(m => m.OrderModule),
canDeactivate: [UnsaveGuard]
,
// canActivate: [HashTypeGuard],
data: {val: '005'}
},
{ path: '**', redirectTo: 'home' }
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes, {
useHash: true,
preloadingStrategy: PreloadAllModules,
// enableTracing: true,
// onSameUrlNavigation: 'reload'
})],
// providers: [UnsaveGuard],
exports: [RouterModule]
})
export class AppRoutingModule {
}

hash-type-guard.service.ts

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateChild, CanLoad } from '@angular/router';
@Injectable({providedIn: 'root'})
export class HashTypeGuard implements CanActivate, CanActivateChild, CanLoad {
canLoad(route: import("@angular/router").Route, segments: import("@angular/router").UrlSegment[]): boolean {
this.val++;
console.log('canload'+this.val);
return true;
}
val = 0;
constructor(
private router: Router
) {}
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if(route.url.length) {
this.val++;
if(this.val%2){
this.router.navigate([state.url], { replaceUrl: true });
return false;
}else{
console.log(this.val);
return true;
}
}
return true;
}
}
评论:
2021-08-05 04:46 回复
在开发angular项目中遇到一个需求是路由跳转不记录在浏览器历史中,即使用浏览器回退时不会退到进入当前页面的前一个页面,而是退到前前一个页面。



大白话听起来就是舒服。比起装逼的博客文绉绉的谢了一堆,最后毛线都没讲明白。
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容