自定义主题

1.安装「主题生成工具」

由于主题工具需要依赖于 node-sass,而node-sass版本兼容性并不好,对应 node 版本可能不兼容直接执行npm i element-theme -g所安装的版本,因此需要自行先安装对应 node 版本的node-sass.

对应版本如下

NodeJS Minimum node-sass version Node Module
Node 14 4.14+ 83
Node 13 4.13+ 79
Node 12 4.12+ 72
Node 11 4.10+ 67
Node 10 4.9+ 64
Node 8 4.5.3+ 57

因为我这里的 node 版本是 12.18.1

# 先安装node-sass
set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ npm install node-sass@4.12.0 --save npm i element-theme -g

特别说明: 若出现 gyp verb check python checking for Python executable "python" in the PATH 错误时。可执行,出现 all done 就算安装完成。

npm install -g node-gyp
npm install --global --production windows-build-tools

2.安装白垩主题

可以从 npm 安装或者从 GitHub 拉取最新代码。

# 从 npm
npm i element-theme-chalk -D # 从 GitHub
npm i https://github.com/ElementUI/theme-chalk -D

3.新建颜色挑选组件

注意:ORIGINAL_THEME 值不能改变,否则默认按钮颜色不会改变。

代码如下:

<template>
<el-tooltip effect="dark" content="换肤" placement="bottom">
<el-color-picker class="theme-picker" popper-class="theme-picker-dropdown" v-model="theme" :size="size"> </el-color-picker>
</el-tooltip>
</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: {
// 初始化主题,可由外部传入
type: String,
default: null,
},
size: {
// 初始化主题,可由外部传入
type: String,
default: 'small',
},
},
data() {
return {
chalk: '', // content of theme-chalk css
theme: ORIGINAL_THEME,
showSuccess: true, // 是否弹出换肤成功消息
}
},
mounted() {
if (this.default != null) {
this.theme = this.default
this.$emit('onThemeChange', this.theme)
this.showSuccess = false
}
},
watch: {
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)
}
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)
}) // 响应外部操作
this.$emit('onThemeChange', val)
if (this.showSuccess) {
this.$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 = () => {
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 对应 vue 模块中,添加颜色管理的状态值。

在 头部添加 颜色选择的组件,供全局选择,代码如下:

import ThemePicker from '@/components/ThemePicker'
//引入组件
components: { ThemePicker }, //使用
<theme-picker
:default="themeColor"
@onThemeChange="onThemeChange">
</theme-picker> methods: {
// 切换主题方法
onThemeChange (themeColor)
{
this.$store.commit("setThemeColor", themeColor);
}
} //将颜色用状态管理器管理。

在每次颜色改变时,设置到 state.themeColor 上,在各个需要改变皮肤的地方,从 state 中取出来,然后赋值进去。

原文地址:http://book.levy.net.cn/doc/frontend/uiframe/custom_theme.html

Vue管理系统前端系列五自定义主题的更多相关文章

  1. Vue管理系统前端系列一vue-cli4.x 初始化项目

    目录 项目介绍 技术基础 开发环境 安装工具 快速原型开发 创建项目 配置相关说明 目录结构 项目介绍 lion-ui 是一个基于 RBAC 的管理系统前端项目,采用 vue 和 element-ui ...

  2. Vue管理系统前端系列三登录页和首页及`vuex`管理登录状态

    目录 登录页面设计 vuex 对应 用户模块 丰富界面 首页相关代码 登录页面设计 该节记录了登录界面的设计,以及 vuex 的简单实用,然后将首页简单搭建完成. 先看最终效果图 先在 views 文 ...

  3. Vue管理系统前端系列六动态路由-权限管理实现

    目录 为什么要使用动态路由? 主流的两种实现方式 前端控制 后端控制 后端控制路由 实现 添加菜单接口 及 菜单状态管理 根据得到的菜单生成动态路由 根据 vuex 中的暂存的菜单生成侧边菜单栏 退出 ...

  4. Vue管理系统前端系列二相关工具引入及封装

    目录 sass-loader/vuex 等的引入说明 引入 element 引入 axios 1.基本使用 2.封装使用 2.1 开发环境配置请求地址 2.2 配置代理 2.3 添加接口相关文件 sa ...

  5. Vue管理系统前端系列四组件拆分封装

    目录 组件封装 首页布局拆分后结构 拆分后代码 状态管理中添加 app 模块 组件封装 在上一篇记录中,首页中有太多的代码,为了避免代码的臃肿,需要对主要的功能模块拆分,来让代码看起来更简洁,且能进行 ...

  6. Vue + Element UI 实现权限管理系统 前端篇(八):管理应用状态

    使用 Vuex 管理应用状态 1. 引入背景 像先前我们是有导航菜单栏收缩和展开功能的,但是因为组件封装的原因,隐藏按钮在头部组件,而导航菜单在导航菜单组件,这样就涉及到了组件收缩状态的共享问题.收缩 ...

  7. vue 快速入门 系列 —— vue-cli 下

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 下 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  8. [后端人员耍前端系列]AngularJs篇:30分钟快速掌握AngularJs

    一.前言 对于前端系列,自然少不了AngularJs的介绍了.在前面文章中,我们介绍了如何使用KnockoutJs来打造一个单页面程序,后面一篇文章将介绍如何使用AngularJs的开发一个单页面应用 ...

  9. vue.js学习系列-第一篇

    VUE系列一 简介    vue是一个兴起的前端js库,是一个精简的MVVM.从技术角度讲,Vue.js专注于 MVVM 模型的 ViewModel 层.它通过双向数据绑定把 View 层和 Mode ...

随机推荐

  1. Android 文件存储浅析

    最近做的一个需求和文件存储有关系.由于之前没有系统梳理过,对文件存储方面的知识一直很懵懂.趁着周末有时间,赶紧梳理一波. 这首从网上找到的一张图,很好的概括了外部存储和内部存储. 下面我们再来具体介绍 ...

  2. acwing 173. 矩阵距离(bfs)

    给定一个N行M列的01矩阵A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为: dist(A[i][j],A[k][l])=|i−k|+|j−l|dist(A[i][j],A[k][l]) ...

  3. Python访问字符串中的值

    Python访问字符串中的值: 1.可以使用索引下标进行访问,索引下标从 0 开始: # 使用索引下标进行访问,索引下标从 0 开始 strs = "ABCDEFG" print( ...

  4. lamp架构搭建

    目录 1. LAMP架构介绍 2.web服务器工作流程 2.1 cgi与fastcgi 2.2 httpd与php结合的方式 2.3 web工作流程 3. lamp平台搭建 3.1 安装httpd 3 ...

  5. 3月21日考试 题解(数据结构+区间DP+贪心)

    前言:T3写挂了,有点难受. --------------- T1 中位数 题意简述:给你一段长度为$n$的序列,分别输出$[1,2k-1]$的中位数$(2k-1\leq n)$. --------- ...

  6. ios 富文本 加颜色 删除线

    UILabel *valueL = [JAppViewTools getLabel:CGRectMake(JFWidth(15), CGRectGetMaxY(proName.frame)+JFWid ...

  7. 强大的输入框-应用快速启动uTools

    uTools uTools是一个 极简.插件化.跨平台 的现代桌面软件.通过自由选配丰富的插件,打造你得心应手的工具集合. 当你熟悉它后,能够为你节约大量时间,让你可以更加专注地改变世界. uTool ...

  8. JAVA程序设计环境

    JDK ,Java Development Kit(Java开发工具包) JRE ,Java Runtime Environment(Java运行时环境) SE   ,Standard Edition ...

  9. C语言学习笔记之进制之间的转换

    这一篇主要是对进制之间转换的讲解,方便查看,以防忘记 二进制      逢二进一 八进制      逢八进一                以0开头, 0就是8进制的标志 十进制      逢十进一 ...

  10. CRF