实现思路
-
使用rem相对单位,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应
-
rem是相对于根元素,这样就意味着,我们只需要在根元素确定一个px字号,子元素使用rem单位来设置字体大小,则可以根据根元素的字号自适应算出子元素的字体大小
-
此案例涉及到多窗口,所以使用了pinia并持久化数据,在app.vue里监听持久化数据,达到统一修改所有窗体字体大小的效果
-
父窗口把改变持久化数据的方法挂载至window对象,window对象是共享的,子窗口则可以调用
pinia仓库【globalStore.ts】
export const useGlobalStore = defineStore('globalStore',{
state: () => {
fontSize: 14,//字体大小
},
getters: {
getFontSize: (state) => {
return state.fontSize;
},
},
persist: {
//部分持久化
key: 'globalStore', //缓存key
storage: window.localStorage, //缓存方式
// 部分持久化状态的点符号路径数组,默认持久化所有数据
paths: [
'fontSize',
]
}
})
封装的公共函数【y9_utils.ts】
import { useGlobalStore } from '@/store/modules/globalStore';
//根据字体大小值来改变html的样式名
export const changeFontSize = (fontSize) => {
document.getElementsByTagName("html")[0].className = `${useGlobalStore().getThemeName} font-size-${fontSize}`
//注意:项目里的设置字体大小的样式请使用rem单位,这样只需要更改html的fontSize,就可以达到全局更新的效果
}
全局样式【global.scss】
html{
font-size: 14px;
}
.font-size-12{
font-size: 12px;
}
.font-size-14{
font-size: 14px;
}
.font-size-16{
font-size: 16px;
}
.font-size-18{
font-size: 18px;
}
.font-size-20{
font-size: 20px;
}
:root{//更改element元素的字体大小
--el-font-size-extra-large: 1.42rem !important;
--el-font-size-large: 1.28rem !important;
--el-font-size-medium: 1.14rem !important;
--el-font-size-base: 1rem !important;
--el-font-size-small: 0.92rem !important;
--el-font-size-extra-small: 0.85rem !important;
.el-dialog{
--el-dialog-content-font-size: 1rem !important;
}
--el-message-close-size: 1.14rem !important;
}
在app文件里监听缓存,就可以达到所有打开的子窗口都能够变化字体大小的效果。【app.vue】
import { useGlobalStore } from '@/store/modules/globalStore';
const globalStore = useGlobalStore(); //全局仓库
import { changeFontSize } from '@/js/y9_utils';
//首次执行
changeFontSize(globalStore.getFontSize);//更改字体大小
//监听缓存,首次不会触发,缓存变化才会触发(window.addEventListener('storage'没办法监听同一页面的变化,所以父窗口需要自己触发,这里的监听只在子窗口生效)
window.addEventListener('storage', (event) => {//监听浏览器的缓存
if(event.key === 'globalStore'){//当key为globalStore的缓存变化时触发
try{
const newGlobalStoreObj = JSON.parse(event.newValue);//新值解析成object对象
if(event.oldValue){
const oldGlobalStoreObj = JSON.parse(event.oldValue)//旧值解析成object对象
if(newGlobalStoreObj.fontSize !== oldGlobalStoreObj.fontSize){///判断字体大小新旧值不一致时,执行改变主题色的方法
changeFontSize(newGlobalStoreObj.fontSize);//更改字体大小
}
}
}catch(e){
}
}
})
父窗口 【index.vue】
<template>
<div class="text">我是文本</div>
</template>
<script lang="ts" setup>
import { useGlobalStore } from '@/store/modules/globalStore';
const globalStore = useGlobalStore(); //全局仓库
import { changeFontSize } from '@/js/y9_utils';
//挂载一个y9ChangeGlobalStore函数到window上,这样子窗口也可以获取得到
window['y9ChangeGlobalStore'] = (key,value) => {
//更改pinia的值
globalStore.$patch(state => {
state[key] = value
})
//app.vue文件的监听浏览器缓存在父窗口不起作用,所以需要手动更改
switch(key){
case 'fontSize':
changeFontSize(value);
break;
}
}
</script>
<style lang="scss" scoped>
.text{
font-size: 2rem;//使用rem单位,就能相对于根节点html的fontSize进行变化
}
</style>
子窗口【setting.vue】
<template>
<div class="setting-container-item item-flex">
<div class="label">字体大小:</div>
<div class="font-size-slider">
<el-slider v-model="fontSize" :step="2" show-stops :marks="fontSizeMarks" :max="20" :min="12" @input="onChangeFontSize"/>
</div>
</div>
</template>
<script lang="ts" setup>
import { useGlobalStore } from '@/store/modules/globalStore';
const globalStore = useGlobalStore();
//字体大小
const fontSize = ref<number>(globalStore.getFontSize);
interface Mark {
style: CSSProperties,
label: string
}
type Marks = Record<number,Mark | string>
//字体大小滑块标记
const fontSizeMarks = reactive<Marks>({
12: '小',
20: {
style: {
fontSize: '20px',
},
label:"大"
},
})
const onChangeFontSize = (fontSize:number) => {
//执行父窗口挂载在window上的y9ChangeGlobalStore方法
window.opener['y9ChangeGlobalStore']('fontSize',fontSize)
}
</script>
子窗口的设置字体大小样式效果截图