Vue:通过js控制css变量 - 一键修改全局样式
背景
最近接到一个需求:在Vue
(版本是2.x)页面有个控制字体大小的选项,修改后全局表格内的字体会变化,且要新打开的页面也会变化。
需求整理
- 在页面上方设置一个修改布局大小的选项
- 点击后会出现滚动条,字体范围为9到23px,默认值为14px
- 拖动字体滚动条时,页面表格字体会随着滚动条值的变化而变化
- 用户每次打开页面时会读取上次设置的字体大小
本文章会记录完成这个需求的思考过程,如果需要直接看代码请拉至"代码实现"章节。
系统现状
技术框架:vue2+ElementUI
,基于若依管理系统的二次开发系统
实现思路
ElementUI
有个控制全局大小的size
变量,只要使用的控件不添加size
属性,就会读取全局的size
变量进行相应大小的展示。- 但该设置只能设置为预设的4种大小(
default
,meduim
,small
,mini
)无法满足需求中的设置字体大小为指定像素(px
)。
- 但该设置只能设置为预设的4种大小(
- 通过修改全局样式
scss
样式文件,需要在每个class
声明fontSize
样式
由上述思考后,决定采用方法2,但如果我用js
每次都更新一大堆class
中的fontSize
,那太痛苦了,如果使用到的class
中fontSize
属性能动态读取同一个变量,用户修改该变量的值后引用该变量的class
值都能改变,那我只用js
修改一个变量即可,那有没有这种方法呢?
css如何读取某个变量
CSS
变量(也称为 CSS 自定义属性)允许你在 CSS 中定义可重用的值。具体特点如下:定义:通过
--
前缀命名,在:root
或其他选择器(如其他的class
)中定义。
使用:通过var()
函数在CSS
属性值中引用。
作用:提高样式的可维护性和一致性,便于全局修改样式。
/* 可由js控制的css传参*/
:root {
--table-font-size: 14px;
--ux-grid-height: 31px;
}
/* 使用var引用--table-font-size和--ux-grid-height变量,后文的ux-grid使用了.elx-table样式类*/
.elx-table.size--default {
font-size: var(--table-font-size);
height: var(--ux-grid-height);
padding-top: 2px;
/* 使用var引用--table-font-size变量*/
.el-button {
font-size: var(--table-font-size);
/* 结合calc和min函数一起使用*/
padding-top: min(calc(var(--ux-grid-height) - var(--table-font-size) - 13px), 20px);
}
}
既然css
已经提供了这种方法,那么最后一个小需求实现起来就更容易了:每次修改字体大小时触发值改变事件,修改字体大小后将值保存在cookie
和vuex
中,用户每次登陆时获取cookie
中的值,如果没有值则默认取:root
的大小。
代码实现
<template>
<el-tooltip content="调整字体" effect="dark" placement="bottom">
<el-popover class="right-menu-item hover-effect"
placement="bottom"
width="200"
trigger="click">
<el-slider :min="9" :max="23" v-model="fontSize" :format-tooltip="(value)=>value + '像素'" @change="changeFontSize"></el-slider>
<i slot="reference" class="el-icon-s-operation"></i>
</el-popover>
</el-tooltip>
</template>
created() {
this.fontSize = parseFloat(this.$store.state.app.tableFontSize)
this.updateCssSize(CSS_FONT_SIZE_NAME, this.fontSize)
},
data() {
return {
fontSize: 0
}
},
/**
* 值变化事件
*/
methods: {
/** 修改字体大小事件*/
changeFontSize(amount) {
this.updateCssSize(CSS_FONT_SIZE_NAME, amount)
// 保存到vuex中
this.$store.dispatch('app/setTableFontSize', amount)
// 表格的行高为fontSize+17,让行高随着字体的变化而变化
let uxGridHeight = '--ux-grid-height'
this.updateCssSize(uxGridHeight, amount + 17)
this.refreshView()
},
/** 修改样式属性值 */
updateCssSize(prop, value) {
const newVal = parseFloat(value)
document.documentElement.style.setProperty(prop, newVal + 'px');
},
/** 重新加载已打开的其他标签页*/
refreshView() {
this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
const { fullPath } = this.$route
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
})
})
}
}
// 在vuex中的代码
const mutations = {
TOGGLE_SIDEBAR: state => {
SET_TABLE_FONT_SIZE: (state, fontSize) => {
state.tableFontSize = fontSize
Cookies.set('tableFontSize', fontSize)
}
}
}
// 在app.js中的代码
const state = {
tableFontSize: Cookies.get('tableFontSize') || window.getComputedStyle(document.documentElement).getPropertyValue('--table-font-size')
}
总结
作为一个常年写java代码的开发人员真的感觉css出神入化,之前还停留在css只能写静态属性的印象中,没想到已经这么方便