有项目需要夜间模式,就开始寻找夜间模式的解决方案。因为项目本身用的是scss,所以思路是scss切换主题。

scss依赖安装(已安装的可以略过)

  • 如果是用vite构建项目的,直接复制下面这段就好了。
shell
1
npm install sass -D

或者

shell
1
yarn add sass -D
  • 如果是使用webpack构建项目的,安装下面的步骤。
    1. 安装依赖
    1
    2
    3
    npm install node-sass sass-loader --save-dev 

    yarn add node-sass sass-loader -D
    1. webpack配置文件中添加scss规则(在rules配置下)。
    webpack.base.conf.js
    1
    2
    3
    4
    5
    {
    test: /\.scss$/,
    loaders: ['style', 'css', 'sass']
    }

全局注册scss变量(有需要可以配置)

  • vite构建项目的
vite.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default defineConfig({
plugins:[vue()],
// --- 这部分是需要添加的 ---
//配置sass
css: {
preprocessorOptions: {
// globalVar.scss 和 globalMixin.scss 为你需要全局注入的scss
scss: {
additionalData: '@import "../assets/scss/globalVar.scss";@import "../assets/scss/globalMixin.scss";'
}
}
},
// --- 添加完毕 ---
})
  • 使用webpack构建项目的。
    1. 安装sass-resources-loader
    1
    2
    3
    npm install sass-resources-loader --save-dev

    yarn add sass-resources-loader -D
    1. 修改build/utils.js中的 exports.cssLoaders函数。
    build/utils.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 定位文件
    function resolveResource(name) {
    return path.resolve(__dirname, '../assets/scss/' + name);
    }

    function generateSassResourceLoader() {
    var loaders = [
    cssLoader,
    'sass-loader',
    {
    loader: 'sass-resources-loader',
    options: {
    // 多个文件时用数组的形式传入,单个文件时可以直接使用 path.resolve(__dirname, '../src/
    // globalVar.scss 和 globalMixin.scss 为你需要全局注入的scss
    resources: [
    resolveResource('globalVar.scss'),
    resolveResource('globalMixin.scss'),
    ]
    }
    }
    ];
    if (options.extract) {
    return ExtractTextPlugin.extract({
    use: loaders,
    fallback: 'vue-style-loader'
    })
    } else {
    return ['vue-style-loader'].concat(loaders)
    }
    }
    1. 修改之前的return
    build/utils.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    // sass: generateLoaders('sass', { indentedSyntax: true }),
    // scss: generateLoaders('sass'),
    sass: generateSassResourceLoader(),
    scss: generateSassResourceLoader(),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
    }

新建themes.scss(主题配置)文件,实现不同主题配色方案

./styles/themes.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$themes: (
// 明亮主题
light: (
bg_color: #ffffff,
font_color: #1c1c1e,
border_color: rgba(0, 0, 0, 0.1)
),
// 黑暗主题
dark: (
bg_color: hsla(0,0%,13%,1),
font_color: #ffffff,
border_color: rgba(255, 255, 255, 0.4)
)
);

// 这个是为了后面演示
$--n-border-r: 4px;

新建handleTheme.scss文件,控制主题配色。

./styles/handleTheme.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 引入刚才建立的主题配色样式文件
@import "./themes.scss";
//遍历主题map
@mixin themeify {
@each $theme-name, $theme-map in $themes {
//!global 把局部变量强升为全局变量
$theme-map: $theme-map !global;
//判断html的data-theme的属性值 #{}是sass的插值表达式
//& sass嵌套里的父容器标识 @content是混合器插槽,像vue的slot
[data-theme="#{$theme-name}"] & {
@content;
}
}
}

// 声明一个根据Key获取颜色的function
@function themed($key) {
@return map-get($theme-map, $key);
}

// 获取背景颜色
@mixin background_color($color) {
@include themeify {
background-color: themed($color)!important;
}
}

// 获取字体颜色
@mixin font_color($color) {
@include themeify {
color: themed($color)!important;
}
}

// 获取边框颜色
@mixin border_color($color) {
@include themeify {
border-color: themed($color)!important;
}
}

切换主题

app.vue或者需要用到主题切换的组件中。

app.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 在js部分
import { onMounted, ref } from "vue";

// 可以将主题配置写在浏览器storage中。
const theme = ref(window.localStorage.getItem("theme") || "light");

// 加载主题
onMounted(() => {
window.document.documentElement.setAttribute("data-theme", theme.value);
});

// 切换主题
const changeTheme = () => {
if (theme.value === "light") {
theme.value = "dark";
} else {
theme.value = "light";
}
window.localStorage.setItem("theme", theme.value);
window.document.documentElement.setAttribute("data-theme", theme.value);
};

如何使用样式

./components/xxx.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 如果没有将 handleTheme.scss 注册到全局的话需要先引入
@import "@/styles/handleTheme.scss";

.details-area, .comment-area {
background-color: #FFFFFF;
// 使用mixin
@include background_color("bg_color");
// 使用变量
border-radius: $--n-border-r;
}

.community-topic-title {
font-weight: 700;
font-size: 22px;
color: #000;
@include font_color("font_color");
padding-top: 0.195rem;
}

scss 非常强大,语法也比较多,感兴趣的可以访问官网。

需要注意的是:

  1. 一般建议主题配置样式和其他全局样式分开写,本文中在主题配置样式文件中加入全局样式本身就是不正确的。
  2. 主题样式和全局样式一般建议全局注册,除非是对项目构建后的大小有要求。

感谢观看,如果对你有帮助可以关注本站,龙小亦在此谢过了