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中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
391 2
|
3月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
356 137
|
7月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
886 0
|
7月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
6月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
518 1
|
6月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
336 0
|
7月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
528 17
|
7月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件实现代码及详细开发流程解析
这是一篇关于 Vue 表情包输入组件的使用方法与封装指南的文章。通过安装依赖、全局注册和局部使用,可以快速集成表情包功能到 Vue 项目中。文章还详细介绍了组件的封装实现、高级配置(如自定义表情列表、主题定制、动画效果和懒加载)以及完整集成示例。开发者可根据需求扩展功能,例如 GIF 搜索或自定义表情上传,提升用户体验。资源链接提供进一步学习材料。
350 1
|
7月前
|
存储 JavaScript 前端开发
如何高效实现 vue 文件批量下载及相关操作技巧
在Vue项目中,实现文件批量下载是常见需求。例如文档管理系统或图片库应用中,用户可能需要一次性下载多个文件。本文介绍了三种技术方案:1) 使用`file-saver`和`jszip`插件在前端打包文件为ZIP并下载;2) 借助后端接口完成文件压缩与传输;3) 使用`StreamSaver`解决大文件下载问题。同时,通过在线教育平台的实例详细说明了前后端的具体实现步骤,帮助开发者根据项目需求选择合适方案。
682 0
|
7月前
|
JavaScript 前端开发 UED
Vue 项目中如何自定义实用的进度条组件
本文介绍了如何使用Vue.js创建一个灵活多样的自定义进度条组件。该组件可接受进度段数据数组作为输入,动态渲染进度段,支持动画效果和内容展示。当进度超出总长时,超出部分将以红色填充。文章详细描述了组件的设计目标、实现步骤(包括props定义、宽度计算、模板渲染、动画处理及超出部分的显示),并提供了使用示例。通过此组件,开发者可根据项目需求灵活展示进度情况,优化用户体验。资源地址:[https://pan.quark.cn/s/35324205c62b](https://pan.quark.cn/s/35324205c62b)。
331 0