封装两个element ui颜色选择器color picker(改变主题颜色)不管是不是element ui的主题颜色都可以更改

封装了两个element ui 颜色选择器,一个是本地储存(local storage)保存颜色,并不需要调取接口即可保存用户的改变的主题颜色。另外一个是改变颜色之后,刷新页面改变的颜色就会变回原来的初始值。需要哪一个看你个人选择。

本地储存颜色:

1.首先封装一个colorPicker组件

<template>
  <el-color-picker
    v-model="theme"
    class="theme-picker"
    :predefine="predefineColors"
    popper-class="theme-picker-dropdown"
  >
  </el-color-picker>
</template>

<script>
const version = require("element-ui/package.json").version; // 版本号
const ORIGINAL_THEME = "#409EFF";

export default {
  name: "colorPicker",
  data() {
    return {
      chalk: "",
      theme: ORIGINAL_THEME,
      predefineColors: [
        "#409EFF",
        "#ff4500",
        "#ff8c00",
        "#ffd700",
        "#90ee90",
        "#00ced1",
        "#1e90ff",
        "#c71585"
      ]
    };
  },
  mounted() {
    if (this.CheckIsColor(localStorage.getItem("colorPicker"))) {
      this.theme = localStorage.getItem("colorPicker");
    }
  },
  watch: {
    theme(val, oldVal) {
      if (typeof val !== "string") return;
      localStorage.setItem("colorPicker", val);
      const themeCluster = this.getThemeCluster(val.replace("#", ""));
      const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
      const getHandler = (variable, id) => {
        return () => {
          const originalCluster = this.getThemeCluster(
            ORIGINAL_THEME.replace("#", "")
          );
          const newStyle = this.updateStyle(
            this[variable],
            originalCluster,
            themeCluster
          );

          let styleTag = document.getElementById(id);
          if (!styleTag) {
            styleTag = document.createElement("style");
            styleTag.setAttribute("id", id);
            document.head.appendChild(styleTag);
          }
          styleTag.innerText = newStyle;
        };
      };

      const chalkHandler = getHandler("chalk", "chalk-style");

      if (!this.chalk) {
        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
        this.getCSSString(url, chalkHandler, "chalk");
      } else {
        chalkHandler();
      }

      const styles = [].slice
        .call(document.querySelectorAll("style"))
        .filter(style => {
          const text = style.innerText;
          return (
            new RegExp(oldVal, "i").test(text) && !/Chalk Variables/.test(text)
          );
        });
      styles.forEach(style => {
        const { innerText } = style;
        if (typeof innerText !== "string") return;
        style.innerText = this.updateStyle(
          innerText,
          originalCluster,
          themeCluster
        );
      });
      /* 当颜色改变时,使用vuex储存改变的颜色值 */
      this.$store.commit({
        type: "getThemeColor",
        color: val
      });
    }
  },

  methods: {
    CheckIsColor(bgVal) {
      var type = "^#[0-9a-fA-F]{6}$";
      var re = new RegExp(type);
      if (bgVal.match(re) == null) {
        type =
          // eslint-disable-next-line no-useless-escape
          "^[rR][gG][Bb][\(]([\\s]*(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)[\\s]*,){2}[\\s]*(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)[\\s]*[\)]{1}$";
        re = new RegExp(type);
        if (bgVal.match(re) == null) {
          return false;
        } else {
          return true;
        }
      } else {
        return true;
      }
    },
    updateStyle(style, oldCluster, newCluster) {
      let newStyle = style;
      oldCluster.forEach((color, index) => {
        newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
      });
      return newStyle;
    },

    getCSSString(url, callback, variable) {
      const xhr = new XMLHttpRequest();
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4 && xhr.status === 200) {
          this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
          callback();
        }
      };
      xhr.open("GET", url);
      xhr.send();
    },

    getThemeCluster(theme) {
      const tintColor = (color, tint) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);

        if (tint === 0) {
          // when primary color is in its rgb space
          return [red, green, blue].join(",");
        } else {
          red += Math.round(tint * (255 - red));
          green += Math.round(tint * (255 - green));
          blue += Math.round(tint * (255 - blue));

          red = red.toString(16);
          green = green.toString(16);
          blue = blue.toString(16);

          return `#${red}${green}${blue}`;
        }
      };

      const shadeColor = (color, shade) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);

        red = Math.round((1 - shade) * red);
        green = Math.round((1 - shade) * green);
        blue = Math.round((1 - shade) * blue);

        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);

        return `#${red}${green}${blue}`;
      };

      const clusters = [theme];
      for (let i = 0; i <= 9; i++) {
        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
      }
      clusters.push(shadeColor(theme, 0.1));
      return clusters;
    }
  }
};
</script>

<style>
.theme-picker .el-color-picker__trigger {
  vertical-align: middle;
}

.theme-picker-dropdown .el-color-dropdown__link-btn {
  display: none;
}
</style>

然后在vuex里面

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    /* 默认的主题颜色 */
    themeColor: "#409EFF"
  },
  getters: {},
  mutations: {
    getThemeColor(state, payload) {
      state.themeColor = payload.color;
    }
  },
  actions: {}
});

然后在main.js里面全局引入一下这个vuex的变量(如果不需要全局引用的话也可以按需引入)

import { mapState } from "vuex";
//全局混入
Vue.mixin({
  data() {
    return {};
  },
  computed: {
    ...mapState(["themeColor"])
  },
  mounted() {},

  methods: {}
});

好了,现在就可以在全局中使用了。

效果如下:

<template>
  <div class="two" :style="{ color: themeColor }">
    <h1>哈哈哈</h1>
    <el-row>
      <el-col :span="6"> </el-col>
      <el-col :span="6">
        <el-date-picker v-model="value1" type="date" placeholder="选择日期">
        </el-date-picker>
      </el-col>
      <el-col :span="6">
        <el-button type="primary">主要按钮</el-button>
      </el-col>
    </el-row>
  </div>
</template>

在这里插入图片描述
刷新页面之后,改变的主题颜色值还在。

第二种方法,刷新之后就变回原来的颜色

首先要安装sass-loader和node-sass

npm install sass-loader
cnpm install node-sass@latest

首先还是封装好一个组件先:

<template>
  <el-color-picker
    v-model="theme"
    :predefine="[
      '#409EFF',
      '#1890ff',
      '#304156',
      '#212121',
      '#11a983',
      '#13c2c2',
      '#6959CD',
      '#f5222d'
    ]"
    class="theme-picker"
    popper-class="theme-picker-dropdown"
  />
</template>

<script>
const version = require("element-ui/package.json").version; // element-ui version from node_modules
const ORIGINAL_THEME = "#409EFF"; // default color

export default {
  data() {
    return {
      chalk: "", // content of theme-chalk css
      theme: ""
    };
  },
  computed: {
    defaultTheme() {
      return this.$store.state.settings.themeColor;
    }
  },
  watch: {
    defaultTheme: {
      // eslint-disable-next-line no-unused-vars
      handler: function(val, oldVal) {
        this.theme = val;
      },
      immediate: true
    },
    async theme(val) {
      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
      if (typeof val !== "string") return;
      const themeCluster = this.getThemeCluster(val.replace("#", ""));
      const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
      console.log(themeCluster, originalCluster);

      const $message = this.$message({
        message: "  Compiling the theme",
        customClass: "theme-message",
        type: "success",
        duration: 0,
        iconClass: "el-icon-loading"
      });

      const getHandler = (variable, id) => {
        return () => {
          const originalCluster = this.getThemeCluster(
            ORIGINAL_THEME.replace("#", "")
          );
          const newStyle = this.updateStyle(
            this[variable],
            originalCluster,
            themeCluster
          );

          let styleTag = document.getElementById(id);
          if (!styleTag) {
            styleTag = document.createElement("style");
            styleTag.setAttribute("id", id);
            document.head.appendChild(styleTag);
          }
          styleTag.innerText = newStyle;
        };
      };

      if (!this.chalk) {
        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
        await this.getCSSString(url, "chalk");
      }

      const chalkHandler = getHandler("chalk", "chalk-style");

      chalkHandler();

      const styles = [].slice
        .call(document.querySelectorAll("style"))
        .filter(style => {
          const text = style.innerText;
          return (
            new RegExp(oldVal, "i").test(text) && !/Chalk Variables/.test(text)
          );
        });
      styles.forEach(style => {
        const { innerText } = style;
        if (typeof innerText !== "string") return;
        style.innerText = this.updateStyle(
          innerText,
          originalCluster,
          themeCluster
        );
      });

      this.$emit("change", val);

      $message.close();
    }
  },

  methods: {
    updateStyle(style, oldCluster, newCluster) {
      let newStyle = style;
      oldCluster.forEach((color, index) => {
        newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
      });
      return newStyle;
    },

    getCSSString(url, variable) {
      return new Promise(resolve => {
        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
          if (xhr.readyState === 4 && xhr.status === 200) {
            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
            resolve();
          }
        };
        xhr.open("GET", url);
        xhr.send();
      });
    },

    getThemeCluster(theme) {
      const tintColor = (color, tint) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);

        if (tint === 0) {
          // when primary color is in its rgb space
          return [red, green, blue].join(",");
        } else {
          red += Math.round(tint * (255 - red));
          green += Math.round(tint * (255 - green));
          blue += Math.round(tint * (255 - blue));

          red = red.toString(16);
          green = green.toString(16);
          blue = blue.toString(16);

          return `#${red}${green}${blue}`;
        }
      };

      const shadeColor = (color, shade) => {
        let red = parseInt(color.slice(0, 2), 16);
        let green = parseInt(color.slice(2, 4), 16);
        let blue = parseInt(color.slice(4, 6), 16);

        red = Math.round((1 - shade) * red);
        green = Math.round((1 - shade) * green);
        blue = Math.round((1 - shade) * blue);

        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);

        return `#${red}${green}${blue}`;
      };

      const clusters = [theme];
      for (let i = 0; i <= 9; i++) {
        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
      }
      clusters.push(shadeColor(theme, 0.1));
      return clusters;
    }
  }
};
</script>

<style>
.theme-message,
.theme-picker-dropdown {
  z-index: 99999 !important;
}

.theme-picker .el-color-picker__trigger {
  height: 26px !important;
  width: 26px !important;
  padding: 2px;
}

.theme-picker-dropdown .el-color-dropdown__link-btn {
  display: none;
}
</style>

然后创建一个vuex,这里建议创建一个modules单独配置

整体的vuex代码

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context("./modules", true, /\.js$/);

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
  const value = modulesFiles(modulePath);
  modules[moduleName] = value.default;
  return modules;
}, {});

const store = new Vuex.Store({
  modules
});

export default store;

在modules里面创建一个settings.js文件
单独的模块代码:

import variables from "@/styles/element-variables.scss";

const state = {
  themeColor: variables.theme
};

const mutations = {
  CHANGE_SETTING: (state, { key, value }) => {
    if (state.hasOwnProperty(key)) {
      state[key] = value;
    }
  }
};

const actions = {
  changeSetting({ commit }, data) {
    commit("CHANGE_SETTING", data);
  }
};

export default {
  namespaced: true,
  state,
  mutations,
  actions
};

element-variables.scss代码:

/**
* I think element-ui's default theme color is too light for long-term use.
* So I modified the default color and you can modify it to your liking.
**/

/* theme color */
$--color-primary: #1890ff;
$--color-success: #13ce66;
$--color-warning: #FFBA00;
$--color-danger: #ff4949;
// $--color-info: #1E1E1E;

$--button-font-weight: 400;

// $--color-text-regular: #1f2d3d;

$--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5;

$--table-border:1px solid#dfe6ec;

/* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts';

@import "~element-ui/packages/theme-chalk/src/index";

// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
  theme: $--color-primary;
}

为了可以改变除了element ui之外的组件颜色,在main.js里面全局混入:

import { mapState } from "vuex";
//全局混入
Vue.mixin({
  data() {
    return {};
  },
  computed: {
    ...mapState("settings", ["themeColor"])
  },
  mounted() {},

  methods: {}
});

好了现在就可以使用了,使用代码如下:

<template>
  <div id="app">
    <div id="nav">
      <color-picker @change="themeChange"></color-picker>
    </div>
    <router-view />
  </div>
</template>

<script>
import colorPicker from "@/components/color_picker/ColorPicker";
export default {
  components: {
    colorPicker
  },
  mounted() {},
  methods: {
    themeChange(val) {
      this.$store.dispatch("settings/changeSetting", {
        key: "themeColor",
        value: val
      });
    }
  }
};
</script>

效果如下:

 <h1 :style="{ color: themeColor }">哈哈哈</h1>

在这里插入图片描述

刷新页面之后就恢复原来的初始值了,这个方法适用于调接口使用(根据每个不同的用户配置他们各自的主题色,这个具体的做法需要后端配合)

这里附上一下我是如何调接口的

created(){
/* 初始化themeColor的值 */
    this.$store.dispatch('settings/changeSetting', {
      key: 'themeColor',
      value: ''
    })
    /* 一开始先得到初始的颜色值,然后上传到vuex */
    getDictViewConfig({
      viewConfigType: '01'
    }).then(res => {
      this.$store.dispatch('settings/changeSetting', {
        key: 'themeColor',
        value: res.data.viewConfigValue
      })
    })
},
methods:{
  themeChange (val) {
      modifyDictViewConfig({
        viewConfigType: '01',
        viewConfigValue: val
      }).then(res => {
        if (res.code === 200) {
          getDictViewConfig({
            viewConfigType: '01'
          }).then(res => {
            this.$store.dispatch('settings/changeSetting', {
              key: 'themeColor',
              value: res.data.viewConfigValue
            })
          })
        }
      })
    }
}
 

如果有不明白的地方可以留言大家一起交流一下。

发布了53 篇原创文章 · 获赞 59 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42268364/article/details/101720295