停止在路线更改时重新加载全部内容

Stop reloading the whole content on route change

我有一个如下所示的路由:page/:id,它为每个 id 加载不同的内容。但是,每次我转到不同的页面时,它都会重新加载全部内容。我只想重新加载来自 API.

的数据

导航:

<ul>
 <li [routerLink]="['/page', 1]">Page 1</li>
 <li [routerLink]="['/page', 2]">Page 2</li>
 <li [routerLink]="['/page', 3]">Page 3</li>
</ul>

模板: <h1 *ngIf="data">{{data.name}}</h1>

组件:

export class DataComponent implements OnInit {

  data: any;
  error: any;

  constructor(
    private route: ActivatedRoute,
    private service: DataService
  ) {}

  ngOnInit() {
    this.getData();
  }

  getData() {
    this.service.getData()
      .subscribe(
        res => this.data = res,
        error => this.error = error
      );
  }

}

如果您转到此 Plunker,您会看到每次路线更改时黑色矩形都会闪烁。理想情况下,黑色部分保持不变,只有里面的数据会发生变化。

我还注意到只有在使用 HTTP 调用时才会出现这种闪烁行为。如果我在那个组件中有其他东西,改变路线时就不会发生这种情况。

关于如何解决这个问题有什么想法吗?

编辑Here's a Plunkr 显示了预期的行为。但是,我使用的是以前的 ROUTER_DIRECTIVES,现在已弃用。

您已经只重新加载来自 API 的内容。黑框在闪烁,因为您正在设置 h1 的样式并且 h1 正在更改。如果您希望每个页面都有该框,请将其向上移动到 AppComponents 模板。

<div class="box">
    <router-outlet></router-outlet>
</div>

然后将样式移动到 .box 选择器而不是 h1

另一个问题是当内容被移除和刷新时框的高度会折叠和展开。您可以通过在路线上使用 resolve guard 来解决此问题。

https://angular.io/docs/ts/latest/guide/router.html#!#resolve-guard

你的闪烁是因为当你导航时,DataComponent 被破坏并重建,但是直到新数据从服务器到达它才能显示,因为你用 *ngIf="data" 阻止了它的显示。 On this plunker,我在服务器响应中添加了 1 秒的延迟以使问题更加明显。请注意,只有 DataComponent 闪烁。其余 PagesComponent 没有。

On this plunker,没有可见的闪烁,因为数据是硬编码的,所以不需要等待服务器的响应。

为了减轻闪烁,不要使用 *ngIf,因为那样会从 dom 中完全删除该元素。 On this plunker,甚至在我们等待数据从服务器到达时也没有闪烁。

基本上,只要您选择隐藏元素直到数据到达,无论何时重新初始化组件,您都会看到闪烁。

扩展@Rob 的回答,我确实设法使用 Resolve 守卫解决了这个问题。但是,我在实现过程中犯了一些错误。

我创建了一个新的 data-resolve,我在初始化路由之前解析了 HTTP 调用:

@Injectable()
export class DataResolve implements Resolve {

  constructor(private service: DataService, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot):
    Observable<any> | Promise<any> | any {
      return this.service.getData().then(data => {
        if (data) {
          return data;
        } else {
          this.router.navigate(['/page/1']);
         return false;
       }
    });
  }
}

然后,我需要将该服务添加到我的模块的提供者中:

providers: [DataService, DataResolve]

并且在加载路由之前告诉路由解决这个问题:

resolve: { pages: DataResolve }

之后,我将有一个数组,我可以在我的组件中使用它来获取数据:

this.route.data.forEach((data: {pages}) => {
  this.data = data.pages;
});

我还用一个工作示例更新了我的 Plunker