Vue+Vuex配合实现动态换肤| 青训营

简介: Vue+Vuex配合实现动态换肤| 青训营

前言


在实际的项目开发需求中,我们经常能遇到动态换肤这个需求,但是到底这个功能是如何实现的呢?那么今天就来让大家学会动态换肤的实现方式。


技术栈


Vue3 Vuex ElementPlus 持久化插件


ElementPlus的动态换肤👨‍🎓👨‍🎓


我在学习这部分的时候,发现网上的做法参差不齐,有些方法过于繁琐,在这里我查看了ElementPlus官方的文档,并且也参考了其他博主的一些文章,在这里写一下自己的认知和理解。

首先是针对ElementPlus的动态换肤,这一部分我参考了ElementPlus官网的动态换肤

官网讲解了官方使用了css变量来进行颜色的替换,废话不多说,直接上代码进行演示

selectColor.vue中的核心代码:

 <el-form>
      <div class="flex flex-wrap">
         <el-form-item
           v-for="color in Object.keys(colors)"
           :label="colors[color].label"
           :key="color"
          >
           <el-color-picker
            v-model="colors[color].value"
            @change="changeColor($event, colors[color].key)"
            :predefine="predefineColors"
            ></el-color-picker>
            </el-form-item>
       </div>
</el-form>
// element-plus主题颜色设置
const colors = reactive({
  primary: {
    label: "主要颜色",
    value: "",
    key: "--el-color-primary",
    type: "element",
  },
  info: {
    label: "次要颜色",
    value: "",
    key: "--el-color-info",
    type: "element",
  },
   //...依次类推设置相应的变量
});
onMounted(() => {
  setColorVar();
});
// 定义全局变量
const currentCss = getComputedStyle(document.documentElement);
// 设置主题颜色
const setColorVar = () => {
  colors.primary.value = currentCss.getPropertyValue("--el-color-primary");
  colors.info.value = currentCss.getPropertyValue("--el-color-info");
  colors.danger.value = currentCss.getPropertyValue("--el-color-danger");
  colors.warning.value = currentCss.getPropertyValue("--el-color-warning");
  colors.bg.value = currentCss.getPropertyValue("--el-bg-color");
};

这里面我们使用了一个颜色选择器el-color-picker对着块不是很熟悉的同=同学可以上官网进行查看

这里面通过getComputedStyle(document.documentElement);这一段代码实现获取全局的变量,然后定义setColorVar方法,通过

getPropertyValue这个方法获取相应变量的颜色,然后设置到colors这个对象中的value值里面,在页面一开始渲染的时候就调用这个方法进行相应的颜色渲染。

更改颜色的方法,在使用ElementPlus颜色选择器中,使用setProperty方法选择颜色之后来进行相应的颜色设置,然后使用了持久化存储,这个我们接下来仔细说明。

// 更改颜色
const changeColor = (color, key) => {
  if (color == null) {
    ElMessage.error("颜色值不能为空");
    return;
  }
  // 设置颜色
  document.documentElement.style.setProperty(key, color);
  // 持久化存储
  store.commit("theme/setCustomized", colors);
};

在这个时候我们已经完成了对属于ElementPlus相关的颜色的设置,但是目前还是存在问题,主要就是在页面刷新之后,颜色还是会恢复之前的原始状态,那么这个时候我们就要使用vuex并且进行持久化的存储。


使用vuex并完成持久化的存储👨‍🔬👨‍🔬


vuex中的相关代码,这里使用了vuex中的模块化的思想,在store/module/theme.js中进行相关的设置。

export default {
  namespaced: true,
  state: {
    // 主题颜色
    mainColor: {},
    globalCss,
  },
  mutations: {
    // 设置主题颜色
    setMainColor(state, { property, colorVal }) {
      // 设置颜色
      state.mainColor[property] = colorVal;
    },
    // 设置侧边栏颜色
    setSideBarColor(state, { property, colorVal }) {
      state.globalCss[property] = colorVal;
    },
    // 设置自定义颜色主题
    setCustomized(state, Colors) {
      Object.keys(Colors).forEach((item) => {
        if (Colors[item].type == "element") {
          this.commit("theme/setMainColor", {
            property: Colors[item].key,
            colorVal: Colors[item].value,
          });
        } else {
          this.commit("theme/setSideBarColor", {
            property: Colors[item].key,
            colorVal: Colors[item].value,
          });
        }
      });
    },
  },
};

其中setCustomized这个方法接收之前定义的colors对象,来进行相关的设置,首先进行判断是否为element-plus的相关设置,然后在调用setMainColor方法,将相应的颜色值进行存储,但是我们知道,如果只是进行到这一步还是不够的,因为vuex中存储的数据在进行刷新之后还是会消失,因此我们要进行持久化的存储,那么这个时候我选择的是时候相关的插件,


下载相关的持久化存储插件


npm i vuex-persistedstate

然后在store/index.js中进行相关的设置

import { createStore } from "vuex";
import theme from "./module/theme";
import getters from "./getters";
// 引入第三方插件,配置持久化
import createPersistedState from "vuex-persistedstate";
export default createStore({
  getters,
  modules: {
    theme,
  },
  plugins: [
    createPersistedState({
      storage: window.localStorage,
      key: "mainColor",
      paths: ["theme"],
    }),
  ],
});

在下载了相关的npm包之后,我们导入createPersistedState这个方法,然后在vuex中的createStore中的plugins中进行相关的配置

这个plugins是一个数组,然后在里面使用createPersistedState方法传入一个对象,进行键值对的设置,其中paths是一个数组,里面表示要持久化存储的模块。storage表示的是使用什么进行持久化的存储,这里我使用的是localStorage来及进行持久化的存储。

到现在如果我们进行页面刷新的时候,会发现还是没有达到相应的要求,这是为什么呢?其实我们会发现我们使用的setVarCss方法设置的还是element-plus默认的初始值,这里虽然进行了持久化的存储,但是相关的值没有使用,因此我又定义了相关的方法来完成这最后一步,代码如下

export default (store) => {
  //  如果存在自定义的颜色
  if (JSON.stringify(store.getters.mainColor) != "{}") {
    Object.keys(store.getters.mainColor).forEach((key) => {
      document.documentElement.style.setProperty(
        key,
        store.getters.mainColor[key]
      );
    });
  }
};

这部分代码直接以函数的形式导出,然后在main.js中进行引入,传入store来完成相应的方法,这个方法其实就是将之前持久化存储的值在这里通过setProperty来进行相关的设置,以便我们之前在组件中setVarCss方法能够正确的完成。

这样我们就算是完成了持久化存储,下面我们实际的演示一下。

image.png

到这里我们就实现了对ElementPlus的动态换肤,那么我认为就是一下步骤:

  • 首先我们肯定要使用ElementPlus官方的组件:el-color-picker,为此我们还准备了一个对象colors,这个对象里面存储的是每种颜色(例如primary,info等等),包含每种颜色的key和value,便于我们进行设置
  • 然后我们还创建了一个changeColor方法,这个方法用了修改选中的一些颜色,并且我们还进行了持久化的存储,使用了一个持久化存储的npm包,并且进行了一些相关的配置。
  • 我们进行页面渲染的核心其实就是setVarCss这个方法,这个方法写在OnMounted中,每次页面渲染的时候,就会调用这个方法,本质就是利用全局变量中存储的变量来进行渲染
  • 在调用全局的css变量的时候使用getPropertyValue这个方法,但是我们注意到我们此时调用的这个全局变量其实还是迷人值,没有利用起来vuex持久化存储的数据,那么为此我又单独创建了一个方法。并且将这个方法导出然后在main.js中进行引用
  • 这个方法接收一个store参数,然后就可以获取到持久化存储的相应值。来进行相应的渲染,这样持久化存储的目的也就达到了。


非ElementPlus的动态换肤


这里我还定义了一些自定义的部分进行颜色换肤,比如我自己写的侧边栏,这里也要拥有动态换肤的功能,其实实现的思路和ElementPlus的换肤思想是类似的,我们现在colors中添加这个颜色对象

  sideBarColor: {
    label: "侧边栏颜色",
    value: "",
    key: "menuBg",
    type: "unelement",
  },

然后在页面初始渲染的时候我们同样也是用vuex中的颜色,注意这里我在本地也定义了css颜色变量,然后我在setVarCss这个方法中新增一个行代码如下:

  colors.sideBarColor.value = store.getters.globalCss.menuBg;

这部分代码就是对侧边栏颜色的设置,以便于当颜色修改之后我们可以在选择器中也随着修改。

import globalCss from "@/style/global.module.scss";
export default{
state: {
    // 主题颜色
    mainColor: {},
    globalCss,
  },
}

我们这里导入的是scss文件,这个引入的就是我在本地定义的一些自定义的颜色变量,在scss中使用下面这种形式来到出css变量

// sidebar
$menuBg: #304156;
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
// JS 与 scss 共享变量,在 scss 中通过 :export 进行导出,在 js 中可通过 ESM 进行导入
:export {
  menuBg: $menuBg;
}

由于颜色太多,这里就不一一展示,只是举例其中的一个例子,别的也是类似的。

其他的其实是类似的,比如在切换颜色之后也需要进行持久化的存储,我们在之前的vuex的方法中也写了,我们定义了两个方法,其中一个是针对ElementPlus的动态换肤来写的,另一个就是针对非ElementPlus换肤来写的。我们在colors这个对象中对每个属性中也增加了区分的方式,通过type这个方式来区分,然后vuex中的方法就会根据这个值来调用不同的方法进行存储。

最后在进行一次演示:

image.png

这样就算最后的功能完成了


总结


掌握了这部分的知识,感觉还是很有收获的,最起码这个学习的过程是很重要的。

相关文章
|
7天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
7天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
7天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
|
13天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
13天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
13天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
13天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
12天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
14天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
12天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
下一篇
无影云桌面