当前位置:   article > 正文

AngularCli主题切换_angular主题从上面切换到侧边

angular主题从上面切换到侧边

AngularCli主题切换

  • 首先要说明的是,这是基于Angualr的一个主题切换策略,不附加任何UI框架的主题系统.

  • 经常使用Angular的小伙伴应该都了解,AngularScss结合的很好,所以这篇Angular的主题切换策略,也主要以Scss预处理器来做。

  • 我这里使用的AngualrCli的版本为12,还是比较新的。这篇策略可以向下兼容,这个不用担心。

这个策略在其他以scss为预处理器的项目中好像也能实现。

实现效果图:

实现效果图

自定义主题

由于不附加任何UI框架的主题系统,所以要实现主题切换,那就需要我们手动的定义一套或多套主题颜色。

自定义一些颜色,是我们很常遇到的,因为设计图!=UI主题,很现实的问题。

进入正题:

我们在angularcli的项目中的新建一个styles文件夹,然后在文件夹内新建三个文件:light.theme.scss dark.theme.scss theme.scss

light.theme.scss:

$color: #fff;
  • 1

dark.theme.scss:

$color: #000;
  • 1

因为是讲解嘛,所以,lightdark的主题样式,我就定义的。。。很简单。


  • 传统的主题切换方案中,主要是通过js来切换引入的主题来进行的,不同的主题引入不同的主题文件,从而适应不同的样式。

  • 或者是,在css中通过

    :root {
        --my-css: #fff;
    }
    .container {
        color: var(--my-css)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这样的方式,定义变量,然后通过js操纵css的变量值来达到样式切换的操作。

但是,我要告诉各位的是,js操纵scss定义的变量值,这是行不通的,可以看这篇博客:如何在 Angular2 组件中操作 scss 变量

通过js切换引入的主题文件,这个也是不好实现的。


所以,最关键的theme.scss文件来了,这个文件,是对light.theme.scssdark.theme.scss的整合,让我们可以只引入这一个文件,使用一套变量也能达到主题切换到效果。

theme.scss

@use './light.theme.scss' as light;
@use './dark.theme.scss' as dark;

// 定义变量
$themeColor:null;

// 选择主题
// 根据参数定义变量值
@mixin choice($theme: null) {
    @debug $theme;
    @if $theme == light {
        $themeColor: light.$color !global; // !global 一定要加,因为$themeColor变量和当前赋值的变量是两个变量,且作用域不同,所以要通过global将变量改为全局变量,进而覆盖我们最外围定义的同名变量。
    } @else if $theme == dark {
        $themeColor: dark.$color !global;
    } @else {
        $themeColor: light.$color !global;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

看不懂这段代码的小伙伴,可要好好看看scss的官网了,传送门:Sass

解释:

  • theme.scss中引入了lightdark的主题文件
  • mixin里通过一段流程控制,来判断用户想使用那一套主题。
  • 然后把对应的主题色,赋值到我们在theme里定义的变量上。

当然这么做的缺点是在theme中我们会定义一堆变量,然后在流程控制里对这一堆变量分别赋值,可能会有点小麻烦。

这么做的好处是,如果以后我们又多增加了一套主题,比如:red主题,那我们就只需要在mixin里新加一个判断,然后引入red.theme.scss定义的变量即可,非常方便。


接下来,我们就可以在我们的组件scss文件中尝试使用了:

home.component.scss:

@import "../../xxx/theme.scss"

@include choice(light);

.text {
    color: $themeColor;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此时我们就可以看到效果了,通过切换choice传入的值,我们就可以看到.text类型所属的dom呈现不同的颜色。

但是,还没完,这么做,我们只是纯手动实现了切换,距离理想的状态还有点距离,比如点击按钮就能自动帮我们切换主题色。

所以我由此延伸:

点击按钮切换主题 ——> 切换传入的变量light | dark——>切换主题.

这么想是好的,但是行不通,我上面也写了,js没法操纵scss,这是我找了好多方法,看了许多文章得出来的结果。


所以,如何切换是一个难题,不过,好在我从这篇博客上得到了启发:angular实现皮肤主题切换的方案

我先说一下原理:

  • 我们都知道scss最终经过编译后,还是要编译成css的。

  • css中,我们也知道一中属性选择器[]:

    input[type="file"]{}
    
    input[type="text"]{}
    
    • 1
    • 2
    • 3

    这两者虽然都是选择input框,但是选择的确实不同类型的input框。

  • 所以,如果我们能让scss在编译之后直接在组件样式文件中生成两套css,然后这两套css以属性选择器来区分,那我们是不是只需要切换属性,是不是就能达到样式切换到效果。


所以,根据理解,我们需要在index.htmlbody上添加一个自定义属性:

<body app-theme-style="light">
    <app-root>Loading</app-root>
</body>
  • 1
  • 2
  • 3

然后在theme.scss中写一个mixin,用来生成以属性区分的两套样式:

@mixin themeContainer() {
    :host-context(body[app-theme-style="dark"]){
        @include choice(dark); // 使用对应的主题
        @content; // 用户自定义样式
    }
    :host-context(body[app-theme-style="light"]){
        @include choice(light);
        @content;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意,这里的:host-context必须要加,因为组件的scss文件是从属于组件本身的,所以我们使用的body[app-theme-style="light"]类名会导致组件无法匹配到对应的元素,而使用:host-context伪类选择器可以让当前宿主元素从祖先节点中查找定义了该css类的元素,直到文档根css类。angular伪类选择器:host-context()

这也就解决了,我们在组件中找不到body的问题。

OK,接下来,我们就不需要在组件的scss中引入choice的混入了,直接使用themeContainer的混入。

home.component.scss

@import "../../xxx/theme.scss"
    
@include themeContainer() {
    .text {
        color: $themeColor;
    }        
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此时,经过编译之后的homecss样式应该是这样的:

body[app-theme-style="light"] .text {
    color: #fff;
}

body[app-theme-style="dark"] .text {
    color: #000;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

接下来,我们就只需要切换body上自定定义属性的值就好了:

home.component.ts

  changeTheme() {
    const body = document.getElementsByTagName('body')[0]; // 获取dom
    const theme = body.getAttribute('app-theme-style'); // 获取属性名
    if(theme === 'light') {
      this.themeNameBtn = theme; // 这是themeNameBtn是为了在页面上展示
      body.setAttribute('app-theme-style','dark'); // 设置新的属性名
    } else {
      this.themeNameBtn = theme;
      body.setAttribute('app-theme-style','light');
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

OK,到此为止,关于AngularCLi主题切换的方法就讲解完毕了。

完结·撒花

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/707658
推荐阅读