You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 18中router.navigateByUrl跳转后页面内容不更新求助

Angular 18登录后路由跳转URL变更但页面不刷新问题

我使用Angular 18开发客户端应用,登录后调用router.navigateByUrl("/tasks")时,URL已成功变更为/tasks,但页面仍停留在登录页,只有手动刷新浏览器才能正常加载tasks页面。我已尝试新建项目排查配置问题,也试过新旧两种路由配置方式,均未解决。

路由配置

import { Routes } from '@angular/router'
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { TaskComponent } from './task/task.component';

export const routes: Routes = [
    {path: 'tasks', component:TaskComponent},
    {path: 'register', component:RegisterComponent},
    {path: 'login', component: LoginComponent},
    {path: '**', component: LoginComponent}
];

Task组件代码

import { Component, Injectable } from '@angular/core';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { MatRadioModule } from '@angular/material/radio';
import { ApiService } from '../api.service';
import { MatIconModule } from '@angular/material/icon'
import { ExcelImport } from '../../models/ExcelImport';
import { NgFor, NgIf, DatePipe } from '@angular/common';
import { MatCardModule } from '@angular/material/card'
import { Router } from '@angular/router';
import { AppModule } from '../app.module';

@Component({
  selector: 'app-task',
  standalone: true,
  imports: [AppModule,MatCardModule,DatePipe,NgIf,NgFor,MatSlideToggle, MatRadioModule, MatIconModule],
  templateUrl: './task.component.html',
  styleUrl: './task.component.css'
})@Injectable()
export class TaskComponent {
  constructor(private service:ApiService, private router:Router){}
  items!:ExcelImport[];
  fileName = '';
  ngOnInit()
  {
    this.items = [];
    this.service.getTasksForUser().subscribe(res => res.forEach(element => {
      this.items.push(new ExcelImport(element.project, element.type, element.workerName, element.workerCompany, element.day))
  }))
  }
}

Login组件代码

import { Component, Injectable, OnDestroy, OnInit } from '@angular/core';
import { Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
import { ApiService } from '../api.service';
import { jwtDecode } from 'jwt-decode';
import { LayoutComponent } from '../layout/layout.component';
import { MatCardModule } from '@angular/material/card';
import { MatInputModule } from '@angular/material/input';
import { AppModule } from '../app.module';
import { webSocket } from 'rxjs/webSocket';
import { SnackBarService } from '../service/snackbar.service';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [AppModule, ReactiveFormsModule, MatCardModule, MatInputModule],
  templateUrl: './login.component.html',
  styleUrl: './login.component.css'
})
@Injectable()
export class LoginComponent {
  
  loginForm = this.fb.group({
    email: ['', Validators.required],
    password: ['',Validators.required]
  });

  url:string = 'ws://localhost:5160/RFID/ConnectClientToWebSocket';
  wsSubject = webSocket({
    url: this.url,
    deserializer: ({data}) => data
  });
  constructor(private fb:FormBuilder, 
    private authComponent:ApiService,
    private router:Router,
    private layout:LayoutComponent,
  private snackbar:SnackBarService) 
  {        
  }
  
  ngOnInit(){
    this.wsSubject.subscribe((message) =>
      {
        if(message === "Connected!" || message === "Already connected!")
          console.log(message)
        else if(message === "Nieznaleziono pracownika!")
        {
          this.snackbar.ShowSnackBar(message);
        }
        else
        {
          this.userLogin(message.replace('"', ''));
        }
      })
  }
  userLogin(token:string)
  {
    this.wsSubject.complete();
    this.wsSubject.unsubscribe();
    const decodedToken: any = jwtDecode(token.toString());
    this.layout.UserName = decodedToken.unique_name
    localStorage.setItem("UserId", decodedToken.TagId)
    localStorage.setItem("Token", token);
    this.router.navigateByUrl("/tasks").then(() => console.log('navigated'))
  }
  login(){
    const val = this.loginForm.value
    if (val.email && val.password)
    {
      this.authComponent.login(val.email, val.password).subscribe(x => 
      {
        if(x == null)
          this.router.navigateByUrl("/login");
        else
        {
          this.userLogin(x.toString())
        }
      }) 
    }
  }
  logout()
  {
    localStorage.removeItem("UserId")
    localStorage.removeItem("Token")
    this.layout.UserName = '';
    this.router.navigateByUrl('/login')
  }
}

app.config配置

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideClientHydration(),
    provideAnimationsAsync(),
    provideHttpClient(withInterceptors([AuthInterceptor])),
  ],
};

问题排查与解决

1. 确认根组件存在<router-outlet>

检查根组件(如app.component.html)是否包含<router-outlet>标签,这是Angular路由渲染组件的核心出口,缺失的话路由跳转后组件无法正常渲染。

2. 移除组件上的@Injectable()装饰器

TaskComponent和LoginComponent都是独立组件,不需要添加@Injectable()(该装饰器用于服务类),多余的装饰器可能导致组件注入异常,影响路由渲染。直接删除两个组件上的@Injectable()即可。

3. 清理独立组件的imports数组

独立组件的imports不应导入整个AppModule,只需导入所需的独立模块/组件:

  • Task组件修改后:
    imports: [MatCardModule, DatePipe, NgIf, NgFor, MatSlideToggle, MatRadioModule, MatIconModule]
    
  • Login组件修改后:
    imports: [ReactiveFormsModule, MatCardModule, MatInputModule]
    

4. 检查AuthInterceptor逻辑

查看AuthInterceptor是否存在拦截逻辑异常,比如是否在请求处理中强制导航回登录页,或者错误处理阻塞了路由跳转。

5. 调整WebSocket订阅与路由跳转顺序

在userLogin方法中,complete()已会关闭WebSocket订阅,无需重复调用unsubscribe()。若路由仍无响应,可尝试将路由跳转放入微任务队列:

userLogin(token:string)
{
  this.wsSubject.complete();
  const decodedToken: any = jwtDecode(token.toString());
  this.layout.UserName = decodedToken.unique_name
  localStorage.setItem("UserId", decodedToken.TagId)
  localStorage.setItem("Token", token);
  setTimeout(() => {
    this.router.navigateByUrl("/tasks");
  }, 0);
}

6. 替换路由跳转方法

尝试用router.navigate()替代navigateByUrl:

this.router.navigate(['/tasks'])

内容的提问来源于stack exchange,提问作者Karo S-S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:07:29