如何在 Angular 上使用 PushState ?

drt*_*pha 3 angular angular-router

我想更改网址而不重新加载页面。我使用定位服务,例如:

this.location.replaceState(`mynewurl`);
Run Code Online (Sandbox Code Playgroud)

当我返回时,历史记录并不好。我找到了 html5 PushState 解决方案。

我问是否没有像 Location 这样的服务可以处理 Angular 上的 PushState

Sid*_*era 7

您可以按照以下步骤来实现:

  1. import { Routes, RouterModule } from '@angular/router';
  2. 创建路由配置:

const routes: Routes = [
  { path: '', redirectTo: '/videos', pathMatch: 'full' },
  { path: 'videos', component: VideosComponent, children: [
    { path: ':id', component: VideoComponent },
    { path: '**', component: PlaceholderComponent }
  ] },
];
Run Code Online (Sandbox Code Playgroud)
  1. 添加RouterModule.forRoot(routes)imports您的数组中@NgModule

@NgModule({
  imports: [..., RouterModule.forRoot(routes), ...],
  ...
})
export class AppModule { }
Run Code Online (Sandbox Code Playgroud)
  1. 添加一个router-outlet标签app.component.html以及一个锚标签来videos路由:

<a routerLink="/videos">
  Videos
</a>

<router-outlet></router-outlet>
Run Code Online (Sandbox Code Playgroud)
  1. 在videos.component.html中创建另一个router-outlet带有视频链接的标签:

...
<div>
  <a routerLink="./1">Video 1</a> | 
  <a routerLink="./2">Video 2</a> | 
  <a routerLink="./3">Video 3</a> | 
  <a routerLink="./4">Video 4</a> | 
  <a routerLink="./5">Video 5</a> | 
</div>
<br>

<router-outlet></router-outlet>
Run Code Online (Sandbox Code Playgroud)
  1. 您现在可以使用 获取视频组件中的视频 ID ActivatedRoute。用它来显示适当的视频:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-video',
  templateUrl: './video.component.html',
  styleUrls: ['./video.component.css']
})
export class VideoComponent implements OnInit {

  videoId;

  constructor(private activatedRoute: ActivatedRoute) { }

  ngOnInit() {
    this.activatedRoute.params.subscribe(params => this.videoId = params['id']);
  }

}
Run Code Online (Sandbox Code Playgroud)

这是一个StackBlitz 示例供您参考。

更新:

如果您不想加载所有视频,则不要将:id路由设置为 的子路由videos。对您的路由配置进行此更改:

const routes: Routes = [
    { path: 'videos', component: VideosComponent },
    { path: 'videos/:id', component: VideoComponent },
    { path: '', redirectTo: '/videos', pathMatch: 'full' }
];
Run Code Online (Sandbox Code Playgroud)

并摆脱额外router-outletVideosComponent。这应该是按照你想要的方式。我也更新了示例 StackBlitz。

更新2

如果你想显示某种模式,那么你可以使用ngx-bootstrap. 然后在视频组件中ngOnInit打开模式。当用户单击关闭模式时,只需导航回/videos路线即可。

import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import { LocationListenerService } from '../location-listener.service';

@Component({
  selector: 'app-video',
  templateUrl: './video.component.html',
  styleUrls: ['./video.component.css']
})
export class VideoComponent implements OnInit {

  videoId;
  modalRef: BsModalRef;
  @ViewChild('template') template: TemplateRef<any>;

  constructor(
    private activatedRoute: ActivatedRoute,
    private modalService: BsModalService,
    private router: Router
  ) { }

  ngOnInit() {
    this.activatedRoute.params.subscribe(params => this.videoId = params['id']);
    if(!this.modalRef) {
      this.openModal(this.template);
    }
  }

  openModal(template: TemplateRef<any>) {
    this.modalRef = this.modalService.show(template);
  }

  closeModal() {
    this.modalRef.hide();
    this.router.navigate(['/videos']);
  }

}
Run Code Online (Sandbox Code Playgroud)

在你的模板中:

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">Modal</h4>
    <button type="button" class="close pull-right" aria-label="Close" (click)="closeModal()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <p>
      Playing Video {{ videoId }}
    </p>
  </div>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

这应该适合你。我重新编辑了 StackBlitz 示例。看看吧。

PS:它不会在/videos覆盖单击时导航回,但模式将关闭。这只是您可以自行处理的一种情况。剩下我在答案中解释的所有内容。希望这可以帮助。

更新3:

为了在后台显示视频,您必须再次创建路径':id',作为路径的子路径videos。但这又会要求您预先显示所有视频,这是您想要避免的情况。

无论如何,考虑到您最近要求我实现的目标,我已经对 StackBlitz 进行了更新。