【问题标题】:How to reload current page?如何重新加载当前页面?
【发布时间】:2019-02-22 15:43:45
【问题描述】:

我有一个编辑用户的页面,里面有一些子组件。每个子组件都可以更改或对其父组件产生一些影响。

因此,我没有向父级发送更改并更新某些字段,而是使用

对当前页面进行了“重新加载”
private route: ActivatedRoute;

reload(){
    this.router.navigate(["/admin/user/edit/"+this.user.id]);
}

基本上,它会重定向到当前页面。例如,当前页面是 http://web.info/admin/user/edit/9 它将被重定向到此页面,希望该页面内的所有数据都重新加载最新数据。

但似乎角度不会重定向/重新加载与router.navigate 相同的页面

我应该如何重新加载当前页面?

编辑:

这就是为什么我需要重新加载页面而不是手动更新当前页面上的数据的原因。我需要对其他组件进行更新,当我进行更新时,它会向历史组件添加一些内容。我需要一起刷新用户组件和历史组件,因为这两个组件都受到其他组件更改的影响。

【问题讨论】:

  • 看这里:github.com/angular/angular/issues/13340 你可以简单地使用window.location.href = '...';
  • 我尝试使用 window.location.href = this.router.url .. 它可以工作,但它看起来不自然/与其他页面不相似。我会用这个作为最后的手段

标签: javascript angular


【解决方案1】:

做这么简单的事情有点棘手,但尝试使用当前解决方案重新加载和重新创建整个父子组件时运气不佳。

Angular 路由器现在提供策略配置来告诉路由器在您导航到该用户在this GitHub issue 中建议的相同 URL 时应该做什么。

首先,您可以在设置路由器(您的路由器模块)时配置要执行的操作。

@NgModule({
   imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
   exports: [RouterModule]
})

或者,如果你和我一样不想改变整个路由器模块的行为,你可以使用这样的方法/函数:

reloadComponent() {
    this._router.routeReuseStrategy.shouldReuseRoute = () => false;
    this._router.onSameUrlNavigation = 'reload';
    this._router.navigate(['/same-route']);
}

当然你必须先在组件的构造函数中注入Router

// import { Router } from '@angular/router';
...
constructor(private _router: Router){}
...

不知何故,正如@Abhiz 指出的那样,您必须设置 shouldReuseRoute,仅通过自身配置路由器,页面重新加载不适用于 这种方法

我为shouldReuseRoute使用了箭头函数,因为新的 TSLint 规则不允许非箭头函数。

【讨论】:

  • 谢谢,第二种方法(不改变整个路由器行为)在 Angular 8 上效果很好。
  • 会影响其他路由吗?还是会在这些更改的属性中被销毁,并且不会影响到项目中的其他路由器?
  • 第二种方法如果使用注入,实际上会影响其他路由器。在我的场景中,其中一个组件使用线性步进器。通过更改策略,该组件进入了无限重新加载状态。我终于选择了 "this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => this.router.navigate(['YourCurrentRoute', this.id]));
  • 第二种方法非常适用于 Angular 7,我们也可以像这样来保存查询参数 this.router.navigate(['./'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' });
  • 我让它在没有这个的情况下工作。_router.onSameUrlNavigation = 'reload';
【解决方案2】:

它将 100% 工作。以下代码行负责我项目中的页面重新加载。

load(val) {
if (val == this.router.url) {
  this.spinnerService.show();
  this.router.routeReuseStrategy.shouldReuseRoute = function () {
    return false;
  };
 }
}

只需在代码中使用以下部分。

this.router.routeReuseStrategy.shouldReuseRoute = function () {
    return false;
  };

【讨论】:

  • 我正在使用 Angular 9,这对我没有任何帮助。 window.location.reload() 有效,但它很笨重。
  • 完整的解决方案需要额外的步骤:this.router.onSameUrlNavigation = 'reload'; 但是如果你只需要在特定场景下重新加载页面,你需要保存路由器状态,改成这个,重新加载并恢复状态为默认值。
  • 这非常适合我的用例。使用this.router.navigateByUrl("someUrl")后,最后使用了2号线。
【解决方案3】:

如果只需要刷新整个页面,这是最简单的解决方案

   refreshPage() {
    window.location.reload();
   }

【讨论】:

  • 这会再次加载所有的块......不是角度解决方案
【解决方案4】:

不指定路径即可:

constructor(private route: ActivatedRoute, private router: Router) { }

reload() {
  this.router.routeReuseStrategy.shouldReuseRoute = () => false;
  this.router.onSameUrlNavigation = 'reload';
  this.router.navigate(['./'], { relativeTo: this.route });
}

如果你使用查询参数,你可以这样做:

reload() {
  ...
  this.router.navigate(['./'], { relativeTo: this.route, queryParamsHandling: 'preserve' });
}

【讨论】:

    【解决方案5】:
    import { DOCUMENT } from '@angular/common';
    import { Component, Inject } from '@angular/core';
    
    @Component({
      selector: 'app-refresh-banner-notification',
      templateUrl: './refresh-banner-notification.component.html',
      styleUrls: ['./refresh-banner-notification.component.scss']
    })
    
    export class RefreshBannerNotificationComponent {
    
      constructor(
        @Inject(DOCUMENT) private _document: Document
      ) {}
    
      refreshPage() {
        this._document.defaultView.location.reload();
      }
    }
    

    【讨论】:

      【解决方案6】:

      因为它是同一个组件。您可以通过注入ActivatedRoute 并响应参数和查询参数的更改来监听路由更改,或者您可以更改默认的RouteReuseStrategy,以便在 URL 更改时销毁并重新渲染组件,而不是重复使用。

      【讨论】:

        【解决方案7】:

        将其写为 2021(运行 Angular 12)。 阅读说明或直接跳到结尾。

        由于不受欢迎的行为,该线程和其他线程上的所有答案都对我没有太大帮助。我所做的是实施了一个 hack。

        对现有答案的一些了解

        Angular 会以特定方式重新加载页面,这意味着页面组件/解析器/防护。

        使用 this.router.onSameUrlNavigation = 'reload';

        大部分时间都不起作用,因为它的主要目的是重新启用解析器/防护。不过,它被误认为是其他含义。另外,我不想将其更改为全局设置,所以不!

        window.location.reload()window.location.href=window.location.href 的另一种方式 是最糟糕的方式,因为它违反了 SPA 规则。再次下载所有块是非常糟糕的解决方案。

        虽然下面的解决方案有效,但对于我的用例,它路由了两次,所以也放弃了这个

        this.router.navigateByUrl('', { skipLocationChange: true }).then(() => {
           this.router.navigate(['/launchpad']);
        });
        

        现在HACK / 解决方案

        为什么不完全告诉 Angular 它的不同路径,所以重新加载由 Angular 自己负责,它还涵盖了守卫、解析器的一切。对于我的用例

        app-routing.module.ts 中,我添加了具有两条不同路线的相同模块

        一个带有''空路由和一个带有''post-login'

          {
            path: '',
            loadChildren: () => import('./post-login/post-login.module').then((m) => m.PostLoginModule),
            canActivate: [AuthGuard],
          },
          {
            path: 'post-login',
            loadChildren: () => import('./post-login/post-login.module').then((m) => m.PostLoginModule),
            canActivate: [AuthGuard],
          }
        

        现在在我想重新加载同一页面的任何地方,注入路由器:路由器

        并像这样简单地使用

         this.router.navigateByUrl(this.router.url.includes('post-login') ? '' : 'post-login');
        

        这会在 Url 中使用备用附加“登录后”重新加载页面,但对我的用例来说很好。希望它有所帮助:)

        【讨论】:

          【解决方案8】:

          使用 angular 11 你可以使用这个:

          在路由配置中添加runGuardsAndResolvers: 'always'

          const routes: Routes = [
            { path: '', component: Component, runGuardsAndResolvers: 'always' },
          ];
          

          这是你重新加载的方法:

            reloadView(): void {
              this.router.navigated = false;
              this.router.navigate(['./'], { relativeTo: this.route });
            }
          

          这将触发该配置上的任何解析器

          【讨论】:

          • this.router.navigated = false; 是我让runGuardsAndResolvers: 'always' 按预期工作所缺少的。
          【解决方案9】:

          通过这种方式,我们也可以保留查询参数

           onReloadPage() {
               this.router.routeReuseStrategy.shouldReuseRoute = () => false;
               this.router.onSameUrlNavigation = 'reload';
               this.router.navigate(['./'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' });
           }
          

          【讨论】:

            【解决方案10】:

            我已经通过这种方式解决了

            import { Router, ActivatedRoute } from '@angular/router';
            
            constructor(private router: Router
                      , private activeRoute: ActivatedRoute) {
            
            }
            reloadCurrentPage(){
               let currentUrl = this.router.url;
               this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => {
               this.router.navigate([currentUrl]);
               });
             }
            

            【讨论】:

            • 最好的解决方案,它不接触角机构并改变它。用一个简单的解决方法解决它
            【解决方案11】:

            我找到了比重新加载页面更好的方法。相反,我将重新加载刚刚更新的数据。这种方式更快更好

            【讨论】:

              【解决方案12】:

              这是一个简单的

              if (this.router && this.router.url === '/') { or your current page url e.g '/home' 
                  window.location.reload();
                } else {
                  this.router.navigate([url]);
                }
              

              【讨论】:

                【解决方案13】:

                我相信 Angular 6 有 BehaviorSubject 对象。下面的示例是使用 Angular 8 完成的,希望也适用于 Angular 6。

                此方法是解决问题的一种更“被动”的方法,并假设您正在使用并且精通 rxjs。

                假设您在父组件(路由定义中使用的组件)中使用 Observable,那么您应该能够非常轻松地脉冲数据流。

                我的示例还假设您在组件中使用视图模型,如下所示...

                vm$: Observable<IViewModel>;
                

                在 HTML 中是这样的......

                <div *ngIf="(vm$ | async) as vm">
                

                在您的组件文件中,添加一个 BehaviorSubject 实例...

                private refreshBs: BehaviorSubject<number> = new BehaviorSubject<number>(0);
                

                然后还添加一个可由 UI 元素调用的操作...

                  refresh() {
                    this.refreshBs.next(1);
                  }
                

                这是 UI sn-p,一个 Material Bootstrap 按钮...

                <button mdbBtn color="primary" class="ml-1 waves-dark" type="button" outline="true"
                                    (click)="refresh()" mdbWavesEffect>Refresh</button>
                

                然后,在你的 ngOnIt 函数中做这样的事情,记住我的例子被简化了一点,所以我不必提供很多代码......

                  ngOnInit() {
                
                    this.vm$ = this.refreshBs.asObservable().pipe(
                      switchMap(v => this.route.queryParamMap),
                      map(qpm => qpm.get("value")),
                      tap(v => console.log(`query param value: "${v}"`)),
                
                      // simulate data load
                      switchMap(v => of(v).pipe(
                        delay(500),
                        map(v => ({ items: [] }))
                      )),
                      
                      catchError(e => of({ items: [], error: e }))
                    );
                    
                  }
                

                【讨论】:

                  【解决方案14】:

                  查看此stackblitz,它使用RouteReuseStrategyonSameUrlNavigation: 'reload' 路由器选项。

                  此策略可确保 Angular 在导航到它认为“相同”的路线(包括具有不同的路径和查询参数)时始终重新渲染组件。

                  @Injectable()
                  export class MyStrategy extends RouteReuseStrategy {
                     shouldDetach(route: ActivatedRouteSnapshot): boolean {
                      return false;
                    }
                    store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
                    shouldAttach(route: ActivatedRouteSnapshot): boolean {
                      return false;
                    }
                    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null {
                      return null;
                    }
                    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
                      return false;
                    }
                  }
                  
                  const routes = [
                    {path: '2', component: Empty2},
                    {path: '', component: Empty},
                  ];
                  
                  @NgModule({
                    imports:      [ BrowserModule, RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload'}) ],
                    declarations: [ AppComponent ],
                    bootstrap:    [ AppComponent ], 
                    providers: [{provide: RouteReuseStrategy, useClass: MyStrategy}]
                  })
                  export class AppModule { }
                  

                  【讨论】:

                    【解决方案15】:

                    在路由器上正确设置shouldReuseRouteonSameUrlNavigation 将在同一页面上导航时强制重新加载角度,但是由于router 是一个单例,在重新加载后设置其初始值可能是相关的页面。

                    以下此方法将备份和恢复路由器的设置,以防止出现副作用。如果您确实有更清洁的解决方案来实现相同的目标,请发表评论。

                    class MyComponent {
                    
                    constructor(private router: Router){}
                    
                    public async reload(): Promise<boolean> {
                        const router = this.router;
                        const routeReuseStrategy = router.routeReuseStrategy.shouldReuseRoute;
                        const onSameUrlNavigation = router.onSameUrlNavigation;
                        try {
                          router.routeReuseStrategy.shouldReuseRoute = () => false;
                          router.onSameUrlNavigation = 'reload';
                          return await router.navigateByUrl(router.url);
                        } finally {
                          router.routeReuseStrategy.shouldReuseRoute = routeReuseStrategy;
                          router.onSameUrlNavigation = onSameUrlNavigation;
                        }
                      }
                    }
                    

                    【讨论】:

                      【解决方案16】:
                      private router: Router
                      
                      this.router.navigateByUrl(url)
                      

                      它将重定向到任何页面而不会丢失数据(甚至是当前页面)。数据将保持原样。

                      【讨论】:

                        猜你喜欢
                        • 2018-04-22
                        • 2011-07-15
                        • 2011-12-31
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-09-24
                        • 2020-04-22
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多