是否有某种方法可以将css动态应用于我的子组件?

是否有某种方法可以将css动态应用于我的子组件?,css,angular,Css,Angular,我有一个可重用的组件。该组件从父组件多次调用,有时父组件的背景页为白色,有时为黑色 My child组件动态生成表单标记-输入、选择、文本区域 这意味着在我的内容组件中,css中不能有固定的样式 因此,当背景页面为白色时,我有一种输入样式,例如黑色背景。当背景页面为黑色时,我有另一种输入样式-例如白色Baggrkound 要解决这个问题,需要: 我试过了 在我的子组件ts文件中添加输入属性 @Input() public cssTemplate; 在html中 <div

我有一个可重用的组件。该组件从父组件多次调用,有时父组件的背景页为白色,有时为黑色

My child组件动态生成表单标记-输入、选择、文本区域

这意味着在我的内容组件中,css中不能有
固定的
样式

因此,当背景页面为白色时,我有一种输入样式,例如黑色背景。当背景页面为黑色时,我有另一种输入样式-例如白色Baggrkound

要解决这个问题,需要:

我试过了

在我的子组件ts文件中添加输入属性

  @Input()
  public cssTemplate;

在html中

    <div [ngClass]="{'form-group-white-bg': cssTemplate == 'white', 'form-group-dark-bg': cssTemplate == 'black'}">
        <label for=""></label>
....



....
在子组件中,我根据调用子组件的位置发送输入属性的值

如果在白色背景的页面上调用

<app-form-group cssTemplate="black" formControlName="address">
</app-form-group>

如果它是在黑色的巴格孔德上调用的

<app-form-group cssTemplate="white" formControlName="address" [data]="{ field: 'address', label: 'Address' }">
</app-form-group>

但这里的问题是,有时在我的父组件上,这个组件被称为乘法 在一个页面上可以调用12次,其中我需要10个输入和2个选择

在其他页面上可以调用15次等

这意味着我需要重新包装自己15次

<app-form-group cssTemplate="white" formControlName="address">
</app-form-group>

<app-form-group cssTemplate="white" formControlName="someItherControlName">
</app-form-group>

到处都可以放置
cssTemplate=“white”

ngFor
不是选项,因为此子组件被称为乘法,但不在父组件的HTML结构中的同一位置


如何解决此问题?

您可以在styles.css(适用于所有应用程序的常规样式)中添加样式。如果你有

.white h1{
  color:red;
}
.black h1{
  color:green;
}
您可以在“父级”中使用[ngClass]

这允许“扩展”组件-在stackblitz中变量“主题”更改-
[1] :

您可以使用输入属性创建css类映射以传递给ngClass。此对象应该是字符串数组的对象。 它可以非常复杂,包含您需要的任意多的类和规则


@输入()颜色:“白色”|“红色”|“热粉色”=“白色”;
类图:任意;
恩戈尼尼特(){
this.updateClassMap();
}
updateClassMap(){
this.classMap={
[this.color]:!!this.color,//如果不为null,则添加此类
};
}
然后在Html中,只需将其传递给ngClass


根据父组件设置子组件的样式 在这种情况下,我通常采用两种方法

  • :ng deep-基于父组件中设置的类创建样式规则
  • 利用
    @ContentChildren()
    直接在子组件上设置属性,并在更改后手动调用
    detectChanges()
  • 要采用第一种解决方案,您需要在css命名规则中更加小心,因为使用ng deep显然打破了这些样式规则的隔离

    采用第二种方法需要一些考虑,因为它在技术上绕过了角度上的标准输入/输出流,因此对于应用程序的任何其他维护人员来说,可能有点意外的“未记录行为”

    我有点犹豫是否我更喜欢一种方法而不是另一种。第一种方法对我来说似乎更微不足道,但它也可能导致意外的样式规则覆盖,而第二种方法涉及更多的脚本编写,看起来有点像黑客

    方法1:ng deep
  • 为父组件提供输入,并更新包装
    的块元素上的类
  • 在子组件中创建所需的样式规则
  • //父组件
    @组件(…)
    导出类FooParent{
    @输入()bgStyle:'light'|'dark'='light';
    }
    
    
    
    //child.css
    ::ng deep.light.child容器{
    背景颜色:浅蓝色;
    }
    ::ng深。深。子容器{
    背景颜色:皇家蓝;
    }
    
    在示例中,我的目标元素是
    .child container
    ,您可以为要影响的每个元素编写类似的样式规则

    方法2:使用ContentChildren传递值
  • @ContentChildren()
    装饰器添加到为子组件选择的父组件
  • 插入一个
    ChangeDetectorRef
  • 实现ngAfterViewInit以循环遍历每个子级并设置值
  • 完成后调用
    detectChanges()
  • 像在子组件中一样添加
    ngClass
    指令
  • 父母亲
    @组件({
    选择器:'父',
    templateUrl:'parent.component.html',
    样式URL:['parent.component.scss']
    })
    导出类ParentComponent实现AfterViewInit,OnChanges{
    @输入()bgStyle:'light'|'dark'='light';
    @ContentChildren(ChildComponent)childComponents!:QueryList;
    构造函数(私有更改:ChangeDetectorRef){
    }
    ngOnChanges(更改:SimpleChanges){
    如果('bgStyle'在更改中){
    this.updateChildComponents();
    }
    }
    updateChildComponents(){
    this.childComponents.forEach(child=>{
    child.bgStyle=this.bgStyle;
    });
    this.change.detectChanges();
    }
    ngAfterViewInit(){
    this.updateChildComponents();
    }
    }
    
    用法
    
    

    注意:如果直接在
    ParentComponent
    自己的模板中创建
    ChildComponent
    ,您需要使用
    @ViewChildren
    而不是
    @ContentChildren

    Tnx来进行响应。但是我仍然需要在每个子组件调用中传递
    cssTemplate=“white”
    ,以判断它是白色还是黑色。这是我的问题,而不是css。为什么?如果使用styles.css,则样式将应用于所有应用程序。这样做的目的是让您的子组件的样式“窗体组白色背景”和“窗体组黑色背景”。我想会的
    <div [ngClass]="toogle?'white':'black'">
      <hello name="{{ name }}"></hello>
    </div>
    <button (click)="toogle=!toogle">toogle</button>
    
    @Directive({
      selector: 'hello', //<--the selector is the selector of the component
      exportAs: 'helloDiv'
    })
    export class HelloDirective implements OnInit{
      constructor(@Self() private component:HelloComponent,private dataService:DataService){
      }
      ngOnInit(){
         console.log(this.component.name)
         this.dataService.theme.subscribe(res=>{
           this.component.theme=res;
         })
      }
    }
    
    <!-- parent.component.html -->
    <ng-content></ng-content>
    
    <!-- child.component.html -->
    <div [ngClass]="{light: bgStyle == 'light', dark: bgStyle == 'dark'}" class="child-container"></div>