【问题标题】:@HostBinding with a variable class in Angular@HostBinding 与 Angular 中的变量类
【发布时间】:2016-05-12 03:44:51
【问题描述】:

我有这段代码在主机上设置一个类:

@HostBinding('class.fixed') true;

我想做的是把它变成一个我可以修改的变量类。 我该怎么做?

【问题讨论】:

标签: angular


【解决方案1】:

已经有很多答案了,但没有一个提到NgClass。 在我看来,最可靠和最一致的方法是扩展 NgClass,因为它提供了我们开箱即用所需的一切:

@Directive({ selector: '[myDirective]'})
export class MyDirective extends NgClass {
  constructor(
    _iterableDiffers: IterableDiffers,
    _keyValueDiffers: KeyValueDiffers,
    _ngEl: ElementRef,
    _renderer: Renderer2
  ) {
    super(_iterableDiffers, _keyValueDiffers, _ngEl, _renderer);
  }

  setClass() {
    this.ngClass = {
      underline: true,
      bold: true,
      italic: true,
      pretty: false
    };

    // or
    this.ngClass = ['asd', 'abc', 'def'];

    // or 
    this.ngClass = 'foo';
  }
}

【讨论】:

    【解决方案2】:

    我必须与其他答案相矛盾,绑定class.foo 没有理由不起作用。实际上,以下格式可以正常工作:

    @HostBinding('class.foo') variableName = true;
    

    如果它在您的情况下不起作用,您可能需要为您的 CSS 类添加一个范围(您可以查看讨论 here)。

    问题是HostBinding 只能看到主机范围,这意味着它只能看到应用于组件本身的类和id,而不是它的子组件。所以当你写你的 CSS 时,你需要指定 CSS 属于组件本身(宿主伪元素)。

    根据Angular documentation

    使用 :host 伪类选择器来定位组件所在元素中的样式(而不是定位组件模板内的元素)。

    您只需在 CSS 规则前添加 :host 即可轻松指定主机范围:

    :host.foo { // It only matches <Component class="foo">
      /* Your CSS here */
    }
    

    代替

    .foo { // It matches any <element class="foo" /> inside <Component>
      /* Your CSS here */
    }
    

    如果你愿意,我创建了一个可以工作的 Plunker,你可以看到 clicking here

    【讨论】:

    • 我认为你不需要在 (.className) 周围加上括号,当你把它链接到 :host 时。我认为您制作链就像任何其他选择器字符串一样。 :host.className
    • 这是一个固定的类名,而不是一个可变的类名。
    【解决方案3】:
    @Input()
      class = '';
    
    @HostBinding('attr.class')
    get btnClasses() {
    return [
        'btn',
        this.someClassAsString,
        this.enableLight ? 'btn-secondary-light' : '',
        this.class,
    ].filter(Boolean).join(' ');
    };
    

    您可以使用输入劫持类属性并在主机绑定中添加您需要的内容

    【讨论】:

    【解决方案4】:

    Günter 的回答在已经将一些类名绑定到变量的情况下并没有真正的帮助。

    可变字符串类名与布尔样式预定义类名结合的好方法是使用classnames npm 包。

    将它与@HostBinding 和一个setter 函数一起使用可以获得惊人的结果:

    import * as classNames from 'classnames';
    
    (...)
    
    @HostBinding('class') get classes(): string {
      return classNames(this.getDynamicClassName(), {
        'is-open': this.isOpen,
        'has-children': this.hasChildren
      });
    }
    

    【讨论】:

      【解决方案5】:

      您可以使用类创建一些单独的指令。

      例如:我的页面中有一个按钮,并且有可能的状态:defaultprimarydangerfluid。按钮可以有许多不同的状态,但是由于代码量很大,我将向您展示这三种状态。那么让我们开始吧!

      button.ts

      //default button
      
      @Directive({
          selector: '[appButtonDefault]'
      })
      export class ButtonDefaultDirective {
      
          // the name of the field is not important
          // if you put this directive to element, 
          // this element will have the class called 'button--default'
      
          @HostBinding("class.button--default")
          private defaultClass: boolean = true;
      }
      
      
      //primary button
      
      @Directive({
          selector: '[appButtonPrimary]'
      })
      export class ButtonPrimaryDirective {
      
          // the name of the field is not important
          // if you put this directive to element, 
          // this element will have the class called 'button--primary'
      
          @HostBinding("class.button--primary")
          private primaryClass: boolean = true;
      }
      
      
      // danger button
      
      @Directive({
          selector: '[appButtonDanger]'
      })
      export class ButtonDangerDirective {
      
          // the name of the field is not important
          // if you put this directive to element, 
          // this element will have the class called 'button--primary'
      
          @HostBinding("class.button--danger")
          private dangerClass: boolean = true;
      }
      
      @Directive({
          selector: '[appButtonFluid]'
      })
      export class ButtonFluidDirective {
      
          // the name of the field is not important
          // if you put this directive to element, 
          // this element will have the class called 'button--primary'
      
          @HostBinding("class.button--fluid")
          private fluidClass: boolean = true;
      }
      
      
      // you need to also create a component class,
      // that import styles for this button
      @Component({
          //just put created selectors in your directives
          selector: `[appButtonDefault], [appButtonPrimary], 
                     [appButtonDanger], [appButtonFluid]`,
          styleUrls: ['<-- enter link to your button styles -->'],
      
          // it is required, because the content of <button> tag will disappear
          template: "<ng-content></ng-content>" 
      })
      export class ButtonComponent {}
      
      
      // you don't have to do it, but I prefet to do it
      
      @NgModule({
          declarations: [
              ButtonDefaultDirective,
              ButtonPrimaryDirective,
              ButtonDangerDirective,
              ButtonFluidDirective,
              ButtonComponent
          ],
          exports: [
              ButtonDefaultDirective,
              ButtonPrimaryDirective,
              ButtonDangerDirective,
              ButtonFluidDirective,
              ButtonComponent
          ]
      })
      export class ButtonModule {}
      

      不要忘记将ButtonModule 导入到您的app.module.ts 文件中。这很重要。

      app.component.html

      <!-- This button will have the class 'button--default' -->
      <button appButtonDefault>Default button</button>
      
      <!-- But this button will have the class 'button--primary button--fluid' -->
      <button appButtonPrimary appButtonFluid>Primary and fluid</button>
      

      希望对你有帮助。

      【讨论】:

      • 我希望这种方法没有用在你的生产代码中...很多代码而不是一行 跨度>
      • 优秀的答案!谢谢
      • @MarkosyanArtur 从这个角度来看,有很多编码。由于不需要额外的指令,您的解决方案也很好,但您知道:如果您创建这些指令,那么您不必记住类名。相反:您可以使用指令名称。这会导致更好的验证。如果您提供错误的指令名称,则应用程序将无法启动。不同的是直接添加类。
      【解决方案6】:

      如果您的课程数量有限,您可以有条件地添加每个课程:

      @HostBinding('class.c1') get c1 () { return this.useC1; } 
      @HostBinding('class.c2') get c2 () { return this.useC2; }
      

      注意.c1.c2需要在组件外定义。

      Plunker

      【讨论】:

      • 我需要添加() 才能使其工作(例如get c1() { return this.useC1; }
      • 如果您使用:host 选择器,则不需要在组件外部定义.c1.c2。例如,请参阅此答案:stackoverflow.com/questions/35168683/…
      • 对我来说,在方法名称之前添加“get”关键字后它就起作用了。谢谢:)
      【解决方案7】:

      这不能是可变的。

      你可以做的是直接绑定到类属性

      @HostBinding('class') classes = 'class1 class2 class3';
      

      【讨论】:

      • 反对票有什么用?它没有工作吗?从那以后发生了一些变化,导致绑定到 [class]="..." 时出现问题,这也可能会影响这种方法。
      • 你先生,你是救命恩人!
      • 这可行,但问题是它会覆盖从父组件添加到宿主元素的任何类
      • @GünterZöchbauer,这个问题是在 GitHub 上的某个地方提出的吗?你能分享一个问题的链接吗?
      • @GünterZöchbauer - 我已经创建了一个问题 (github.com/angular/angular/issues/26251) - 看看会发生什么。
      猜你喜欢
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 2018-04-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多