Example code for implementing dynamic skinning with vue+element

Example code for implementing dynamic skinning with vue+element

Sometimes the theme of a project cannot satisfy everyone's aesthetics. At this time, the skin-changing function is very friendly. This project implements the skin-changing function of the background management project based on vue+element

1. Create a skinning component

<template>
  <el-color-picker
    class="theme-picker"
    popper-class="theme-picker-dropdown"
    v-model="theme"
    :predefine="predefineColors"
  ></el-color-picker>
</template>
 
<script>
const version = require("element-ui/package.json").version; // element-ui version from node_modules
const ORIGINAL_THEME = "#409EFF"; // default color
export default {
  name: "ThemePicker",
  props: {
    default: {
      // Initialize the topic, which can be passed in from outside type: String
      // default: '#2668b1'
      // default: `${localStorage.getItem("tremePackers")==null?"#C60404":localStorage.getItem("tremePackers")}`
    }
    // size: { // Initialize the topic, which can be passed in from outside // type: String,
    // default: 'small'
    // },
  },
  data() {
    return {
      chalk: "", // content of theme-chalk css
      theme: ORIGINAL_THEME,
      showSuccess: true, // Whether to pop up the skin change success message predefineColors: [
        "#2668b1",
        "#52b493",
        "#429798",
        "#32789c",
        "#1944a5",
        "#5944bc",
        "#995dcd",
        "#ce7e5b",
        "#ee8b9b",
        "#283551"
      ]
    };
  },
  mounted() {
    this.theme = this.defaultTheme;
    // this.$emit('onThemeChange', this.theme)
    this.showSuccess = true;
  },
  computed: {
    defaultTheme() {
      return this.$store.state.theme;
    }
  },
  watch:
    async theme(val, oldVal) {
          if (typeof val !== "string") return;
          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)
                document
                  .getElementsByTagName("style")[0]
                  .insertBefore(styleTag, null);
              }
              styleTag.innerText = newStyle;
            };
          };
 
          const chalkHandler = getHandler("chalk", "chalk-style");
 
          if (!this.chalk) {
            const url = `../../assets/style/theme/index.css`; //Local CSS style address // const url = `./dist/index.css`; //CSS address after project packaging (the original file is placed in the public folder)
            // const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`; //If it is a company intranet, this URL is not applicable 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
            );
          });
          this.$store.commit("themColor", val);//Save the changed color to the store
          this.$emit("onThemeChange", val);
 
        // Respond to external operations // Store in localStorage
        // localStorage.setItem('tremePackers',val);
        // if(this.showSuccess) {
        // this.$message({
        // message: 'Skin change successful',
        // type: 'success'
        // })
        // } else {
        // this.showSuccess = true
        // }
      
    }
  },
  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, 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;
}
.el-color-picker--small .el-color-picker__trigger {
  border: none;
}
</style> 

The code above is worth noting. The code in the red box inserts a new style tag after all nodes in the head. After packaging, it has a higher priority, but there is a problem. The color of some places disappears directly and becomes blank, affecting the style. So it is changed to the code in the green box. However, the priority of the code in the green box will be lower than the priority of the original style color after packaging, so the style priority needs to be adjusted according to the project.

This code also needs attention. If the company directly uses the external network, then you can directly use the third URL. If the company uses the internal network that cannot access external web pages, you can download the css style of the element version of the project through the third URL and put the css file in the project, but be careful to put it in the folder that will not be compiled. My project uses vue cli4, so the css file I dynamically converted is placed in the public folder. The style file in the assets folder will be compiled, so the path will report 404, and the url used in this block is the path of the style after the file is packaged and compiled. This is worth noting.

2. If some style colors in the project do not use element, you can cache the color in vuex, and then obtain it through calculated properties in the specific step and then dynamically bind it to the style

vuex:

Components used:

This concludes this article about the sample code for implementing dynamic skin changing with vue+element. For more relevant vue+element dynamic skin changing content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Integration practice of Vue+Element background management framework
  • Use Element+vue to implement start and end time limits
  • Antdesign-vue combined with sortablejs to achieve the function of dragging and sorting two tables
  • Detailed explanation of dragging table columns using Vue Element Sortablejs

<<:  Docker+K8S cluster environment construction and distributed application deployment

>>:  VS2019 connects to mysql8.0 database tutorial with pictures and text

Recommend

Serial and parallel operations in JavaScript

Table of contents 1. Introduction 2. es5 method 3...

The meaning of status code in HTTP protocol

A status code that indicates a provisional respon...

The difference between HTML name id and class_PowerNode Java Academy

name Specify a name for the tag. Format <input...

How to configure MySQL master-slave synchronization in Ubuntu 16.04

Preparation 1. The master and slave database vers...

Vue component library ElementUI realizes the paging effect of table list

ElementUI implements the table list paging effect...

Vue implements local storage add, delete and modify functions

This article example shares the specific code of ...

How to use a game controller in CocosCreator

Table of contents 1. Scene layout 2. Add a handle...

HTML basic syntax is convenient for those who are just starting to learn HTML

1.1 General marking A general tag consists of an ...

HTML+CSS+JS to implement the Don't Step on the Whiteboard game

Table of contents Background 1. Thought Analysis ...

Common writing examples for MySQL and Oracle batch insert SQL

Table of contents For example: General writing: S...

A brief discussion on the principle of js QR code scanning login

Table of contents The essence of QR code login Un...

Design Tips: We think you will like it

<br />Looking at this title, you may find it...

Native JS to implement paging click control

This is an interview question, which requires the...