在Vue3里使用scss实现简单的换肤功能
主题色就是网站主色,可以配置到组件库上面;亮色模式又分为两种风格:纯白风格和背景图风格,不需要背景图的话可以删掉这部分逻辑和相关定义;暗黑模式就是黑底白字。
写法仅在vue3里有效,vue2或其他框架自行修改写法
换肤示例
scss文件定义
先在variables.module.scss
文件定义并导出初始样式
注意此文件必须以.module.scss结尾
$main-color: #1677ff; // while $while-bg-color: #fafafa; $while-first-text: #000000e0; $while-second-text: #000000a6; $while-third-text: #00000040; $while-box-bg-color: rgba(255, 255, 255, 0.6); //dark $dark-bg-color: #141414; $dark-first-text: #ffffffd9; $dark-second-text: #ffffffa6; $dark-third-text: #ffffff40; $dark-box-bg-color: rgba(255, 255, 255, 0.05); :export { MainColor: $main-color; //while WhileBgColor: $while-bg-color; WhileFirstText: $while-first-text; WhileSecondText: $while-second-text; WhileThirdText: $while-third-text; WhileBoxBgColor: $while-box-bg-color; //dark DarkBgColor: $dark-bg-color; DarkFirstText: $dark-first-text; DarkSecondText: $dark-second-text; DarkThirdText: $dark-third-text; DarkBoxBgColor: $dark-box-bg-color; }
然后在base.scss
里定义不同模式下的css属性
此文件可以随意命名
@import "./variables.module"; :root { --main-width: 1280px; // 切换背景图需要的变量 --base-background:url('../bgImgs/bgImg_53.jpeg'); } // 亮色模式下文字颜色变量 html[data-theme='light']:root{ --first-lv-text: #{$while-first-text}; --second-lv-text: #{$while-second-text}; --third-lv-text: #{$while-third-text}; --box-bg-color: #{$while-box-bg-color}; } // 暗色模式下的文字颜色变量 html[data-theme='dark']:root{ --first-lv-text: #{$dark-first-text}; --second-lv-text: #{$dark-second-text}; --third-lv-text:#{$dark-third-text}; --box-bg-color: #{$dark-box-bg-color}; } html[data-theme='dark']{ div,p,span,a,h1,h2,h3,h4,h5,h6,h7,ul,li,button,i{ color: #{$dark-first-text}; } }
然后在mian.scss
里引入这两个文件并使用css变量
@import './base.scss'; @import "./variables.module"; body { min-width: var(--main-width); overflow-x: hidden; background: var(--base-background) left top no-repeat; background-size: cover; transition: all 0.3s ease; }
修改主题方法定义
然后在
store
里定义需要的方法
先定义下ts类型themeTypes.ts
(没有ts的可以忽略)
export interface themeType { mode: themeMode bgImg: string isWhile: boolean isDark: boolean mainColor: string } export enum themeMode { light = 'light', dark = 'dark' }
再定义个修改css变量的工具类
/** 修改css样式 * @param {string} property css属性名 * @param {string} value 要修改的值 */ export function setCssProperty(property: string, value: string) { document.documentElement.style.setProperty(property, value); }
然后在theme.ts里定义
因为亮色模式下分为纯白和背景图,所以需要mode + isWhile和isDark来区分是亮色模式还是暗黑模式,不需要背景图的话可以修改这部分逻辑
亮色模式和暗黑模式修改关键代码:window.document.documentElement.setAttribute(‘data-theme’, themeMode.light)
import { computed, reactive, ref } from 'vue' import { defineStore } from 'pinia' import { themeMode, type themeType } from './types/themeTypes' import { setCssProperty } from '@/utils/index' import variable from '@/assets/styles/variables.module.scss' export const useThemeStore = defineStore('theme', () => { /** * 主题分为两种模式:亮色和暗黑 * 亮色下又分为两种风格:纯白色风格 和 背景图风格 * 暗黑模式就是纯黑背景模式 * 三种风格不可兼容 * */ const theme = reactive<themeType>({ mode: themeMode.light, // 修改为你真实的背景图地址 bgImg: new URL('@/assets/bgImgs/bgImg_53.jpeg', import.meta.url).href, // 仅在mode === light时生效 isWhile: false, // 仅在mode === light时生效 isDark: false, mainColor: variable.MainColor }) const setTheme = (mode: themeMode, imgUrl?: string) => { theme.mode = mode // theme.isWhile为true表示使用纯白模式;确保isDark为false,并且移除背景图,背景色修改为纯白 if (theme.isWhile && mode === themeMode.light) { theme.isDark = false window.document.documentElement.setAttribute('data-theme', themeMode.light) setCssProperty('--base-background', variable.WhileBgColor) } else if (theme.isDark && mode === themeMode.dark) { // 暗黑模式,确保isWhile为false,并且移除背景图,背景色为纯黑 theme.isWhile = false window.document.documentElement.setAttribute('data-theme', themeMode.dark) setCssProperty('--base-background', variable.DarkBgColor) } else { // theme.isWhile和theme.isWhile都为false表示使用背景图,此时mode必须为light theme.mode = themeMode.light theme.isWhile = false theme.isDark = false theme.bgImg = imgUrl || theme.bgImg window.document.documentElement.setAttribute('data-theme', themeMode.light) setCssProperty('--base-background', `url(${theme.bgImg})`) } // 这里把配置存在了本地,有条件的可以存在后台跟用户绑定用接口加载 localStorage.setItem('theme', JSON.stringify(theme)) } //页面加载时使用此方法加载配置的主体 const loadTheme = () => { const localTheme = localStorage.getItem('theme') if (theme) { Object.assign(theme, JSON.parse(localTheme as string)) setTheme(theme.mode, theme.bgImg) } } return { theme, setTheme, loadTheme } })
使用
然后在换肤vue文件里使用这些方法,注:template非完整代码,仅示例如何调用
<template> <!--修改主题色我使用的vue3-colorpicker组件 --> <ColorPicker is-widget picker-type="chrome" shape="square" v-model:pure-color="theme.mainColor" format="hex" @pureColorChange="setMainColor" /> <!--修改为纯白 暗黑模式--> <div class="use-style"> <span>纯白</span> <a-switch v-model:checked="theme.isWhile" @change="themeStore.setTheme(themeMode.light)" /> </div> <div class="use-style"> <span>暗黑</span> <a-switch v-model:checked="theme.isDark" @change="themeStore.setTheme(themeMode.dark)" /> </div> <!--选择皮肤(纯白/暗黑模式下,不能选择)--> <div class="img-list"> <div v-for="(img, index) in bgImgList" :key="index" class="img-item" > <img :src="img" :alt="'皮肤' + index" :style="{ cursor: theme.isWhile || theme.isDark ? 'not-allowed' : 'pointer' }" loading="lazy" @click="useImg(img)" /> <CheckCircleFilled v-if="theme.bgImg === img" class="selected-icon" /> </div> </div> </template> <script setup lang="ts"> import { reactive, ref, watch } from 'vue'; // 把sotre和类型导入进来 import { useThemeStore } from '@/stores/theme'; import { themeMode } from '@/stores/types/appTypes'; import { ColorPicker } from 'vue3-colorpicker'; import 'vue3-colorpicker/style.css'; import { storeToRefs } from 'pinia'; const themeStore = useThemeStore(); const { theme } = storeToRefs(themeStore); themeStore.loadTheme(); const bgImgList = reactive<string[]>([]); const imgCurrent = ref(1); // 获取图片列表,我这样写是因为放在了本地,根据你的实际情况修改 function getBgImgList() { for (let i = 0; i < 100; i++) { bgImgList.push(new URL(`../../assets/bgImgs/bgImg_${i}.jpeg`, import.meta.url).href); } } onMounted(()=>{ getBgImgList(); }) // 设置主题色, function setMainColor() { localStorage.setItem('theme', JSON.stringify(theme.value)); } function useImg(imgUrl: string) { if (theme.value.isWhile || theme.value.isDark) return; themeStore.setTheme(themeMode.light, imgUrl); } </script>
如果使用了组件库,别忘了把主题色配置到组件上
<template> <a-config-provider :locale="zhCN" :theme="{ algorithm: appStore.theme.isDark ? theme.darkAlgorithm : theme.defaultAlgorithm, token: { colorPrimary: appStore.theme.mainColor, }, }" > <a-app> <RouterView /> </a-app> </a-config-provider> </template> <script setup lang="ts"> import zhCN from 'ant-design-vue/es/locale/zh_CN'; import { theme } from 'ant-design-vue'; import { useThemeStore } from '@/stores/theme'; const themeStore = useThemeStore(); </script>
要在不同模式下修改组件库的样式,可以创建如antDesign.scss
文件来修改
// 主题兼容 html[data-theme='light']{ .ant-layout-sider{ background: rgba(255,255,255,0.4); } .ant-layout-header{ background: rgba(255,255,255,0.2); } } html[data-theme='dark']{ .ant-layout-sider{ background: rgba(255,255,255,0.08); } .ant-layout-header{ background: rgba(255,255,255,0.05); } }
需要其他配置可以自行往关键文件里添加
以上就是在Vue3里使用scss实现简单的换肤功能的详细内容,更多关于Vue3 scss换肤功能的资料请关注脚本之家其它相关文章!
相关文章
vue.prototype和vue.use的区别和注意点小结
这篇文章主要介绍了vue.prototype和vue.use的区别和注意点小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2023-04-04Vue element-ui中表格过长内容隐藏显示的实现方式
在Vue项目中,使用ElementUI渲染表格数据时,如果某一个列数值长度超过列宽,会默认换行,造成显示不友好,下面这篇文章主要给大家介绍了关于Vue element-ui中表格过长内容隐藏显示的实现方式,需要的朋友可以参考下2022-09-09
最新评论