我有一个可重复使用的组件。这个组件被父组件多次调用,父组件的背景页面有时是白色的,有时是黑色的。
我的子组件动态生成表单标签 - 输入、选择、文本区域。
这意味着我的内容的组件中的 css 中不能有 fixed
样式。
因此,当背景页面为白色时 - 我的输入只有一种样式 - 例如黑色背景。当背景页面为黑色时,我的输入有另一种样式 - 例如白色 bacgrkound。
要解决这个问题:
我试过了
在我的子组件 ts 文件中添加输入属性
@Input()
public cssTemplate;
在 html 中
<div [ngClass]="{'form-group-white-bg': cssTemplate == 'white', 'form-group-dark-bg': cssTemplate == 'black'}">
<label for=""></label>
....
在 CHILD 组件中,我根据子组件的调用位置发送输入属性的值
如果是在白色背景的页面上调用
<app-form-group cssTemplate="black" formControlName="address">
</app-form-group>
如果它是在黑色 bacgrkound 上调用的
<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 结构中的同一位置。
我该如何解决这个 DRY
?
答案 0 :(得分:0)
您可以在styles.css 中添加样式(所有应用程序的通用样式)。如果例如你有
.white h1{
color:red;
}
.black h1{
color:green;
}
您可以在“父级”中使用 [ngClass]
<div [ngClass]="toogle?'white':'black'">
<hello name="{{ name }}"></hello>
</div>
<button (click)="toogle=!toogle">toogle</button>
见[stackblitz][1]
注意:我使用的方式 [ngClass]="expresion"
(其中表达式使用条件运算符)比 [ngClass]="{'classname1':condition;'classname2':!condition}"
更新关于您的评论“我怎样才能防止在给孩子打电话时重复我自己”,我真的不太明白。我不知道你是否想制定一个指令,例如
@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;
})
}
}
这允许“扩展”组件-在stackblitz中变量“主题”更改- [1]:https://stackblitz.com/edit/angular-ivy-sjwxyq?file=src%2Fapp%2Fapp.component.html
答案 1 :(得分:0)
您可以使用输入属性创建一个 css 类映射以传递给 ngClass。这个对象应该是字符串数组的对象。 它可以非常复杂,并包含您需要的尽可能多的类和规则
@Input() color: 'white' | 'red' | 'hotpink' = 'white';
classMap: any;
ngOnInit() {
this.updateClassMap();
}
updateClassMap() {
this.classMap = {
[this.color]: !!this.color, // Add this class if not null
};
}
然后在 Html 中简单地将其传递给 ngClass
<div [ngClass]="classMap">
答案 2 :(得分:0)
在这种情况下,我通常采用两种方法
@ContentChildren()
直接在子组件上设置属性,并在更改后手动调用 detectChanges()
。要采用第一个解决方案,您需要更加注意 css 命名规则,因为使用 ng-deep 显然打破了这些样式规则的隔离。
采用第二种方法需要一些考虑,因为它在技术上绕过了 Angular 中的标准输入/输出流,因此对于应用程序的任何其他维护者来说,这可能是一个令人惊讶的“未记录行为”。
对于我是否更喜欢一种方法而不是另一种方法,我有点犹豫。第一种方法对我来说似乎更简单,但它也可能导致意外的样式规则覆盖,而第二种方法涉及更多的脚本,似乎有点黑客。
<ng-content>
的块元素上的类。// parent component
@Component(...)
export class FooParent {
@Input() bgStyle: 'light' | 'dark' = 'light';
}
<!-- parent component template -->
<div class="parent" [ngClass]="{light: bgStyle == 'light', dark: bgStyle == 'dark'}">
<ng-content></ng-content>
</div>
// child.css
::ng-deep .light .child-container {
background-color: lightblue;
}
::ng-deep .dark .child-container {
background-color: royalblue;
}
示例中我的目标元素是 .child-container
,您可以为要影响的每个元素编写类似的样式规则。
@ContentChildren()
装饰器,用于为您的子组件选择。ChangeDetectorRef
detectChanges()
。ngClass
指令。@Component({
selector: 'parent',
templateUrl: 'parent.component.html',
styleUrls: ['parent.component.scss']
})
export class ParentComponent implements AfterViewInit, OnChanges {
@Input() bgStyle: 'light' | 'dark' = 'light';
@ContentChildren(ChildComponent) childComponents!: QueryList<ChildComponent>;
constructor(private change: ChangeDetectorRef) {
}
ngOnChanges(changes: SimpleChanges) {
if ('bgStyle' in changes) {
this.updateChildComponents();
}
}
updateChildComponents() {
this.childComponents.forEach(child => {
child.bgStyle = this.bgStyle;
});
this.change.detectChanges();
}
ngAfterViewInit() {
this.updateChildComponents();
}
}
<!-- parent.component.html -->
<ng-content></ng-content>
@Component({
selector: 'child',
templateUrl: 'child.component.html',
styleUrls: ['child.component.scss']
})
export class ChildComponent implements OnInit {
bgStyle: 'light' | 'dark' = 'light';
constructor() {
}
ngOnInit(): void {
}
}
<!-- child.component.html -->
<div [ngClass]="{light: bgStyle == 'light', dark: bgStyle == 'dark'}" class="child-container"></div>
// child.component.css - you would apply styles as you needed obviously.
.child-container {
width: 40px;
height: 40px;
margin: .5rem;
}
.light.child-container {
background-color: lightblue;
}
.dark.child-container {
background-color: royalblue;
}
<!-- any other template -->
<parent>
<child></child>
<child></child>
<child></child>
</parent>
注意:如果您直接在 ChildComponent
自己的模板中创建 ParentComponent
,您需要使用 @ViewChildren
而不是 @ContentChildren