有关如何制作影响 Angular 中所有组件的主题机制的指南?
Guidance on how to make a theming mechanism that effects all components in Angular?
问题:
我需要有关如何在 Angular 中编写机制以在我的应用程序中全局设置 "Look and Feel" 组件的指导。请注意,我正在尝试学习 @ngrx/platform,我认为这将是一个有趣的设计约束;但是,如果它没有意义,我愿意放手。
细分:
我正在处理一个包含许多组件的应用程序。我的应用程序中的每个组件目前有 3 个可能 "look and feels(L&F)":
- 早上(棕褐色)
- 下午(白色)
- 晚上(黑暗)
请注意,可能会有基于更精细时间的颜色光谱。
这些 L&F 由当前用户的一天中的时间设置,例如,如果用户当前时间是早上 7 点,则计算的 L&F 将设置为 "Morning"。我在名为 SundialModule
的 angular 模块的 ngrx/store 中跟踪此状态,而 gnomon
是 getting
或 [=19= 的减速器和操作机制] 状态:
sundial/reducers/gnomon.ts:
import * as gnomon from '../actions';
export interface State {
currentHour: number,
}
const initialState: State = {
currentHour: new Date().getHours()
};
export function reducer(state = initialState,
action: gnomon.Actions) {
console.log(action, 'action');
switch(action.type) {
case gnomon.MORNING:
return {
...state,
currentHour: 6,
};
case gnomon.AFTERNOON:
return {
...state,
currentHour: 12,
};
case gnomon.EVENING:
return {
...state,
currentHour: 7,
};
default:
return state;
}
}
现在我在其放置的元素上有一个 Angular Attribute directive called [sundialTheme]
that will set a HostBinding('class') theme = 'light'
。
sundial/directives/theme.ts
@Directive({
selector: '[sundialTheme]'
})
export class SundialThemeDirective implements OnInit {
@HostBinding('class') theme = 'light';
private gnomon: Observable<any>;
constructor(private store: Store<fromGnomon.State>) {
this.gnomon = store.select<any>('gnomon');
}
ngOnInit() {
this.gnomon.subscribe((theme) => {
if(theme.currentHour >= 7 && theme.currentHour <= 11){
this.theme = 'sepia';
} else if( theme.currentHour >= 12 && theme.currentHour <= 18) {
this.theme = 'light'
} else {
this.theme = 'dark'
}
});
}
}
问题: 我的应用程序中的每个组件都需要具有 sundialTheme
这个属性;此外,每个组件都会订阅 this.gnomon = store.select<any>('gnomon');
,感觉 expensive/heavyhanded。最后,顺便说一句,每个组件都需要在每个功能模块中注入我的 sundialModule
,并且每个组件都需要为一天中的每个时间设置一组主题:
这方面的一个例子,每个模板的组件。
注意:sundialTheme
属性指令:
<mh-pagination sundialTheme></mh-pagination>
<canvas glBootstrap class="full-bleed" sundialTheme></canvas>
<running-head [state]="(state$ | async)" sundialTheme></running-head>
<menu-navigation sundialTheme></menu-navigation>
<folio sundialTheme></folio>
<mh-footer sundialTheme></mh-footer>
具有 SundialModule
依赖关系的每个功能模块:
@NgModule({
imports: [
SundialModule
],
})
export class MenuModule {
}
每个组件 styleUrls sundial-links
:
注意丑陋的日晷-morning.scss
@Component({
selector: 'running-head',
templateUrl: 'running-head.component.html',
styleUrls: [
'running-head.component.scss',
'../../../components/sundial/sundial-morning.scss', // This !
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RunningHeadComponent {
}
终于有人给我提供了其他方式:
1) 因为我使用的是 Angular CLI,所以我可以在全局范围内添加我的样式,并在主体上设置一个指令 class。这似乎违反了任何一种网络组件标准。
2) 我可以在每个组件中使用工厂加载程序 styleUrls:[]
;我还没有弄清楚如何实施。
3) 我可以遵循 Material Design 组件架构,将主题直接添加到组件中,感觉不会很枯燥? (不过我没研究太深)
4) 我可以为每个组件制作自定义装饰器(可能可行,但我不确定如何实现)
还有其他建议吗?任何推理的最佳实践?
@HostBinding('class') theme = 'light'
最好是
@HostBinding('class.light') isLight = theme === 'light';
不覆盖此元素上的所有其他 classes。
您可以只在 AppComponent 中设置 class 并在组件样式中使用
:host-context(.light) {
// my light component styles here
}
问题:
我需要有关如何在 Angular 中编写机制以在我的应用程序中全局设置 "Look and Feel" 组件的指导。请注意,我正在尝试学习 @ngrx/platform,我认为这将是一个有趣的设计约束;但是,如果它没有意义,我愿意放手。
细分:
我正在处理一个包含许多组件的应用程序。我的应用程序中的每个组件目前有 3 个可能 "look and feels(L&F)":
- 早上(棕褐色)
- 下午(白色)
- 晚上(黑暗)
请注意,可能会有基于更精细时间的颜色光谱。
这些 L&F 由当前用户的一天中的时间设置,例如,如果用户当前时间是早上 7 点,则计算的 L&F 将设置为 "Morning"。我在名为 SundialModule
的 angular 模块的 ngrx/store 中跟踪此状态,而 gnomon
是 getting
或 [=19= 的减速器和操作机制] 状态:
sundial/reducers/gnomon.ts:
import * as gnomon from '../actions';
export interface State {
currentHour: number,
}
const initialState: State = {
currentHour: new Date().getHours()
};
export function reducer(state = initialState,
action: gnomon.Actions) {
console.log(action, 'action');
switch(action.type) {
case gnomon.MORNING:
return {
...state,
currentHour: 6,
};
case gnomon.AFTERNOON:
return {
...state,
currentHour: 12,
};
case gnomon.EVENING:
return {
...state,
currentHour: 7,
};
default:
return state;
}
}
现在我在其放置的元素上有一个 Angular Attribute directive called [sundialTheme]
that will set a HostBinding('class') theme = 'light'
。
sundial/directives/theme.ts
@Directive({
selector: '[sundialTheme]'
})
export class SundialThemeDirective implements OnInit {
@HostBinding('class') theme = 'light';
private gnomon: Observable<any>;
constructor(private store: Store<fromGnomon.State>) {
this.gnomon = store.select<any>('gnomon');
}
ngOnInit() {
this.gnomon.subscribe((theme) => {
if(theme.currentHour >= 7 && theme.currentHour <= 11){
this.theme = 'sepia';
} else if( theme.currentHour >= 12 && theme.currentHour <= 18) {
this.theme = 'light'
} else {
this.theme = 'dark'
}
});
}
}
问题: 我的应用程序中的每个组件都需要具有 sundialTheme
这个属性;此外,每个组件都会订阅 this.gnomon = store.select<any>('gnomon');
,感觉 expensive/heavyhanded。最后,顺便说一句,每个组件都需要在每个功能模块中注入我的 sundialModule
,并且每个组件都需要为一天中的每个时间设置一组主题:
这方面的一个例子,每个模板的组件。
注意:sundialTheme
属性指令:
<mh-pagination sundialTheme></mh-pagination>
<canvas glBootstrap class="full-bleed" sundialTheme></canvas>
<running-head [state]="(state$ | async)" sundialTheme></running-head>
<menu-navigation sundialTheme></menu-navigation>
<folio sundialTheme></folio>
<mh-footer sundialTheme></mh-footer>
具有 SundialModule
依赖关系的每个功能模块:
@NgModule({
imports: [
SundialModule
],
})
export class MenuModule {
}
每个组件 styleUrls sundial-links
:
注意丑陋的日晷-morning.scss
@Component({
selector: 'running-head',
templateUrl: 'running-head.component.html',
styleUrls: [
'running-head.component.scss',
'../../../components/sundial/sundial-morning.scss', // This !
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RunningHeadComponent {
}
终于有人给我提供了其他方式:
1) 因为我使用的是 Angular CLI,所以我可以在全局范围内添加我的样式,并在主体上设置一个指令 class。这似乎违反了任何一种网络组件标准。
2) 我可以在每个组件中使用工厂加载程序 styleUrls:[]
;我还没有弄清楚如何实施。
3) 我可以遵循 Material Design 组件架构,将主题直接添加到组件中,感觉不会很枯燥? (不过我没研究太深)
4) 我可以为每个组件制作自定义装饰器(可能可行,但我不确定如何实现)
还有其他建议吗?任何推理的最佳实践?
@HostBinding('class') theme = 'light'
最好是
@HostBinding('class.light') isLight = theme === 'light';
不覆盖此元素上的所有其他 classes。
您可以只在 AppComponent 中设置 class 并在组件样式中使用
:host-context(.light) {
// my light component styles here
}