1.0.2 • Published 3 years ago
set-font-size v1.0.2
utils - setFontSize - 设置字体大小
intro
原理
使用 postcss-plugin-px2rem
将 px
转为rem
,在根节点设置font-size
notice
webpack ie 兼容
rem 是基于html,不是body
style
postcss-plugin-px2rem
未转换 style
内 px
解决方案
- 调用转换方法
// xxx.vue
<el-table-column
:width="pxtorem(100)"
></el-table-column>
/**
* @method pxtorem
* @param {*} size Number|String 转换大小
* @param {*} base Number|String 基础大小 1rem对应px值
* @returns
*/
export function pxtorem(size = 0, base = 16) {
let baseSize = formatValue(document.documentElement.style.fontSize);
base = formatValue(base);
return baseSize === base
? formatValue(size)
: (formatValue(size) * baseSize) / base;
}
export function formatValue(val, offset = 1.03) {
let type = Object.prototype.toString.call(val).slice(8, -1),
methods = {
String: () => Number(val.replace('px', '')),
Number: () => val,
};
return methods[type]
? (() => {
return methods[type]() * offset;
})()
: (() => {
throw new Error(
`Params not support ${type}, please use String or Number!!!`
);
})();
}
utils
/**
* @class 设置字号
* @description
* @version
* - 20220125
1. 避免刷新页面重新请求接口,只做页面重排
2. 添加响应式
1. 根据屏幕尺寸变化设置不同字体大小
3. 初始化
1. 优先指定(缓存设置)
2. 响应式自动设置
*/
class SetFontSize {
constructor(options = {}) {
Object.assign(
this,
{
currentType: null, // 当前类型
defaultType: null, // 默认类型,
openResize: true, // 启用响应式
// 响应式目标:
// resizeTarget:'window', // 分辨率
resizeTarget: 'document', // 浏览器窗口
currentResizeKey: null, // 当前分辨率 key 值
// 响应式尺寸项: <= key 时,取 value
resizeOptions: {
1366: 'small',
1920: 'medium',
},
// 字体大小类型
types: {
default: '',
large: 18,
medium: 16,
small: 14,
mini: 12,
},
change: null, // Function
iframeDom: null,
},
options
);
}
init(options = {}) {
Object.assign(this, options);
// console.log(this);
this.resizeOptionsToArray();
// 初始化,有指定值则指定,无则根据屏幕尺寸自动设置
this.defaultType ? this.set() : this.resize();
if (this.openResize)
window.onresize = this.throttle(this.resize.bind(this));
// 不 bind 则 this = Window
}
resize() {
let type = this.getResizeType();
if (type !== this.currentType) this.set(type);
}
resizeOptionsToArray() {
this.resizeOptionsArray = Object.entries(this.resizeOptions)
.map((v) => {
return {
size: v[0],
type: v[1],
};
})
.sort((a, b) => a.size - b.size);
}
getResizeType() {
const widths = {
window: () => window.screen.width,
document: () => document.body.clientWidth,
};
const resizeWidth = widths[this.resizeTarget]();
for (let { size, type } of this.resizeOptionsArray) {
if (resizeWidth <= size) {
this.currentResizeKey = size;
return type;
}
}
return 'small';
}
set(type = this.defaultType || 'small') {
// console.log(type, this.types[type]);
if (!this.types[type]) {
console.warn(`${type} fontSize not exist!!!`);
return this.resize();
}
document.documentElement.style.fontSize = this.types[type] + 'px';
if (type !== this.currentType) {
this.currentType = type;
if (typeof this.change === 'function') this.change(type);
}
if (this.iframeDom) this.setIframe();
}
initIframe(iframeDom) {
this.iframeDom = iframeDom;
Object.assign(iframeDom, {
onload: this.iframeOnload.bind(this),
});
}
setIframe(type = this.currentType) {
this.iframeDom.contentDocument.documentElement.style.fontSize = this.types[type] + 'px';
}
iframeOnload() {
this.setIframe();
}
throttle(func, delay = 1000) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
};
}
}
export default new SetFontSize();
使用
初始化
// /main.js
import setFontSize from '@/utils/setFontSize';
import { resizeOptions } from '@/config';
setFontSize.init({
resizeOptions {
1366: 'mini',
1920: 'medium',
1520: 'small',
},
defaultType: Cookies.get('size'),
change: (size) => {
store.commit('config/SET_SIZE', size);
},
});
change.vue
<template>
<el-dropdown trigger="click" @command="handleSetSize">
<div>
<svg-icon class-name="size-icon" icon-class="size" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
{{
item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
data() {
return {
sizeOptions: [
{ label: 'Default', value: 'default' },
{ label: 'Large', value: 'large' },
{ label: 'Medium', value: 'medium' },
{ label: 'Small', value: 'small' },
{ label: 'Mini', value: 'mini' }
]
}
},
computed: {
size() {
return this.$store.state.config.size
}
},
methods: {
handleSetSize(size) {
this.$ELEMENT.size = size
this.$store.dispatch('config/setSize', size)
// this.refreshView() // 避免重新请求接口
this.$message({
message: 'Switch Size Success',
type: 'success'
})
},
refreshView() {
// In order to make the cached page re-rendered
this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
const { fullPath } = this.$route
this.$nextTick(() => {
// redirect router
// path: '/redirect/:path(.*)'
this.$router.replace({
path: '/redirect' + fullPath
})
})
}
}
}
</script>
iframe 同步 rem
setFontSize.initIframe(this.$refs.iframeDom);
// utils 原理
initIframe(iframeDom) {
this.iframeDom = iframeDom;
Object.assign(iframeDom, {
onload: this.iframeOnload.bind(this),
});
}
setIframe(type = this.currentType) {
this.iframeDom.contentDocument.documentElement.style.fontSize = this.types[type] + 'px';
}
set(type = this.defaultType || 'small') {
// console.log(type, this.types[type]);
if (!this.types[type]) {
console.warn(`${type} fontSize not exist!!!`);
return this.resize();
}
document.documentElement.style.fontSize = this.types[type] + 'px';
if (type !== this.currentType) {
this.currentType = type;
if (typeof this.change === 'function') this.change(type);
}
if (this.iframeDom) this.setIframe();
}
store
// @/store/modules/config.js
import setFontSize from '@/utils/setFontSize'
const state = {
size: Cookies.get('size') || 'medium',
}
const mutations = {
SET_SIZE: (state, size) => {
state.size = size
Cookies.set('size', size)
}
}
const actions = {
setSize({ commit }, size) {
setFontSize.set(size)
commit('SET_SIZE', size)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}