Angular7预渲染+Cordova9环境下location.back()路由异常求助
哥们,我之前在Angular+Cordova的项目里刚好踩过几乎一模一样的坑,结合你Angular7+预渲染+Cordova9的场景,大概率是这几个原因在搞鬼:
预渲染与Cordova本地文件系统的路径冲突
预渲染默认基于Web服务器根目录生成静态文件,但Cordova是在本地文件系统(比如file:///android_asset/www/)加载页面的。如果你的index.html里还在用<base href="/">根路径,调用location.back()时,浏览器会把路径解析到file:///(直接跳出www目录),而非file:///android_asset/www/。
解决办法:把<base href="/">改成<base href="./">,或者构建Angular项目时加上--base-href ./参数,确保所有路由路径都是相对www目录的。原生
location.back()与Angular路由栈不同步
Angular维护自己的路由栈,而window.location.back()操作的是Cordova WebView的浏览器历史栈。预渲染页面加载时,WebView的历史栈可能会多一条初始的file:///android_asset/www/记录,调用location.back()时就会退到这条跳出www的路径。
解决办法:别用原生的location.back(),改用Angular自带的Location服务的back()方法,它会和Angular路由栈同步。先在组件里注入Location:import { Location } from '@angular/common'; constructor(private location: Location) {} goBack() { this.location.back(); // 仅操作Angular路由栈,不会触发WebView的错误历史跳转 }物理返回键的默认行为与Angular路由冲突
Cordova的物理返回键默认操作WebView的历史栈,如果Angular路由跳转没有正确同步WebView的历史记录(比如用了skipLocationChange选项),或者预渲染导致历史栈混乱,就会出现跳去www外的情况。
解决办法:重写物理返回键的事件监听,优先处理Angular路由栈。比如在app.component.ts里添加:import { Router } from '@angular/router'; constructor(private router: Router) {} ngOnInit() { // 确保在Cordova deviceready事件触发后注册监听 document.addEventListener('deviceready', () => { document.addEventListener('backbutton', () => { // 如果当前不是根路由,用Angular路由后退 if (this.router.url !== '/') { this.router.navigate(['../'], { relativeTo: this.router.routerState.root }); } else { // 根路由时退出应用 navigator.app.exitApp(); } }); }); }PathLocationStrategy在本地文件系统的兼容性问题
Angular默认用PathLocationStrategy(干净的URL路径),但这种策略依赖Web服务器的URL重写,而Cordova的本地文件系统没有这个能力。预渲染生成的静态路由页面,在本地访问时会被解析成真实的文件路径,后退时容易跳出www目录。
解决办法:切换到HashLocationStrategy,在AppModule的路由配置里加上useHash: true:import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [...]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule] }) export class AppRoutingModule {}这样路由会变成
/#/your-route的形式,所有路径都基于index.html,不会跳出www目录。
内容的提问来源于stack exchange,提问作者MazarD

