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

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


总结


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

相关文章
|
4天前
|
缓存 监控 JavaScript
探讨优化Vue应用性能和加载速度的策略
【5月更文挑战第17天】本文探讨了优化Vue应用性能和加载速度的策略:1) 精简代码和组件拆分以减少冗余;2) 使用计算属性和侦听器、懒加载、预加载和预获取优化路由;3) 数据懒加载和防抖节流处理高频事件;4) 图片压缩和选择合适格式,使用CDN加速资源加载;5) 利用浏览器缓存和组件缓存提高效率;6) 使用Vue Devtools和性能分析工具监控及调试。通过这些方法,可提升用户在复杂应用中的体验。
15 0
|
4天前
|
JavaScript 前端开发
vue(1),小白看完都会了
vue(1),小白看完都会了
|
4天前
|
JavaScript 开发工具 git
Vue 入门系列:.env 环境变量
Vue 入门系列:.env 环境变量
10 1
|
4天前
|
JavaScript 前端开发 定位技术
Vue使用地图以及实现轨迹回放 附完整代码
Vue使用地图以及实现轨迹回放 附完整代码
Vue使用地图以及实现轨迹回放 附完整代码
|
4天前
|
JavaScript
Vue中避免滥用this去读取data中数据
Vue中避免滥用this去读取data中数据
|
5天前
|
JavaScript
vue中使用pinia及持久化
vue中使用pinia及持久化
8 0
|
5天前
|
JavaScript 前端开发 UED
Vue class和style绑定:动态美化你的组件
Vue class和style绑定:动态美化你的组件
|
5天前
|
JavaScript 前端开发 API
Vue 监听器:让你的应用实时响应变化
Vue 监听器:让你的应用实时响应变化
|
5天前
|
JavaScript
vue封装svg
vue封装svg
10 0
|
5天前
|
JavaScript
vue封装面包屑组件
vue封装面包屑组件
8 0