Angular 4 CLI,WebPack,为整个网站动态切换引导主题

Posted

技术标签:

【中文标题】Angular 4 CLI,WebPack,为整个网站动态切换引导主题【英文标题】:Angular 4 CLI, WebPack, switching bootstrap theme dynamically for the entire website 【发布时间】:2017-11-26 02:23:44 【问题描述】:

我想为用户提供一个按钮来改变整个网站的主题。我对所有内容都使用引导程序“.scss”文件。 这是我所做的:

我在“src/styles”文件夹中有“dark-styles.scss”和“light-styles.scss”。这两个文件都覆盖了我需要覆盖的类和方法,并且还从“node-module”导入了“bootstrap.scss”作为默认值。当我通过“.angular-cli.json”向应用程序提供任何这些文件时,如下所示;它完美地工作。

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css",
        "../src/styles/dark-styles.scss"
      ],

或者,

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css",
        "../src/styles/light-styles.scss"
      ],

如果我提供黑暗,主题就是黑暗,如果我提供光明,主题就是光明。

但我想要实现的是动态地允许用户更改主题。因此,基于***中的其他答案;我访问了我的应用程序组件中的“文档”,这也是我的根组件。它使我可以访问整个 html 页面,其中我有一个可以从 app-component 设置的链接标签。

HTML 文件

<head>
<link id="theme" type="text/scss" rel="stylesheet" src="">
</head>
<body>
content .....
</body>

Angular-cli.json

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "../node_modules/@swimlane/ngx-datatable/release/index.css",
        "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css"
      ],

应用组件:

import  Component, OnInit, Inject  from '@angular/core';
import  DOCUMENT  from '@angular/platform-browser';

@Component(
  selector: 'app-root',
  templateUrl: './app.component.html',
      styleUrls: ['./app.component.scss'],
    )
    export class AppComponent implements OnInit 
      currentTheme: string;

      constructor( @Inject(DOCUMENT) private document) 
      

      ngOnInit() 
        this.currentTheme = 'dark';
        this.document.getElementById('theme').href = '../styles/dark-styles.scss';
      

      handelChangeTheme(event) 
        if (this.currentTheme === 'dark') 
        this.document.getElementById('theme').href = '../styles/light-styles.scss';
          this.currentTheme = 'light';
          console.log('light');
         else 
        this.document.getElementById('theme').href = '../styles/dark-styles.scss';
          this.currentTheme = 'dark';
          console.log('dark');
        
      
    

在触发事件“handleChangeTheme”时,html 文件中#theme 的 href 更改。但它不会更新或应用样式。我知道它与 WebPack 以及它编译 scss 文件的方式有关。有没有人遇到过类似的情况或知道这个问题的解决方案。谢谢

【问题讨论】:

我猜你必须编译两个 scss 文件并让它们可供应用程序选择(即将它们打包到你的 webapp 中) @ochi ...也尝试过...没有用。这样做时,将应用默认引导程序,覆盖全部被拒绝。 你解决了吗?我被指派做同样的事情。任何帮助将不胜感激 不,我暂时把它放在一边......在材料中实现这一点很容易 Webpack 使用处理器来转换 Sass -> CSS。假设路径和文件类型正确,这似乎与 Material doc 使用的技术相同(右上角的油漆桶,选择主题更新 href 为 link.style-manager-theme:material.angular.io) 【参考方案1】:

我刚刚在本地完成了您的示例,在我将其更改为 text/css 后,type="text/scss" 似乎有问题,它开始工作。我首先认为您需要重新创建元素,但问题似乎与类型有关

由于它的主题,我建议您使用这些文件的编译 css 版本,将它们放入 assets 文件夹中,angular-cli 会将它们复制到 servebuild

此外,当您在 Angular 中引用 scss 时,它会使用 webpack 编译为 css。

【讨论】:

我开始悬赏这个问题,因为我遇到了同样的问题。我结束了使用另一种方法解决它,更准确地说,类似于:sitepoint.com/sass-theming-neverending-story @MarcusVinicius - 对您的方法进行更详细的解释会有所帮助。您是否将 scss 预编译为 css(如 Volodymyr Bilyachat 所建议的那样) - 这是使用 angular-cli 本身发生的,还是您必须添加一些手动 node-sass 命令才能使 htis 工作......以及您是如何切换主题的(使用链接?正如 Virodh 最初提出的那样?) @RafiAliKhan,我添加了一个答案,更详细地解释了我如何设法使动态主题工作。【参考方案2】:

我通过使用以下方法设法让动态主题在 Angular 4 + Bootstrap 中工作:

使用地图定义主题颜色:

$themes: (
    alpha: (
        primary: #2b343e,
        info: #3589c7,
        top-color: #000000,
        top-font-color: #ffffff,
        ...
    ),
    beta: (
        primary: #d2a444,
        info: #d2a444,
        top-color: #ffffff,
        top-font-color: #000000,
        ...
    )
)

然后,创建以下 mixin 来为每个主题名称和给定属性输出颜色

@mixin theme($property, $key, $themes: $themes) 
  @each $theme, $colors in $themes 
    &.theme-#$theme,
    .theme-#$theme & 
      #$property: map-get($colors, $key);
    
  

我使用 mixins 来控制单个属性:

@mixin color($arguments...) 
  @include themify('color', $arguments...);


@mixin background-color($arguments...) 
  @include themify('background-color', $arguments...);

对于每个“主题化”组件,我在声明属性时必须使用上面的 mixins

.page-top 
    @include background-color('top-color');
    @include color('top-font-color');    
    height: 66px;
    width: 100%;
    ...    

CSS 输出类似于:

.page-top 
    height: 66px;
    width: 100%;
    ...    


.page-top.theme-alpha,
.theme-alpha .page-top 
    background-color: #000000;
    color: #ffffff;


.page-top.theme-beta,
.theme-beta .page-top 
    background-color: #ffffff;
    color: #000000;

最后,要使主题可用,您必须在某些父组件中控制主题类:

<!-- class="theme-alpha" -->
<main themeChange>
    <page-top></page-top>
    <sidebar></sidebar>
    <page-bottom></page-bottom>
</main>

themeChange 指令可以这样写:

@Directive(
  selector: '[themeChange]'
)
export class ThemeChange implements OnInit 
    @HostBinding('class') classes: string;
    private _classes: string[] = [];

    ngOnInit()         
        // grab the theme name from some config, variable or user input
        this.classesString = myConfig.theme;
    

【讨论】:

【参考方案3】:

经过几个小时的尝试,我终于让 bootstrap 主题切换器 工作了。这是我的解决方案:

    不要使用 bootswatch.scss,而是下载每个主题的编译版本,将它们放在同一个资产文件夹中并相应地重命名文件。

    将此行添加到 index.html。选择默认主题:

    < link id="theme" type="text/css" rel="stylesheet" href="/assets/css/theme_slate_bootstrap.min.css">
    ...
    ...
    <body class="theme-slate">
    ...
    

3.目前在app.component中设置了切换主题的快捷方式。所以这是 app.component.ts

    import  Component, OnInit, Renderer2, Inject  from '@angular/core';
    import  DOCUMENT  from '@angular/platform-browser';

    @Component(
    selector: 'apps',
    templateUrl: './app.component.html'
    )
    export class AppComponent implements OnInit, OnDestroy 
        private currentTheme: string = 'slate';

        constructor(private renderer: Renderer2, @Inject(DOCUMENT) private document)  

        ngOnInit() 

        theme(type) 
            this.renderer.removeClass(document.body, 'theme-'+this.currentTheme);
            this.currentTheme = type;
            this.renderer.addClass(document.body, 'theme-'+this.currentTheme);
            this.document.getElementById('theme').href = '/assets/css/theme_'+type+'_bootstrap.min.css';
        
    

    主题切换按钮

    <div style="display:block; position: absolute; top:0; right:0; text-align:right; z-index:100000;">
        <button class="btn btn-primary btn-sm" (click)="theme('slate')">Slate</button>
        <button class="btn btn-secondary btn-sm" (click)="theme('yeti')">Yeti</button>
        <button class="btn btn-secondary btn-sm" (click)="theme('darkly')">Darkly</button>
    </div>
    

    在 angular.json 中添加这个自定义文件

    "styles": [
        "src/assets/scss/custom.scss"
    ],
    

    custom.scss - 添加您的自定义代码以在此处工作

    $themes: (
        slate: (
            name: 'slate',
            primary: #3A3F44,
            secondary: #7A8288,
            ...
        ),
        yeti: (
            name: 'yeti',
            primary: #008cba,
            secondary: #eee,
            ...
        ),
        darkly: (
            name: 'darkly',
            primary: #008cba,
            secondary: #eee,
            ...
        ),
    );
    
    /*
    * Implementation of themes
    */
    @mixin themify($themes) 
        @each $theme, $map in $themes 
            .theme-#$theme & 
            $theme-map: () !global;
            @each $key, $submap in $map 
                $value: map-get(map-get($themes, $theme), '#$key');
                $theme-map: map-merge($theme-map, ($key: $value)) !global;
            
            @content;
            $theme-map: null !global;
            
        
    
    
    @function themed($key) 
        @return map-get($theme-map, $key);
    
    
    
    * 
        @include themify($themes) 
            // custom theme to your needs. Add here
            @if themed('name') == 'slate' 
            
    
    
            @if themed('name') == 'yeti' 
            
    
    
            @if themed('name') == 'darkly' 
            
    
    
            // Below will effect all themes
            .btn, .form-control, .dropdown, .dropdown-menu 
                border-radius: 0;
            
    
            // This is just example to code. When switching theme, primary button theme should changed. Below code is not required. 
            .btn-primary 
                background-color: themed('primary');
                border-color: themed('primary');
            
    
        
    
    // ***********************************************************************
    
    @import "custom-additional-classes";
    

希望这对寻求引导主题切换器解决方案的每个人都有帮助

【讨论】:

以上是关于Angular 4 CLI,WebPack,为整个网站动态切换引导主题的主要内容,如果未能解决你的问题,请参考以下文章

使用 @ngtools/webpack 在 Angular 11 + Webpack 4 中实现 AOT

带有primeng 404问题的angular-cli@webpack

在 angular-cli@webpack 中使用 socket.io-client

Angular-cli.json 、 webpack.conf 和 tsconfig.json 之间的区别

StoryBook Angular - 错误! => 无法获取 Angular cli webpack 配置

将常规 npm 包加载到 webpack/angular cli [找不到模块]