关于如何建立影响Angular中所有组件的主题化机制的指南? [英] Guidance on how to make a theming mechanism that effects all components in Angular?

查看:93
本文介绍了关于如何建立影响Angular中所有组件的主题化机制的指南?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要有关如何在Angular中编写机制以在我的应用程序中全局设置组件的外观"的指南.请注意,我正在尝试学习 @ ngrx/platform ,我认为这将是一个有趣的设计约束;但是,如果它没有意义,我愿意放手.

I need guidance on how to write a mechanism in Angular to set the "Look and Feel" of components globally in my application. Please note, I'm trying to learn @ngrx/platform and I thought this would be an interesting design constraint; however, I'm willing to let it go if it just doesn't make sense.

故障:

我正在处理包含许多组件的应用程序.我的应用程序中的每个组件目前都有3种可能的外观(L& F)":

I have an application in progress with many components. Each component in my application has currently 3 possible "look and feels(L&F)":

  • 早晨(深褐色)
  • 下午(白色)
  • 晚上(黑暗)

请注意,根据更精细的时间,可能会出现一系列颜色.

通过当前用户的一天中的时间设置这些L& F,例如,如果用户当前时间是7 AM,则将计算出的L& F设置为早晨".我正在 ngrx/store 中跟踪此状态一个名为SundialModulegnomon的角模块是化简器和gettingsetting状态的动作的机制:

These L&Fs are set by the time of day of the current user e.g if user current time is 7 AM, the calculated L&F would be set to "Morning". I'm tracking this state inside ngrx/store of an angular module called SundialModule and gnomon is the mechanism of reducers and actions for getting or setting state:

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;
    }
}

现在,我有一个名为[sundialTheme] Angular Attribute指令,它将设置一个 HostBinding('class') theme = 'light' 放置在其上的元素上.

Now I have an Angular Attribute directive called [sundialTheme] that will set a HostBinding('class') theme = 'light' on the element it's placed upon.

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');订阅,这感觉很贵/繁重.最后,顺便说一句,每个组件都需要在每个功能模块中注入我的sundialModule,并且每个组件在一天中的每个时间都需要一组主题:

The problem: Every component in my application will need to have this attribute of sundialTheme; moreover, every component will have a subscription to the this.gnomon = store.select<any>('gnomon');, which feels expensive/heavyhanded. Lastly, and as an aside gripe, is that, every component will need to have my sundialModule injected at every feature module, and every component will need the set of themes for each Time of day:

一个示例,每个模板的组件. 注意:sundialTheme属性指令:

An example of this, every template's component. note: sundialTheme attribute directive:

<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依赖项的功能模块:

Every Feature Module with a SundialModule dependency:

@NgModule({
  imports: [
    SundialModule
  ],
})
export class MenuModule {
}

带有sundial-links的每个组件styleUrls: 注意丑陋的sundial-morning.scss

Every component styleUrls with sundial-links: note the ugly sundial-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 {
}

最后,我还提供了其他方法:

Finally I've had other ways offered to me:

1)由于我使用的是Angular CLI,因此可以全局添加样式,并可以在主体上设置一个指令来设置类.这似乎违反了任何一种Web组件标准.

1) Since I'm using Angular CLI, I could add my styles globally and have a directive set a class on the body. Which seems to break any kind of web component standards.

2)我可以在每个组件中使用工厂装载程序.我还不清楚如何实现.

2) I could use a factory loader in each components styleUrls:[]; which I havent gotten clarity on how to implement.

3)我可以遵循材料设计组件架构,该架构将主题直接添加到感觉不太干燥的组件中? (但是,我还没有做过深入的研究)

3) I could follow material design components architecture which adds the themes directly into the components which doesn't feel very dry? (however, I havent researched too deeply into)

4)我可以为每个组件创建一个自定义装饰器(可能可行,但我不确定如何实现)

4) I could make a custom decorator for each component (could be viable but I'm nto sure how to implement)

还有其他建议吗?有推理的最佳做法吗?

Any other suggestions? Any best practices with reasoning?

推荐答案

@HostBinding('class') theme = 'light'

最好是

@HostBinding('class.light') isLight = theme === 'light';

不覆盖此元素上的所有其他类.

to not overwriting all other classes on this element.

您只能在AppComponent中设置类并以组件样式使用

You can set the class only in AppComponent and use in component styles

:host-context(.light) {
  // my light component styles here
}

这篇关于关于如何建立影响Angular中所有组件的主题化机制的指南?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆