angular配置全局路由跳转不添加到历史记录之曲线救国

2019-10-13 Jon angular

在开发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项目中遇到一个需求是路由跳转不记录在浏览器历史中,即使用浏览器回退时不会退到进入当前页面的前一个页面,而是退到前前一个页面。



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

发表评论:

皖ICP备15010162号-1 ©2015-2022 知向前端
qq:1614245331 邮箱:13515678147@163.com Powered by emlog sitemap