一、安装依赖
1.1 安装必要插件
在这里我们会用到两个样式处理插件,项目执行以下命令:
npm install style-resources-loader -D
npm install vue-cli-plugin-style-resources-loader -D
为了让我们的Vue项目里面能够使用less,还需要安装less相关插件:
npm install less-loader@5.0.0 --save
npm install less --save
Vue项目如何配置less这里不做过多的介绍,因为我们的重点不在这里,我们的最终目的就是在项目里面能够使用less。
二、配置
2.1 新建style.less
style.less用于配置全局的默认样式,也可以是默认主题或字体颜色。在项目src目录下新建theme文件夹,然后新建style.less,代码如下:
/src/theme/style.less
// 默认的主题颜色
@primaryColor: var(--primaryColor, #000);
@primaryTextColor: var(--primaryTextColor, green);
// 导出变量
:export {
name: "less";
primaryColor: @primaryColor;
primaryTextColor: @primaryTextColor;
}
2.2 配置vue.config.js
在项目根目录新建vue.config.js文件,编写配置,代码如下:
const path = require("path");
module.exports = {
pluginOptions: {
"style-resources-loader": {
preProcessor: "less",
patterns: [
// 这个是加上自己的路径,不能使用(如下:alias)中配置的别名路径
path.resolve(__dirname, "./src/theme/style.less"),
],
},
},
};
当我们配置好vue.config.js文件后,就可以在项目的任何地方使用我们预先定义的less变量了,示例代码如下:
<style lang="less" scoped>
p {
color: @primaryTextColor;
}
</style>
我们随意更改一下我们的Vue项目: 修改HelloWorld组件,在组件中使用less语法以及刚刚我们定义的全局变量。 组件代码如下:
<template>
<div class="hello">
<p>我是测试文字</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
};
</script>
<style scoped lang="less">
.hello {
p {
color: @primaryTextColor;
}
}
</style>
此时的文字颜色便是我们刚刚设置的绿色了。
2.3 配置几套可选主题
在/src/theme目录下新建model.js,编写自定义主题代码,代码如下:
// 一套默认主题以及一套暗黑主题
// 一套默认主题以及一套暗黑主题
export const themes = {
default: {
primaryColor: `${74}, ${144},${226}`,
primaryTextColor: `${74}, ${144},${226}`,
},
dark: {
primaryColor: `${0},${0},${0}`,
primaryTextColor: `${0},${0},${0}`,
},
};
这里我们定义了两套默认主题,目的就是为了让用户能够在这两套主题中切换,其中主题颜色我们采用了rgba的写法,因为有可能我们需要在不用的地方使用同一主题色,但是透明度不一样。
2.4 编写修改主题的方法
全局的颜色变量以及两套默认主题我们都编写好了,在这里我们已经实现了静态更改主题,即可以更改颜色,项目重新运行后便可生效。但是这还达不到我们的目的,我们需要动态更改主题,所以我们还需要编写一个能够动态更改主题的方法。
在/src/theme文件夹下新建theme.js文件,代码如下:
import { themes } from "./model";
// 修改页面中的样式变量值
const changeStyle = (obj) => {
for (let key in obj) {
document
.getElementsByTagName("body")[0]
.style.setProperty(`--${key}`, obj[key]);
}
};
// 改变主题的方法
export const setTheme = (themeName) => {
localStorage.setItem("theme", themeName); // 保存主题到本地,下次进入使用该主题
const themeConfig = themes[themeName];
// 如果有主题名称,那么则采用我们定义的主题
if (themeConfig) {
localStorage.setItem("primaryColor", themeConfig.primaryColor); // 保存主题色到本地
localStorage.setItem("primaryTextColor", themeConfig.primaryTextColor); // 保存文字颜色到本地
changeStyle(themeConfig); // 改变样式
} else {
let themeConfig = {
primaryColor: localStorage.getItem("primaryColor"),
primaryTextColor: localStorage.getItem("primaryTextColor"),
};
changeStyle(themeConfig);
}
};
这里我们编写了两个方法,一个是更改全局css变量值的方法,达到更改样式的作用,另一个是更改主题的方法,可以让用户选择我们准备的几套主题或者自定义颜色。
2.5 动态变换主题
修改我们的HelloWorld组件,演示如何动态修改主题。
测试代码如下:
<template>
<div class="hello">
<div class="box-1"></div>
<div class="box-2"></div>
<p>我是测试文字</p>
<button @click="defaultTheme">默认主题</button>
<button @click="dark">暗黑主题</button>
<button @click="custom">自定义主题</button>
</div>
</template>
<script>
import { setTheme } from "../theme/theme";
export default {
name: "HelloWorld",
mounted() {
this.init(); // 初始化主题
},
methods: {
init() {
setTheme("default"); // 初始化未默认主题
},
// 更改为默认主题
defaultTheme() {
setTheme("default");
},
// 更改为暗黑主题
dark() {
setTheme("dark");
},
// 更改为自定义主题
custom() {
let newColor = {
r: 12,
g: 33,
b: 234,
};
let newPrimaryColor = `${newColor.r},${newColor.g},${newColor.b}`;
localStorage.setItem("primaryColor", newPrimaryColor); // 将新的主题色存入本地
setTheme();
},
},
};
</script>
<style scoped lang="less">
.hello {
display: flex;
flex-direction: column;
align-items: center;
.box-1 {
width: 50px;
height: 50px;
margin-bottom: 30px;
background: rgba(@primaryColor, 1);
}
.box-2 {
width: 50px;
height: 50px;
margin-bottom: 30px;
background: rgba(@primaryColor, 0.3);
}
p {
color: @primaryTextColor;
}
}
</style>
当我们进入页面是,会采用默认主题样式,然后用户可以点击按钮更改自定义的样式,并且会保存到本地。
2.6 总结
利用less和css变量动态修改主题,我们主要新建了3个样式文件,作用分别是默认主题、自定义的几套主题以及修改主题的工具函数。本篇文章只是一个简单的入门,通常自定义主题我们会提供给用户颜色选择面板,大家可以结合使用,如vue-color插件
三、优化配置
- 实现初始化默认主题
- 实现主题切换后,刷新进入页面保持主题效果
- 优化自定义主题配置
- 引入颜色面板
3.1 修改 主题配置配置文件
// theme.js
import { themes } from "./model";
// 修改页面中的样式变量值
const changeStyle = (obj) => {
for (let key in obj) {
document
.getElementsByTagName("body")[0]
.style.setProperty(`--${key}`, obj[key]);
}
};
// 改变主题的方法
export const changeTheme = (themeName) => {
themeName = themeName ? themeName : localStorage.getItem("theme") || "default";
const themeConfig = themes[themeName];
// 如果有主题名称,那么则采用我们定义的主题
if (themeConfig) {
localStorage.setItem("theme", themeName); // 保存主题到本地,下次进入使用该主题
setTheme(themeConfig);
} else {
// 采用自定义
customTheme();
}
};
// 设置主题
export const setTheme = (themeConfig) => {
localStorage.setItem("themeConfig", JSON.stringify(themeConfig)); // 保存主题色到本地
changeStyle(themeConfig); // 改变样式
};
// 自定义主题
export const customTheme = (config) => {
let themeConfig = localStorage.getItem("themeConfig")
? JSON.parse(localStorage.getItem("themeConfig"))
: {};
themeConfig = { ...themeConfig, ...config };
localStorage.setItem("theme", "custom");
setTheme(themeConfig);
};
3.2 修改vue文件
<template>
<div class="hello">
<div class="box-1"></div>
<div class="box-2"></div>
<p>我是测试文字</p>
<button @click="defaultTheme">默认主题</button>
<button @click="dark">暗黑主题</button>
<button @click="custom">自定义主题</button>
<Chrome v-model="customColor" />
</div>
</template>
<script>
import { changeTheme, customTheme } from "./theme/theme";
// 引入颜色面板
import { Chrome } from "vue-color";
export default {
name: "HelloWorld",
data() {
return {
customColor: {}, // 自定义颜色面板
};
},
mounted() {
this.init(); // 初始化主题
},
methods: {
init() {
changeTheme(); // 初始化未默认主题
},
// 更改为默认主题
defaultTheme() {
changeTheme("default");
},
// 更改为暗黑主题
dark() {
changeTheme("dark");
},
// 更改为自定义主题
custom() {
// 通过颜色面板自定义颜色
const { rgba = {} } = this.customColor;
if (!rgba.a) return;
const primaryColor = `${rgba.r},${rgba.g},${rgba.b},${rgba.a}`;
customTheme({ primaryColor });
},
},
components: {
Chrome,
},
};
</script>
<style scoped lang="scss">
.hello {
display: flex;
flex-direction: column;
align-items: center;
.box-1 {
width: 50px;
height: 50px;
margin-bottom: 30px;
background: rgba($primaryColor);
}
.box-2 {
width: 50px;
height: 50px;
margin-bottom: 30px;
background: rgba($primaryTextColor);
}
p {
color: $primaryTextColor;
}
}
</style>
参考