【问题标题】:How to apply css class to a component element when it's created by router-outlet?由路由器插座创建时如何将css类应用于组件元素?
【发布时间】:2021-05-11 20:50:17
【问题描述】:

我的 DOM 看起来像这样:

<app>
    <router-outlet></router-outlet>
    <project>...</project>
</app>

project 元素被路由器插入的位置。

如何向该元素添加类?

【问题讨论】:

    标签: angular angular2-routing


    【解决方案1】:

    假设你总是希望类应用到这个组件,你可以在你的组件元数据中使用host

    @Component({
      selector:'project',
      host: {
          class:'classYouWantApplied'
      }
    })
    

    导致:

    <app>
        <router-outlet></router-outlet>
        <project class="classYouWantApplied">...</project>
    </app>
    

    【讨论】:

    • 如果你不这样做呢?做&lt;router-outlet class="..."&gt;... 不起作用:/
    • 如果我想将类应用到所有路由组件怎么办?
    • 澄清:这样做之后,您必须将样式添加到 style.css... 至少对我而言,将其放在父级或子级中是行不通的。
    【解决方案2】:

    使用adjacent sibling selector* 通配符选择紧跟router-outlet 的元素


    styles.css

    router-outlet + * {
      /* your css */
    }
    

    【讨论】:

    • 据我所知,Angular 使用[_nghost_c1]-like 属性限定元素,例如router-outlet + *[_nghost_c1]。这也被添加到我的 css 中(我正在编译 scss,也许这就是原因),并且它不会应用于以另一种方式作用域的以下元素。
    • 您可以使用::ng-deep router-outlet.router-flex + * { display: flex; flex: 1 1 auto; flex-direction: column } 之类的东西并在组件中定义它。并且不要有人敢说它已被弃用。
    • 非常聪明!但是,就我而言,它并不能完美地工作,因为我在路线之间使用动画过渡。在过渡期间,&lt;router-outlet&gt; 有两个同级组件。传入和传出。要解决这个问题,只需将“+”替换为“~”即可。那是router-outlet ~ *
    • 完美运行。谢谢
    【解决方案3】:

    关键是/deep/关键字:

        :host /deep/ router-outlet + project {
            display: block;
            border: 10px solid black;
        }
    

    这无需任何额外配置即可工作。

    :host /deep/ router-outlet + * 用于 Angular 路由器动态创建的任何组件。

    于 2018 年 3 月 5 日编辑:

    由于Angular 4.3.0 已弃用/deep/,因此建议的替代方案是::ng-deep。还有一个long discussion 与此有关。

    【讨论】:

    • 看起来/deep/ 已被弃用。根据这个issue::ng-deep 可能是它现在的替代品。
    • @mfink 谢谢。我修改了答案。
    • ::ng-deep 现在也已弃用 (v8.0.0)
    【解决方案4】:

    你可以使用相邻兄弟选择器

    router-outlet + project { ... }
    

    https://developer.mozilla.org/en/docs/Web/CSS/Adjacent_sibling_selectors

    但前提是@drewmoore 的方法不适用。

    【讨论】:

    • 除非你关闭样式封装,否则它不会工作。
    • 你是什么意思,@MarcinKról?
    • 通过模拟视图封装,Angular 将兄弟选择器的范围限定为应用于路由器出口的属性。结果,兄弟姐妹没有样式。
    【解决方案5】:

    您可以使用HostBinding 执行此操作,这实际上与使用已经提到的host 属性相同,尽管该方法使用默认列表规则会引发 TSLint 错误。

    在要应用类的组件中:

    import { Component, HostBinding, Host (optional for typing) } from '@angular/core';
    
    @Component({...})
    export class GiveMeAClassComponent {
        @HostBinding('class.some-class') someClass: Host = true;
        ...
    }
    

    然后在您的根styles.scss 文件中,您可以添加以下内容:

    .some-class {
        // Styles in here will now be applied to your GiveMeAClassComponent at a root level
    }
    

    【讨论】:

      【解决方案6】:
      <app>
        <div class="your css class">
         <router-outlet></router-outlet>
      </div>
      </app>
      

      这对我有用

      【讨论】:

        【解决方案7】:

        如果您需要有条件地添加一个类,您可以从组件中以编程方式添加它:

        constructor(private renderer: Renderer2, private elemRef: ElementRef) {
          if(someCondition){
            renderer.addClass(elemRef.nativeElement, 'myClass');
          }
        }
        

        【讨论】:

          【解决方案8】:

          由于路由器在 router-outler 元素之后注入组件, 如果我们想用相同的规则集为所有注入的组件设置样式,那么以下规则可能会有所帮助。

          css "+" 操作符选择特定类型的第一个兄弟元素,而星号 (*) 用作通配符来选择 router-outlet 的任何第一个兄弟元素

          router-outlet + * {
            // your rules
          }
          

          【讨论】:

          • 你能提供一个更完整的例子吗?
          • ...并解释这段代码如何回答这个问题。
          【解决方案9】:

          目前,Angular 6 建议我使用 @HostBindings 和 @HostListeners 而不是主机属性:

          export class ProjectComponent {
            @HostBinding('class') classes = 'classYouWantApplied';
          }
          

          【讨论】:

            【解决方案10】:

            我创建了一个RouterOutletHelperDirective,可以根据需要进行修改。

            您的用例可能会有所不同,但对我来说:

            • 我需要在每个 router-outlet 生成的项目上设置一组默认类
            • 我需要防止基于特定条件(例如ActivatedRoute 数据)的这种默认设置。

            你这样使用它(类是可选的):

            <router-outlet routerOutletHelper
                           [routerOutletHelperClass]="'blue-border'"></router-outlet>
            

            然后创建指令,添加并导出到您的应用模块。

            import { Directive, ElementRef, Renderer2, Input } from "@angular/core";
            import { RouterOutlet } from "@angular/router";
            import { Subscription } from "rxjs";
            
            @Directive({
                selector: 'router-outlet[routerOutletHelper]'
            })
            export class RouterOutletHelperDirective
            {
                constructor(private routerOutlet: RouterOutlet,
                            private element: ElementRef<HTMLElement>,
                            private renderer: Renderer2) { }
            
                subscription = new Subscription();
            
                @Input('routerOutletHelperClass')
                customClassName: string | undefined;
            
                ngOnInit() 
                {
                    this.subscription.add(this.routerOutlet.activateEvents.subscribe((_evt: any) => {
            
                        // find the component element that was just added
                        const componentElement = this.element.nativeElement.nextSibling;
            
                        // add a custom class
                        if (this.customClassName) 
                        {
                            this.renderer.addClass(componentElement, this.customClassName);
                        }
            
                        // add my default classes, unless the activated route data 
                        // (specified in module routing file) has { addDefaultClasses: false }
                        if (this.routerOutlet.activatedRouteData && this.routerOutlet.activatedRouteData.addDefaultClasses !== false)
                        {
                            // these are my application's default classes (material / theming)
                            // (an additional data parameter could be 'darkTheme: boolean')
                            this.renderer.addClass(componentElement, 'mat-typography');
                            this.renderer.addClass(componentElement, 'rr-theme-light');
                        }
                    }));
                }
            
                ngOnDestroy()
                {    
                    this.subscription.unsubscribe();
                }
            }
            

            【讨论】:

            • 这不再适用于 ivy,因为新节点是在现有节点之后添加的,而在它之前添加之前
            【解决方案11】:

            对我来说,它有助于将路由器插座包装到另一个容器中。

            <div class="classYouWantApplied">
              <router-outlet>
            </div>
            

            像这样,您可以将类应用到周围的容器。

            【讨论】:

              【解决方案12】:

              添加主机类名,它将向组件添加一个类,然后使用相邻来定位元素。

              @Component({
                selector:'project',
                host: {
                    class:'Project-wrapper'
                }
              })
              

              现在使用与 angular 相邻的 CSS

              ::ng-deep to target it:
              ::ng-deep .Project-wrapper {}
              

              【讨论】:

                猜你喜欢
                • 2020-01-13
                • 1970-01-01
                • 2019-01-08
                • 2021-03-13
                • 2017-02-15
                • 2017-04-29
                • 2023-02-02
                • 2017-03-11
                • 1970-01-01
                相关资源
                最近更新 更多