关于如何制作影响Angular中所有组件的主题机制的指导?

Mat*_*ood 11 themes global-state redux ngrx angular

题:

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

分解:

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

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

请注意,基于更精细的时间,可能会有一系列颜色.

这些L&F由当前用户的时间设置,例如,如果用户当前时间是早上7点,则计算的L&F将被设置为"早晨".我在一个名为ncurx/store的角度模块中跟踪这个状态,SundialModule并且gnomongetting或者setting状态的reducers和actions的机制:

日晷/减速/ 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

日晷/指令/ 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'
      }
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

问题:我的应用程序中的每个组件都需要具有以下属性sundialTheme; 此外,每个组件都会订阅this.gnomon = store.select<any>('gnomon');,这感觉很昂贵/笨重.最后,作为一个侧面抱怨,每个组件都需要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>
Run Code Online (Sandbox Code Playgroud)

具有SundialModule依赖关系的每个功能模块:

@NgModule({
  imports: [
    SundialModule
  ],
})
export class MenuModule {
}
Run Code Online (Sandbox Code Playgroud)

每个组件样式都带有sundial-links: 注意丑陋的日su-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 {
}
Run Code Online (Sandbox Code Playgroud)

最后我还有其他方式提供给我:

1)因为我使用的是Angular CLI,所以我可以在全局添加我的样式,并在主体上设置一个类.这似乎打破了任何类型的Web组件标准.

2)我可以在每个组件中使用工厂装载机styleUrls:[]; 我还没有明确如何实施.

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

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

还有其他建议吗?任何推理的最佳实践?

Gün*_*uer 6

@HostBinding('class') theme = 'light'
Run Code Online (Sandbox Code Playgroud)

应该更好

@HostBinding('class.light') isLight = theme === 'light';
Run Code Online (Sandbox Code Playgroud)

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

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

:host-context(.light) {
  // my light component styles here
}
Run Code Online (Sandbox Code Playgroud)