基于SCSS的angular项目的主题切换
2021-01-03 05:30
标签:event 多少 独立 har 而且 这一 好处 通过 切换 目前的主题切换大多要求动态主题切换,即用户点击切换主题button后不需要重新加载页面,页面不需要刷新即可切换主题。这就需要思考如下几点: 类似:hover这一类的伪元素选择器,css会动态监听,当元素被hover时,css就会被添加上去。 css也会监听元素上的attribute的值的变化,这样我们可以利用这个特性来实现css监听用户行为。 实现原理是这样的,我们在body元素上添加一个data-theme-style属性,让它的值根据用户的行为变化,比如dark或者light。 可以看到,点击button时修改body的data-theme-style的值,这样css就会监听到变化来切换css,也就是主题切换的最基本的功能。 实际上,这是主题切换的最基本的原理:用户触发html元素属性的变化,利用css监听属性的变化,再把需要变化的css添加到属性选择器下面,这样就能够让css跟着属性选择器的变化来变化了。 作为一个合格的单身的脱离了高级趣味的程序员来说,重复的代码是不可容忍的。 我们来解决一下这个问题,这里需要用到一些css的高级语法,所以我们使用scss完成,我们先把代码迁移到使用了scss的angular项目中。 index.html app.component.html app.component.scss app.component.ts 如果运行了代码之后,你会发现content1 和 content2并没有作用在元素上。 这是因为angular对于组件内的css是封闭的,[data-theme-style=dark]并不能找到body元素上,那怎么找到呢? css中有一个选择器:host-context,它在当前组件宿主元素的祖先节点中查找 CSS 类, 直到文档的根节点为止。 我们来修改scss app.component.scss 这样,就又可以使用了。 :host-context([data-theme-style=dark]) 就可以找到body元素了。 我们来使用scss的mixin来去掉重复的代码: @mixin是可以传递参数的,并且,&符号可以引用父级元素。 目前为止,并没有去掉多少重复的代码,下面我们来定义2个map,一个是dark主题下的css值,一个是light主题下的css值。 我们的目标是去掉重复的代码,需要想办法把2个mixin合并在一起。可以把变量的名称通过mixin的参数传递进去。 来来来,看看,选择变成一个mixin了,我们再来简化一下,mixin中的css会根据主题的数量增加而增加,比如这个时候再加个default theme,mixin中就会有3个了。 观察一下,重复的地方很多,只有主题名称不同,我们再定义一个主题的map,然后在mixin中使用@each来循环这个集合: 这样就把能简化的都简化了。 但是对于项目来说,需要把目录整理一下,我们给主题单独建立一个文件夹,把之前定义的主题$dark,$light独立成文件。把mixin指令独立成单独的文件。 app/theme/dark.scss app/theme/light.scss app/theme/mixin.scss 在app.component.scss中使用 app.component.scss 这样,我们基本完成了主题的切换了。 使用主题时需要注意的是,mixin theme的第一个参数是css的属性,比如border,比如background,第二个参数是定义在主题文件中的变量名称。 使用scss来实现主题切换的好处是可以动态切换主题,不需要重新加载页面,而且代码实现比较简洁。 基于SCSS的angular项目的主题切换 标签:event 多少 独立 har 而且 这一 好处 通过 切换 原文地址:https://www.cnblogs.com/JasonWang-code/p/13646103.html
一、原理
1 DOCTYPE html>
2 html lang="en">
3 head>
4 meta charset="UTF-8">
5 meta name="viewport" content="width=device-width, initial-scale=1.0">
6 title>Documenttitle>
7 style>
8 [data-theme-style=dark] .content1{
9 background: black;
10 }
11 [data-theme-style=light] .content1{
12 background: gray;
13 }
14 [data-theme-style=dark] .content2{
15 background: red;
16 }
17 [data-theme-style=light] .content2{
18 background: blue;
19 }
20 .content {
21 width: 200px;
22 height: 200px;
23 border: 1px solid red;
24 }
25 style>
26
27 head>
28 body data-theme-style="dark">
29 button>Change Themebutton>
30
31 div class="content content1">div>
32 div class="content content2">div>
33 script>
34 const button = document.getElementsByTagName(‘button‘)[0];
35 const body = document.body;
36 button.addEventListener(‘click‘, () => {
37 body.setAttribute(‘data-theme-style‘, body.getAttribute(‘data-theme-style‘) === ‘dark‘ ? ‘light‘ : ‘dark‘)
38 })
39 script>
40 body>
41 html>
二、优化
doctype html>
html lang="en">
head>
meta charset="utf-8">
title>CustomElementsDemotitle>
base href="/">
meta name="viewport" content="width=device-width, initial-scale=1">
link rel="icon" type="image/x-icon" href="favicon.ico">
head>
body data-theme-style="dark">
app-root>app-root>
body>
html>
button>Change Themebutton>
div class="content content1">div>
div class="content content2">div>
[data-theme-style=dark] .content1{
background: black;
}
[data-theme-style=light] .content1{
background: gray;
}
[data-theme-style=dark] .content2{
}
[data-theme-style=light] .content2{
border: 20px solid blue;
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
import { Component, AfterViewInit } from ‘@angular/core‘;
@Component({
selector: ‘app-root‘,
templateUrl: ‘./app.component.html‘,
styleUrls: [‘./app.component.scss‘]
})
export class AppComponent implements AfterViewInit{
ngAfterViewInit(): void {
const button = document.getElementsByTagName(‘button‘)[0];
const body = document.body;
button.addEventListener(‘click‘, () => {
body.setAttribute(‘data-theme-style‘, body.getAttribute(‘data-theme-style‘) === ‘dark‘ ? ‘light‘ : ‘dark‘)
});
}
}
:host-context([data-theme-style=dark]) .content1{
background: black;
}
:host-context([data-theme-style=light]) .content1{
background: gray;
}
:host-context([data-theme-style=dark]) .content2{
border: 20px solid red;
}
:host-context([data-theme-style=light]) .content2{
border: 20px solid blue;
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
@mixin bg-context1() {
:host-context([data-theme-style=dark]) .content1 {
background: black;
}
:host-context([data-theme-style=light]) .content1{
background: gray;
}
}
@mixin border-context2() {
:host-context([data-theme-style=dark]) .content2 {
border: 20px solid red;
}
:host-context([data-theme-style=light]) .content2 {
border: 20px solid blue;
}
}
.content1 {
// 使用@include来使用@mixin
@include bg-context1();
}
.content2 {
@include border-context2();
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
// @mixin指令是可以传递参数的
@mixin bg-context1($propname) {
// & 符号可以引用父级元素
:host-context([data-theme-style=dark]) & {
// 当变量使用在属性名称时,需要使用插值表达式来使用变量
#{$propname}: black;
}
:host-context([data-theme-style=light]) & {
#{$propname}: gray;
}
}
@mixin border-context2($propname) {
:host-context([data-theme-style=dark]) & {
#{$propname}: 20px solid red;
}
:host-context([data-theme-style=light]) & {
#{$propname}: 20px solid blue;
}
}
.content1 {
// 使用@include来使用@mixin
@include bg-context1(background);
}
.content2 {
@include border-context2(border);
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
$dark: (
context1-bg-color: black,
context2-border: 20px solid red,
);
$light: (
context1-bg-color: gray,
context2-border: 20px solid blue,
);
// @mixin指令是可以传递参数的
@mixin bg-context1($propname) {
// & 符号可以引用父级元素
:host-context([data-theme-style=dark]) & {
// 当变量使用在属性名称时,需要使用插值表达式来使用变量
// map-get是scss提供的获取map中的value的方法
#{$propname}: map-get($dark, context1-bg-color);
}
:host-context([data-theme-style=light]) & {
#{$propname}: map-get($light, context1-bg-color);
}
}
@mixin border-context2($propname) {
:host-context([data-theme-style=dark]) & {
#{$propname}: map-get($dark, context2-border);
}
:host-context([data-theme-style=light]) & {
#{$propname}: map-get($light, context2-border);
}
}
.content1 {
// 使用@include来使用@mixin
@include bg-context1(background);
}
.content2 {
@include border-context2(border);
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
$dark: (
context1-bg-color: black,
context2-border: 20px solid red,
);
$light: (
context1-bg-color: gray,
context2-border: 20px solid blue,
);
// @mixin指令是可以传递参数的
@mixin theme($propname, $varname) {
// & 符号可以引用父级元素
:host-context([data-theme-style=dark]) & {
// 当变量使用在属性名称时,需要使用插值表达式来使用变量
// map-get是scss提供的获取map中的value的方法
#{$propname}: map-get($dark, $varname);
}
:host-context([data-theme-style=light]) & {
#{$propname}: map-get($light, $varname);
}
}
.content1 {
// 使用@include来使用@mixin
@include theme(background, context1-bg-color);
}
.content2 {
@include theme(border, context2-border);
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
$dark: (
context1-bg-color: black,
context2-border: 20px solid red,
);
$light: (
context1-bg-color: gray,
context2-border: 20px solid blue,
);
$themes: (
dark: $dark,
light: $light,
);
// @mixin指令是可以传递参数的
@mixin theme($propname, $varname) {
// @each循环map时,第一个参数是map的key,第二个参数是map的value
@each $themename, $theme in $themes {
// & 符号可以引用父级元素
// 不能直接使用变量,需要使用插值表达式包含变量
:host-context([data-theme-style=#{$themename}]) & {
// 当变量使用在属性名称时,需要使用插值表达式来使用变量
// map-get是scss提供的获取map中的value的方法
#{$propname}: map-get($theme, $varname);
}
}
}
.content1 {
// 使用@include来使用@mixin
@include theme(background, context1-bg-color);
}
.content2 {
@include theme(border, context2-border);
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
$dark: (
context1-bg-color: black,
context2-border: 20px solid red,
);
$light: (
context1-bg-color: gray,
context2-border: 20px solid blue,
);
@import ‘src/app/theme/dark.scss‘;
@import ‘src/app/theme/light.scss‘;
$themes: (
dark: $dark,
light: $light,
);
// @mixin指令是可以传递参数的
@mixin theme($propname, $varname) {
// @each循环map时,第一个参数是map的key,第二个参数是map的value
@each $themename, $theme in $themes {
// & 符号可以引用父级元素
// 不能直接使用变量,需要使用插值表达式包含变量
:host-context([data-theme-style=#{$themename}]) & {
// 当变量使用在属性名称时,需要使用插值表达式来使用变量
// map-get是scss提供的获取map中的value的方法
#{$propname}: map-get($theme, $varname);
}
}
}
@import ‘src/app/theme/mixin.scss‘;
.content1 {
// 使用@include来使用@mixin
@include theme(background, context1-bg-color);
}
.content2 {
@include theme(border, context2-border);
}
.content {
width: 200px;
height: 200px;
border: 1px solid red;
}
三、总结
文章标题:基于SCSS的angular项目的主题切换
文章链接:http://soscw.com/index.php/essay/39748.html