如何在Angular 7中处理连接丢失页面?

11

我希望的是,如果网络不可用,并且用户尝试导航到下一页,ConnectionLost 组件应该存在。

但是,如果没有网络,并且用户不采取任何操作,也就是不导航到第二页,则不应该有连接丢失页面。用户应该停留在当前页面。

为此,我已经实现了 canActivate 守卫,如下所示:

@Injectable({
  providedIn: 'root'
})
export class NetworkGuard implements CanActivate {
  constructor(private router: Router, private network: NetworkService) {
  }

  canActivate(next: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if (window.navigator.onLine) {
      return true;
    } else {
      if (!this.isConnectionLostComponent()) {
        this.router.navigate(['/connection-lost'], {skipLocationChange: true});
      }
      return false;
    }
  }

  private isConnectionLostComponent() {
    // check whether connection lost component is added on not
    return this.network.isActive;
  }
}

除了一个情况外,它的工作正常。 这是如果我从浏览器点击后退或前进,它会将更新URL connection-lost地址栏

我该怎么解决这个问题? 可以在这里查看示例

产生问题的步骤:

  1. 点击横幅(按钮)-> URL更改为'/banner'
  2. 点击品牌(按钮)-> URL更改为'/brand'
  3. 在那个品牌页面上断开网络连接
  4. 从浏览器点击后退-> ConnectionLostComponent和url是'/brand',没问题
  5. 再次点击后退-> ConnectionLostComponent但URL也更改为'/connection-lost'。 这就是我面临的问题。

我只是不想使用'/connection-lost'更新URL,因此在NetworkGuard中的router.navigate方法中添加了skipLocationChange: true选项,但仍然无效。


你可以存储最后访问的URL,如果用户返回到它,那么防止你的条件?除此之外,你不能做太多事情,因为浏览器禁止你知道用户是否点击了后退按钮。 - user4676340
https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine - Reactgular
@trichetriche 我可以检查最近访问的URL,但是我该如何防止用户在离线状态下回退呢?我已经在isConnectionLostComponent()方法中添加了类似类型的条件,请查看我的更新问题。 - Ravi Sevta
2个回答

10

我不知道这是否对你来说是正确的解决方案,但在我的项目中,我所做的是以下操作:

app.component.ts

constructor(){
this.onlineOffline = Observable.merge(of(navigator.onLine),
      fromEvent(window, 'online').pipe(map(() => true)),
      fromEvent(window, 'offline').pipe(map(() => false))
    );
}
<ng-container *ngIf="onlineOffline | async; then thenTemplate; else elseTemplate"></ng-container>
<ng-template #thenTemplate>
 <router-outlet></router-outlet>
</ng-template>
<ng-template #elseTemplate>
  <app-no-network></app-no-network>
</ng-template>

如果它没有按照你需要实现的方式工作,请告诉我。


这是一个很好的答案,我之前尝试过了,但这次我想在导航上展示“app-no-network”组件,而不是在用户断开网络时才显示。 - Ravi Sevta
顺便问一下,这样做有什么好处吗?我只是想知道。@RaviSevta - AlokeT
如果没有网络,用户可以查看当前页面内容。采取行动是次要的事情。@AlokeT - Ravi Sevta
2
你可以制作一个透明的覆盖层,并在没有网络时激活它,这样用户只能看到内容,但无法进行任何操作。还可以添加一个名为“show”的属性<app-no-network>,它将像YouTube的Android应用程序一样,在页面上显示小的变化。 - AlokeT
是的,那就是我想要的。 - Ravi Sevta
显示剩余2条评论

6

在稍微搜索一下并得到@AlokeT的帮助后,我解决了这个问题。

@AlokeT的建议是当用户失去网络连接时立即显示连接丢失页面。但我的需求是在用户尝试导航到另一个页面时显示该连接丢失页面。

在这个答案中,我只是添加了那个缺失的部分。

为此,我只需要从Guard更新那个isNetworkStopped标志,因为每个CanActivate守卫在导航开始之前都会执行。所以当用户更改路径时,连接丢失组件将显示。

这是我在NetworkGuard中正在使用的NetworkService的代码。

@Injectable({providedIn: 'root'})
export class NetworkService {

  online: boolean;
  isNetworkStopped = false;

  constructor() {
    this.online = window.navigator.onLine;

    fromEvent(window, 'online').subscribe(e => {
      this.online = true;
    });

    fromEvent(window, 'offline').subscribe(e => {
      this.online = false;
    });
  }
}

在上面的代码中,我只是添加了一个标志isNetworkStopped。并且从NetworkGuard更新了该标志,这意味着当用户尝试导航到下一页时发现没有网络。

同时还删除了NetworkGuard中的导航。 请查看下面我更新后的NetoworkGuard代码:

@Injectable({providedIn: 'root'})
export class NetworkGuard implements CanActivate {
  constructor(private network: NetworkService) {
  }

  canActivate(next: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if (this.network.online) {
      return true;
    }
    this.network.isNetworkStopped = true;
    return false;
  }
}

根据该标志位,我成功展示了“连接已断开”组件。 为此,在根组件的模板中添加了基于条件的ConnectionLost组件。

app.component.html

<router-outlet *ngIf="!networkService.isNetworkStopped"></router-outlet>
<app-connection *ngIf="networkService.isNetworkStopped"></app-connection>

如果用户在ConnectionLost组件中点击重新加载按钮,则通过检查网络连接,我会更新NetworkService的isNetworkStopped标志。


既然networkService已经有了“online”属性,为什么还需要isNetworkStopped标志呢? - peanut
是的,@peanut,这是真的,但是当用户导航到另一个组件时,我会更改此(isNetworkStopped)标志。这样,用户在更改路由时可以看到连接丢失组件,而不是立即看到连接丢失。这是我的主要需求。 - Ravi Sevta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接