rem+vue3+pinia+element-plus实现同时改变多窗口的字体大小

实现思路

  • 使用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>

子窗口的设置字体大小样式效果截图

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值