1. 环境准备
安装scss解析环境:
npm i sass
// 注意 sass-loader 安装需要指定版本 如果安装最新版本会报错 this.getOptions 这个方法未定义
npm i -D sass-loader@10.1.0
// 利用 normalize.css 初始化页面样式
npm i -S normalize.css
vue.config.js 配置项处理:
module.exports = {
...
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {
scss: {
additionalData: (content) => {
// 注入全局, 在每个vue文件中都会自动引入,方便做主题切换
let filePath = ''
filePath += `@import "@/styles/variables.scss"; `
return filePath + content
}
}
}
},
}
定义主题
在src/styles/theme下编定义主题:
src/styles/theme/main.scss定义整体风格(深色、浅色):
/** 整体风格-深色 */
$main-dark: (
header-background: #1B213B,
header-color: #FFFFFF,
menu-background: #31374E,
menu-text: #fff,
menu-bborder: 1px solid rgba(70, 75, 96, .88),
menu-hover: #141826,
menu-active: #141826,
sidebar-close-icon: #FFFFFF,
sidebar-text: #FFFFFF,
sidebar-submenu3-bg: #31374E,
sidebar-submenu1-bborder: 1px solid rgba(255, 255, 255, .16)
);
/** 整体风格-浅色 */
$main-light: (
header-background: #FFFFFF,
header-color: #333333,
menu-background: #FFFFFF,
menu-text: #333333,
menu-bborder: 1px solid rgba(221, 221, 221, .88),
menu-hover: #F0F0F0,
menu-active: #F0F0F0,
sidebar-close-icon: #333333,
sidebar-text: #333333,
sidebar-submenu3-bg: #D3D4D8,
sidebar-submenu1-bborder: 1px solid #DDDDDD
);
src/styles/theme/color.scss定义主题色(红色、蓝色):
/** 主题色-红色 */
$color-red: (
submenu-active: linear-gradient(135deg, #F55448 0%, #FF8076 100%),
sidebar-text1: #F55448,
menu-background-imag: url('~@/assets/theme/menuBgRed.png') no-repeat bottom,
button-color: #4E5A70,
tab-active-color: #F55448
);
/** 主题色-蓝色 */
$color-blue: (
submenu-active: linear-gradient(135deg, #356FFB 0%, #6E98FF 100%),
sidebar-text1: #2D82F9,
menu-background-imag: url('~@/assets/theme/menuBgBlue.png') no-repeat bottom,
button-color: #2D82F9,
tab-active-color: #2D82F9
);
src/styles/theme/mixed.scss定义混合样式(整体风格和主题色共同决定的样式):
// 深-红
$dark-red: (
more-menu: url('~@/assets/theme/dark-red/more.png')
);
// 深-蓝
$dark-blue: (
more-menu: url('~@/assets/theme/dark-blue/more.png')
);
// 浅-红
$light-red: (
more-menu: url('~@/assets/theme/light-red/more.png')
);
// 浅-蓝
$light-blue: (
more-menu: url('~@/assets/theme/light-blue/more.png')
);
src/styles/theme/index.scss定义皮肤:
@import "./main.scss";
@import "./color.scss";
@import "./mixed.scss";
// 整体风格
$main-themes: (
dark: $main-dark,
light: $main-light
);
// 主题颜色
$color-themes: (
red: $color-red,
blue: $color-blue
);
// 多个主题共同控制的样式
$mixed-themes: (
dark-red: $dark-red,
dark-blue: $dark-blue,
light-red: $light-red,
light-blue: $light-blue
);
$theme-map: null;
// 定义混合指令, 切换主题,并将主题中的所有规则添加到theme-map中
@mixin themify() {
// 将main-themes中规则放入theme-map
@each $theme-name, $map in $main-themes {
// & 表示父级元素 !global 表示覆盖原来的
[main-theme="#{$theme-name}"] & {
$theme-map: () !global;
// 根据主题命名,循环出对应作用域下的样式键值对
@each $key, $value in $map {
$theme-map: map-merge(
$theme-map,
(
$key: $value,
)
) !global;
}
// 表示包含下面函数 themed(), 类似于插槽
@content;
}
}
// 将color-themes中规则放入theme-map
@each $theme-name, $map in $color-themes {
[color-theme="#{$theme-name}"] & {
$theme-map: () !global;
@each $key, $value in $map {
$theme-map: map-merge(
$theme-map,
(
$key: $value,
)
) !global;
}
@content;
}
}
// 将mixed-themes中规则放入theme-map
@each $theme-name, $map in $mixed-themes {
[mixed-theme="#{$theme-name}"] & {
$theme-map: () !global;
@each $key, $value in $map {
$theme-map: map-merge(
$theme-map,
(
$key: $value,
)
) !global;
}
@content;
}
}
}
@function themed($key) {
@return map-get($theme-map, $key);
}
切换主题
定义切换组件,并绑事件:
<template>
<div class="style-conf-container">
<div class="style-conf-item-theme">
<div>
<i class="theme-color-item red-theme" @click.stop="changeThemeColor('main', 'light')" />
<i class="theme-color-item blue-theme" @click.stop="changeThemeColor('main', 'dark')" />
</div>
</div>
<div class="style-conf-item theme-color-bar">
<span>{{ $t('navbar.theme') }}</span>
<div>
<i class="theme-color-item red-theme" @click.stop="changeThemeColor('color', 'red')" />
<i class="theme-color-item blue-theme" @click.stop="changeThemeColor('color', 'blue')" />
</div>
</div>
</div>
</template>
<script>
changeThemeColor(flag, type) {
document.documentElement.setAttribute('main-theme', this.mainTheme)
document.documentElement.setAttribute('color-theme', this.colorTheme)
document.body.setAttribute('mixed-theme', this.mainTheme + '-' + this.colorTheme)
}
</scrtpt>
在需要跟随皮肤切换样式的页面中使用主题变量,如下:
<style lang="scss" scoped>
@import "~@/styles/theme/index.scss";
.header {
width: 100%;
height: 48px;
// 使用主题
@include themify() {
background: themed("header-background");
color: themed("header-color");
}
box-shadow: 0 1px 4px rgba(0,21,41,.08);
}
</style>
实现效果
深-红主题:
浅-蓝主题:
第一次写文章,请大家多多提意见哈~ 有问题也欢迎大家留言,我会及时回复噢~