我有一个简单的TopbarComponent,它基本上在我的 View 顶部添加了一个引导导航栏。

由于90%的模板都应包含此指令,因此我想通过app.component来处理它,如下所示:

import ...;

@Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html',
    directives: [ROUTER_DIRECTIVES, TopbarComponent, ...],
    providers: [ROUTER_PROVIDERS, ...]
})

@RouteConfig([
{
    path: '/login',
    name: 'Login',
    component: LoginComponent
},
{
    path: '/dashboard',
    name: 'Dashboard',
    component: DashboardComponent,
    useAsDefault: true
}
])

其模板如下所示:
<my-topbar></my-topbar>

<div class="container-fluid">
    <div class="row">
        <router-outlet></router-outlet>
    </div>
</div>

现在,我想使用ngIf(或使用CSS将其隐藏以外的任何其他方式)来隐藏多条路线上的顶部栏,例如/login
我尝试了几种使用@CanAcitvate()或在自己的OnActivate中实现LoginComponent的方法(以及从AppComponent中尝试它的方法),但是没有任何效果(甚至无法启动函数也有问题)。
我最近得到的是在Router中直接使用AppComponent,如下所示:
export class AppComponent implements OnInit{
    showTopbar:boolean;

    constructor(private _router:Router) {}

    ngOnInit():any {
        this.showTopbar = this._router.lastNavigationAttempt != '/login';
    }
}

在我的app.component.html中,我将指令更改为<my-topbar *ngIf="showTopbar"></my-topbar>
但这仅适用于我的应用程序的初始加载,因为不会在每次状态更改时触发ngOnInit。我是否可以使用(并且找不到)类似的方法?或者我在朝错误的方向移动吗?

编辑:

目前,PierreDuc的答案对我不起作用,但是我尝试了使用location.path()的类似方法,如下所示:
constructor(private _location:Location) {}

private get _hideTopbar() : boolean {
    switch(this._location.path()){
        case '/register':
        case '/login':
            return true;
        default:
            return false;
    }
};

太糟糕了,我无法以这种方式在data中使用@RouteConfig属性。感觉会更好。

最佳答案

我已经将类似问题困扰了一段时间。
起初,我发现的解决方案似乎有些棘手,但将来可以为我解决许多类似的问题。

基本上,您必须使router-outlet在路由更改时发出事件,让AppComponent监听该自定义事件。

第一步是创建自定义路由器导出:

@Directive({
selector: 'custom-router-outlet'
})
export class CustomRouterOutlet extends RouterOutlet {
    private parentRouter:Router;

    constructor(_elementRef: ElementRef,
            _loader: DynamicComponentLoader,
            _parentRouter: Router,
            @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);
    this.parentRouter = _parentRouter;
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
        //***YOUR CUSTOM LOGIC HERE***
        return super.activate(nextInstruction);
    }
}

这是自定义路由器导出的非常基本的实现。您的逻辑必须在Activate方法中实现,每次更改路径时都要调用该方法。
通过这种方法,您可以检查 route 的data属性。

主要的问题是,指令现在无法发出事件...它们仅接受输入,不能触发任何输出...

我找到了解决此问题的方法:使用EventEmitter创建一个服务以在组件和指令之间进行通信:
@Injectable()
export class PubsubService {
    private _pubSubber: EventEmitter<any> = new EventEmitter();

    routeisChanging(obj:any) {
        this._pubSubber.emit(obj);
    }

    onRouteChanged() {
        return this._pubSubber;
    }
}

AppComponent订阅onRouteChanged事件:
subscription:any;
constructor(private _pubsubService:PubsubService) {
    this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {
        /**YOUR CUSTOM LOGIC HERE*/});
}

需要时,CustomRouterOutlet会在activate方法中触发事件:
activate(nextInstruction: ComponentInstruction): Promise<any> {
    //***YOUR CUSTOM LOGIC HERE***
    this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);
    return super.activate(nextInstruction);
}

这样,您可以使用任何逻辑轻松实现路由器与AppComponent之间的通信。

您必须记住将通信服务注入(inject)应用程序的RootComponent中。

10-06 12:25