1. 程式人生 > 程式設計 >vue+element實現動態換膚的示例程式碼

vue+element實現動態換膚的示例程式碼

有時候一個專案的主題並不能滿足所有人的審美,這時候換膚功能就很友好,本專案基於+element實現後臺管理專案的換膚功能

1.建立換膚元件

<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.on").version; // element-ui version from node_modules
const ORIGINAL_THEME = "#409EFF"; // default color
export default {
  name: "ThemePicker",props: {
    default: {
      // 初始化主題,可由外部傳入
      type: String
      // default: '#2668b1'
      // default: `${localStorage.getItem("tremePackers")==null?"#C60404":localStorage.getItem("tremePackers")}`
    }
    // size: { // 初始化主題,可由外部傳入
    //   type: String,/
/ default: 'small' // },},data() { return { chalk: "",// content of theme-chalk theme: ORIGINAL_THEME,showSuccess: true,// 是否彈出換膚成功訊息 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( www.cppcns.com
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`;//本地css樣式地址 // const url = `./dist/index.css`;//專案打包後css地址(原檔案放入public資料夾中) // 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,themeCluster ); }); http://www.cppcns.com
this.$store.commit("themColor",val);//將更換的顏色存入store this.$emit("onThemeChange",val); // 響應外部操作 //存入localStorage // localStorage.setItem('tremePackers',val); // if(this.showSuccess) { // http://www.cppcns.comthis.$message({ // message: '換膚成功',// 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 = () http://www.cppcns.com=> { 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,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>

vue+element實現動態換膚的示例程式碼

上面這塊程式碼值得注意,紅框裡的程式碼是在head裡所有節點後插入一個新的style標籤,打包後優先順序較高,但有個問題,有些地方的顏色直接消失變成空白影響了樣式,於是改成綠框裡的程式碼,但綠框裡的程式碼打包後優先順序會低於原來樣式顏色的而優先順序,所以需要根據專案調樣式優先順序

vue+element實現動態換膚的示例程式碼

這塊的程式碼也需要注意,如果公司直接使用的外網那麼直接使用第三個url就行,如果公司使用的內網訪問不了外部那麼可以通過第三條url下載專案對應element版本的css樣式,把css檔案放到專案裡,但要注意放到不會被編譯的問價夾裡,我專案用的是vue cli4,所以我動態轉換的css檔案放在public資料夾裡,放到assets問價夾中樣式檔案會被編譯,因而路徑會報404,並且這塊使用的url是檔案打包編譯後樣式的路徑,這是值得注意的地方

2.如果專案中有的樣式顏色沒有用到element,可以把顏色快取到vuex裡,然後在具體逐漸裡通過計算屬性獲取再在樣式上動態繫結

vuex:

vue+element實現動態換膚的示例程式碼

使用的元件中:

vue+element實現動態換膚的示例程式碼

vue+element實現動態換膚的示例程式碼

到此這篇關於vue+element實現動態換膚的示例程式碼的文章就介紹到這了,更多相關vue+element動態換膚內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!