如何在不使用组件的情况下从angular2路由重定向到外部URL?

时间:2016-10-20 09:23:07

标签: javascript angular angular2-routing

我想创建一个外部重定向,但为了使所有路由保持一致,我认为在路由器状态配置下做所有事情(包括外部重定向)会很好。

这样:

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'first', component: FirstComponent},
  {path: 'second', component: SecondComponent},
  {path: 'external-link', /*would like to have redirect here*/}      
];

UPD :和我不想在这种情况下使用空组件,如 @koningdavid 建议。对我来说这个解决方案看起来很奇怪。对于没有虚拟组件的情况,这应该是非常容易实现的。

10 个答案:

答案 0 :(得分:53)

您可以使用路线的resolve选项通过技巧实现您想要的效果。 Resolve是Angular2将为要初始化的路由获取的一些数据值。您可以在官方文档中找到更多详细信息here

我尝试过这种方法,但确实有效。例如:

将此添加到提供程序部分(再从路由导入所需的类)

@NgModule({
    providers: [
        {
            provide: 'externalUrlRedirectResolver',
            useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
            {
                window.location.href = (route.data as any).externalUrl;
            }
        }
    ]
})

然后你可以这样定义你的路线:

{
        path: 'test',
        component: AnyRandomComponent,
        resolve: {
            url: 'externalUrlRedirectResolver'
        },
        data: {
            externalUrl: 'http://www.google.com'
        }
    }

这将重定向到外部URL。这真的是一种hackish的方式。我试图在不使用组件的情况下实现结果,但您必须使用redirectTocomponentchildrenloadChildren。 <{1}}不会触发决心,我不确定孩子,虽然你可以试验。

您可以在一个很好的类中实现它,而不是在提供程序中直接执行它。文档中的更多信息(参见上面的参考资料)。

P.S。我想我自己宁愿使用重定向组件。只需使用数据技巧并通过redirectTo从路由器获取状态即可将其作为参数。

答案 1 :(得分:20)

您可以创建RedirectGuard:

import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, Router, RouterStateSnapshot} from '@angular/router';

@Injectable()
export class RedirectGuard implements CanActivate {

  constructor(private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {

      window.location.href = route.data['externalUrl'];
      return true;

  }
}

将其导入app.module:

providers: [RedirectGuard],

并定义您的路线:

{
     path: 'youtube',
     canActivate: [RedirectGuard],
     component: RedirectGuard,
     data: {
       externalUrl: 'https://www.youtube.com/'
     }
 }

答案 2 :(得分:16)

据我所知,NG2路由器不支持外部重定向。您可以创建重定向组件作为解决方法。

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

@Component({
  selector: 'redirect',
  template: 'redirecting...'
})
export class RedirectComponent implements OnInit {
  constructor() { }

  ngOnInit() {
    window.location.href = 'http://www.redirecturl.com'
  }
}

并在路由中使用

{ path: 'login', component: RedirectComponent, pathmath: 'full'},

答案 3 :(得分:8)

嗯...

我认为你可以简单地请求URL而不是调用ng2 Router ...

例如......

<a href="http://example.com">External</a>

而不是

<a routerLink="/someRoute" routerLinkActive="active">External</a>

window.location.href = 'http://www.example.com'

而不是

this.router.navigate( [ '/someRoute', 'someParam' ] );

右键...?

答案 4 :(得分:4)

路由器无法从外部重定向。外部资源不能是应用程序的状态。

如果只是为了清晰起见,保持所有路线在一个地点可见,你可以定义另一个常数阵列,其中所有外部路径与路线在同一个文件中。

答案 5 :(得分:2)

我认为你不想为每个网址创建一个组件,这就是为什么你不想在没有组件的情况下这样做的原因......

所以你可以尝试创建一个为你生成组件对象的函数......

例如......

function generateLinkingComponent( url ) {
  // Generate your component using koningdavid's code
  // replace 'http://www.redirecturl.com' with url param
  // and return it...
}

并在路由器配置中添加这样的内容......

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'first', component: FirstComponent},
  {path: 'second', component: SecondComponent},
  {path: 'external-link', component: generateLinkingComponent( 'http://example.com' )},
  {path: 'client-login', component: generateLinkingComponent( 'http://client-login.example.com' )},
  {path: 'admin-login', component: generateLinkingComponent( 'http://admin.example.com' )},
];

这对于JS来说很容易......但是不确定如何在typeScript函数中返回一个类...

希望有帮助...

答案 6 :(得分:1)

结束伊利亚的回答:

添加此模块。

import { Component, Injectable, NgModule } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';

@Component({
  template: ''
})
class ExternalLinkComponent {
  constructor() {
  }
}

@Injectable()
class ExternalLinkResolver implements Resolve<any> {
  resolve(route: ActivatedRouteSnapshot): any {
    window.location.href = route.data.targetUri;
    return true;
  }
}

export class ExternalRoute {
  data: {
    targetUri: string;
  };
  path: string;
  pathMatch = 'full';
  resolve = { link: ExternalLinkResolver };
  component = ExternalLinkComponent;

  constructor(path: string, targetUri: string) {
    this.path = path;
    this.data = { targetUri: targetUri };
  }

}

@NgModule({
  providers: [ ExternalLinkResolver ],
  declarations: [ExternalLinkComponent]
})
export class ExternalRoutesModule { }

然后导入ExternalRoutesModule并添加ExternalRoute的实例。

const childRoutes: Routes = [
  new ExternalRoute('', '/settings/account'),
  { path: 'staff-profiles', component:  StaffProfilesComponent},
  { path: 'staff-assignments', component:  StaffAssignmentsComponent}
];

const routes: Routes = [
  { path: '', component: BaseComponent, children: childRoutes }
];

@NgModule({
  imports: [ ExternalRoutesModule, RouterModule.forChild(routes) ],
  exports: [ RouterModule ]
})
export class SettingsRoutingModule { }

注意我在这个例子中通过loadChildren挂载子模块路径。

答案 7 :(得分:0)

您可以使用 NavigationEnd 事件。

从“ @ angular / router”导入{NavigationEnd,Router};

app.component.ts

this.router.events.subscribe(event => {
  if (event instanceof NavigationEnd) {
    if (event.url.includes('faq')) {
      // open in the same tab:
      window.location.href = 'https://faq.website.com';

      // open a new tab:
      // window.open('https://faq.website.com', '_blank');

      // and redirect the current page:
      // this.router.navigate(['/']);
    }
  }
});

PS 。别忘了从AppRoutingModule中删除路线。

答案 8 :(得分:0)

只需使用:

{
    path: 'external-link',
    loadChildren: () => new Promise( () => { if(window.location.href.match(/external-link/) ) window.location.href = 'https://external-link.com/'; } ) 
  },

答案 9 :(得分:0)

这是一个应该可以为您工作而不会出现很多问题的代码。仅供参考,路由器事件错误处理程序可以放在任何位置,而不管组件中的位置如何。

app.component.html

Angular Port is in 4200
<a routerLink="/test">Main Link - 1</a> |

<a [routerLink]="getLinkWithExternal({url: '/test', external:false})">Other Link - 1a</a> |
<a [routerLink]="getLinkWithExternal({url: 'http://localhost:4211', external:true})">Other Link - 1b</a> |

<a [routerLink]="getLink({url: '/test'})">Other Link - 1a</a> |
<a [routerLink]="getLink({url: 'http://localhost:4211'})">Other Link - 1b</a> |


<a style="cursor: pointer; text-decoration: underline;" (click)="routeLink('/test')">Other Link - 1c</a> |
<a style="cursor: pointer; text-decoration: underline;" (click)="routeLink('http://localhost:4211')">Other Link - 1d</a>

<router-outlet></router-outlet>

app.component.ts

import { Component } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(private router: Router) { }

  // RECOMMENDATION - Add following in menus of each microservice (individual and different)
  //    external: true
  // Will make it a better menu structure for each microservice
  // If Single and same menu for all microservices then remove external === true
  // Logic One
  getLinkWithExternal(sidebarnavLink: any) {
    this.router.errorHandler = function (error: any) {
      if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
        window.location.href = sidebarnavLink.url.toString();
        return true;
      }
      return null;
    }.bind(sidebarnavLink);
    return [sidebarnavLink.url];
  }

  getLinkWithExternalWithEventSubscribe(sidebarnavLink: any) {
    this.router.events.subscribe(function (event) {
      if (event instanceof NavigationEnd) {
        if (event.url.includes('http')) {
          if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
            window.location.href = sidebarnavLink.url.toString();
            return true;
          }
          return this.router.navigateByUrl(sidebarnavLink.url);
          // return this.router.navigate([sidebarnavLink.url]);
        }
        return this.router.navigateByUrl(sidebarnavLink.url);
        // return this.router.navigate([sidebarnavLink.url]);
      }
    }.bind(sidebarnavLink))
  }

  getLinkWithExternalImplementationTwoWithNoRouteError(sidebarnavLink: any) {
    if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http") && sidebarnavLink.external === true) {
      window.location.href = sidebarnavLink.url.toString();
      return true;
    }
    return [sidebarnavLink.url];
  }

  // Logic Two
  getLink(sidebarnavLink: any) {
    this.router.errorHandler = function (error: any) {
      if (!sidebarnavLink.url.includes(window.location.origin.toString()) && sidebarnavLink.url.includes("http")) {
        window.location.href = sidebarnavLink.url.toString();
        return true;
      }
      return null;
    }.bind(sidebarnavLink);
    return [sidebarnavLink.url];
  }

  // Logic Three
  routeLink(lnk: any) {
    if (lnk.includes("http")) {
      console.log("Test");
      window.location.href = lnk;
      return true;
    }
    return this.router.navigateByUrl(lnk);
    // return this.router.navigate([lnk]);
  }

}