autofit.js
autofit.js是一个可以让你的PC项目自适应屏幕的工具,其原理非常简单,即在scale等比缩放的基础上,向右或向下增加了宽度或高度,以达到充满全屏的效果,使用autofit.js不会挤压、拉伸元素,它只是单纯的设置了容器的宽高。
源码
let currRenderDom = null;
let currelRectification = ''
let currelRectificationLevel = ''
let resizeListener = null;
let timer = null
let currScale = 1
let isAutofitRunnig = false
let isElRectification = false
const autofit = {
init(options = {}, isShowInitTip = true) {
if (isShowInitTip) {
console.log(`%c` + `autofit.js` + ` is running`, `font-weight: bold; color: #ffb712; background:linear-gradient(-45deg, #bd34fe 50%, #47caff 50% );background: -webkit-linear-gradient( 120deg, #bd34fe 30%, #41d1ff );background-clip: text;-webkit-background-clip: text; -webkit-text-fill-color:linear-gradient( -45deg, #bd34fe 50%, #47caff 50% ); padding: 8px 12px; border-radius: 4px;`);
}
const {
designWidth = 1920,
dw = 1920,
designHeight = 929,
dh = 929,
renderDom = typeof options === 'string' ? options : "#app",
el = typeof options === 'string' ? options : "#app",
resize = true,
ignore = [],
transition = 'none',
delay = 0
} = options;
currRenderDom = el || renderDom;
let dom = document.querySelector(el)
if (!dom) {
console.error(`autofit: '${el}' is not exist`);
return
}
const style = document.createElement('style');
const ignoreStyle = document.createElement('style');
style.lang = 'text/css';
ignoreStyle.lang = 'text/css';
style.id = 'autofit-style';
ignoreStyle.id = 'ignoreStyle';
style.innerHTML = `
body {
overflow: hidden;
}
`;
dom.appendChild(style);
dom.appendChild(ignoreStyle);
dom.style.height = `${dh || designHeight}px`;
dom.style.width = `${dw || designWidth}px`;
dom.style.transformOrigin = `0 0`;
keepFit(dw || designWidth, dh || designHeight, dom, ignore);
resizeListener = () => {
clearTimeout(timer)
if (delay != 0)
timer = setTimeout(() => {
keepFit(dw || designWidth, dh || designHeight, dom, ignore);
isElRectification && elRectification(currelRectification, currelRectificationLevel)
}, delay)
else {
keepFit(dw || designWidth, dh || designHeight, dom, ignore);
isElRectification && elRectification(currelRectification, currelRectificationLevel)
}
}
resize && window.addEventListener('resize', resizeListener)
isAutofitRunnig = true
setTimeout(() => {
dom.style.transition = `${transition}s`
});
},
off(el = "#app") {
try {
isElRectification = false
window.removeEventListener("resize", resizeListener);
document.querySelector('#autofit-style').remove();
document.querySelector(currRenderDom ? currRenderDom : el).style = '';
for (let item of document.querySelectorAll(currelRectification)) {
item.style.width = ``
item.style.height = ``
item.style.transform = ``
}
} catch (error) {
console.error(`autofit: Failed to remove normally`, error);
isAutofitRunnig = false
}
isAutofitRunnig && console.log(`%c` + `autofit.js` + ` is off`, `font-weight: bold;color: #707070; background: #c9c9c9; padding: 8px 12px; border-radius: 4px;`);
},
}
function elRectification(el, level = 1) {
if (!isAutofitRunnig) {
console.error("autofit.js:autofit has not been initialized yet")
}
!el && console.error(`autofit.js:bad selector: ${el}`)
currelRectification = el
currelRectificationLevel = level
const currEl = document.querySelectorAll(el)
if (currEl.length == 0) {
console.error("autofit.js:elRectification found no element")
return
}
for (let item of currEl) {
if (!isElRectification) {
item.originalWidth = item.clientWidth
item.originalHeight = item.clientHeight
}
let rectification = currScale == 1 ? 1 : currScale * level
item.style.width = `${item.originalWidth * rectification}px`
item.style.height = `${item.originalHeight * rectification}px`
item.style.transform = `scale(${1 / currScale})`
item.style.transformOrigin = `0 0`
}
isElRectification = true
}
function keepFit(dw, dh, dom, ignore) {
let clientHeight = document.documentElement.clientHeight;
let clientWidth = document.documentElement.clientWidth;
currScale = (clientWidth / clientHeight < dw / dh) ? (clientWidth / dw) : (clientHeight / dh)
dom.style.height = `${clientHeight / currScale}px`;
dom.style.width = `${clientWidth / currScale}px`;
dom.style.transform = `scale(${currScale})`
for (let item of ignore) {
let itemEl = item.el || item.dom
if (!itemEl) {
console.error(`autofit: bad selector: ${itemEl}`)
continue
}
let realScale = (item.scale ? item.scale : 1 / currScale)
let realFontSize = realScale != currScale ? item.fontSize : 'autofit'
let realWidth = realScale != currScale ? item.width : 'autofit'
let realHeight = realScale != currScale ? item.height : 'autofit'
let regex = new RegExp(`${itemEl}(\x20|{)`, 'gm')
let isIgnored = regex.test(document.querySelector('#ignoreStyle').innerHTML);
if (isIgnored) {
continue
}
document.querySelector('#ignoreStyle').innerHTML += `\n${itemEl} {
transform: scale(${realScale})!important;
transform-origin: 0 0;
width: ${realWidth}px!important;
height: ${realHeight}px!important;
}`;
document.querySelector('#ignoreStyle').innerHTML += `\n${itemEl} div ,${itemEl} span,${itemEl} a,${itemEl} * {
font-size: ${realFontSize}px;
}`;
}
}
export {
elRectification
}
export default autofit;
类型
declare interface autofit {
/**
* 参数列表
* 对象:
*
* @param {Object|String} options
* - 传入对象,对象中的属性如下:
* - el(可选):渲染的元素,默认是 "#app"
* - dw(可选):设计稿的宽度,默认是 1920
* - dh(可选):设计稿的高度,默认是 929 ,如果项目以全屏展示,则可以设置为1080
* - resize(可选):是否监听resize事件,默认是 true
* - ignore(可选):忽略缩放的元素(该元素将反向缩放),参数见readme.md
* - transition(可选):过渡时间,默认是 0
* - delay(可选):延迟,默认是 0
*/
init(options: { el: String, dw: Number, dh: Number, resize: Boolean, ignore: Array<Object>, transition: Number, delay: Number } | String): void;
/**
* @param {String} id
* 关闭autofit.js造成的影响
*
*/
off(id: String): void;
}
declare const autofit: autofit;
export default autofit;
使用
export default {
mounted() {
autofit.init({
dh: 1080,
dw: 1920,
el:"#app",
resize: true
},false) // 可关闭控制台运行提示输出
},
}
- 以上使用的是默认参数,可根据实际情况调整,可选参数有
- el:渲染的dom,默认是 "#app",必须使用id选择器
- dw:设计稿的宽度,默认是 1920
- dh:设计稿的高度,默认是 929 ,如果项目以全屏展示,则可以设置为1080
- resize:是否监听resize事件,默认是 true
- ignore:忽略缩放的元素(该元素将反向缩放),参数见readme.md
- transition:过渡时间,默认是 0.6
- delay:默认是 1000
忽略某些元素
autofit.init({
ignore: [
{
dom: ".gaodeMap",
},
]
})
传入 ignore 以使元素不被缩放
更个性化的设置:
autofit.init({
ignore: [
{
dom: ".gaodeMap", //必填
height: 300,//可选,写数字即可(px)
width: 300,//可选,写数字即可(px)
scale:1.2, //可选:回放程度,基于主元素缩放后的大小
fontSize:26 //可选,如果自定义缩放后文字大小不合适,可以在这里设置文字大小
},
{
//...
}
]
})
如果反向缩放后的元素大小使结构发生变化,你还可以手动传入宽高、回放程度。
elRectification
一些canvas渲染的图表也会有事件偏移,而图表不同于地图,当使用ignore时,过大的图表可能会显示不全,因此可以使用elRectification (性能上不如ignore)
如果ignore无法满足需求,可以使用 autofit.elRectification(".classNameOrId")
import { elRectification } from 'autofit.js'
<div class="G2plot"></div>
<div class="G2plot"></div>
<div class="G2plot"></div>
onMounted(() => {
elRectification(".G2plot")
})
使用 elRectification 时,需要被矫正的元素已经挂载
关闭 autofit.js造成的影响
autofit.off()